svn merge -r39930:39947 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / nodes / composite / nodes / node_composite_bilateralblur.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2006 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Vilem Novak
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/nodes/composite/nodes/node_composite_bilateralblur.c
31  *  \ingroup cmpnodes
32  */
33
34 #include "node_composite_util.h"
35
36 /* **************** BILATERALBLUR ******************** */
37 static bNodeSocketTemplate cmp_node_bilateralblur_in[]= {
38         { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f}, 
39         { SOCK_RGBA, 1, "Determinator", 0.8f, 0.8f, 0.8f, 1.0f}, 
40         { -1, 0, "" } 
41 };
42
43 static bNodeSocketTemplate cmp_node_bilateralblur_out[]= { 
44         { SOCK_RGBA, 0, "Image"}, 
45         { -1, 0, "" } 
46 };
47
48 #define INIT_C3\
49         mean0 = 1; mean1[0] = src[0];mean1[1] = src[1];mean1[2] = src[2];mean1[3] = src[3];
50
51 /* finds color distances */
52 #define COLOR_DISTANCE_C3(c1, c2)\
53         ((c1[0] - c2[0])*(c1[0] - c2[0]) + \
54         (c1[1] - c2[1])*(c1[1] - c2[1]) + \
55         (c1[2] - c2[2])*(c1[2] - c2[2]) + \
56         (c1[3] - c2[3])*(c1[3] - c2[3]))
57
58 /* this is the main kernel function for comparing color distances
59  and adding them weighted to the final color */
60 #define KERNEL_ELEMENT_C3(k)\
61         temp_color = src + deltas[k];\
62         ref_color = ref + deltas[k];\
63         w = weight_tab[k] + COLOR_DISTANCE_C3(ref, ref_color )*i2sigma_color;\
64         w = 1./(w*w + 1); \
65         mean0 += w;\
66         mean1[0] += temp_color[0]*w; \
67         mean1[1] += temp_color[1]*w; \
68         mean1[2] += temp_color[2]*w; \
69         mean1[3] += temp_color[3]*w;
70
71 /* write blurred values to image */
72 #define UPDATE_OUTPUT_C3\
73         mean0 = 1./mean0;\
74         dest[x*pix + 0] = mean1[0]*mean0; \
75         dest[x*pix + 1] = mean1[1]*mean0; \
76         dest[x*pix + 2] = mean1[2]*mean0; \
77         dest[x*pix + 3] = mean1[3]*mean0;
78
79 /* initializes deltas for fast access to neighbour pixels */
80 #define INIT_3X3_DELTAS( deltas, step, nch )            \
81         ((deltas)[0] =  (nch),  (deltas)[1] = -(step) + (nch),  \
82         (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch),  \
83         (deltas)[4] = -(nch),  (deltas)[5] =  (step) - (nch),  \
84         (deltas)[6] =  (step), (deltas)[7] =  (step) + (nch));
85
86
87 /* code of this node was heavily inspired by the smooth function of opencv library.
88 The main change is an optional image input */
89 static void node_composit_exec_bilateralblur(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
90 {
91         NodeBilateralBlurData *nbbd= node->storage;
92         CompBuf *new, *source, *img= in[0]->data , *refimg= in[1]->data;
93         double mean0, w, i2sigma_color, i2sigma_space;
94         double mean1[4];
95         double weight_tab[8];
96         float *src, *dest, *ref, *temp_color, *ref_color;
97         float sigma_color, sigma_space;
98         int imgx, imgy, x, y, pix, i, step;
99         int deltas[8];
100         short found_determinator= 0;
101
102         if(img == NULL || out[0]->hasoutput == 0)
103                 return;
104
105         if(img->type != CB_RGBA) {
106                 img= typecheck_compbuf(in[0]->data, CB_RGBA);
107         }
108
109         imgx= img->x;
110         imgy= img->y;
111         pix= img->type;
112         step= pix * imgx;
113
114         if(refimg) {
115                 if(refimg->x == imgx && refimg->y == imgy) {
116                         if(ELEM3(refimg->type, CB_VAL, CB_VEC2, CB_VEC3)) {
117                                 refimg= typecheck_compbuf(in[1]->data, CB_RGBA);
118                                 found_determinator= 1;
119                         }
120                 }
121         }
122         else {
123                 refimg= img;
124         }
125
126         /* allocs */
127         source= dupalloc_compbuf(img);
128         new= alloc_compbuf(imgx, imgy, pix, 1);
129         
130         /* accept image offsets from other nodes */
131         new->xof= img->xof;
132         new->yof= img->yof;
133
134         /* bilateral code properties */
135         sigma_color= nbbd->sigma_color;
136         sigma_space= nbbd->sigma_space;
137         
138         i2sigma_color= 1. / (sigma_color * sigma_color);
139         i2sigma_space= 1. / (sigma_space * sigma_space);
140
141         INIT_3X3_DELTAS(deltas, step, pix);
142
143         weight_tab[0] = weight_tab[2] = weight_tab[4] = weight_tab[6] = i2sigma_space;
144         weight_tab[1] = weight_tab[3] = weight_tab[5] = weight_tab[7] = i2sigma_space * 2;
145
146         /* iterations */
147         for(i= 0; i < nbbd->iter; i++) {
148                 src= source->rect;
149                 ref= refimg->rect;
150                 dest= new->rect;
151                 /*goes through image, there are more loops for 1st/last line and all other lines*/
152                 /*kernel element accumulates surrounding colors, which are then written with the update_output function*/
153                 for(x= 0; x < imgx; x++, src+= pix, ref+= pix) {
154                         INIT_C3;
155
156                         KERNEL_ELEMENT_C3(6);
157
158                         if(x > 0) {
159                                 KERNEL_ELEMENT_C3(5);
160                                 KERNEL_ELEMENT_C3(4);
161                         }
162
163                         if(x < imgx - 1) {
164                                 KERNEL_ELEMENT_C3(7);
165                                 KERNEL_ELEMENT_C3(0);
166                         }
167
168                         UPDATE_OUTPUT_C3;
169                 }
170
171                 dest+= step;
172
173                 for(y= 1; y < imgy - 1; y++, dest+= step, src+= pix, ref+= pix) {
174                         x= 0;
175
176                         INIT_C3;
177
178                         KERNEL_ELEMENT_C3(0);
179                         KERNEL_ELEMENT_C3(1);
180                         KERNEL_ELEMENT_C3(2);
181                         KERNEL_ELEMENT_C3(6);
182                         KERNEL_ELEMENT_C3(7);
183
184                         UPDATE_OUTPUT_C3;
185
186                         src+= pix;
187                         ref+= pix;
188
189                         for(x= 1; x < imgx - 1; x++, src+= pix, ref+= pix) {
190                                 INIT_C3;
191
192                                 KERNEL_ELEMENT_C3(0);
193                                 KERNEL_ELEMENT_C3(1);
194                                 KERNEL_ELEMENT_C3(2);
195                                 KERNEL_ELEMENT_C3(3);
196                                 KERNEL_ELEMENT_C3(4);
197                                 KERNEL_ELEMENT_C3(5);
198                                 KERNEL_ELEMENT_C3(6);
199                                 KERNEL_ELEMENT_C3(7);
200
201                                 UPDATE_OUTPUT_C3;
202                         }
203
204                         INIT_C3;
205
206                         KERNEL_ELEMENT_C3(2);
207                         KERNEL_ELEMENT_C3(3);
208                         KERNEL_ELEMENT_C3(4);
209                         KERNEL_ELEMENT_C3(5);
210                         KERNEL_ELEMENT_C3(6);
211
212                         UPDATE_OUTPUT_C3;
213                 }
214
215                 for(x= 0; x < imgx; x++, src+= pix, ref+= pix) {
216                         INIT_C3;
217
218                         KERNEL_ELEMENT_C3(2);
219
220                         if(x > 0) {
221                                 KERNEL_ELEMENT_C3(3);
222                                 KERNEL_ELEMENT_C3(4);
223                         }
224                         if(x < imgx - 1) {
225                                 KERNEL_ELEMENT_C3(1);
226                                 KERNEL_ELEMENT_C3(0);
227                         }
228
229                         UPDATE_OUTPUT_C3;
230                 }
231
232                 if(node->exec & NODE_BREAK) break;
233
234                 SWAP(CompBuf, *source, *new);
235         }
236
237         if(img != in[0]->data)
238                 free_compbuf(img);
239
240         if(found_determinator == 1) {
241                 if(refimg != in[1]->data)
242                         free_compbuf(refimg);
243         }
244
245         out[0]->data= source;
246
247         free_compbuf(new);
248 }
249
250 static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *UNUSED(ntemp))
251 {
252         NodeBilateralBlurData *nbbd= MEM_callocN(sizeof(NodeBilateralBlurData), "node bilateral blur data");
253         node->storage= nbbd;
254         nbbd->sigma_color= 0.3;
255         nbbd->sigma_space= 5.0;
256 }
257
258 void register_node_type_cmp_bilateralblur(ListBase *lb)
259 {
260         static bNodeType ntype;
261
262         node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, NODE_OPTIONS);
263         node_type_socket_templates(&ntype, cmp_node_bilateralblur_in, cmp_node_bilateralblur_out);
264         node_type_size(&ntype, 150, 120, 200);
265         node_type_init(&ntype, node_composit_init_bilateralblur);
266         node_type_storage(&ntype, "NodeBilateralBlurData", node_free_standard_storage, node_copy_standard_storage);
267         node_type_exec(&ntype, node_composit_exec_bilateralblur);
268
269         nodeRegisterType(lb, &ntype);
270 }
271