OpenShot Library | libopenshot  0.4.0
ChromaKey.cpp
Go to the documentation of this file.
1 
10 // Copyright (c) 2008-2019 OpenShot Studios, LLC
11 //
12 // SPDX-License-Identifier: LGPL-3.0-or-later
13 
14 #include "ChromaKey.h"
15 #include "Exceptions.h"
16 #if USE_BABL
17 #include <babl/babl.h>
18 #endif
19 #include <vector>
20 #include <cmath>
21 
22 using namespace openshot;
23 
25 ChromaKey::ChromaKey() : fuzz(5.0), halo(0), method(CHROMAKEY_BASIC) {
26  // Init default color
27  color = Color();
28 
29  // Init effect properties
30  init_effect_details();
31 }
32 
33 // Standard constructor, which takes an openshot::Color object, a 'fuzz' factor,
34 // an optional halo distance and an optional keying method.
36  color(color), fuzz(fuzz), halo(halo), method(method)
37 {
38  // Init effect properties
39  init_effect_details();
40 }
41 
42 // Init effect settings
43 void ChromaKey::init_effect_details()
44 {
47 
49  info.class_name = "ChromaKey";
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).";
52  info.has_audio = false;
53  info.has_video = true;
54 }
55 
56 // This method is required for all derived classes of EffectBase, and returns a
57 // modified openshot::Frame object
58 //
59 // Because a frame's QImage is always in Format_RGB8888_Premultiplied, we do not
60 // need to muck about with QRgb and its helper functions, qRed, QGreen, QBlue and
61 // qAlpha, and indeed doing so will get wrong results on almost every platform
62 // when we operate on the pixel buffers instead of calling the pixel methods in
63 // QImage. QRgb is always in the form 0xAARRGGBB, but treating the pixel buffer
64 // as an array of QRgb will yield values of the form 0xAABBGGRR on little endian
65 // systems and 0xRRGGBBAA on big endian systems.
66 //
67 // We need to operate on the pixel buffers here because doing this all pixel by
68 // pixel is be horribly slow, especially with keying methods other than basic.
69 // The babl conversion functions are very slow if iterating over pixels and every
70 // effort should be made to do babl conversions in blocks of as many pixels as
71 // can be done at once.
72 //
73 // The default keying method tries to ascertain the original pixel color by
74 // dividing the red, green and blue channels by the alpha (and multiplying by
75 // 255). The other methods do not do this for several reasons:
76 //
77 // 1. The calculation will not necessarily return the original value, because
78 // the premultiplication of alpha using unsigned 8 bit integers loses
79 // accuracy at the least significant bit. Even an alpha of 0xfe means that
80 // we are left with only 255 values to start with and cannot regain the full
81 // 256 values that could have been in the input. At an alpha of 0x7f the
82 // entire least significant bit has been lost, and at an alpho of 0x3f the
83 // two entire least significant bits have been lost. Chroma keying is very
84 // sensitive to these losses of precision so if the alpha has been applied
85 // already at anything other than 0xff and 0x00, we are already screwed and
86 // this calculation will not help.
87 //
88 // 2. The calculation used for the default method seems to be wrong anyway as
89 // it always rounds down rather than to the nearest whole number.
90 //
91 // 3. As mentioned above, babl conversion functions are very slow when iterating
92 // over individual pixels. We would have to convert the entire input buffer
93 // in one go to avoid this. It just does not seem worth it given the loss
94 // of accuracy we already have.
95 //
96 // 4. It is difficult to see how it could make sense to apply chroma keying
97 // after other non-chroma-key effects. The purpose is to remove an unwanted
98 // background in the input stream, rather than removing some calculated
99 // value that is the output of another effect.
100 std::shared_ptr<openshot::Frame> ChromaKey::GetFrame(std::shared_ptr<openshot::Frame> frame, int64_t frame_number)
101 {
102  int threshold = fuzz.GetInt(frame_number);
103  int halothreshold = halo.GetInt(frame_number);
104  long mask_R = color.red.GetInt(frame_number);
105  long mask_G = color.green.GetInt(frame_number);
106  long mask_B = color.blue.GetInt(frame_number);
107 
108  // Get source image
109  std::shared_ptr<QImage> image = frame->GetImage();
110 
111  int width = image->width();
112  int height = image->height();
113 
114  int pixelcount = width * height;
115 
116 #if USE_BABL
117  if (method > CHROMAKEY_BASIC && method <= CHROMAKEY_LAST_METHOD)
118  {
119  static bool need_init = true;
120 
121  if (need_init)
122  {
123  babl_init();
124  need_init = false;
125  }
126 
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;
131  int rowwidth = 0;
132 
133  switch(method)
134  {
135  case CHROMAKEY_HSVL_H:
136  case CHROMAKEY_HSV_S:
137  case CHROMAKEY_HSV_V:
138  format = babl_format("HSV float");
139  rowwidth = width * sizeof(float) * 3;
140  break;
141 
142  case CHROMAKEY_HSL_S:
143  case CHROMAKEY_HSL_L:
144  format = babl_format("HSL float");
145  rowwidth = width * sizeof(float) * 3;
146  break;
147 
148  case CHROMAKEY_CIE_LCH_L:
149  case CHROMAKEY_CIE_LCH_C:
150  case CHROMAKEY_CIE_LCH_H:
151  format = babl_format("CIE LCH(ab) float");
152  rowwidth = width * sizeof(float) * 3;
153  break;
154 
156  format = babl_format("CIE Lab u8");
157  rowwidth = width * 3;
158  break;
159 
160  case CHROMAKEY_YCBCR:
161  format = babl_format("Y'CbCr u8");
162  rowwidth = width * 3;
163  break;
164 
165  case CHROMAKEY_BASIC:
166  break;
167  }
168 
169  pixelbuf.resize(rowwidth * height);
170 
171  if (rgb && format && (fish = babl_fish(rgb, format)) != 0)
172  {
173  int idx = 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();
178 
179  mask_in[0] = mask_R;
180  mask_in[1] = mask_G;
181  mask_in[2] = mask_B;
182  mask_in[3] = 255;
183  babl_process(fish, mask_in, &mask, 1);
184 
185  if (0) //image->bytesPerLine() == width * 4)
186  {
187  // Because babl_process is expensive to call, but efficient
188  // with long sequences of pixels, attempt to convert the
189  // entire buffer at once if we can
190  babl_process(fish, image->bits(), pixelbuf.data(), pixelcount);
191  }
192  else
193  {
194  unsigned char *rowdata = pixelbuf.data();
195 
196  for (int y = 0; y < height; ++y, rowdata += rowwidth)
197  babl_process(fish, image->scanLine(y), rowdata, width);
198  }
199 
200  switch(method)
201  {
202  case CHROMAKEY_HSVL_H:
203  for (int y = 0; y < height; ++y)
204  {
205  unsigned char *pixel = image->scanLine(y);
206 
207  for (int x = 0; x < width; ++x, pixel += 4, pf += 3)
208  {
209  float tmp = fabs(pf[0] - mask.f[0]);
210 
211  if (tmp > 0.5)
212  tmp = 1.0 - tmp;
213  tmp *= 500;
214  if (tmp <= threshold)
215  {
216  pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
217  }
218  else if (tmp <= threshold + halothreshold)
219  {
220  float alphamult = (tmp - threshold) / halothreshold;
221 
222  pixel[0] *= alphamult;
223  pixel[1] *= alphamult;
224  pixel[2] *= alphamult;
225  pixel[3] *= alphamult;
226  }
227  }
228  }
229  break;
230 
231  case CHROMAKEY_HSV_S:
232  case CHROMAKEY_HSL_S:
233  for (int y = 0; y < height; ++y)
234  {
235  unsigned char *pixel = image->scanLine(y);
236 
237  for (int x = 0; x < width; ++x, pixel += 4, pf += 3)
238  {
239  float tmp = fabs(pf[1] - mask.f[1]) * 255;
240 
241  if (tmp <= threshold)
242  {
243  pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
244  }
245  else if (tmp <= threshold + halothreshold)
246  {
247  float alphamult = (tmp - threshold) / halothreshold;
248 
249  pixel[0] *= alphamult;
250  pixel[1] *= alphamult;
251  pixel[2] *= alphamult;
252  pixel[3] *= alphamult;
253  }
254  }
255  }
256  break;
257 
258  case CHROMAKEY_HSV_V:
259  case CHROMAKEY_HSL_L:
260  for (int y = 0; y < height; ++y)
261  {
262  unsigned char *pixel = image->scanLine(y);
263 
264  for (int x = 0; x < width; ++x, pixel += 4, pf += 3)
265  {
266  float tmp = fabs(pf[2] - mask.f[2]) * 255;
267 
268  if (tmp <= threshold)
269  {
270  pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
271  }
272  else if (tmp <= threshold + halothreshold)
273  {
274  float alphamult = (tmp - threshold) / halothreshold;
275 
276  pixel[0] *= alphamult;
277  pixel[1] *= alphamult;
278  pixel[2] *= alphamult;
279  pixel[3] *= alphamult;
280  }
281  }
282  }
283  break;
284 
285  case CHROMAKEY_YCBCR:
286  for (int y = 0; y < height; ++y)
287  {
288  unsigned char *pixel = image->scanLine(y);
289 
290  for (int x = 0; x < width; ++x, pixel += 4, pc += 3)
291  {
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);
295 
296  if (tmp <= threshold)
297  {
298  pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
299  }
300  else if (tmp <= threshold + halothreshold)
301  {
302  float alphamult = (tmp - threshold) / halothreshold;
303 
304  pixel[0] *= alphamult;
305  pixel[1] *= alphamult;
306  pixel[2] *= alphamult;
307  pixel[3] *= alphamult;
308  }
309  }
310  }
311  break;
312 
313  case CHROMAKEY_CIE_LCH_L:
314  for (int y = 0; y < height; ++y)
315  {
316  unsigned char *pixel = image->scanLine(y);
317 
318  for (int x = 0; x < width; ++x, pixel += 4, pf += 3)
319  {
320  float tmp = fabs(pf[0] - mask.f[0]);
321 
322  if (tmp <= threshold)
323  {
324  pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
325  }
326  else if (tmp <= threshold + halothreshold)
327  {
328  float alphamult = (tmp - threshold) / halothreshold;
329 
330  pixel[0] *= alphamult;
331  pixel[1] *= alphamult;
332  pixel[2] *= alphamult;
333  pixel[3] *= alphamult;
334  }
335  }
336  }
337  break;
338 
339  case CHROMAKEY_CIE_LCH_C:
340  for (int y = 0; y < height; ++y)
341  {
342  unsigned char *pixel = image->scanLine(y);
343 
344  for (int x = 0; x < width; ++x, pixel += 4, pf += 3)
345  {
346  float tmp = fabs(pf[1] - mask.f[1]);
347 
348  if (tmp <= threshold)
349  {
350  pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
351  }
352  else if (tmp <= threshold + halothreshold)
353  {
354  float alphamult = (tmp - threshold) / halothreshold;
355 
356  pixel[0] *= alphamult;
357  pixel[1] *= alphamult;
358  pixel[2] *= alphamult;
359  pixel[3] *= alphamult;
360  }
361  }
362  }
363  break;
364 
365  case CHROMAKEY_CIE_LCH_H:
366  for (int y = 0; y < height; ++y)
367  {
368  unsigned char *pixel = image->scanLine(y);
369 
370  for (int x = 0; x < width; ++x, pixel += 4, pf += 3)
371  {
372  // Hues in LCH(ab) are an angle on a color wheel.
373  // We are tring to find the angular distance
374  // between the two angles. It can never be more
375  // than 180 degrees - if it is, there is a closer
376  // angle that can be calculated by going in the
377  // other diretion, which can be found by
378  // subtracting the angle we have from 360.
379  float tmp = fabs(pf[2] - mask.f[2]);
380 
381  if (tmp > 180.0)
382  tmp = 360.0 - tmp;
383  if (tmp <= threshold)
384  pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
385  }
386  }
387  break;
388 
390  {
391  float KL = 1.0;
392  float KC = 1.0;
393  float KH = 1.0;
394  float pi = 4 * std::atan(1);
395 
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);
400 
401  for (int y = 0; y < height; ++y)
402  {
403  unsigned char *pixel = image->scanLine(y);
404 
405  for (int x = 0; x < width; ++x, pixel += 4, pc += 3)
406  {
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);
411 
412  float delta_L_prime = L2 - L1;
413  float L_bar = (L1 + L2) / 2;
414  float C_bar = (C1 + C2) / 2;
415 
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;
419 
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;
424 
425  float h1_prime = std::atan2(b1, a1_prime) * 180 / pi;
426  float h2_prime = std::atan2(b2, a2_prime) * 180 / pi;
427 
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);
430 
431  if (delta_h_prime < -180)
432  {
433  delta_h_prime += 360;
434  if (H_prime_bar < 180)
435  H_prime_bar += 180;
436  else
437  H_prime_bar -= 180;
438  }
439  else if (delta_h_prime > 180)
440  {
441  delta_h_prime -= 360;
442  if (H_prime_bar < 180)
443  H_prime_bar += 180;
444  else
445  H_prime_bar -= 180;
446  }
447 
448  float delta_H_prime = 2 * std::sqrt(C1_prime * C2_prime) * std::sin(delta_h_prime * pi / 360);
449 
450  float T = 1
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);
455 
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)
465  {
466  pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
467  }
468  else if (delta_E <= threshold + halothreshold)
469  {
470  float alphamult = (delta_E - threshold) / halothreshold;
471 
472  pixel[0] *= alphamult;
473  pixel[1] *= alphamult;
474  pixel[2] *= alphamult;
475  pixel[3] *= alphamult;
476  }
477  }
478  }
479  }
480  break;
481  }
482 
483  return frame;
484  }
485  }
486 #endif
487 
488  // Loop through pixels
489  for (int y = 0; y < height; ++y)
490  {
491  unsigned char * pixel = image->scanLine(y);
492 
493  for (int x = 0; x < width; ++x, pixel += 4)
494  {
495  float A = pixel[3];
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;
499 
500  // Get distance between mask color and pixel color
501  long distance = Color::GetDistance((long)R, (long)G, (long)B, mask_R, mask_G, mask_B);
502 
503  if (distance <= threshold) {
504  // MATCHED - Make pixel transparent
505  // Due to premultiplied alpha, we must also zero out
506  // the individual color channels (or else artifacts are left behind)
507  pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0;
508  }
509  }
510  }
511 
512  // return the modified frame
513  return frame;
514 }
515 
516 // Generate JSON string of this object
517 std::string ChromaKey::Json() const {
518 
519  // Return formatted string
520  return JsonValue().toStyledString();
521 }
522 
523 // Generate Json::Value for this object
524 Json::Value ChromaKey::JsonValue() const {
525 
526  // Create root json object
527  Json::Value root = EffectBase::JsonValue(); // get parent properties
528  root["type"] = info.class_name;
529  root["color"] = color.JsonValue();
530  root["fuzz"] = fuzz.JsonValue();
531  root["halo"] = halo.JsonValue();
532  root["keymethod"] = method;
533 
534  // return JsonValue
535  return root;
536 }
537 
538 // Load JSON string into this object
539 void ChromaKey::SetJson(const std::string value) {
540 
541  // Parse JSON string into JSON objects
542  try
543  {
544  const Json::Value root = openshot::stringToJson(value);
545  // Set all values that match
546  SetJsonValue(root);
547  }
548  catch (const std::exception& e)
549  {
550  // Error parsing JSON (or missing keys)
551  throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
552  }
553 }
554 
555 // Load Json::Value into this object
556 void ChromaKey::SetJsonValue(const Json::Value root) {
557 
558  // Set parent data
560 
561  // Set data from Json (if key is found)
562  if (!root["color"].isNull())
563  color.SetJsonValue(root["color"]);
564  if (!root["fuzz"].isNull())
565  fuzz.SetJsonValue(root["fuzz"]);
566  if (!root["halo"].isNull())
567  halo.SetJsonValue(root["halo"]);
568  if (!root["keymethod"].isNull())
569  method = (ChromaKeyMethod) root["keymethod"].asInt();
570 }
571 
572 // Get all properties for a specific frame
573 std::string ChromaKey::PropertiesJSON(int64_t requested_frame) const {
574 
575  // Generate JSON properties list
576  Json::Value root = BasePropertiesJSON(requested_frame);
577 
578  // Keyframes
579  root["color"] = add_property_json("Key Color", 0.0, "color", "", &color.red, 0, 255, false, requested_frame);
580  root["color"]["red"] = add_property_json("Red", color.red.GetValue(requested_frame), "float", "", &color.red, 0, 255, false, requested_frame);
581  root["color"]["blue"] = add_property_json("Blue", color.blue.GetValue(requested_frame), "float", "", &color.blue, 0, 255, false, requested_frame);
582  root["color"]["green"] = add_property_json("Green", color.green.GetValue(requested_frame), "float", "", &color.green, 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);
585  root["keymethod"] = add_property_json("Key Method", method, "int", "", NULL, 0, CHROMAKEY_LAST_METHOD, false, requested_frame);
586  root["keymethod"]["choices"].append(add_property_choice_json("Basic keying", 0, method));
587  root["keymethod"]["choices"].append(add_property_choice_json("HSV/HSL hue", 1, method));
588  root["keymethod"]["choices"].append(add_property_choice_json("HSV saturation", 2, method));
589  root["keymethod"]["choices"].append(add_property_choice_json("HSL saturation", 3, method));
590  root["keymethod"]["choices"].append(add_property_choice_json("HSV value", 4, method));
591  root["keymethod"]["choices"].append(add_property_choice_json("HSL luminance", 5, method));
592  root["keymethod"]["choices"].append(add_property_choice_json("LCH luminosity", 6, method));
593  root["keymethod"]["choices"].append(add_property_choice_json("LCH chroma", 7, method));
594  root["keymethod"]["choices"].append(add_property_choice_json("LCH hue", 8, method));
595  root["keymethod"]["choices"].append(add_property_choice_json("CIE Distance", 9, method));
596  root["keymethod"]["choices"].append(add_property_choice_json("Cb,Cr vector", 10, method));
597 
598  // Return formatted string
599  return root.toStyledString();
600 }
openshot::ClipBase::add_property_json
Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, const Keyframe *keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) const
Generate JSON for a property.
Definition: ClipBase.cpp:96
openshot::stringToJson
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:16
openshot::EffectBase::info
EffectInfoStruct info
Information about the current effect.
Definition: EffectBase.h:69
openshot::ChromaKey::SetJsonValue
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
Definition: ChromaKey.cpp:556
openshot::CHROMAKEY_HSL_S
@ CHROMAKEY_HSL_S
Difference between HSL saturations.
Definition: Enums.h:125
openshot::CHROMAKEY_BASIC
@ CHROMAKEY_BASIC
Length of difference between RGB vectors.
Definition: Enums.h:122
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:28
openshot::ClipBase::add_property_choice_json
Json::Value add_property_choice_json(std::string name, int value, int selected_value) const
Generate JSON choice for a property (dropdown properties)
Definition: ClipBase.cpp:132
openshot::EffectBase::JsonValue
virtual Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: EffectBase.cpp:79
openshot::CHROMAKEY_HSV_V
@ CHROMAKEY_HSV_V
Difference between HSV values.
Definition: Enums.h:126
openshot::ChromaKeyMethod
ChromaKeyMethod
This enumeration determines the algorithm used by the ChromaKey filter.
Definition: Enums.h:120
openshot::Keyframe::SetJsonValue
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: KeyFrame.cpp:372
openshot::Color::GetDistance
static long GetDistance(long R1, long G1, long B1, long R2, long G2, long B2)
Get the distance between 2 RGB pairs. (0=identical colors, 10=very close colors, 760=very different c...
Definition: Color.cpp:69
openshot::CHROMAKEY_CIE_LCH_H
@ CHROMAKEY_CIE_LCH_H
Difference between CIE LCH(ab) hues.
Definition: Enums.h:130
ChromaKey.h
Header file for ChromaKey class.
openshot::Keyframe::JsonValue
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: KeyFrame.cpp:339
openshot::Color
This class represents a color (used on the timeline and clips)
Definition: Color.h:27
openshot::EffectBase::BasePropertiesJSON
Json::Value BasePropertiesJSON(int64_t requested_frame) const
Generate JSON object of base properties (recommended to be used by all effects)
Definition: EffectBase.cpp:179
openshot::Keyframe
A Keyframe is a collection of Point instances, which is used to vary a number or property over time.
Definition: KeyFrame.h:53
openshot::Color::SetJsonValue
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: Color.cpp:117
openshot::CHROMAKEY_HSV_S
@ CHROMAKEY_HSV_S
Difference between HSV saturations.
Definition: Enums.h:124
openshot::InvalidJSON
Exception for invalid JSON.
Definition: Exceptions.h:217
openshot::CHROMAKEY_YCBCR
@ CHROMAKEY_YCBCR
YCbCr vector difference of CbCr.
Definition: Enums.h:132
openshot::EffectBase::InitEffectInfo
void InitEffectInfo()
Definition: EffectBase.cpp:24
openshot::Color::green
openshot::Keyframe green
Curve representing the green value (0 - 255)
Definition: Color.h:31
openshot::EffectInfoStruct::has_audio
bool has_audio
Determines if this effect manipulates the audio of a frame.
Definition: EffectBase.h:41
openshot::ChromaKey::JsonValue
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition: ChromaKey.cpp:524
openshot::CHROMAKEY_CIE_LCH_L
@ CHROMAKEY_CIE_LCH_L
Difference between CIE LCH(ab) luminousities.
Definition: Enums.h:128
openshot::CHROMAKEY_HSVL_H
@ CHROMAKEY_HSVL_H
Difference between HSV/HSL hues.
Definition: Enums.h:123
openshot::EffectInfoStruct::class_name
std::string class_name
The class name of the effect.
Definition: EffectBase.h:36
openshot::Color::JsonValue
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: Color.cpp:86
openshot::Keyframe::GetInt
int GetInt(int64_t index) const
Get the rounded INT value at a specific index.
Definition: KeyFrame.cpp:282
openshot::CHROMAKEY_CIE_DISTANCE
@ CHROMAKEY_CIE_DISTANCE
CIEDE2000 perceptual difference.
Definition: Enums.h:131
openshot::EffectInfoStruct::description
std::string description
The description of this effect and what it does.
Definition: EffectBase.h:38
openshot::ChromaKey::SetJson
void SetJson(const std::string value) override
Load JSON string into this object.
Definition: ChromaKey.cpp:539
openshot::EffectInfoStruct::has_video
bool has_video
Determines if this effect manipulates the image of a frame.
Definition: EffectBase.h:40
openshot::EffectInfoStruct::name
std::string name
The name of the effect.
Definition: EffectBase.h:37
openshot::CHROMAKEY_HSL_L
@ CHROMAKEY_HSL_L
Difference between HSL luminances.
Definition: Enums.h:127
openshot::Color::red
openshot::Keyframe red
Curve representing the red value (0 - 255)
Definition: Color.h:30
openshot::ChromaKey::Json
std::string Json() const override
Generate JSON string of this object.
Definition: ChromaKey.cpp:517
openshot::ChromaKey::GetFrame
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number) override
This method is required for all derived classes of ClipBase, and returns a new openshot::Frame object...
Definition: ChromaKey.h:87
openshot::CHROMAKEY_CIE_LCH_C
@ CHROMAKEY_CIE_LCH_C
Difference between CIE LCH(ab) chromas.
Definition: Enums.h:129
openshot::Color::blue
openshot::Keyframe blue
Curve representing the red value (0 - 255)
Definition: Color.h:32
openshot::ChromaKey::ChromaKey
ChromaKey()
Blank constructor, useful when using Json to load the effect properties.
Definition: ChromaKey.cpp:25
Exceptions.h
Header file for all Exception classes.
openshot::ChromaKey::PropertiesJSON
std::string PropertiesJSON(int64_t requested_frame) const override
Definition: ChromaKey.cpp:573
openshot::EffectBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: EffectBase.cpp:115
openshot::Keyframe::GetValue
double GetValue(int64_t index) const
Get the value at a specific index.
Definition: KeyFrame.cpp:258
openshot::CHROMAKEY_LAST_METHOD
@ CHROMAKEY_LAST_METHOD
Definition: Enums.h:133