Color drift as video loopback
Manipulate an image stream with OpenCL
Combining OpenCL and ‘analog Not analog’
This OpenCL program reads from buffer A and the upstream image buffer. The color values from the two buffers are mixed by a formula. The result is written to buffer B. Afterwards buffer A and B are swapped.
The formula is designed so that the color values of the upstream image buffer contribute only slightly to the result. Thus the color values in buffers A and B circle. However, when reading a buffer, two neighboring positions are also read and calculated with the color values of the current position. This results in a drift.
The drift is supported by the fact that the film recording is shaky.
Processing pipline
Read the video and send it as an upstream image to the OpenCL ping pong buffer.
(ns lv.demo)
(use 'lv.core)
(layout "grid" [mov0 clipp1])
(movie "bkgrd/*.MOV")
; two movies, bou useing only the first
(hsv :mov0 [c0 c1]
(sy 2.5)
(ty 0.1)
(hsv c0.hsv)
)
; read from nanoKONTROL2
; kp0 0.29134
;
; ks0 1
; ks1 0
; ks2 0.41732
; ks3 0
;
; ks7 0.54331
(expr :clipp1 [mov0]
"cl/image-color-drift.cl"
(paint 1)
; kp0 = mix upstren image
(p0 (* kp0 0.1))
; ks0 .. ks3 = direction of the drift
; ks7 = damping the feedback loop
(p1 (* ks7 (- ks0 0.5) 8))
(p2 (* ks7 (- ks1 0.5) 8))
(p3 (* ks7 (- ks2 0.5) 8))
(p4 (* ks7 (- ks3 0.5) 8))
)
(render 1)
Color drift.
OpenCL kernels for the ping pong buffers.
__kernel void image_setup(
__read_only image2d_t image_in,
__read_only image2d_t image_src,
__write_only image2d_t image_dst,
const float p0,
const float p1,
const float p2,
const float p3,
const float p4,
const float p5,
const float p6,
const float p7
)
{
// setup code not used in this exsample
}
__kernel void image_change(
__read_only image2d_t image_in,
__read_only image2d_t image_src,
__write_only image2d_t image_dst,
const float p0,
const float p1,
const float p2,
const float p3,
const float p4,
const float p5,
const float p6,
const float p7
)
{
const int x = get_global_id(0);
const int y = get_global_id(1);
sampler_t smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR;
const int2 center = (int2)(x, y);
// upstream color
float4 color_up = read_imagef(image_in, smp, center);
// colors from the current source buffer
const float2 drift1 = (float2)(x+p1, y+p2);
const float2 drift2 = (float2)(x+p3, y+p4);
float4 color_bc = read_imagef(image_src, smp, center);
float4 color_d1 = read_imagef(image_src, smp, drift1);
float4 color_d2 = read_imagef(image_src, smp, drift2);
// merge upstream color to the feedback loop
float a = p0;
float b = 1.0 - a;
float c = b / 2.975;
write_imagef(image_dst, center, (float4)(
a*color_up.x + c*color_d1.x + c*color_bc.x + c*color_d2.x,
a*color_up.y + c*color_d1.y + c*color_bc.y + c*color_d2.y,
a*color_up.z + c*color_d1.z + c*color_bc.z + c*color_d2.z,
1.0
));
}