1 /*
2  */
3 
4 /*
5 
6 	Copyright (C) 2014 Ferrero Andrea
7 
8 	This program is free software: you can redistribute it and/or modify
9 	it under the terms of the GNU General Public License as published by
10 	the Free Software Foundation, either version 3 of the License, or
11 	(at your option) any later version.
12 
13 	This program is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 	GNU General Public License for more details.
17 
18 	You should have received a copy of the GNU General Public License
19 	along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21 
22 */
23 
24 /*
25 
26 	These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
27 
28 */
29 
30 #ifndef PF_WHITE_BALANCE_H
31 #define PF_WHITE_BALANCE_H
32 
33 #include <string>
34 
35 #include "../base/processor.hh"
36 #include "../base/rawmatrix.hh"
37 
38 #include "raw_image.hh"
39 
40 
41 //#define RT_EMU 1
42 
43 
44 //#define __CLIP(a)  CLIP(a)
45 #define __CLIP(a) (a)
46 
47 namespace PF
48 {
49 
50   extern int wb_sample_x;
51   extern int wb_sample_y;
52 
53   class WhiteBalancePar: public OpParBase
54   {
55     dcraw_data_t* image_data;
56 
57     PropertyBase wb_mode;
58 
59     Property<float>* wb_red[WB_LAST];
60     Property<float>* wb_green[WB_LAST];
61     Property<float>* wb_blue[WB_LAST];
62 
63     Property<float> camwb_corr_red;
64     Property<float> camwb_corr_green;
65     Property<float> camwb_corr_blue;
66 
67     Property<float> wb_target_L;
68     Property<float> wb_target_a;
69     Property<float> wb_target_b;
70 
71     Property<float> saturation_level_correction;
72     Property<float> black_level_correction;
73 
74     float wb_red_current, wb_green_current, wb_blue_current;
75 
76   public:
77     WhiteBalancePar();
78 
79     /* Set processing hints:
80        1. the intensity parameter makes no sense for an image,
81 			 creation of an intensity map is not allowed
82        2. the operation can work without an input image;
83 			 the blending will be set in this case to "passthrough" and the image
84 			 data will be simply linked to the output
85 		*/
has_intensity()86     bool has_intensity() { return false; }
has_opacity()87     bool has_opacity() { return true; }
needs_input()88     bool needs_input() { return true; }
89 
get_image_data()90     dcraw_data_t* get_image_data() {return image_data; }
91 
92     void init_wb_coefficients( dcraw_data_t* idata, std::string camera_maker, std::string camera_model );
93 
get_wb_mode()94     wb_mode_t get_wb_mode() { return (wb_mode_t)(wb_mode.get_enum_value().first); }
get_wb_red()95     float get_wb_red() { return wb_red_current; /*wb_red.get();*/ }
get_wb_green()96     float get_wb_green() { return wb_green_current; /*wb_green.get();*/ }
get_wb_blue()97     float get_wb_blue() { return wb_blue_current; /*wb_blue.get();*/ }
98 
get_preset_wb_red(int id)99     float get_preset_wb_red(int id) { return wb_red[id]->get(); }
get_preset_wb_green(int id)100     float get_preset_wb_green(int id ) { return wb_green[id]->get(); }
get_preset_wb_blue(int id)101     float get_preset_wb_blue(int id) { return wb_blue[id]->get(); }
102 
get_camwb_corr_red()103     float get_camwb_corr_red() { return camwb_corr_red.get(); }
get_camwb_corr_green()104     float get_camwb_corr_green() { return camwb_corr_green.get(); }
get_camwb_corr_blue()105     float get_camwb_corr_blue() { return camwb_corr_blue.get(); }
106 
get_wb(float * mul)107     void get_wb(float* mul) {
108       mul[0] = get_wb_red();
109       mul[1] = get_wb_green();
110       mul[2] = get_wb_blue();
111     }
set_wb(float r,float g,float b)112     void set_wb(float r, float g, float b) {
113       wb_red_current = r;
114       wb_green_current = g;
115       wb_blue_current = b;
116       std::cout<<"WhiteBalancePar: setting WB coefficients to "<<r<<","<<g<<","<<b<<std::endl;
117     }
118 
get_saturation_level_correction()119     float get_saturation_level_correction() { return saturation_level_correction.get(); }
get_black_level_correction()120     float get_black_level_correction() { return black_level_correction.get(); }
121 
122     VipsImage* build(std::vector<VipsImage*>& in, int first,
123 										 VipsImage* imap, VipsImage* omap, unsigned int& level);
124   };
125 
126 
127 
128   template < OP_TEMPLATE_DEF >
129   class WhiteBalance
130   {
131   public:
render(VipsRegion ** ireg,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * oreg,OpParBase * par)132     void render(VipsRegion** ireg, int n, int in_first,
133 								VipsRegion* imap, VipsRegion* omap,
134 								VipsRegion* oreg, OpParBase* par)
135     {
136       WhiteBalancePar* rdpar = dynamic_cast<WhiteBalancePar*>(par);
137       if( !rdpar ) return;
138 
139       float mul[4] = {1,1,1,1};
140 
141       //std::cout<<"WhiteBalance::render(): rdpar->get_wb_mode()="<<rdpar->get_wb_mode()<<std::endl;
142       //switch( rdpar->get_wb_mode() ) {
143       //case WB_SPOT:
144       //case WB_COLOR_SPOT:
145 				//render_spotwb(ireg, n, in_first, imap, omap, oreg, rdpar);
146 				//std::cout<<"render_spotwb() called"<<std::endl;
147         mul[0] = rdpar->get_wb_red();
148         mul[1] = rdpar->get_wb_green();
149         mul[2] = rdpar->get_wb_blue();
150         mul[3] = rdpar->get_wb_green();
151 				//break;
152       //default:
153         //render_camwb(ireg, n, in_first, imap, omap, oreg, rdpar);
154         //std::cout<<"render_camwb() called"<<std::endl;
155         //mul[0] = rdpar->get_wb_red()*rdpar->get_camwb_corr_red();
156         //mul[1] = rdpar->get_wb_green()*rdpar->get_camwb_corr_green();
157         //mul[2] = rdpar->get_wb_blue()*rdpar->get_camwb_corr_blue();
158         //mul[3] = rdpar->get_wb_green()*rdpar->get_camwb_corr_green();
159         //break;
160       //}
161 
162       dcraw_data_t* image_data = rdpar->get_image_data();
163       VipsRect *r = &oreg->valid;
164       int nbands = ireg[in_first]->im->Bands;
165 
166       int x, y;
167       //float range = image_data->color.maximum - image_data->color.black;
168       float range = 1;
169       float min_mul = mul[0];
170       float max_mul = mul[0];
171       /*
172       for(int i = 0; i < 4; i++) {
173         std::cout<<"cam_mu["<<i<<"]="<<image_data->color.cam_mul[i]<<"  ";
174       }
175       std::cout<<std::endl;
176       */
177       for(int i = 1; i < 4; i++) {
178         if( mul[i] < min_mul )
179           min_mul = mul[i];
180         if( mul[i] > max_mul )
181           max_mul = mul[i];
182       }
183       //std::cout<<"range="<<range<<"  min_mul="<<min_mul<<"  new range="<<range*min_mul<<std::endl;
184       range *= min_mul;
185 
186       //for(int i = 0; i < 4; i++) {
187       //  mul[i] = mul[i] / range;
188       //}
189 
190       float* p;
191       float* pout;
192       int line_sz = r->width*3;
193       for( y = 0; y < r->height; y++ ) {
194         p = (float*)VIPS_REGION_ADDR( ireg[in_first], r->left, r->top + y );
195         pout = (float*)VIPS_REGION_ADDR( oreg, r->left, r->top + y );
196         for( x=0; x < line_sz; x+=3) {
197           //pout[x] = __CLIP( (p[x]-black[0]) * sat_corr * mul[0] - black[0]);
198           //pout[x+1] = __CLIP(p[x+1] * sat_corr * mul[1] - black[1]);
199           //pout[x+2] = __CLIP(p[x+2] * sat_corr * mul[2] - black[2]);
200           pout[x] = __CLIP( p[x] * mul[0] );
201           pout[x+1] = __CLIP( p[x+1] * mul[1] );
202           pout[x+2] = __CLIP( p[x+2] * mul[2] );
203           if(false && r->left==0 && r->top==0) std::cout<<"  p["<<x<<"]="<<p[x]<<"  pout["<<x<<"]="<<pout[x]<<std::endl;
204         }
205       }
206     }
207   };
208 
209 
210 
211 
212   ProcessorBase* new_white_balance();
213 }
214 
215 #endif
216 
217 
218