doxygen: blender/nodes tagged.
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/nodes/intern/CMP_nodes/CMP_levels.c
31  *  \ingroup cmpnodes
32  */
33
34
35 #include "../CMP_util.h"
36
37
38 /* **************** LEVELS ******************** */
39 static bNodeSocketType cmp_node_view_levels_in[]= {
40         {       SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
41         {       -1, 0, ""       }
42 };
43
44 static bNodeSocketType cmp_node_view_levels_out[]={
45         {SOCK_VALUE, 0,"Mean",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
46         {SOCK_VALUE, 0,"Std Dev",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
47         {-1,0,""}
48 };
49
50 static void rgb_tobw(float r, float g, float b, float* out)
51 {
52         *out= r*0.35f + g*0.45f + b*0.2f;
53 }
54
55 static void fill_bins(bNode* node, CompBuf* in, int* bins, int colorcor)
56 {
57         float value[4];
58         int ivalue=0;
59         int x,y;
60
61         /*fill bins */
62         for(y=0; y<in->y; y++) {
63                 for(x=0; x<in->x; x++) {
64
65                         /* get the pixel */
66                         qd_getPixel(in, x, y, value);
67
68                         if(value[3] > 0.0) { /* don't count transparent pixels */
69                                 switch(node->custom1) {
70                                         case 1: { /* all colors */
71                                                 if(colorcor)
72                                                         linearrgb_to_srgb_v3_v3(&value[0],&value[0]);
73                                                 rgb_tobw(value[0],value[1],value[2], &value[0]);
74                                                 value[0]=value[0]*255; /* scale to 0-255 range */
75                                                 ivalue=(int)value[0];
76                                                 break;
77                                         }
78                                         case 2: { /* red channel */
79                                                 if(colorcor)
80                                                         value[0]=linearrgb_to_srgb(value[0]);
81                                                 value[0]=value[0]*255; /* scale to 0-255 range */
82                                                 ivalue=(int)value[0];
83                                                 break;
84                                         }
85                                         case 3:  { /* green channel */
86                                                 if(colorcor)
87                                                         value[1]=linearrgb_to_srgb(value[1]);
88                                                 value[1]=value[1]*255; /* scale to 0-255 range */
89                                                 ivalue=(int)value[1];
90                                                 break;
91                                         }
92                                         case 4: /*blue channel */
93                                         {
94                                                 if(colorcor)
95                                                         value[2]=linearrgb_to_srgb(value[2]);
96                                                 value[2]=value[2]*255; /* scale to 0-255 range */
97                                                 ivalue=(int)value[2];
98                                                 break;
99                                         }
100                                         case 5: /* luminence */
101                                         {
102                                                 if(colorcor)
103                                                         linearrgb_to_srgb_v3_v3(&value[0],&value[0]);
104                                                 rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
105                                                 value[0]=value[0]*255; /* scale to 0-255 range */
106                                                 ivalue=(int)value[0];
107                                                 break;
108                                         }
109                                 } /*end switch */
110
111                                 /*clip*/
112                                 if(ivalue<0) ivalue=0;
113                                 if(ivalue>255) ivalue=255;
114
115                                 /*put in the correct bin*/
116                                 bins[ivalue]+=1;
117                         } /*end if alpha */
118                 }
119         }       
120 }
121
122 static float brightness_mean(bNode* node, CompBuf* in)
123 {
124         float sum=0.0;
125         int numPixels=0.0;
126         int x,y;
127         float value[4];
128
129         for(x=0; x< in->x; x++) {
130                 for(y=0; y < in->y; y++) {
131                         
132                         /* get the pixel */
133                         qd_getPixel(in, x, y, value);
134
135                         if(value[3] > 0.0) { /* don't count transparent pixels */
136                                 numPixels++;
137                                 switch(node->custom1)
138                                 {
139                                 case 1:
140                                         {
141                                                 rgb_tobw(value[0],value[1],value[2], &value[0]);
142                                                 sum+=value[0];
143                                                 break;
144                                         }
145                                 case 2:
146                                         {
147                                                 sum+=value[0];
148                                                 break;
149                                         }
150                                 case 3:
151                                         {
152                                                 sum+=value[1];
153                                                 break;
154                                         }
155                                 case 4:
156                                         {
157                                                 sum+=value[2];
158                                                 break;
159                                         }
160                                 case 5:
161                                         {
162                                                 rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
163                                                 sum+=value[0];
164                                                 break;
165                                         }
166                                 }
167                         }
168                 }
169         }
170
171         return sum/numPixels;
172 }
173
174 static float brightness_standard_deviation(bNode* node, CompBuf* in, float mean)
175 {
176         float sum=0.0;
177         int numPixels=0.0;
178         int x,y;
179         float value[4];
180
181         for(x=0; x< in->x; x++) {
182                 for(y=0; y < in->y; y++) {
183                         
184                         /* get the pixel */
185                         qd_getPixel(in, x, y, value);
186
187                         if(value[3] > 0.0) { /* don't count transparent pixels */
188                                 numPixels++;
189                                 switch(node->custom1)
190                                 {
191                                 case 1:
192                                         {
193                                                 rgb_tobw(value[0],value[1],value[2], &value[0]);
194                                                 sum+=(value[0]-mean)*(value[0]-mean);
195                                                 break;
196                                         }
197                                 case 2:
198                                         {
199                                                 sum+=value[0];
200                                                 sum+=(value[0]-mean)*(value[0]-mean);
201                                                 break;
202                                         }
203                                 case 3:
204                                         {
205                                                 sum+=value[1];
206                                                 sum+=(value[1]-mean)*(value[1]-mean);
207                                                 break;
208                                         }
209                                 case 4:
210                                         {
211                                                 sum+=value[2];
212                                                 sum+=(value[2]-mean)*(value[2]-mean);
213                                                 break;
214                                         }
215                                 case 5:
216                                         {
217                                                 rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
218                                                 sum+=(value[0]-mean)*(value[0]-mean);
219                                                 break;
220                                         }
221                                 }
222                         }
223                 }
224         }
225
226
227         return sqrt(sum/(float)(numPixels-1));
228 }
229
230 static void draw_histogram(bNode *node, CompBuf *out, int* bins)
231 {
232         int x,y;
233         float color[4]; 
234         float value;
235         int max;
236
237         /* find max value */
238         max=0;
239         for(x=0; x<256; x++) {
240                 if(bins[x]>max) max=bins[x];
241         }
242
243         /*draw histogram in buffer */
244         for(x=0; x<out->x; x++) {
245                 for(y=0;y<out->y; y++) {
246
247                         /* get normalized value (0..255) */
248                         value=((float)bins[x]/(float)max)*255.0; 
249
250                         if(y < (int)value) { /*if the y value is below the height of the bar for this line then draw with the color */
251                                 switch (node->custom1) {
252                                         case 1: { /* draw in black */
253                                                 color[0]=0.0; color[1]=0.0; color[2]=0.0; color[3]=1.0;
254                                                 break;
255                                         }
256                                         case 2: { /* draw in red */
257                                                 color[0]=1.0; color[1]=0.0; color[2]=0.0; color[3]=1.0;
258                                                 break;
259                                         }
260                                         case 3: { /* draw in green */
261                                                 color[0]=0.0; color[1]=1.0; color[2]=0.0; color[3]=1.0;
262                                                 break;
263                                         }
264                                         case 4: { /* draw in blue */
265                                                 color[0]=0.0; color[1]=0.0; color[2]=1.0; color[3]=1.0;
266                                                 break;
267                                         }
268                                         case 5: { /* draw in white */
269                                                 color[0]=1.0; color[1]=1.0; color[2]=1.0; color[3]=1.0;
270                                                 break;
271                                         }
272                                 }
273                         }
274                         else{
275                                 color[0]=0.8; color[1]=0.8; color[2]=0.8; color[3]=1.0;
276                         }
277
278                         /* set the color */
279                         qd_setPixel(out, x, y, color);
280                 }
281         }
282 }
283
284 static void node_composit_exec_view_levels(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
285 {
286         CompBuf* cbuf;
287         CompBuf* histogram;
288         RenderData *rd=data;
289         float mean, std_dev;
290         int bins[256];
291         int x;
292
293         if(in[0]->hasinput==0)  return;
294         if(in[0]->data==NULL) return;
295
296         histogram=alloc_compbuf(256, 256, CB_RGBA, 1);  
297         cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);   
298                 
299         /*initalize bins*/
300         for(x=0; x<256; x++) {
301                 bins[x]=0;
302         }
303         
304         /*fill bins */
305         fill_bins(node, in[0]->data, bins, rd->color_mgt_flag & R_COLOR_MANAGEMENT);
306
307         /* draw the histogram chart */
308         draw_histogram(node, histogram, bins);
309
310         /* calculate the average brightness and contrast */
311         mean=brightness_mean(node, in[0]->data);
312         std_dev=brightness_standard_deviation(node, in[0]->data, mean);
313
314         /*  Printf debuging ;) 
315         printf("Mean: %f\n", mean);
316         printf("Std Dev: %f\n", std_dev);
317         */
318
319         if(out[0]->hasoutput)
320                         out[0]->vec[0]= mean;
321         if(out[1]->hasoutput)
322                         out[1]->vec[0]= std_dev;
323
324         generate_preview(data, node, histogram);
325
326         if(cbuf!=in[0]->data)
327                 free_compbuf(cbuf);
328         free_compbuf(histogram);
329 }
330
331 static void node_composit_init_view_levels(bNode* node)
332 {
333    node->custom1=1; /*All channels*/
334 }
335
336 void register_node_type_cmp_view_levels(ListBase *lb)
337 {
338         static bNodeType ntype;
339
340         node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_OPTIONS|NODE_PREVIEW,
341                 cmp_node_view_levels_in, cmp_node_view_levels_out);
342         node_type_size(&ntype, 140, 100, 320);
343         node_type_init(&ntype, node_composit_init_view_levels);
344         node_type_storage(&ntype, "ImageUser", NULL, NULL);
345         node_type_exec(&ntype, node_composit_exec_view_levels);
346
347         nodeRegisterType(lb, &ntype);
348 }
349
350