17 #include <babl/babl.h> 
   30     init_effect_details();
 
   36     color(color), fuzz(fuzz), halo(halo), method(method)
 
   39     init_effect_details();
 
   43 void ChromaKey::init_effect_details()
 
   50     info.
name = 
"Chroma Key (Greenscreen)";
 
   51     info.
description = 
"Replaces the color (or chroma) of the frame with transparency (i.e. keys out the color).";
 
  100 std::shared_ptr<openshot::Frame> 
ChromaKey::GetFrame(std::shared_ptr<openshot::Frame> frame, int64_t frame_number)
 
  102     int threshold = fuzz.
GetInt(frame_number);
 
  103     int halothreshold = halo.
GetInt(frame_number);
 
  104     long mask_R = color.
red.
GetInt(frame_number);
 
  106     long mask_B = color.
blue.
GetInt(frame_number);
 
  109     std::shared_ptr<QImage> image = frame->GetImage();
 
  111     int width = image->width();
 
  112     int height = image->height();
 
  114     int pixelcount = width * height;
 
  119         static bool need_init = 
true;
 
  127         Babl 
const *rgb = babl_format(
"R'G'B'A u8");
 
  128         Babl 
const *format = 0;
 
  129         Babl 
const *fish = 0;
 
  130         std::vector<unsigned char> pixelbuf;
 
  138             format = babl_format(
"HSV float");
 
  139             rowwidth = width * 
sizeof(float) * 3;
 
  144             format = babl_format(
"HSL float");
 
  145             rowwidth = width * 
sizeof(float) * 3;
 
  151             format = babl_format(
"CIE LCH(ab) float");
 
  152             rowwidth = width * 
