183 needs_refresh =
false;
186 if (lut_data.empty() || lut_size <= 0 || lut_type == LUTType::None)
189 auto image = frame->GetImage();
190 int w = image->width(), h = image->height();
191 unsigned char *pixels = image->bits();
193 float overall = float(
intensity.GetValue(frame_number));
194 float tR = float(
intensity_r.GetValue(frame_number)) * overall;
195 float tG = float(
intensity_g.GetValue(frame_number)) * overall;
196 float tB = float(
intensity_b.GetValue(frame_number)) * overall;
198 const bool use3d = (lut_type == LUTType::LUT3D);
199 const bool use1d = (lut_type == LUTType::LUT1D);
200 const int lut_dim = lut_size;
201 const std::vector<float> &table = lut_data;
202 const int data_count = int(table.size());
204 auto sample1d = [&](
float value,
int channel) ->
float {
206 int base = std::min(channel, data_count - 1);
209 float scaled = value * float(lut_dim - 1);
210 int i0 = int(floor(scaled));
211 int i1 = std::min(i0 + 1, lut_dim - 1);
212 float t = scaled - i0;
213 int base0 = std::max(0, std::min(i0 * 3 + channel, data_count - 1));
214 int base1 = std::max(0, std::min(i1 * 3 + channel, data_count - 1));
215 float v0 = table[base0];
216 float v1 = table[base1];
217 return v0 * (1.0f - t) + v1 * t;
220 int pixel_count = w * h;
221 #pragma omp parallel for
222 for (
int i = 0; i < pixel_count; ++i) {
224 int A = pixels[idx + 3];
225 float alpha = A / 255.0f;
226 if (alpha == 0.0f)
continue;
229 float R = pixels[idx + 0] / alpha;
230 float G = pixels[idx + 1] / alpha;
231 float B = pixels[idx + 2] / alpha;
234 float Rn = R * (1.0f / 255.0f);
235 float Gn = G * (1.0f / 255.0f);
236 float Bn = B * (1.0f / 255.0f);
238 auto normalize_to_domain = [&](
float value,
int channel) ->
float {
239 float min_val = lut_domain_min[channel];
240 float max_val = lut_domain_max[channel];
241 float range = max_val - min_val;
243 return std::clamp(value, 0.0f, 1.0f);
244 float normalized = (value - min_val) / range;
245 return std::clamp(normalized, 0.0f, 1.0f);
247 float Rdn = normalize_to_domain(Rn, 0);
248 float Gdn = normalize_to_domain(Gn, 1);
249 float Bdn = normalize_to_domain(Bn, 2);
256 float rf = Rdn * (lut_dim - 1);
257 float gf = Gdn * (lut_dim - 1);
258 float bf = Bdn * (lut_dim - 1);
260 int r0 = int(floor(rf)), r1 = std::min(r0 + 1, lut_dim - 1);
261 int g0 = int(floor(gf)), g1 = std::min(g0 + 1, lut_dim - 1);
262 int b0 = int(floor(bf)), b1 = std::min(b0 + 1, lut_dim - 1);
268 int base000 = ((b0 * lut_dim + g0) * lut_dim + r0) * 3;
269 int base100 = ((b0 * lut_dim + g0) * lut_dim + r1) * 3;
270 int base010 = ((b0 * lut_dim + g1) * lut_dim + r0) * 3;
271 int base110 = ((b0 * lut_dim + g1) * lut_dim + r1) * 3;
272 int base001 = ((b1 * lut_dim + g0) * lut_dim + r0) * 3;
273 int base101 = ((b1 * lut_dim + g0) * lut_dim + r1) * 3;
274 int base011 = ((b1 * lut_dim + g1) * lut_dim + r0) * 3;
275 int base111 = ((b1 * lut_dim + g1) * lut_dim + r1) * 3;
277 float c00 = table[base000 + 0] * (1 - dr) + table[base100 + 0] * dr;
278 float c01 = table[base001 + 0] * (1 - dr) + table[base101 + 0] * dr;
279 float c10 = table[base010 + 0] * (1 - dr) + table[base110 + 0] * dr;
280 float c11 = table[base011 + 0] * (1 - dr) + table[base111 + 0] * dr;
281 float c0 = c00 * (1 - dg) + c10 * dg;
282 float c1 = c01 * (1 - dg) + c11 * dg;
283 lr = c0 * (1 - db) + c1 * db;
285 c00 = table[base000 + 1] * (1 - dr) + table[base100 + 1] * dr;
286 c01 = table[base001 + 1] * (1 - dr) + table[base101 + 1] * dr;
287 c10 = table[base010 + 1] * (1 - dr) + table[base110 + 1] * dr;
288 c11 = table[base011 + 1] * (1 - dr) + table[base111 + 1] * dr;
289 c0 = c00 * (1 - dg) + c10 * dg;
290 c1 = c01 * (1 - dg) + c11 * dg;
291 lg = c0 * (1 - db) + c1 * db;
293 c00 = table[base000 + 2] * (1 - dr) + table[base100 + 2] * dr;
294 c01 = table[base001 + 2] * (1 - dr) + table[base101 + 2] * dr;
295 c10 = table[base010 + 2] * (1 - dr) + table[base110 + 2] * dr;
296 c11 = table[base011 + 2] * (1 - dr) + table[base111 + 2] * dr;
297 c0 = c00 * (1 - dg) + c10 * dg;
298 c1 = c01 * (1 - dg) + c11 * dg;
299 lb = c0 * (1 - db) + c1 * db;
301 lr = sample1d(Rdn, 0);
302 lg = sample1d(Gdn, 1);
303 lb = sample1d(Bdn, 2);
307 float outR = (lr * tR + Rn * (1 - tR)) * alpha;
308 float outG = (lg * tG + Gn * (1 - tG)) * alpha;
309 float outB = (lb * tB + Bn * (1 - tB)) * alpha;
311 pixels[idx + 0] =
constrain(outR * 255.0f);
312 pixels[idx + 1] =
constrain(outG * 255.0f);
313 pixels[idx + 2] =
constrain(outB * 255.0f);