Merge ../mlt
[melted] / src / modules / effectv / image.c
1 /*
2 * EffecTV - Realtime Digital Video Effector
3 * Copyright (C) 2001-2006 FUKUCHI Kentaro
4 *
5 * image.c: utilities for image processing.
6 *
7 */
8
9 #include <string.h>
10 #include <stdlib.h>
11 #include "utils.h"
12
13
14 /*
15 * Collection of background subtraction functions
16 */
17
18 /* checks only fake-Y value */
19 /* In these function Y value is treated as R*2+G*4+B. */
20
21 int image_set_threshold_y(int threshold)
22 {
23 int y_threshold = threshold * 7; /* fake-Y value is timed by 7 */
24
25 return y_threshold;
26 }
27
28 void image_bgset_y(RGB32 *background, const RGB32 *src, int video_area, int y_threshold)
29 {
30 int i;
31 int R, G, B;
32 const RGB32 *p;
33 short *q;
34
35 p = src;
36 q = (short *)background;
37 for(i=0; i<video_area; i++) {
38 /* FIXME: endianess */
39
40 R = ((*p)&0xff0000)>>(16-1);
41 G = ((*p)&0xff00)>>(8-2);
42 B = (*p)&0xff;
43 *q = (short)(R + G + B);
44 p++;
45 q++;
46 }
47 }
48
49 void image_bgsubtract_y(unsigned char *diff, const RGB32 *background, const RGB32 *src, int video_area, int y_threshold)
50 {
51 int i;
52 int R, G, B;
53 const RGB32 *p;
54 const short *q;
55 unsigned char *r;
56 int v;
57
58 p = src;
59 q = (const short *)background;
60 r = diff;
61 for(i=0; i<video_area; i++) {
62 /* FIXME: endianess */
63
64 R = ((*p)&0xff0000)>>(16-1);
65 G = ((*p)&0xff00)>>(8-2);
66 B = (*p)&0xff;
67 v = (R + G + B) - (int)(*q);
68 *r = ((v + y_threshold)>>24) | ((y_threshold - v)>>24);
69
70 p++;
71 q++;
72 r++;
73 }
74
75 /* The origin of subtraction function is;
76 * diff(src, dest) = (abs(src - dest) > threshold) ? 0xff : 0;
77 *
78 * This functions is transformed to;
79 * (threshold > (src - dest) > -threshold) ? 0 : 0xff;
80 *
81 * (v + threshold)>>24 is 0xff when v is less than -threshold.
82 * (v - threshold)>>24 is 0xff when v is less than threshold.
83 * So, ((v + threshold)>>24) | ((threshold - v)>>24) will become 0xff when
84 * abs(src - dest) > threshold.
85 */
86 }
87
88 /* Background image is refreshed every frame */
89 void image_bgsubtract_update_y(unsigned char *diff, RGB32 *background, const RGB32 *src, int video_area, int y_threshold)
90 {
91 int i;
92 int R, G, B;
93 const RGB32 *p;
94 short *q;
95 unsigned char *r;
96 int v;
97
98 p = src;
99 q = (short *)background;
100 r = diff;
101 for(i=0; i<video_area; i++) {
102 /* FIXME: endianess */
103
104 R = ((*p)&0xff0000)>>(16-1);
105 G = ((*p)&0xff00)>>(8-2);
106 B = (*p)&0xff;
107 v = (R + G + B) - (int)(*q);
108 *q = (short)(R + G + B);
109 *r = ((v + y_threshold)>>24) | ((y_threshold - v)>>24);
110
111 p++;
112 q++;
113 r++;
114 }
115 }
116
117 /* checks each RGB value */
118
119 /* The range of r, g, b are [0..7] */
120 RGB32 image_set_threshold_RGB(int r, int g, int b)
121 {
122 unsigned char R, G, B;
123 RGB32 rgb_threshold;
124
125 R = G = B = 0xff;
126 R = R<<r;
127 G = G<<g;
128 B = B<<b;
129 rgb_threshold = (RGB32)(R<<16 | G<<8 | B);
130
131 return rgb_threshold;
132 }
133
134 void image_bgset_RGB(RGB32 *background, const RGB32 *src, int video_area)
135 {
136 int i;
137 RGB32 *p;
138
139 p = background;
140 for(i=0; i<video_area; i++) {
141 *p++ = (*src++) & 0xfefefe;
142 }
143 }
144
145 void image_bgsubtract_RGB(unsigned char *diff, const RGB32 *background, const RGB32 *src, int video_area, RGB32 rgb_threshold)
146 {
147 int i;
148 const RGB32 *p, *q;
149 unsigned a, b;
150 unsigned char *r;
151
152 p = src;
153 q = background;
154 r = diff;
155 for(i=0; i<video_area; i++) {
156 a = (*p++)|0x1010100;
157 b = *q++;
158 a = a - b;
159 b = a & 0x1010100;
160 b = b - (b>>8);
161 b = b ^ 0xffffff;
162 a = a ^ b;
163 a = a & rgb_threshold;
164 *r++ = (0 - a)>>24;
165 }
166 }
167
168 void image_bgsubtract_update_RGB(unsigned char *diff, RGB32 *background, const RGB32 *src, int video_area, RGB32 rgb_threshold)
169 {
170 int i;
171 const RGB32 *p;
172 RGB32 *q;
173 unsigned a, b;
174 unsigned char *r;
175
176 p = src;
177 q = background;
178 r = diff;
179 for(i=0; i<video_area; i++) {
180 a = *p|0x1010100;
181 b = *q&0xfefefe;
182 *q++ = *p++;
183 a = a - b;
184 b = a & 0x1010100;
185 b = b - (b>>8);
186 b = b ^ 0xffffff;
187 a = a ^ b;
188 a = a & rgb_threshold;
189 *r++ = (0 - a)>>24;
190 }
191 }
192
193 /* noise filter for subtracted image. */
194 void image_diff_filter(unsigned char *diff2, const unsigned char *diff, int width, int height)
195 {
196 int x, y;
197 const unsigned char *src;
198 unsigned char *dest;
199 unsigned int count;
200 unsigned int sum1, sum2, sum3;
201
202 src = diff;
203 dest = diff2 + width +1;
204 for(y=1; y<height-1; y++) {
205 sum1 = src[0] + src[width] + src[width*2];
206 sum2 = src[1] + src[width+1] + src[width*2+1];
207 src += 2;
208 for(x=1; x<width-1; x++) {
209 sum3 = src[0] + src[width] + src[width*2];
210 count = sum1 + sum2 + sum3;
211 sum1 = sum2;
212 sum2 = sum3;
213 *dest++ = (0xff*3 - count)>>24;
214 src++;
215 }
216 dest += 2;
217 }
218 }
219
220 /* Y value filters */
221 void image_y_over(unsigned char *diff, const RGB32 *src, int video_area, int y_threshold)
222 {
223 int i;
224 int R, G, B, v;
225 unsigned char *p = diff;
226
227 for(i = video_area; i>0; i--) {
228 R = ((*src)&0xff0000)>>(16-1);
229 G = ((*src)&0xff00)>>(8-2);
230 B = (*src)&0xff;
231 v = y_threshold - (R + G + B);
232 *p = (unsigned char)(v>>24);
233 src++;
234 p++;
235 }
236 }
237
238 void image_y_under(unsigned char *diff, const RGB32 *src, int video_area, int y_threshold)
239 {
240 int i;
241 int R, G, B, v;
242 unsigned char *p = diff;
243
244 for(i = video_area; i>0; i--) {
245 R = ((*src)&0xff0000)>>(16-1);
246 G = ((*src)&0xff00)>>(8-2);
247 B = (*src)&0xff;
248 v = (R + G + B) - y_threshold;
249 *p = (unsigned char)(v>>24);
250 src++;
251 p++;
252 }
253 }
254
255 /* tiny edge detection */
256 void image_edge(unsigned char *diff2, const RGB32 *src, int width, int height, int y_threshold)
257 {
258 int x, y;
259 const unsigned char *p;
260 unsigned char *q;
261 int r, g, b;
262 int ar, ag, ab;
263 int w;
264
265 p = (const unsigned char *)src;
266 q = diff2;
267 w = width * sizeof(RGB32);
268
269 for(y=0; y<height - 1; y++) {
270 for(x=0; x<width - 1; x++) {
271 b = p[0];
272 g = p[1];
273 r = p[2];
274 ab = abs(b - p[4]);
275 ag = abs(g - p[5]);
276 ar = abs(r - p[6]);
277 ab += abs(b - p[w]);
278 ag += abs(g - p[w+1]);
279 ar += abs(r - p[w+2]);
280 b = ab+ag+ar;
281 if(b > y_threshold) {
282 *q = 255;
283 } else {
284 *q = 0;
285 }
286 q++;
287 p += 4;
288 }
289 p += 4;
290 *q++ = 0;
291 }
292 memset(q, 0, width);
293 }
294
295 /* horizontal flipping */
296 void image_hflip(const RGB32 *src, RGB32 *dest, int width, int height)
297 {
298 int x, y;
299
300 src += width - 1;
301 for(y=0; y<height; y++) {
302 for(x=0; x<width; x++) {
303 *dest++ = *src--;
304 }
305 src += width * 2;
306 }
307 }
308