/** * $Id: CMP_bilateralblur.c 11945 2007-09-05 17:55:44Z $ * * ***** 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): none yet. * * ***** END GPL LICENSE BLOCK ***** */ #include "../CMP_util.h" /* **************** BILATERALBLUR ******************** */ static bNodeSocketType cmp_node_bilateralblur_in[]= { { SOCK_RGBA, 1, "Color(input)", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { SOCK_RGBA, 1, "determinator 1", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { -1, 0, "" } }; static bNodeSocketType cmp_node_bilateralblur_out[]= { { SOCK_RGBA, 0, "Color", 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 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 acces 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)); static void node_composit_exec_bilateralblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { /*code of this node was heavily inspired by the smooth function of opencv library. The main change is an optional image input*/ /* stack order in: Image, Image*/ /* stack order out: Image */ /*buffers initialization*/ CompBuf *new, *source, *img= in[0]->data , *refimg=in[1]->data; CompBuf *unused; NodeBilateralBlurData *nbbd= node->storage; int imgx= img->x, imgy= img->y; int x, y; int pix= img->type; float *src, *dest, *ref, *temp_color, *ref_color; short is_determinator=0; double mean1[4]; double mean0; double w; int i; int deltas[8]; double weight_tab[8]; int step = pix*imgx; float sigma_color,sigma_space; double i2sigma_color = 1./(sigma_color*sigma_color); double i2sigma_space = 1./(sigma_space*sigma_space); if(img==NULL || out[0]->hasoutput==0) return; if(img->type==CB_VEC2 || img->type==CB_VEC3) { img= typecheck_compbuf(in[0]->data, CB_RGBA); } if (refimg != NULL ){ if(refimg->type==CB_VEC2 || refimg->type==CB_VEC3) { refimg= typecheck_compbuf(in[1]->data, CB_RGBA); is_determinator = 1; } }else{ refimg = img; } /* allocs */ source= dupalloc_compbuf(img); new= alloc_compbuf(imgx, imgy, img->type, 1); /* accept image offsets from other nodes */ new->xof = img->xof; new->yof = img->yof; /*here start the bilateral code specific properties*/ sigma_color=nbbd->sigma_color; sigma_space=nbbd->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; iiter; 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++) { 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; src+= pix; ref+= pix; } dest += step; for( y = 1; y < imgy - 1; y++, dest += step ){ 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++ ){ 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; src += pix ; ref += pix ; } 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; src += pix ; ref += pix ; } for( x = 0; x < imgx; x++){ 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; src += pix ; ref += pix ; } /*switch buffer pointers for next iteration*/ unused = source; source = new; new = unused; } if(node->exec & NODE_BREAK) { free_compbuf(source); source=NULL; } if(img!=in[0]->data) free_compbuf(img); if((refimg!=in[1]->data) & (is_determinator == 1)) free_compbuf(refimg); out[0]->data= source; free_compbuf(new); new= NULL; } static void node_composit_init_bilateralblur(bNode *node) { NodeBilateralBlurData *nbbd= MEM_callocN(sizeof(NodeBilateralBlurData), "node bilateral blur data"); node->storage= nbbd; nbbd->iter= 1; nbbd->sigma_color= 0.3f; nbbd->sigma_space= 100.0f; } /* custom1 = mix type */ bNodeType cmp_node_bilateralblur= { /* *next,*prev */ NULL, NULL, /* type code */ CMP_NODE_BILATERALBLUR, /* name */ "Bilateral Blur", /* width+range */ 120, 220, 140, /* 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 };