Public feed
#726639
/**
* $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; 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++) {
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
};