16 #include <QRegularExpression> 
   20 void ColorMap::load_cube_file()
 
   22     if (lut_path.empty()) {
 
   25         needs_refresh = 
false;
 
   30     std::vector<float> parsed_data;
 
   32     #pragma omp critical(load_lut) 
   34         QFile file(QString::fromStdString(lut_path));
 
   35         if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
 
   38             QTextStream in(&file);
 
   40             QRegularExpression ws_re(
"\\s+");
 
   44                 line = in.readLine().trimmed();
 
   45                 if (line.startsWith(
"LUT_3D_SIZE")) {
 
   46                     auto parts = line.split(ws_re);
 
   47                     if (parts.size() >= 2) {
 
   48                         parsed_size = parts[1].toInt();
 
   55             if (parsed_size > 0) {
 
   56                 int total = parsed_size * parsed_size * parsed_size;
 
   57                 parsed_data.reserve(
size_t(total * 3));
 
   58                 while (!in.atEnd() && 
int(parsed_data.size()) < total * 3) {
 
   59                     line = in.readLine().trimmed();
 
   61                         line.startsWith(
"#") ||
 
   62                         line.startsWith(
"TITLE") ||
 
   63                         line.startsWith(
"DOMAIN"))
 
   67                     auto vals = line.split(ws_re);
 
   68                     if (vals.size() >= 3) {
 
   70                         parsed_data.push_back(vals[0].toFloat());
 
   71                         parsed_data.push_back(vals[1].toFloat());
 
   72                         parsed_data.push_back(vals[2].toFloat());
 
   75                 if (
int(parsed_data.size()) != total * 3) {
 
   83     if (parsed_size > 0) {
 
   84         lut_size = parsed_size;
 
   85         lut_data.swap(parsed_data);
 
   90     needs_refresh = 
false;
 
   93 void ColorMap::init_effect_details()
 
   98     info.
description = 
"Adjust colors using 3D LUT lookup tables (.cube format)";
 
  104     : lut_path(
""), lut_size(0), needs_refresh(true),
 
  105       intensity(1.0), intensity_r(1.0), intensity_g(1.0), intensity_b(1.0)
 
  107     init_effect_details();
 
  124     init_effect_details();
 
  128 std::shared_ptr<openshot::Frame>
 
  134         needs_refresh = 
false;
 
  137     if (lut_data.empty())
 
  140     auto image = frame->GetImage();
 
  141     int w = image->width(), h = image->height();
 
  142     unsigned char *pixels = image->bits();
 
  149     int pixel_count = w * h;
 
  150     #pragma omp parallel for 
  151     for (
int i = 0; i < pixel_count; ++i) {
 
  153         int A = pixels[idx + 3];
 
  154         float alpha = A / 255.0f;
 
  155         if (alpha == 0.0f) 
continue;
 
  158         float R = pixels[idx + 0] / alpha;
 
  159         float G = pixels[idx + 1] / alpha;
 
  160         float B = pixels[idx + 2] / alpha;
 
  163         float Rn = R * (1.0f / 255.0f);
 
  164         float Gn = G * (1.0f / 255.0f);
 
  165         float Bn = B * (1.0f / 255.0f);
 
  168         float rf = Rn * (lut_size - 1);
 
  169         float gf = Gn * (lut_size - 1);
 
  170         float bf = Bn * (lut_size - 1);
 
  172         int r0 = int(floor(rf)), r1 = std::min(r0 + 1, lut_size - 1);
 
  173         int g0 = int(floor(gf)), g1 = std::min(g0 + 1, lut_size - 1);
 
  174         int b0 = int(floor(bf)), b1 = std::min(b0 + 1, lut_size - 1);
 
  181         int base000 = ((b0 * lut_size + g0) * lut_size + r0) * 3;
 
  182         int base100 = ((b0 * lut_size + g0) * lut_size + r1) * 3;
 
  183         int base010 = ((b0 * lut_size + g1) * lut_size + r0) * 3;
 
  184         int base110 = ((b0 * lut_size + g1) * lut_size + r1) * 3;
 
  185         int base001 = ((b1 * lut_size + g0) * lut_size + r0) * 3;
 
  186         int base101 = ((b1 * lut_size + g0) * lut_size + r1) * 3;
 
  187         int base011 = ((b1 * lut_size + g1) * lut_size + r0) * 3;
 
  188         int base111 = ((b1 * lut_size + g1) * lut_size + r1) * 3;
 
  192         float c00 = lut_data[base000 + 0] * (1 - dr) + lut_data[base100 + 0] * dr;
 
  193         float c01 = lut_data[base001 + 0] * (1 - dr) + lut_data[base101 + 0] * dr;
 
  194         float c10 = lut_data[base010 + 0] * (1 - dr) + lut_data[base110 + 0] * dr;
 
  195         float c11 = lut_data[base011 + 0] * (1 - dr) + lut_data[base111 + 0] * dr;
 
  196         float c0  = c00 * (1 - dg) + c10 * dg;
 
  197         float c1  = c01 * (1 - dg) + c11 * dg;
 
  198         float lr = c0 * (1 - db) + c1 * db;
 
  201         c00 = lut_data[base000 + 1] * (1 - dr) + lut_data[base100 + 1] * dr;
 
  202         c01 = lut_data[base001 + 1] * (1 - dr) + lut_data[base101 + 1] * dr;
 
  203         c10 = lut_data[base010 + 1] * (1 - dr) + lut_data[base110 + 1] * dr;
 
  204         c11 = lut_data[base011 + 1] * (1 - dr) + lut_data[base111 + 1] * dr;
 
  205         c0  = c00 * (1 - dg) + c10 * dg;
 
  206         c1  = c01 * (1 - dg) + c11 * dg;
 
  207         float lg = c0 * (1 - db) + c1 * db;
 
  210         c00 = lut_data[base000 + 2] * (1 - dr) + lut_data[base100 + 2] * dr;
 
  211         c01 = lut_data[base001 + 2] * (1 - dr) + lut_data[base101 + 2] * dr;
 
  212         c10 = lut_data[base010 + 2] * (1 - dr) + lut_data[base110 + 2] * dr;
 
  213         c11 = lut_data[base011 + 2] * (1 - dr) + lut_data[base111 + 2] * dr;
 
  214         c0  = c00 * (1 - dg) + c10 * dg;
 
  215         c1  = c01 * (1 - dg) + c11 * dg;
 
  216         float lb = c0 * (1 - db) + c1 * db;
 
  219         float outR = (lr * tR + Rn * (1 - tR)) * alpha;
 
  220         float outG = (lg * tG + Gn * (1 - tG)) * alpha;
 
  221         float outB = (lb * tB + Bn * (1 - tB)) * alpha;
 
  223         pixels[idx + 0] = 
constrain(outR * 255.0f);
 
  224         pixels[idx + 1] = 
constrain(outG * 255.0f);
 
  225         pixels[idx + 2] = 
constrain(outB * 255.0f);
 
  242     root[
"lut_path"]     = lut_path;
 
  257         throw InvalidJSON(
"Invalid JSON for ColorMap effect");
 
  264     if (!root[
"lut_path"].isNull())
 
  266         lut_path = root[
"lut_path"].asString();
 
  267         needs_refresh = 
true;
 
  269     if (!root[
"intensity"].isNull())
 
  271     if (!root[
"intensity_r"].isNull())
 
  273     if (!root[
"intensity_g"].isNull())
 
  275     if (!root[
"intensity_b"].isNull())
 
  284         "LUT File", 0.0, 
"string", lut_path, 
nullptr, 0, 0, 
false, requested_frame);
 
  289         "float", 
"", &
intensity, 0.0, 1.0, 
false, requested_frame);
 
  294         "float", 
"", &
intensity_r, 0.0, 1.0, 
false, requested_frame);
 
  299         "float", 
"", &
intensity_g, 0.0, 1.0, 
false, requested_frame);
 
  304         "float", 
"", &
intensity_b, 0.0, 1.0, 
false, requested_frame);
 
  306     return root.toStyledString();