Blender V4.5
sequencer_scopes.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006-2008 Peter Schlaile < peter [at] schlaile [dot] de >.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10#include <cstring>
11
12#include "BLI_math_vector.hh"
13#include "BLI_task.hh"
14
16#include "IMB_imbuf.hh"
17#include "IMB_imbuf_types.hh"
18
19#include "sequencer_scopes.hh"
20
21// #define DEBUG_TIME
22
23#ifdef DEBUG_TIME
24# include "BLI_timeit.hh"
25#endif
26
27namespace blender::ed::vse {
28
33
35{
36 if (zebra_ibuf) {
38 zebra_ibuf = nullptr;
39 }
40 if (waveform_ibuf) {
42 waveform_ibuf = nullptr;
43 }
46 sep_waveform_ibuf = nullptr;
47 }
48 if (vector_ibuf) {
50 vector_ibuf = nullptr;
51 }
52 histogram.data.reinitialize(0);
53 reference_ibuf = nullptr;
55}
56
57static blender::float2 rgb_to_uv_normalized(const float rgb[3])
58{
59 /* Exact same math as rgb_to_yuv BT709 case. Duplicated here
60 * since this function is called a lot, and non-inline function
61 * call plus color-space switch in there overhead does add up. */
62 float r = rgb[0], g = rgb[1], b = rgb[2];
63 /* We don't need Y. */
64 float u = -0.09991f * r - 0.33609f * g + 0.436f * b;
65 float v = 0.615f * r - 0.55861f * g - 0.05639f * b;
66
67 /* Normalize to 0..1 range. */
68 u = clamp_f(u * SeqScopes::VECSCOPE_U_SCALE + 0.5f, 0.0f, 1.0f);
69 v = clamp_f(v * SeqScopes::VECSCOPE_V_SCALE + 0.5f, 0.0f, 1.0f);
70 return float2(u, v);
71}
72
73static void scope_put_pixel(const uchar *table, uchar *pos)
74{
75 uchar newval = table[*pos];
76 pos[0] = pos[1] = pos[2] = newval;
77 pos[3] = 255;
78}
79
80static void scope_put_pixel_single(const uchar *table, uchar *pos, int col)
81{
82 uint newval = table[pos[col]];
83 /* So that the separate waveforms are not just pure RGB primaries, put
84 * some amount of value into the other channels too: slightly reduce it,
85 * and raise to 4th power. */
86 uint other = newval * 31 / 32;
87 other = (other * other) >> 8;
88 other = (other * other) >> 8;
89 pos[0] = pos[1] = pos[2] = uchar(other);
90 pos[col] = uchar(newval);
91 pos[3] = 255;
92}
93
94static void init_wave_table(int height, uchar wtable[256])
95{
96 /* For each pixel column of the image, waveform plots the intensity values
97 * with height proportional to the intensity. So depending on the height of
98 * the image, different amount of pixels are expected to hit the same
99 * intensity. Adjust the waveform plotting table gamma factor so that
100 * the waveform has decent visibility without saturating or being too dark:
101 * 0.3 gamma at height=360 and below, 0.9 gamma at height 2160 (4K) and up,
102 * and interpolating between those. */
103 float alpha = clamp_f(ratiof(360.0f, 2160.0f, height), 0.0f, 1.0f);
104 float gamma = interpf(0.9f, 0.3f, alpha);
105 for (int x = 0; x < 256; x++) {
106 wtable[x] = uchar(pow((float(x) + 1.0f) / 256.0f, gamma) * 255.0f);
107 }
108}
109
111{
112#ifdef DEBUG_TIME
113 SCOPED_TIMER(__func__);
114#endif
115 const int w = ibuf->x;
116 const int h = 256;
117 ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_byte_data);
118 uchar *tgt = rval->byte_buffer.data;
119
120 uchar wtable[256];
121 init_wave_table(ibuf->y, wtable);
122
123 /* IMB_colormanagement_get_luminance_byte for each pixel is quite a lot of
124 * overhead, so instead get luma coefficients as 16-bit integers. */
125 float coeffs[3];
127 const int muls[3] = {int(coeffs[0] * 65535), int(coeffs[1] * 65535), int(coeffs[2] * 65535)};
128
129 /* Parallel over x, since each column is easily independent from others. */
130 threading::parallel_for(IndexRange(ibuf->x), 32, [&](IndexRange x_range) {
131 if (ibuf->float_buffer.data) {
132 /* Float image. */
133 const float *src = ibuf->float_buffer.data;
134 for (int y = 0; y < ibuf->y; y++) {
135 for (const int x : x_range) {
136 const float *rgb = src + 4 * (ibuf->x * y + x);
137 float v = IMB_colormanagement_get_luminance(rgb);
138 uchar *p = tgt;
139
140 int iv = clamp_i(int(v * h), 0, h - 1);
141
142 p += 4 * (w * iv + x);
143 scope_put_pixel(wtable, p);
144 }
145 }
146 }
147 else {
148 /* Byte image. */
149 const uchar *src = ibuf->byte_buffer.data;
150 for (int y = 0; y < ibuf->y; y++) {
151 for (const int x : x_range) {
152 const uchar *rgb = src + 4 * (ibuf->x * y + x);
153 /* +1 is "Sree's solution" from http://stereopsis.com/doubleblend.html */
154 int rgb0 = rgb[0] + 1;
155 int rgb1 = rgb[1] + 1;
156 int rgb2 = rgb[2] + 1;
157 int luma = (rgb0 * muls[0] + rgb1 * muls[1] + rgb2 * muls[2]) >> 16;
158 int luma_y = clamp_i(luma, 0, 255);
159 uchar *p = tgt + 4 * (w * luma_y + x);
160 scope_put_pixel(wtable, p);
161 }
162 }
163 }
164 });
165
166 return rval;
167}
168
170{
171#ifdef DEBUG_TIME
172 SCOPED_TIMER(__func__);
173#endif
174 int w = ibuf->x;
175 int h = 256;
176 ImBuf *rval = IMB_allocImBuf(w, h, 32, IB_byte_data);
177 uchar *tgt = rval->byte_buffer.data;
178 int sw = ibuf->x / 3;
179
180 uchar wtable[256];
181 init_wave_table(ibuf->y, wtable);
182
183 /* Parallel over x, since each column is easily independent from others. */
184 threading::parallel_for(IndexRange(ibuf->x), 32, [&](IndexRange x_range) {
185 if (ibuf->float_buffer.data) {
186 /* Float image. */
187 const float *src = ibuf->float_buffer.data;
188 for (int y = 0; y < ibuf->y; y++) {
189 for (const int x : x_range) {
190 const float *rgb = src + 4 * (ibuf->x * y + x);
191 for (int c = 0; c < 3; c++) {
192 uchar *p = tgt;
193 float v = rgb[c];
194 int iv = clamp_i(int(v * h), 0, h - 1);
195
196 p += 4 * (w * iv + c * sw + x / 3);
197 scope_put_pixel_single(wtable, p, c);
198 }
199 }
200 }
201 }
202 else {
203 /* Byte image. */
204 const uchar *src = ibuf->byte_buffer.data;
205 for (int y = 0; y < ibuf->y; y++) {
206 for (const int x : x_range) {
207 const uchar *rgb = src + 4 * (ibuf->x * y + x);
208 for (int c = 0; c < 3; c++) {
209 uchar *p = tgt;
210 p += 4 * (w * rgb[c] + c * sw + x / 3);
211 scope_put_pixel_single(wtable, p, c);
212 }
213 }
214 }
215 }
216 });
217
218 return rval;
219}
220
221ImBuf *make_zebra_view_from_ibuf(const ImBuf *ibuf, float perc)
222{
223#ifdef DEBUG_TIME
224 SCOPED_TIMER(__func__);
225#endif
226 ImBuf *res = IMB_allocImBuf(ibuf->x, ibuf->y, 32, IB_byte_data | IB_uninitialized_pixels);
227
228 threading::parallel_for(IndexRange(ibuf->y), 16, [&](IndexRange y_range) {
229 if (ibuf->float_buffer.data) {
230 /* Float image. */
231 const float limit = perc / 100.0f;
232 const float *p = ibuf->float_buffer.data + y_range.first() * ibuf->x * 4;
233 uchar *o = res->byte_buffer.data + y_range.first() * ibuf->x * 4;
234 for (const int y : y_range) {
235 for (int x = 0; x < ibuf->x; x++) {
236 float pix[4];
237 memcpy(pix, p, sizeof(pix));
238 if (pix[0] >= limit || pix[1] >= limit || pix[2] >= limit) {
239 if (((x + y) & 0x08) != 0) {
240 pix[0] = 1.0f - pix[0];
241 pix[1] = 1.0f - pix[1];
242 pix[2] = 1.0f - pix[2];
243 }
244 }
245 rgba_float_to_uchar(o, pix);
246 p += 4;
247 o += 4;
248 }
249 }
250 }
251 else {
252 /* Byte image. */
253 const uint limit = 255.0f * perc / 100.0f;
254 const uchar *p = ibuf->byte_buffer.data + y_range.first() * ibuf->x * 4;
255 uchar *o = res->byte_buffer.data + y_range.first() * ibuf->x * 4;
256 for (const int y : y_range) {
257 for (int x = 0; x < ibuf->x; x++) {
258 uchar pix[4];
259 memcpy(pix, p, sizeof(pix));
260
261 if (pix[0] >= limit || pix[1] >= limit || pix[2] >= limit) {
262 if (((x + y) & 0x08) != 0) {
263 pix[0] = 255 - pix[0];
264 pix[1] = 255 - pix[1];
265 pix[2] = 255 - pix[2];
266 }
267 }
268 memcpy(o, pix, sizeof(pix));
269 p += 4;
270 o += 4;
271 }
272 }
273 }
274 });
275 return res;
276}
277
285
287{
288#ifdef DEBUG_TIME
289 SCOPED_TIMER(__func__);
290#endif
291
292 const bool is_float = ibuf->float_buffer.data != nullptr;
293 const int hist_size = is_float ? BINS_FLOAT : BINS_BYTE;
294
295 Array<uint3> counts(hist_size, uint3(0));
297 IndexRange(ibuf->y),
298 256,
299 counts,
300 [&](const IndexRange y_range, const Array<uint3> &init) {
301 Array<uint3> res = init;
302
303 if (is_float) {
304 for (const int y : y_range) {
305 const float *src = ibuf->float_buffer.data + y * ibuf->x * 4;
306 for (int x = 0; x < ibuf->x; x++) {
307 res[get_bin_float(src[0])].x++;
308 res[get_bin_float(src[1])].y++;
309 res[get_bin_float(src[2])].z++;
310 src += 4;
311 }
312 }
313 }
314 else {
315 /* Byte images just use 256 histogram bins, directly indexed by value. */
316 for (const int y : y_range) {
317 const uchar *src = ibuf->byte_buffer.data + y * ibuf->x * 4;
318 for (int x = 0; x < ibuf->x; x++) {
319 res[src[0]].x++;
320 res[src[1]].y++;
321 res[src[2]].z++;
322 src += 4;
323 }
324 }
325 }
326 return res;
327 },
328 [&](const Array<uint3> &a, const Array<uint3> &b) {
329 BLI_assert(a.size() == b.size());
330 Array<uint3> res(a.size());
331 for (int i = 0; i < a.size(); i++) {
332 res[i] = a[i] + b[i];
333 }
334 return res;
335 });
336
337 max_value = uint3(0);
338 for (const uint3 &v : data) {
339 max_value = math::max(max_value, v);
340 }
341}
342
344{
345#ifdef DEBUG_TIME
346 SCOPED_TIMER(__func__);
347#endif
348 const int size = 512;
349 const float size_mul = size - 1.0f;
351
352 uchar *dst = rval->byte_buffer.data;
353 float rgb[3];
354
355 uchar wtable[256];
356 init_wave_table(math::midpoint(ibuf->x, ibuf->y), wtable);
357
358 if (ibuf->float_buffer.data) {
359 /* Float image. */
360 const float *src = ibuf->float_buffer.data;
361 for (int y = 0; y < ibuf->y; y++) {
362 for (int x = 0; x < ibuf->x; x++) {
363 memcpy(rgb, src, sizeof(float[3]));
364 clamp_v3(rgb, 0.0f, 1.0f);
365
366 float2 uv = rgb_to_uv_normalized(rgb) * size_mul;
367
368 uchar *p = dst + 4 * (size * int(uv.y) + int(uv.x));
369 scope_put_pixel(wtable, p);
370
371 src += 4;
372 }
373 }
374 }
375 else {
376 /* Byte image. */
377 const uchar *src = ibuf->byte_buffer.data;
378 for (int y = 0; y < ibuf->y; y++) {
379 for (int x = 0; x < ibuf->x; x++) {
380 rgb[0] = float(src[0]) * (1.0f / 255.0f);
381 rgb[1] = float(src[1]) * (1.0f / 255.0f);
382 rgb[2] = float(src[2]) * (1.0f / 255.0f);
383
384 float2 uv = rgb_to_uv_normalized(rgb) * size_mul;
385
386 uchar *p = dst + 4 * (size * int(uv.y) + int(uv.x));
387 scope_put_pixel(wtable, p);
388
389 src += 4;
390 }
391 }
392 }
393
394 return rval;
395}
396
397} // namespace blender::ed::vse
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE float clamp_f(float value, float min, float max)
MINLINE float interpf(float target, float origin, float t)
MINLINE int clamp_i(int value, int min, int max)
MINLINE float ratiof(float min, float max, float pos)
MINLINE void clamp_v3(float vec[3], float min, float max)
unsigned char uchar
unsigned int uint
#define SCOPED_TIMER(name)
Definition BLI_timeit.hh:70
BLI_INLINE void IMB_colormanagement_get_luminance_coefficients(float r_rgb[3])
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
@ IB_byte_data
@ IB_uninitialized_pixels
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
int64_t size() const
Definition BLI_array.hh:245
BLI_INLINE int get_bin_float(float f)
uint pos
uint col
#define pow
ImBuf * make_waveform_view_from_ibuf(const ImBuf *ibuf)
ImBuf * make_vectorscope_view_from_ibuf(const ImBuf *ibuf)
static void init_wave_table(int height, uchar wtable[256])
ImBuf * make_sep_waveform_view_from_ibuf(const ImBuf *ibuf)
ImBuf * make_zebra_view_from_ibuf(const ImBuf *ibuf, float perc)
static void scope_put_pixel(const uchar *table, uchar *pos)
static blender::float2 rgb_to_uv_normalized(const float rgb[3])
static void scope_put_pixel_single(const uchar *table, uchar *pos, int col)
T midpoint(const T &a, const T &b)
T max(const T &a, const T &b)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
VecBase< uint32_t, 3 > uint3
VecBase< float, 2 > float2
static void init(bNodeTree *, bNode *node)
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
static constexpr float FLOAT_VAL_MAX
static constexpr float FLOAT_VAL_MIN
void calc_from_ibuf(const ImBuf *ibuf)
static constexpr float VECSCOPE_V_SCALE
static constexpr float VECSCOPE_U_SCALE
i
Definition text_draw.cc:230