1 /* blur.h
2 * Copyright (C) 2004--2005 Mathieu Guindon
3 * Julien Keable
4 * Jean-Sebastien Senecal (js@drone.ws)
5 *
6 * Modified by Richard Spindler (richard.spindler AT gmail.com) for blurring in
7 * the mask0mate Frei0r plugin.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <string.h>
27
28 #include "frei0r.h"
29
30 #define SIZE_RGBA 4
31
MAX(int a,int b)32 static inline int MAX(int a, int b)
33 {
34 return (a > b ? a : b);
35 }
36
MIN(int a,int b)37 static inline int MIN(int a, int b)
38 {
39 return (a < b ? a : b);
40 }
41
subtract_acc(uint32_t * dst,const uint32_t * src)42 static inline void subtract_acc(uint32_t *dst, const uint32_t *src)
43 {
44 int n=SIZE_RGBA;
45 while (n--)
46 *dst++ -= *src++;
47 }
48
add_acc(uint32_t * dst,const uint32_t * src)49 static inline void add_acc(uint32_t *dst, const uint32_t *src)
50 {
51 int n=SIZE_RGBA;
52 while (n--)
53 *dst++ += *src++;
54 }
55
divide(unsigned char * dst,const uint32_t * src,const unsigned int val)56 static inline void divide(unsigned char *dst, const uint32_t *src, const unsigned int val)
57 {
58 int n=SIZE_RGBA;
59 while (n--)
60 *dst++ = *src++ / val;
61 }
62
63 typedef struct squareblur_instance
64 {
65 unsigned int width;
66 unsigned int height;
67 double kernel; /* the kernel size, as a percentage of the biggest of width and height */
68 uint32_t *mem; /* memory accumulation matrix of uint32_t (size = acc_width*acc_height*SIZE_RGBA) */
69 uint32_t **acc; /* accumulation matrix of pointers to SIZE_RGBA consecutive uint32_t in mem (size = acc_width*acc_height) */
70 } squareblur_instance_t;
71
72 /* Updates the summed area table. */
update_summed_area_table(squareblur_instance_t * inst,const uint32_t * src)73 static void update_summed_area_table(squareblur_instance_t *inst, const uint32_t *src)
74 {
75 register unsigned char *iter_data;
76 register uint32_t *iter_mem;
77 register unsigned int i, x, y;
78
79 uint32_t acc_buffer[SIZE_RGBA]; /* accumulation buffer */
80
81 unsigned int row_width;
82 unsigned int width, height;
83 unsigned int cell_size;
84
85 /* Compute basic params. */
86 width = inst->width+1;
87 height = inst->height+1;
88 row_width = SIZE_RGBA * width;
89 cell_size = SIZE_RGBA * sizeof(uint32_t);
90
91 /* Init iterators. */
92 iter_data = (unsigned char*) src;
93 iter_mem = inst->mem;
94
95 /* Process first row (all zeros). */
96 memset(iter_mem, 0, row_width * cell_size);
97 iter_mem += row_width;
98
99 if (height >= 1)
100 {
101 /* Process second row. */
102 memset(acc_buffer, 0, cell_size);
103 memset(iter_mem, 0, cell_size); /* first column is void */
104 iter_mem += SIZE_RGBA;
105 for (x=1; x<width; ++x)
106 {
107 for (i=0; i<SIZE_RGBA; ++i)
108 *iter_mem++ = (acc_buffer[i] += *iter_data++);
109 }
110
111 /* Process other rows. */
112 for (y=2; y<height; ++y)
113 {
114 /* Copy upper line. */
115 memcpy(iter_mem, iter_mem - row_width, row_width * sizeof(uint32_t));
116
117 /* Process row. */
118 memset(acc_buffer, 0, cell_size);
119 memset(iter_mem, 0, cell_size); /* first column is void */
120 iter_mem += SIZE_RGBA;
121 for (x=1; x<width; ++x)
122 {
123 for (i=0; i<SIZE_RGBA; ++i)
124 *iter_mem++ += (acc_buffer[i] += *iter_data++);
125 }
126 }
127 }
128 }
129
blur_get_param_info(f0r_param_info_t * info,int param_index)130 static void blur_get_param_info(f0r_param_info_t* info, int param_index)
131 {
132 switch(param_index)
133 {
134 case 0:
135 info->name = "Kernel size";
136 info->type = F0R_PARAM_DOUBLE;
137 info->explanation = "The size of the kernel, as a proportion to its coverage of the image";
138 break;
139 }
140 }
141
blur_construct(unsigned int width,unsigned int height)142 static f0r_instance_t blur_construct(unsigned int width, unsigned int height)
143 {
144 squareblur_instance_t* inst =
145 (squareblur_instance_t*)malloc(sizeof(squareblur_instance_t));
146 unsigned int i;
147 unsigned int acc_width, acc_height = height+1;
148 uint32_t* iter_mem;
149 uint32_t** iter_acc;
150 /* set params */
151 inst->width = width; inst->height = height;
152 acc_width = width+1; acc_height = height+1;
153 inst->kernel = 0.0;
154 /* allocate memory for the summed-area-table */
155 inst->mem = (uint32_t*) malloc(acc_width*acc_height*SIZE_RGBA*sizeof(uint32_t));
156 inst->acc = (uint32_t**) malloc(acc_width*acc_height*sizeof(uint32_t*));
157 /* point at the right place */
158 iter_mem = inst->mem;
159 iter_acc = inst->acc;
160 for (i=0; i<acc_width*acc_height; ++i)
161 {
162 *iter_acc++ = iter_mem;
163 iter_mem += SIZE_RGBA;
164 }
165 return (f0r_instance_t)inst;
166 }
167
blur_destruct(f0r_instance_t instance)168 static void blur_destruct(f0r_instance_t instance)
169 {
170 squareblur_instance_t* inst =
171 (squareblur_instance_t*)instance;
172 free(inst->acc);
173 free(inst->mem);
174 free(instance);
175 }
176
blur_set_param_value(f0r_instance_t instance,f0r_param_t param,int param_index)177 static void blur_set_param_value(f0r_instance_t instance,
178 f0r_param_t param, int param_index)
179 {
180 assert(instance);
181 squareblur_instance_t* inst = (squareblur_instance_t*)instance;
182
183 switch(param_index)
184 {
185 case 0:
186 /* kernel size */
187 inst->kernel = *((double*)param);
188 break;
189 }
190 }
191
blur_get_param_value(f0r_instance_t instance,f0r_param_t param,int param_index)192 static void blur_get_param_value(f0r_instance_t instance,
193 f0r_param_t param, int param_index)
194 {
195 assert(instance);
196 squareblur_instance_t* inst = (squareblur_instance_t*)instance;
197
198 switch(param_index)
199 {
200 case 0:
201 *((double*)param) = inst->kernel;
202 break;
203 }
204 }
205
blur_update(f0r_instance_t instance,double time,const uint32_t * inframe,uint32_t * outframe)206 static void blur_update(f0r_instance_t instance, double time,
207 const uint32_t* inframe, uint32_t* outframe)
208 {
209 assert(instance);
210 squareblur_instance_t* inst = (squareblur_instance_t*)instance;
211
212 unsigned int width = inst->width;
213 unsigned int height = inst->height;
214 unsigned int acc_width = width+1; /* width of the summed area table */
215 unsigned int max = MAX(width, height);
216 unsigned int kernel_size = (unsigned int) (inst->kernel * max / 2.0);
217
218 unsigned int x, y;
219 unsigned int x0, x1, y0, y1;
220 unsigned int area;
221
222 if (kernel_size <= 0)
223 {
224 /* No blur, just copy image. */
225 memcpy(outframe, inframe, width*height*sizeof(uint32_t));
226 }
227 else
228 {
229 assert(inst->acc);
230 unsigned char* dst = (unsigned char*)outframe;
231 uint32_t** acc = inst->acc;
232 uint32_t sum[SIZE_RGBA];
233 unsigned int y0_offset, y1_offset;
234
235 /* Compute the summed area table. */
236 update_summed_area_table(inst, inframe);
237
238 /* Loop through the image's pixels. */
239 for (y=0;y<height;y++)
240 {
241 for (x=0;x<width;x++)
242 {
243 /* The kernel's coordinates. */
244 x0 = MAX(x - kernel_size, 0);
245 x1 = MIN(x + kernel_size + 1, width);
246 y0 = MAX(y - kernel_size, 0);
247 y1 = MIN(y + kernel_size + 1, height);
248
249 /* Get the sum in the current kernel. */
250 area = (x1-x0)*(y1-y0);
251
252 y0_offset = y0*acc_width;
253 y1_offset = y1*acc_width;
254
255 /* it is assumed that (x0,y0) <= (x1,y1) */
256 memcpy(sum, acc[y1_offset + x1], SIZE_RGBA*sizeof(uint32_t));
257 subtract_acc(sum, acc[y1_offset + x0]);
258 subtract_acc(sum, acc[y0_offset + x1]);
259 add_acc(sum, acc[y0_offset + x0]);
260
261 /* Take the mean and copy it to output. */
262 divide(dst, sum, area);
263
264 /* Increment iterator. */
265 dst += SIZE_RGBA;
266 }
267 }
268 }
269 }
270
271