sizeof(float) * 3;
 
  156             format = babl_format(
"CIE Lab u8");
 
  157             rowwidth = width * 3;
 
  161             format = babl_format(
"Y'CbCr u8");
 
  162             rowwidth = width * 3;
 
  169         pixelbuf.resize(rowwidth * height);
 
  171         if (rgb && format && (fish = babl_fish(rgb, format)) != 0)
 
  174             unsigned char   mask_in[4];
 
  175             union { 
float f[4]; 
unsigned char u[4]; } mask;
 
  176             float const *pf = (
float *) pixelbuf.data();
 
  177             unsigned char const *pc = pixelbuf.data();
 
  183             babl_process(fish, mask_in, &mask, 1);
 
  190                 babl_process(fish, image->bits(), pixelbuf.data(), pixelcount);
 
  194                 unsigned char *rowdata = pixelbuf.data();
 
  196                 for (
int y = 0; y < height; ++y, rowdata += rowwidth)
 
  197                     babl_process(fish, image->scanLine(y), rowdata, width);
 
  203                 for (
int y = 0; y < height; ++y)
 
  205                     unsigned char *pixel = image->scanLine(y);
 
  207                     for (
int x = 0; x < width; ++x, pixel += 4, pf += 3)
 
  209                         float tmp = fabs(pf[0] - mask.f[0]);
 
  214                         if (tmp <= threshold)
 
  216                             pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
 
  218                         else if (tmp <= threshold + halothreshold)
 
  220                             float alphamult = (tmp - threshold) / halothreshold;
 
  222                             pixel[0] *= alphamult;
 
  223                             pixel[1] *= alphamult;
 
  224                             pixel[2] *= alphamult;
 
  225                             pixel[3] *= alphamult;
 
  233                 for (
int y = 0; y < height; ++y)
 
  235                     unsigned char *pixel = image->scanLine(y);
 
  237                     for (
int x = 0; x < width; ++x, pixel += 4, pf += 3)
 
  239                         float tmp = fabs(pf[1] - mask.f[1]) * 255;
 
  241                         if (tmp <= threshold)
 
  243                             pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
 
  245                         else if (tmp <= threshold + halothreshold)
 
  247                             float alphamult = (tmp - threshold) / halothreshold;
 
  249                             pixel[0] *= alphamult;
 
  250                             pixel[1] *= alphamult;
 
  251                             pixel[2] *= alphamult;
 
  252                             pixel[3] *= alphamult;
 
  260                 for (
int y = 0; y < height; ++y)
 
  262                     unsigned char *pixel = image->scanLine(y);
 
  264                     for (
int x = 0; x < width; ++x, pixel += 4, pf += 3)
 
  266                         float tmp = fabs(pf[2] - mask.f[2]) * 255;
 
  268                         if (tmp <= threshold)
 
  270                             pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
 
  272                         else if (tmp <= threshold + halothreshold)
 
  274                             float alphamult = (tmp - threshold) / halothreshold;
 
  276                             pixel[0] *= alphamult;
 
  277                             pixel[1] *= alphamult;
 
  278                             pixel[2] *= alphamult;
 
  279                             pixel[3] *= alphamult;
 
  286                 for (
int y = 0; y < height; ++y)
 
  288                     unsigned char *pixel = image->scanLine(y);
 
  290                     for (
int x = 0; x < width; ++x, pixel += 4, pc += 3)
 
  292                         int db = (int) pc[1] - mask.u[1];
 
  293                         int dr = (
int) pc[2] - mask.u[2];
 
  294                         float tmp = sqrt(db * db + dr * dr);
 
  296                         if (tmp <= threshold)
 
  298                             pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
 
  300                         else if (tmp <= threshold + halothreshold)
 
  302                             float alphamult = (tmp - threshold) / halothreshold;
 
  304                             pixel[0] *= alphamult;
 
  305                             pixel[1] *= alphamult;
 
  306                             pixel[2] *= alphamult;
 
  307                             pixel[3] *= alphamult;
 
  314                 for (
int y = 0; y < height; ++y)
 
  316                     unsigned char *pixel = image->scanLine(y);
 
  318                     for (
int x = 0; x < width; ++x, pixel += 4, pf += 3)
 
  320                         float tmp = fabs(pf[0] - mask.f[0]);
 
  322                         if (tmp <= threshold)
 
  324                             pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
 
  326                         else if (tmp <= threshold + halothreshold)
 
  328                             float alphamult = (tmp - threshold) / halothreshold;
 
  330                             pixel[0] *= alphamult;
 
  331                             pixel[1] *= alphamult;
 
  332                             pixel[2] *= alphamult;
 
  333                             pixel[3] *= alphamult;
 
  340                 for (
int y = 0; y < height; ++y)
 
  342                     unsigned char *pixel = image->scanLine(y);
 
  344                     for (
int x = 0; x < width; ++x, pixel += 4, pf += 3)
 
  346                         float tmp = fabs(pf[1] - mask.f[1]);
 
  348                         if (tmp <= threshold)
 
  350                             pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
 
  352                         else if (tmp <= threshold + halothreshold)
 
  354                             float alphamult = (tmp - threshold) / halothreshold;
 
  356                             pixel[0] *= alphamult;
 
  357                             pixel[1] *= alphamult;
 
  358                             pixel[2] *= alphamult;
 
  359                             pixel[3] *= alphamult;
 
  366                 for (
int y = 0; y < height; ++y)
 
  368                     unsigned char *pixel = image->scanLine(y);
 
  370                     for (
int x = 0; x < width; ++x, pixel += 4, pf += 3)
 
  379                         float tmp = fabs(pf[2] - mask.f[2]);
 
  383                         if (tmp <= threshold)
 
  384                             pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
 
  394                     float pi = 4 * std::atan(1);
 
  396                     float L1 = ((float) mask.u[0]) / 2.55;
 
  397                     float a1 = mask.u[1] - 127;
 
  398                     float b1 = mask.u[2] - 127;
 
  399                     float C1 = std::sqrt(a1 * a1 + b1 * b1);
 
  401                     for (
int y = 0; y < height; ++y)
 
  403                         unsigned char *pixel = image->scanLine(y);
 
  405                         for (
int x = 0; x < width; ++x, pixel += 4, pc += 3)
 
  407                             float L2 = ((float) pc[0]) / 2.55;
 
  408                             int   a2 = pc[1] - 127;
 
  409                             int   b2 = pc[2] - 127;
 
  410                             float C2 = std::sqrt(a2 * a2 + b2 * b2);
 
  412                             float delta_L_prime = L2 - L1;
 
  413                             float L_bar = (L1 + L2) / 2;
 
  414                             float C_bar = (C1 + C2) / 2;
 
  416                             float a_prime_multiplier = 1 + 0.5 * (1 - std::sqrt(C_bar / (C_bar + 25)));
 
  417                             float a1_prime = a1 * a_prime_multiplier;
 
  418                             float a2_prime = a2 * a_prime_multiplier;
 
  420                             float C1_prime = std::sqrt(a1_prime * a1_prime + b1 * b1);
 
  421                             float C2_prime = std::sqrt(a2_prime * a2_prime + b2 * b2);
 
  422                             float C_prime_bar = (C1_prime + C2_prime) / 2;
 
  423                             float delta_C_prime = C2_prime - C1_prime;
 
  425                             float h1_prime = std::atan2(b1, a1_prime) * 180 / pi;
 
  426                             float h2_prime = std::atan2(b2, a2_prime) * 180 / pi;
 
  428                             float delta_h_prime = h2_prime - h1_prime;
 
  429                             double H_prime_bar = (C1_prime != 0 && C2_prime != 0) ? (h1_prime + h2_prime) / 2 : (h1_prime + h2_prime);
 
  431                             if (delta_h_prime < -180)
 
  433                                 delta_h_prime += 360;
 
  434                                 if (H_prime_bar < 180)
 
  439                             else if (delta_h_prime > 180)
 
  441                                 delta_h_prime -= 360;
 
  442                                 if (H_prime_bar < 180)
 
  448                             float delta_H_prime = 2 * std::sqrt(C1_prime * C2_prime) * std::sin(delta_h_prime * pi / 360);
 
  451                                 - 0.17 * std::cos((H_prime_bar - 30) * pi / 180)
 
  452                                 + 0.24 * std::cos(H_prime_bar * pi / 90)
 
  453                                 + 0.32 * std::cos((3 * H_prime_bar + 6) * pi / 180)
 
  454                                 - 0.20 * std::cos((4 * H_prime_bar - 64) * pi / 180);
 
  456                             float SL = 1 + 0.015 * std::pow(L_bar - 50, 2) / std::sqrt(20 + std::pow(L_bar - 50, 2));
 
  457                             float SC = 1 + 0.045 * C_prime_bar;
 
  458                             float SH = 1 + 0.015 * C_prime_bar * T;
 
  459                             float RT = -2 * std::sqrt(C_prime_bar / (C_prime_bar + 25)) * std::sin(pi / 3 * std::exp(-std::pow((H_prime_bar - 275) / 25, 2)));
 
  460                             float delta_E = std::sqrt(std::pow(delta_L_prime / KL / SL, 2)
 
  461                                         + std::pow(delta_C_prime / KC / SC, 2)
 
  462                                         + std::pow(delta_h_prime / KH / SH, 2)
 
  463                                         + RT * delta_C_prime / KC / SC * delta_H_prime / KH / SH);
 
  464                             if (delta_E <= threshold)
 
  466                                 pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
 
  468                             else if (delta_E <= threshold + halothreshold)
 
  470                                 float alphamult = (delta_E - threshold) / halothreshold;
 
  472                                 pixel[0] *= alphamult;
 
  473                                 pixel[1] *= alphamult;
 
  474                                 pixel[2] *= alphamult;
 
  475                                 pixel[3] *= alphamult;
 
  489     for (
int y = 0; y < height; ++y)
 
  491         unsigned char * pixel = image->scanLine(y);
 
  493         for (
int x = 0; x < width; ++x, pixel += 4)
 
  496             unsigned char R = (pixel[0] / A) * 255.0;
 
  497             unsigned char G = (pixel[1] / A) * 255.0;
 
  498             unsigned char B = (pixel[2] / A) * 255.0;
 
  501             long distance = 
Color::GetDistance((
long)R, (
long)G, (
long)B, mask_R, mask_G, mask_B);
 
  503             if (distance <= threshold) {
 
  507                 pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
 
  532     root[
"keymethod"] = method;
 
  548     catch (
const std::exception& e)
 
  551         throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
 
  562     if (!root[
"color"].isNull())
 
  564     if (!root[
"fuzz"].isNull())
 
  566     if (!root[
"halo"].isNull())
 
  568     if (!root[
"keymethod"].isNull())
 
  579     root[
"color"] = 
add_property_json(
"Key Color", 0.0, 
"color", 
"", &color.
red, 0, 255, 
false, requested_frame);
 
  583     root[
"fuzz"] = 
add_property_json(
"Threshold", fuzz.
GetValue(requested_frame), 
"float", 
"", &fuzz, 0, 125, 
false, requested_frame);
 
  584     root[
"halo"] = 
add_property_json(
"Halo", halo.
GetValue(requested_frame), 
"float", 
"", &halo, 0, 125, 
false, requested_frame);
 
  599     return root.toStyledString();