Public feed #726640

bilateral 2

public text v1 · immutable
Raw Edit
·published 2007-10-05 11:44 UTC
rendered paste body
/**
 * $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
	
};