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