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