Merge from trunk -r 23000:23968.
[blender.git] / source / blender / nodes / intern / CMP_nodes / CMP_levels.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2006 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Bob Holcomb.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include "../CMP_util.h"
31
32
33 /* **************** LEVELS ******************** */
34 static bNodeSocketType cmp_node_view_levels_in[]= {
35         {       SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
36         {       -1, 0, ""       }
37 };
38
39 static bNodeSocketType cmp_node_view_levels_out[]={
40         {SOCK_VALUE, 0,"Mean",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
41         {SOCK_VALUE, 0,"Std Dev",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
42         {-1,0,""}
43 };
44
45 static void rgb_tobw(float r, float g, float b, float* out)
46 {
47         *out= r*0.35f + g*0.45f + b*0.2f;
48 }
49
50 static void fill_bins(bNode* node, CompBuf* in, int* bins)
51 {
52         float value[4];
53     int ivalue;
54         int x,y;
55
56         /*fill bins */
57         for(y=0; y<in->y; y++) {
58                 for(x=0; x<in->x; x++) {
59
60                         /* get the pixel */
61                         qd_getPixel(in, x, y, value);
62
63                         if(value[3] > 0.0) { /* don't count transparent pixels */
64                                 switch(node->custom1) {
65                                         case 1: { /* all colors */
66                                                 rgb_tobw(value[0],value[1],value[2], &value[0]);
67                                                 value[0]=value[0]*255; /* scale to 0-255 range */
68                                                 ivalue=(int)value[0];
69                                                 break;
70                                         }
71                                         case 2: { /* red channel */
72                                                 value[0]=value[0]*255; /* scale to 0-255 range */
73                                                 ivalue=(int)value[0];
74                                                 break;
75                                         }
76                                         case 3:  { /* green channel */
77                                                 value[1]=value[1]*255; /* scale to 0-255 range */
78                                                 ivalue=(int)value[1];
79                                                 break;
80                                         }
81                                         case 4: /*blue channel */
82                                         {
83                                                 value[2]=value[2]*255; /* scale to 0-255 range */
84                                                 ivalue=(int)value[2];
85                                                 break;
86                                         }
87                                         case 5: /* luminence */
88                                         {
89                                                 rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
90                                                 value[0]=value[0]*255; /* scale to 0-255 range */
91                                                 ivalue=(int)value[0];
92                                                 break;
93                                         }
94                                 } /*end switch */
95
96                                 /*clip*/
97                                 if(ivalue<0) ivalue=0;
98                                 if(ivalue>255) ivalue=255;
99
100                                 /*put in the correct bin*/
101                                 bins[ivalue]+=1;
102                         } /*end if alpha */
103                 }
104         }       
105 }
106
107 static float brightness_mean(bNode* node, CompBuf* in)
108 {
109         float sum=0.0;
110         int numPixels=0.0;
111         int x,y;
112         float value[4];
113
114         for(x=0; x< in->x; x++) {
115                 for(y=0; y < in->y; y++) {
116                         
117                         /* get the pixel */
118                         qd_getPixel(in, x, y, value);
119
120                         if(value[3] > 0.0) { /* don't count transparent pixels */
121                                 numPixels++;
122                                 switch(node->custom1)
123                                 {
124                                 case 1:
125                                         {
126                                                 rgb_tobw(value[0],value[1],value[2], &value[0]);
127                                                 sum+=value[0];
128                                                 break;
129                                         }
130                                 case 2:
131                                         {
132                                                 sum+=value[0];
133                                                 break;
134                                         }
135                                 case 3:
136                                         {
137                                                 sum+=value[1];
138                                                 break;
139                                         }
140                                 case 4:
141                                         {
142                                                 sum+=value[2];
143                                                 break;
144                                         }
145                                 case 5:
146                                         {
147                                                 rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
148                                                 sum+=value[0];
149                                                 break;
150                                         }
151                                 }
152                         }
153                 }
154         }
155
156         return sum/numPixels;
157 }
158
159 static float brightness_standard_deviation(bNode* node, CompBuf* in, float mean)
160 {
161         float sum=0.0;
162         int numPixels=0.0;
163         int x,y;
164         float value[4];
165
166         for(x=0; x< in->x; x++) {
167                 for(y=0; y < in->y; y++) {
168                         
169                         /* get the pixel */
170                         qd_getPixel(in, x, y, value);
171
172                         if(value[3] > 0.0) { /* don't count transparent pixels */
173                                 numPixels++;
174                                 switch(node->custom1)
175                                 {
176                                 case 1:
177                                         {
178                                                 rgb_tobw(value[0],value[1],value[2], &value[0]);
179                                                 sum+=(value[0]-mean)*(value[0]-mean);
180                                                 break;
181                                         }
182                                 case 2:
183                                         {
184                                                 sum+=value[0];
185                                                 sum+=(value[0]-mean)*(value[0]-mean);
186                                                 break;
187                                         }
188                                 case 3:
189                                         {
190                                                 sum+=value[1];
191                                                 sum+=(value[1]-mean)*(value[1]-mean);
192                                                 break;
193                                         }
194                                 case 4:
195                                         {
196                                                 sum+=value[2];
197                                                 sum+=(value[2]-mean)*(value[2]-mean);
198                                                 break;
199                                         }
200                                 case 5:
201                                         {
202                                                 rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
203                                                 sum+=(value[0]-mean)*(value[0]-mean);
204                                                 break;
205                                         }
206                                 }
207                         }
208                 }
209         }
210
211
212         return sqrt(sum/(float)(numPixels-1));
213 }
214
215 static void draw_histogram(bNode *node, CompBuf *out, int* bins)
216 {
217         int x,y;
218         float color[4]; 
219         float value;
220         int max;
221
222         /* find max value */
223         max=0;
224         for(x=0; x<256; x++) {
225                 if(bins[x]>max) max=bins[x];
226         }
227
228         /*draw histogram in buffer */
229         for(x=0; x<out->x; x++) {
230                 for(y=0;y<out->y; y++) {
231
232                         /* get normalized value (0..255) */
233                         value=((float)bins[x]/(float)max)*255.0; 
234
235                         if(y < (int)value) { /*if the y value is below the height of the bar for this line then draw with the color */
236                                 switch (node->custom1) {
237                                         case 1: { /* draw in black */
238                                                 color[0]=0.0; color[1]=0.0; color[2]=0.0; color[3]=1.0;
239                                                 break;
240                                         }
241                                         case 2: { /* draw in red */
242                                                 color[0]=1.0; color[1]=0.0; color[2]=0.0; color[3]=1.0;
243                                                 break;
244                                         }
245                                         case 3: { /* draw in green */
246                                                 color[0]=0.0; color[1]=1.0; color[2]=0.0; color[3]=1.0;
247                                                 break;
248                                         }
249                                         case 4: { /* draw in blue */
250                                                 color[0]=0.0; color[1]=0.0; color[2]=1.0; color[3]=1.0;
251                                                 break;
252                                         }
253                                         case 5: { /* draw in white */
254                                                 color[0]=1.0; color[1]=1.0; color[2]=1.0; color[3]=1.0;
255                                                 break;
256                                         }
257                                 }
258                         }
259                         else{
260                                 color[0]=0.8; color[1]=0.8; color[2]=0.8; color[3]=1.0;
261                         }
262
263                         /* set the color */
264                         qd_setPixel(out, x, y, color);
265                 }
266         }
267 }
268
269 static void node_composit_exec_view_levels(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
270 {
271         CompBuf* cbuf;
272         CompBuf* histogram;
273         float mean, std_dev;
274         int bins[256];
275         int x;
276
277         if(in[0]->hasinput==0)  return;
278         if(in[0]->data==NULL) return;
279
280         histogram=alloc_compbuf(256, 256, CB_RGBA, 1);  
281         cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);   
282                 
283         /*initalize bins*/
284         for(x=0; x<256; x++) {
285                 bins[x]=0;
286         }
287         
288         /*fill bins */
289         fill_bins(node, in[0]->data, bins);
290
291         /* draw the histogram chart */
292         draw_histogram(node, histogram, bins);
293
294         /* calculate the average brightness and contrast */
295         mean=brightness_mean(node, in[0]->data);
296         std_dev=brightness_standard_deviation(node, in[0]->data, mean);
297
298         /*  Printf debuging ;) 
299         printf("Mean: %f\n", mean);
300         printf("Std Dev: %f\n", std_dev);
301         */
302
303         if(out[0]->hasoutput)
304                         out[0]->vec[0]= mean;
305         if(out[1]->hasoutput)
306                         out[1]->vec[0]= std_dev;
307
308         generate_preview(data, node, histogram);
309
310         if(cbuf!=in[0]->data)
311                 free_compbuf(cbuf);
312         free_compbuf(histogram);
313 }
314
315 static void node_composit_init_view_levels(bNode* node)
316 {
317    node->custom1=1; /*All channels*/
318 }
319
320 bNodeType cmp_node_view_levels= {
321         /* *next,*prev */       NULL, NULL,
322         /* type code   */       CMP_NODE_VIEW_LEVELS,
323         /* name        */       "Levels",
324         /* widthrange */        140, 100, 320,
325         /* classopts  */        NODE_CLASS_OUTPUT, NODE_OPTIONS|NODE_PREVIEW,
326         /* input sock  */       cmp_node_view_levels_in,
327         /* output sock */       cmp_node_view_levels_out,
328         /* storage     */       "ImageUser",
329         /* execfunc    */       node_composit_exec_view_levels,
330         /* butfunc     */       NULL,
331         /* initfunc    */       node_composit_init_view_levels,
332         /* freestoragefunc    */        NULL,
333         /* copystoragefunc    */        NULL,
334         /* id          */       NULL
335         
336 };
337