/** * $Id$ * * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2006 Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): Bob Holcomb. * * ***** END GPL LICENSE BLOCK ***** */ #include "../CMP_util.h" /* **************** LEVELS ******************** */ static bNodeSocketType cmp_node_view_levels_in[]= { { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, { -1, 0, "" } }; static bNodeSocketType cmp_node_view_levels_out[]={ {SOCK_VALUE, 0,"Mean",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {SOCK_VALUE, 0,"Std Dev",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f}, {-1,0,""} }; static void rgb_tobw(float r, float g, float b, float* out) { *out= r*0.35f + g*0.45f + b*0.2f; } static void fill_bins(bNode* node, CompBuf* in, int* bins) { float value[4]; int ivalue=0; int x,y; /*fill bins */ for(y=0; yy; y++) { for(x=0; xx; x++) { /* get the pixel */ qd_getPixel(in, x, y, value); if(value[3] > 0.0) { /* don't count transparent pixels */ switch(node->custom1) { case 1: { /* all colors */ rgb_tobw(value[0],value[1],value[2], &value[0]); value[0]=value[0]*255; /* scale to 0-255 range */ ivalue=(int)value[0]; break; } case 2: { /* red channel */ value[0]=value[0]*255; /* scale to 0-255 range */ ivalue=(int)value[0]; break; } case 3: { /* green channel */ value[1]=value[1]*255; /* scale to 0-255 range */ ivalue=(int)value[1]; break; } case 4: /*blue channel */ { value[2]=value[2]*255; /* scale to 0-255 range */ ivalue=(int)value[2]; break; } case 5: /* luminence */ { rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]); value[0]=value[0]*255; /* scale to 0-255 range */ ivalue=(int)value[0]; break; } } /*end switch */ /*clip*/ if(ivalue<0) ivalue=0; if(ivalue>255) ivalue=255; /*put in the correct bin*/ bins[ivalue]+=1; } /*end if alpha */ } } } static float brightness_mean(bNode* node, CompBuf* in) { float sum=0.0; int numPixels=0.0; int x,y; float value[4]; for(x=0; x< in->x; x++) { for(y=0; y < in->y; y++) { /* get the pixel */ qd_getPixel(in, x, y, value); if(value[3] > 0.0) { /* don't count transparent pixels */ numPixels++; switch(node->custom1) { case 1: { rgb_tobw(value[0],value[1],value[2], &value[0]); sum+=value[0]; break; } case 2: { sum+=value[0]; break; } case 3: { sum+=value[1]; break; } case 4: { sum+=value[2]; break; } case 5: { rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]); sum+=value[0]; break; } } } } } return sum/numPixels; } static float brightness_standard_deviation(bNode* node, CompBuf* in, float mean) { float sum=0.0; int numPixels=0.0; int x,y; float value[4]; for(x=0; x< in->x; x++) { for(y=0; y < in->y; y++) { /* get the pixel */ qd_getPixel(in, x, y, value); if(value[3] > 0.0) { /* don't count transparent pixels */ numPixels++; switch(node->custom1) { case 1: { rgb_tobw(value[0],value[1],value[2], &value[0]); sum+=(value[0]-mean)*(value[0]-mean); break; } case 2: { sum+=value[0]; sum+=(value[0]-mean)*(value[0]-mean); break; } case 3: { sum+=value[1]; sum+=(value[1]-mean)*(value[1]-mean); break; } case 4: { sum+=value[2]; sum+=(value[2]-mean)*(value[2]-mean); break; } case 5: { rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]); sum+=(value[0]-mean)*(value[0]-mean); break; } } } } } return sqrt(sum/(float)(numPixels-1)); } static void draw_histogram(bNode *node, CompBuf *out, int* bins) { int x,y; float color[4]; float value; int max; /* find max value */ max=0; for(x=0; x<256; x++) { if(bins[x]>max) max=bins[x]; } /*draw histogram in buffer */ for(x=0; xx; x++) { for(y=0;yy; y++) { /* get normalized value (0..255) */ value=((float)bins[x]/(float)max)*255.0; if(y < (int)value) { /*if the y value is below the height of the bar for this line then draw with the color */ switch (node->custom1) { case 1: { /* draw in black */ color[0]=0.0; color[1]=0.0; color[2]=0.0; color[3]=1.0; break; } case 2: { /* draw in red */ color[0]=1.0; color[1]=0.0; color[2]=0.0; color[3]=1.0; break; } case 3: { /* draw in green */ color[0]=0.0; color[1]=1.0; color[2]=0.0; color[3]=1.0; break; } case 4: { /* draw in blue */ color[0]=0.0; color[1]=0.0; color[2]=1.0; color[3]=1.0; break; } case 5: { /* draw in white */ color[0]=1.0; color[1]=1.0; color[2]=1.0; color[3]=1.0; break; } } } else{ color[0]=0.8; color[1]=0.8; color[2]=0.8; color[3]=1.0; } /* set the color */ qd_setPixel(out, x, y, color); } } } static void node_composit_exec_view_levels(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { CompBuf* cbuf; CompBuf* histogram; float mean, std_dev; int bins[256]; int x; if(in[0]->hasinput==0) return; if(in[0]->data==NULL) return; histogram=alloc_compbuf(256, 256, CB_RGBA, 1); cbuf=typecheck_compbuf(in[0]->data, CB_RGBA); /*initalize bins*/ for(x=0; x<256; x++) { bins[x]=0; } /*fill bins */ fill_bins(node, in[0]->data, bins); /* draw the histogram chart */ draw_histogram(node, histogram, bins); /* calculate the average brightness and contrast */ mean=brightness_mean(node, in[0]->data); std_dev=brightness_standard_deviation(node, in[0]->data, mean); /* Printf debuging ;) printf("Mean: %f\n", mean); printf("Std Dev: %f\n", std_dev); */ if(out[0]->hasoutput) out[0]->vec[0]= mean; if(out[1]->hasoutput) out[1]->vec[0]= std_dev; generate_preview(data, node, histogram); if(cbuf!=in[0]->data) free_compbuf(cbuf); free_compbuf(histogram); } static void node_composit_init_view_levels(bNode* node) { node->custom1=1; /*All channels*/ } bNodeType cmp_node_view_levels= { /* *next,*prev */ NULL, NULL, /* type code */ CMP_NODE_VIEW_LEVELS, /* name */ "Levels", /* widthrange */ 140, 100, 320, /* classopts */ NODE_CLASS_OUTPUT, NODE_OPTIONS|NODE_PREVIEW, /* input sock */ cmp_node_view_levels_in, /* output sock */ cmp_node_view_levels_out, /* storage */ "ImageUser", /* execfunc */ node_composit_exec_view_levels, /* butfunc */ NULL, /* initfunc */ node_composit_init_view_levels, /* freestoragefunc */ NULL, /* copystoragefunc */ NULL, /* id */ NULL };