22 init_effect_details();
30 init_effect_details();
34 void Brightness::init_effect_details()
42 info.
description =
"Adjust the brightness and contrast of the frame's image.";
49 std::shared_ptr<openshot::Frame>
Brightness::GetFrame(std::shared_ptr<openshot::Frame> frame, int64_t frame_number)
52 std::shared_ptr<QImage> frame_image = frame->GetImage();
59 const float contrast_factor = (259.0f * (contrast_value + 255.0f)) / (255.0f * (259.0f - contrast_value));
60 const int brightness_offset_i =
static_cast<int>(255.0f * brightness_value);
63 unsigned char *pixels =
reinterpret_cast<unsigned char *
>(frame_image->bits());
64 const int pixel_count = frame_image->width() * frame_image->height();
66 static const std::array<float, 256> inv_alpha = [] {
67 std::array<float, 256> lut{};
69 for (
int i = 1; i < 256; ++i)
70 lut[i] = 255.0f /
static_cast<float>(i);
73 const auto clamp_u8 = [](
int value) ->
unsigned char {
74 if (value < 0)
return 0;
75 if (value > 255)
return 255;
76 return static_cast<unsigned char>(value);
78 const auto clamp_i = [](
int value) ->
int {
79 if (value < 0)
return 0;
80 if (value > 255)
return 255;
84 const auto adjust_contrast_and_brightness = [&](
int &R,
int &G,
int &B) {
85 R = clamp_u8(clamp_i(
static_cast<int>((contrast_factor * (R - 128)) + 128.0f)) + brightness_offset_i);
86 G = clamp_u8(clamp_i(
static_cast<int>((contrast_factor * (G - 128)) + 128.0f)) + brightness_offset_i);
87 B = clamp_u8(clamp_i(
static_cast<int>((contrast_factor * (B - 128)) + 128.0f)) + brightness_offset_i);
90 #pragma omp parallel for if(pixel_count >= 16384) schedule(static)
91 for (
int pixel = 0; pixel < pixel_count; ++pixel)
93 const int idx = pixel * 4;
96 const int A = pixels[idx + 3];
106 adjust_contrast_and_brightness(R, G, B);
107 pixels[idx + 0] =
static_cast<unsigned char>(R);
108 pixels[idx + 1] =
static_cast<unsigned char>(G);
109 pixels[idx + 2] =
static_cast<unsigned char>(B);
111 const float alpha_percent =
static_cast<float>(A) * (1.0f / 255.0f);
112 const float inv_alpha_percent = inv_alpha[A];
115 R =
static_cast<int>(pixels[idx + 0] * inv_alpha_percent);
116 G =
static_cast<int>(pixels[idx + 1] * inv_alpha_percent);
117 B =
static_cast<int>(pixels[idx + 2] * inv_alpha_percent);
118 adjust_contrast_and_brightness(R, G, B);
121 pixels[idx + 0] =
static_cast<unsigned char>(R * alpha_percent);
122 pixels[idx + 1] =
static_cast<unsigned char>(G * alpha_percent);
123 pixels[idx + 2] =
static_cast<unsigned char>(B * alpha_percent);
137 std::shared_ptr<QImage> mask_image, int64_t frame_number)
const {
139 if (!original_image || !effected_image || !mask_image)
141 if (original_image->size() != effected_image->size() || effected_image->size() != mask_image->size())
144 unsigned char* original_pixels =
reinterpret_cast<unsigned char*
>(original_image->bits());
145 unsigned char* effected_pixels =
reinterpret_cast<unsigned char*
>(effected_image->bits());
146 unsigned char* mask_pixels =
reinterpret_cast<unsigned char*
>(mask_image->bits());
147 const int pixel_count = effected_image->width() * effected_image->height();
150 #pragma omp parallel for schedule(static)
151 for (
int i = 0; i < pixel_count; ++i) {
152 const int idx = i * 4;
153 float factor =
static_cast<float>(qGray(mask_pixels[idx], mask_pixels[idx + 1], mask_pixels[idx + 2])) / 255.0f;
154 factor = 1.0f - factor;
155 factor = factor * factor;
156 const float inverse = 1.0f - factor;
158 effected_pixels[idx] =
static_cast<unsigned char>(
159 (original_pixels[idx] * inverse) + (effected_pixels[idx] * factor));
160 effected_pixels[idx + 1] =
static_cast<unsigned char>(
161 (original_pixels[idx + 1] * inverse) + (effected_pixels[idx + 1] * factor));
162 effected_pixels[idx + 2] =
static_cast<unsigned char>(
163 (original_pixels[idx + 2] * inverse) + (effected_pixels[idx + 2] * factor));
164 effected_pixels[idx + 3] = original_pixels[idx + 3];
167 #pragma omp parallel for schedule(static)
168 for (
int i = 0; i < pixel_count; ++i) {
169 const int idx = i * 4;
170 float factor =
static_cast<float>(qGray(mask_pixels[idx], mask_pixels[idx + 1], mask_pixels[idx + 2])) / 255.0f;
171 factor = factor * factor;
172 const float inverse = 1.0f - factor;
174 effected_pixels[idx] =
static_cast<unsigned char>(
175 (original_pixels[idx] * inverse) + (effected_pixels[idx] * factor));
176 effected_pixels[idx + 1] =
static_cast<unsigned char>(
177 (original_pixels[idx + 1] * inverse) + (effected_pixels[idx + 1] * factor));
178 effected_pixels[idx + 2] =
static_cast<unsigned char>(
179 (original_pixels[idx + 2] * inverse) + (effected_pixels[idx + 2] * factor));
180 effected_pixels[idx + 3] = original_pixels[idx + 3];
216 catch (
const std::exception& e)
219 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
230 if (!root[
"brightness"].isNull())
232 if (!root[
"contrast"].isNull())
234 if (!root[
"mask_mode"].isNull())
252 return root.toStyledString();