Blender  V2.59
CMP_bilateralblur.c
Go to the documentation of this file.
00001 /*
00002  *
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2006 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): Vilem Novak
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00034 #include "../CMP_util.h"
00035 
00036 /* **************** BILATERALBLUR ******************** */
00037 static bNodeSocketType cmp_node_bilateralblur_in[]= {
00038         { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, 
00039         { SOCK_RGBA, 1, "Determinator", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, 
00040         { -1, 0, "" } 
00041 };
00042 
00043 static bNodeSocketType cmp_node_bilateralblur_out[]= { 
00044         { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, 
00045         { -1, 0, "" } 
00046 };
00047 
00048 #define INIT_C3\
00049         mean0 = 1; mean1[0] = src[0];mean1[1] = src[1];mean1[2] = src[2];mean1[3] = src[3];
00050 
00051 /* finds color distances */
00052 #define COLOR_DISTANCE_C3(c1, c2)\
00053         ((c1[0] - c2[0])*(c1[0] - c2[0]) + \
00054         (c1[1] - c2[1])*(c1[1] - c2[1]) + \
00055         (c1[2] - c2[2])*(c1[2] - c2[2]) + \
00056         (c1[3] - c2[3])*(c1[3] - c2[3]))
00057 
00058 /* this is the main kernel function for comparing color distances
00059  and adding them weighted to the final color */
00060 #define KERNEL_ELEMENT_C3(k)\
00061         temp_color = src + deltas[k];\
00062         ref_color = ref + deltas[k];\
00063         w = weight_tab[k] + COLOR_DISTANCE_C3(ref, ref_color )*i2sigma_color;\
00064         w = 1./(w*w + 1); \
00065         mean0 += w;\
00066         mean1[0] += temp_color[0]*w; \
00067         mean1[1] += temp_color[1]*w; \
00068         mean1[2] += temp_color[2]*w; \
00069         mean1[3] += temp_color[3]*w;
00070 
00071 /* write blurred values to image */
00072 #define UPDATE_OUTPUT_C3\
00073         mean0 = 1./mean0;\
00074         dest[x*pix + 0] = mean1[0]*mean0; \
00075         dest[x*pix + 1] = mean1[1]*mean0; \
00076         dest[x*pix + 2] = mean1[2]*mean0; \
00077         dest[x*pix + 3] = mean1[3]*mean0;
00078 
00079 /* initializes deltas for fast access to neighbour pixels */
00080 #define INIT_3X3_DELTAS( deltas, step, nch )            \
00081         ((deltas)[0] =  (nch),  (deltas)[1] = -(step) + (nch),  \
00082         (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch),  \
00083         (deltas)[4] = -(nch),  (deltas)[5] =  (step) - (nch),  \
00084         (deltas)[6] =  (step), (deltas)[7] =  (step) + (nch));
00085 
00086 
00087 /* code of this node was heavily inspired by the smooth function of opencv library.
00088 The main change is an optional image input */
00089 static void node_composit_exec_bilateralblur(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
00090 {
00091         NodeBilateralBlurData *nbbd= node->storage;
00092         CompBuf *new, *source, *img= in[0]->data , *refimg= in[1]->data;
00093         double mean0, w, i2sigma_color, i2sigma_space;
00094         double mean1[4];
00095         double weight_tab[8];
00096         float *src, *dest, *ref, *temp_color, *ref_color;
00097         float sigma_color, sigma_space;
00098         int imgx, imgy, x, y, pix, i, step;
00099         int deltas[8];
00100         short found_determinator= 0;
00101 
00102         if(img == NULL || out[0]->hasoutput == 0)
00103                 return;
00104 
00105         if(img->type != CB_RGBA) {
00106                 img= typecheck_compbuf(in[0]->data, CB_RGBA);
00107         }
00108 
00109         imgx= img->x;
00110         imgy= img->y;
00111         pix= img->type;
00112         step= pix * imgx;
00113 
00114         if(refimg) {
00115                 if(refimg->x == imgx && refimg->y == imgy) {
00116                         if(ELEM3(refimg->type, CB_VAL, CB_VEC2, CB_VEC3)) {
00117                                 refimg= typecheck_compbuf(in[1]->data, CB_RGBA);
00118                                 found_determinator= 1;
00119                         }
00120                 }
00121         }
00122         else {
00123                 refimg= img;
00124         }
00125 
00126         /* allocs */
00127         source= dupalloc_compbuf(img);
00128         new= alloc_compbuf(imgx, imgy, pix, 1);
00129         
00130         /* accept image offsets from other nodes */
00131         new->xof= img->xof;
00132         new->yof= img->yof;
00133 
00134         /* bilateral code properties */
00135         sigma_color= nbbd->sigma_color;
00136         sigma_space= nbbd->sigma_space;
00137         
00138         i2sigma_color= 1. / (sigma_color * sigma_color);
00139         i2sigma_space= 1. / (sigma_space * sigma_space);
00140 
00141         INIT_3X3_DELTAS(deltas, step, pix);
00142 
00143         weight_tab[0] = weight_tab[2] = weight_tab[4] = weight_tab[6] = i2sigma_space;
00144         weight_tab[1] = weight_tab[3] = weight_tab[5] = weight_tab[7] = i2sigma_space * 2;
00145 
00146         /* iterations */
00147         for(i= 0; i < nbbd->iter; i++) {
00148                 src= source->rect;
00149                 ref= refimg->rect;
00150                 dest= new->rect;
00151                 /*goes through image, there are more loops for 1st/last line and all other lines*/
00152                 /*kernel element accumulates surrounding colors, which are then written with the update_output function*/
00153                 for(x= 0; x < imgx; x++, src+= pix, ref+= pix) {
00154                         INIT_C3;
00155 
00156                         KERNEL_ELEMENT_C3(6);
00157 
00158                         if(x > 0) {
00159                                 KERNEL_ELEMENT_C3(5);
00160                                 KERNEL_ELEMENT_C3(4);
00161                         }
00162 
00163                         if(x < imgx - 1) {
00164                                 KERNEL_ELEMENT_C3(7);
00165                                 KERNEL_ELEMENT_C3(0);
00166                         }
00167 
00168                         UPDATE_OUTPUT_C3;
00169                 }
00170 
00171                 dest+= step;
00172 
00173                 for(y= 1; y < imgy - 1; y++, dest+= step, src+= pix, ref+= pix) {
00174                         x= 0;
00175 
00176                         INIT_C3;
00177 
00178                         KERNEL_ELEMENT_C3(0);
00179                         KERNEL_ELEMENT_C3(1);
00180                         KERNEL_ELEMENT_C3(2);
00181                         KERNEL_ELEMENT_C3(6);
00182                         KERNEL_ELEMENT_C3(7);
00183 
00184                         UPDATE_OUTPUT_C3;
00185 
00186                         src+= pix;
00187                         ref+= pix;
00188 
00189                         for(x= 1; x < imgx - 1; x++, src+= pix, ref+= pix) {
00190                                 INIT_C3;
00191 
00192                                 KERNEL_ELEMENT_C3(0);
00193                                 KERNEL_ELEMENT_C3(1);
00194                                 KERNEL_ELEMENT_C3(2);
00195                                 KERNEL_ELEMENT_C3(3);
00196                                 KERNEL_ELEMENT_C3(4);
00197                                 KERNEL_ELEMENT_C3(5);
00198                                 KERNEL_ELEMENT_C3(6);
00199                                 KERNEL_ELEMENT_C3(7);
00200 
00201                                 UPDATE_OUTPUT_C3;
00202                         }
00203 
00204                         INIT_C3;
00205 
00206                         KERNEL_ELEMENT_C3(2);
00207                         KERNEL_ELEMENT_C3(3);
00208                         KERNEL_ELEMENT_C3(4);
00209                         KERNEL_ELEMENT_C3(5);
00210                         KERNEL_ELEMENT_C3(6);
00211 
00212                         UPDATE_OUTPUT_C3;
00213                 }
00214 
00215                 for(x= 0; x < imgx; x++, src+= pix, ref+= pix) {
00216                         INIT_C3;
00217 
00218                         KERNEL_ELEMENT_C3(2);
00219 
00220                         if(x > 0) {
00221                                 KERNEL_ELEMENT_C3(3);
00222                                 KERNEL_ELEMENT_C3(4);
00223                         }
00224                         if(x < imgx - 1) {
00225                                 KERNEL_ELEMENT_C3(1);
00226                                 KERNEL_ELEMENT_C3(0);
00227                         }
00228 
00229                         UPDATE_OUTPUT_C3;
00230                 }
00231 
00232                 if(node->exec & NODE_BREAK) break;
00233 
00234                 SWAP(CompBuf, *source, *new);
00235         }
00236 
00237         if(img != in[0]->data)
00238                 free_compbuf(img);
00239 
00240         if(found_determinator == 1) {
00241                 if(refimg != in[1]->data)
00242                         free_compbuf(refimg);
00243         }
00244 
00245         out[0]->data= source;
00246 
00247         free_compbuf(new);
00248 }
00249 
00250 static void node_composit_init_bilateralblur(bNode* node)
00251 {
00252         NodeBilateralBlurData *nbbd= MEM_callocN(sizeof(NodeBilateralBlurData), "node bilateral blur data");
00253         node->storage= nbbd;
00254         nbbd->sigma_color= 0.3;
00255         nbbd->sigma_space= 5.0;
00256 }
00257 
00258 void register_node_type_cmp_bilateralblur(ListBase *lb)
00259 {
00260         static bNodeType ntype;
00261 
00262         node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, NODE_OPTIONS,
00263                 cmp_node_bilateralblur_in, cmp_node_bilateralblur_out);
00264         node_type_size(&ntype, 150, 120, 200);
00265         node_type_init(&ntype, node_composit_init_bilateralblur);
00266         node_type_storage(&ntype, "NodeBilateralBlurData", node_free_standard_storage, node_copy_standard_storage);
00267         node_type_exec(&ntype, node_composit_exec_bilateralblur);
00268 
00269         nodeRegisterType(lb, &ntype);
00270 }
00271