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();