diff options
Diffstat (limited to 'source/blender/nodes/intern/CMP_nodes/CMP_bilateralblur.c')
-rw-r--r-- | source/blender/nodes/intern/CMP_nodes/CMP_bilateralblur.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_bilateralblur.c b/source/blender/nodes/intern/CMP_nodes/CMP_bilateralblur.c new file mode 100644 index 00000000000..b954e876ea1 --- /dev/null +++ b/source/blender/nodes/intern/CMP_nodes/CMP_bilateralblur.c @@ -0,0 +1,272 @@ +/** + * + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Vilem Novak + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include "../CMP_util.h" + +/* **************** BILATERALBLUR ******************** */ +static bNodeSocketType cmp_node_bilateralblur_in[]= { + { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_RGBA, 1, "Determinator", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static bNodeSocketType cmp_node_bilateralblur_out[]= { + { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +#define INIT_C3\ + mean0 = 1; mean1[0] = src[0];mean1[1] = src[1];mean1[2] = src[2];mean1[3] = src[3]; + +/* finds color distances */ +#define COLOR_DISTANCE_C3(c1, c2)\ + ((c1[0] - c2[0])*(c1[0] - c2[0]) + \ + (c1[1] - c2[1])*(c1[1] - c2[1]) + \ + (c1[2] - c2[2])*(c1[2] - c2[2]) + \ + (c1[3] - c2[3])*(c1[3] - c2[3])) + +/* this is the main kernel function for comparing color distances + and adding them weighted to the final color */ +#define KERNEL_ELEMENT_C3(k)\ + temp_color = src + deltas[k];\ + ref_color = ref + deltas[k];\ + w = weight_tab[k] + COLOR_DISTANCE_C3(ref, ref_color )*i2sigma_color;\ + w = 1./(w*w + 1); \ + mean0 += w;\ + mean1[0] += temp_color[0]*w; \ + mean1[1] += temp_color[1]*w; \ + mean1[2] += temp_color[2]*w; \ + mean1[3] += temp_color[3]*w; + +/* write blurred values to image */ +#define UPDATE_OUTPUT_C3\ + mean0 = 1./mean0;\ + dest[x*pix + 0] = mean1[0]*mean0; \ + dest[x*pix + 1] = mean1[1]*mean0; \ + dest[x*pix + 2] = mean1[2]*mean0; \ + dest[x*pix + 3] = mean1[3]*mean0; + +/* initializes deltas for fast access to neighbour pixels */ +#define INIT_3X3_DELTAS( deltas, step, nch ) \ + ((deltas)[0] = (nch), (deltas)[1] = -(step) + (nch), \ + (deltas)[2] = -(step), (deltas)[3] = -(step) - (nch), \ + (deltas)[4] = -(nch), (deltas)[5] = (step) - (nch), \ + (deltas)[6] = (step), (deltas)[7] = (step) + (nch)); + + +/* code of this node was heavily inspired by the smooth function of opencv library. +The main change is an optional image input */ +static void node_composit_exec_bilateralblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out) +{ + NodeBilateralBlurData *nbbd= node->storage; + CompBuf *new, *source, *img= in[0]->data , *refimg= in[1]->data; + double mean0, w, i2sigma_color, i2sigma_space; + double mean1[4]; + double weight_tab[8]; + float *src, *dest, *ref, *temp_color, *ref_color; + float sigma_color, sigma_space; + int imgx, imgy, x, y, pix, i, step; + int deltas[8]; + short found_determinator= 0; + + if(img == NULL || out[0]->hasoutput == 0) + return; + + if(img->type != CB_RGBA) { + img= typecheck_compbuf(in[0]->data, CB_RGBA); + } + + imgx= img->x; + imgy= img->y; + pix= img->type; + step= pix * imgx; + + if(refimg) { + if(refimg->x == imgx && refimg->y == imgy) { + if(ELEM3(refimg->type, CB_VAL, CB_VEC2, CB_VEC3)) { + refimg= typecheck_compbuf(in[1]->data, CB_RGBA); + found_determinator= 1; + } + } + } + else { + refimg= img; + } + + /* allocs */ + source= dupalloc_compbuf(img); + new= alloc_compbuf(imgx, imgy, pix, 1); + + /* accept image offsets from other nodes */ + new->xof= img->xof; + new->yof= img->yof; + + /* bilateral code properties */ + sigma_color= nbbd->sigma_color; + sigma_space= nbbd->sigma_space; + + i2sigma_color= 1. / (sigma_color * sigma_color); + i2sigma_space= 1. / (sigma_space * sigma_space); + + INIT_3X3_DELTAS(deltas, step, pix); + + weight_tab[0] = weight_tab[2] = weight_tab[4] = weight_tab[6] = i2sigma_space; + weight_tab[1] = weight_tab[3] = weight_tab[5] = weight_tab[7] = i2sigma_space * 2; + + /* iterations */ + for(i= 0; i < nbbd->iter; i++) { + src= source->rect; + ref= refimg->rect; + dest= new->rect; + /*goes through image, there are more loops for 1st/last line and all other lines*/ + /*kernel element accumulates surrounding colors, which are then written with the update_output function*/ + for(x= 0; x < imgx; x++, src+= pix, ref+= pix) { + INIT_C3; + + KERNEL_ELEMENT_C3(6); + + if(x > 0) { + KERNEL_ELEMENT_C3(5); + KERNEL_ELEMENT_C3(4); + } + + if(x < imgx - 1) { + KERNEL_ELEMENT_C3(7); + KERNEL_ELEMENT_C3(0); + } + + UPDATE_OUTPUT_C3; + } + + dest+= step; + + for(y= 1; y < imgy - 1; y++, dest+= step, src+= pix, ref+= pix) { + x= 0; + + INIT_C3; + + KERNEL_ELEMENT_C3(0); + KERNEL_ELEMENT_C3(1); + KERNEL_ELEMENT_C3(2); + KERNEL_ELEMENT_C3(6); + KERNEL_ELEMENT_C3(7); + + UPDATE_OUTPUT_C3; + + src+= pix; + ref+= pix; + + for(x= 1; x < imgx - 1; x++, src+= pix, ref+= pix) { + INIT_C3; + + KERNEL_ELEMENT_C3(0); + KERNEL_ELEMENT_C3(1); + KERNEL_ELEMENT_C3(2); + KERNEL_ELEMENT_C3(3); + KERNEL_ELEMENT_C3(4); + KERNEL_ELEMENT_C3(5); + KERNEL_ELEMENT_C3(6); + KERNEL_ELEMENT_C3(7); + + UPDATE_OUTPUT_C3; + } + + INIT_C3; + + KERNEL_ELEMENT_C3(2); + KERNEL_ELEMENT_C3(3); + KERNEL_ELEMENT_C3(4); + KERNEL_ELEMENT_C3(5); + KERNEL_ELEMENT_C3(6); + + UPDATE_OUTPUT_C3; + } + + for(x= 0; x < imgx; x++, src+= pix, ref+= pix) { + INIT_C3; + + KERNEL_ELEMENT_C3(2); + + if(x > 0) { + KERNEL_ELEMENT_C3(3); + KERNEL_ELEMENT_C3(4); + } + if(x < imgx - 1) { + KERNEL_ELEMENT_C3(1); + KERNEL_ELEMENT_C3(0); + } + + UPDATE_OUTPUT_C3; + } + + if(node->exec & NODE_BREAK) break; + + SWAP(CompBuf, *source, *new); + } + + if(node->exec & NODE_BREAK) + free_compbuf(source); + + if(img != in[0]->data) + free_compbuf(img); + + if(found_determinator == 1) { + if(refimg != in[1]->data) + free_compbuf(refimg); + } + + out[0]->data= source; + + free_compbuf(new); +} + +static void node_composit_init_bilateralblur(bNode* node) +{ + NodeBilateralBlurData *nbbd= MEM_callocN(sizeof(NodeBilateralBlurData), "node bilateral blur data"); + node->storage= nbbd; + nbbd->sigma_color= 0.3; + nbbd->sigma_space= 5.0; +} + +bNodeType cmp_node_bilateralblur= { + /* *next,*prev */ NULL, NULL, + /* type code */ CMP_NODE_BILATERALBLUR, + /* name */ "Bilateral Blur", + /* width+range */ 150, 120, 200, + /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS, + /* input sock */ cmp_node_bilateralblur_in, + /* output sock */ cmp_node_bilateralblur_out, + /* storage */ "NodeBilateralBlurData", + /* execfunc */ node_composit_exec_bilateralblur, + /* butfunc */ NULL, + /* initfunc */ node_composit_init_bilateralblur, + /* freestoragefunc */ node_free_standard_storage, + /* copystoragefunc */ node_copy_standard_storage, + /* id */ NULL + +}; |