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 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33
34 #include "../../operations/convertformat.hh"
35 #include "raw_preprocessor.hh"
36 #include "../../operations/ca_correct.hh"
37 #include "../../operations/amaze_demosaic.hh"
38 #include "../../operations/lmmse_demosaic.hh"
39 #include "../../operations/igv_demosaic.hh"
40 #include "../../operations/xtrans_demosaic.hh"
41 #include "../../operations/fast_demosaic.hh"
42 #include "../../operations/fast_demosaic_xtrans.hh"
43 #include "../../operations/false_color_correction.hh"
44 #include "raw_output.hh"
45 #include "../../operations/hotpixels.hh"
46 #include "../../operations/lensfun.hh"
47
48 #include "raw_developer.hh"
49
50
RawDeveloperV1Par()51 PF::RawDeveloperV1Par::RawDeveloperV1Par():
52 OpParBase(), output_format( VIPS_FORMAT_NOTSET ),
53 lf_prop_camera_maker( "lf_camera_maker", this ),
54 lf_prop_camera_model( "lf_camera_model", this ),
55 lf_prop_lens( "lf_lens", this ),
56 enable_distortion( "lf_enable_distortion", this, false ),
57 enable_tca( "lf_enable_tca", this, false ),
58 enable_vignetting( "lf_enable_vignetting", this, false ),
59 enable_all( "lf_enable_all", this, false ),
60 tca_method("tca_method",this,PF::PF_TCA_CORR_PROFILED_AUTO,"TCA_CORR_PROFILED_AUTO",_("profiled + auto")),
61 demo_method("demo_method",this,PF::PF_DEMO_AMAZE,"AMAZE","Amaze"),
62 fcs_steps("fcs_steps",this,0),
63 caching_enabled( true )
64 {
65 tca_method.add_enum_value(PF::PF_TCA_CORR_AUTO,"TCA_CORR_AUTO",_("auto"));
66 tca_method.add_enum_value(PF::PF_TCA_CORR_PROFILED,"TCA_CORR_PROFILED",_("profiled"));
67 tca_method.add_enum_value(PF::PF_TCA_CORR_PROFILED_AUTO,"TCA_CORR_PROFILED_AUTO",_("profiled + auto"));
68 //tca_method.add_enum_value(PF::PF_TCA_CORR_MANUAL,"TCA_CORR_MANUAL",_("manual"));
69
70 demo_method.add_enum_value(PF::PF_DEMO_AMAZE,"AMAZE","Amaze");
71 //demo_method.add_enum_value(PF::PF_DEMO_FAST,"FAST","Fast");
72 demo_method.add_enum_value(PF::PF_DEMO_LMMSE,"LMMSE","LMMSE");
73 demo_method.add_enum_value(PF::PF_DEMO_IGV,"IGV","Igv");
74
75 amaze_demosaic = new_amaze_demosaic();
76 lmmse_demosaic = new_lmmse_demosaic();
77 igv_demosaic = new_igv_demosaic();
78 xtrans_demosaic = new_xtrans_demosaic();
79 fast_demosaic = new_fast_demosaic();
80 fast_demosaic_xtrans = new_fast_demosaic_xtrans();
81 FastDemosaicXTransPar* xtrans_par =
82 dynamic_cast<FastDemosaicXTransPar*>(fast_demosaic_xtrans->get_par());
83 if( xtrans_par ) xtrans_par->set_normalize( true );
84 raw_preprocessor = new_raw_preprocessor_v1();
85 ca_correct = new_ca_correct();
86 lensfun = new_lensfun();
87 raw_output = new_raw_output_v1();
88 hotpixels = new_hotpixels();
89 convert_format = new_convert_format();
90 for(int ifcs = 0; ifcs < 4; ifcs++)
91 fcs[ifcs] = new_false_color_correction();
92
93 map_properties( raw_preprocessor->get_par()->get_properties() );
94 map_properties( ca_correct->get_par()->get_properties() );
95 map_properties( raw_output->get_par()->get_properties() );
96 map_properties( hotpixels->get_par()->get_properties() );
97
98 set_type("raw_developer" );
99
100 set_default_name( _("RAW developer") );
101 }
102
103
104
get_wb_mode()105 PF::wb_mode_t PF::RawDeveloperV1Par::get_wb_mode()
106 {
107 PF::wb_mode_t result = PF::WB_CAMERA;
108 PF::RawPreprocessorV1Par* par = dynamic_cast<PF::RawPreprocessorV1Par*>( raw_preprocessor->get_par() );
109 if( par ) result = par->get_wb_mode();
110 return result;
111 }
112
113
set_wb(float r,float g,float b)114 void PF::RawDeveloperV1Par::set_wb(float r, float g, float b)
115 {
116 PF::RawPreprocessorV1Par* par = dynamic_cast<PF::RawPreprocessorV1Par*>( raw_preprocessor->get_par() );
117 if( par ) par->set_wb(r,g,b);
118 }
119
get_hotp_fixed()120 int PF::RawDeveloperV1Par::get_hotp_fixed()
121 {
122 int result = 0;
123 PF::HotPixelsPar* par = dynamic_cast<PF::HotPixelsPar*>( hotpixels->get_par() );
124 if( par ) result = par->get_pixels_fixed();
125 return result;
126 }
127
get_wb(float * mul)128 void PF::RawDeveloperV1Par::get_wb(float* mul)
129 {
130 PF::RawPreprocessorV1Par* par = dynamic_cast<PF::RawPreprocessorV1Par*>( raw_preprocessor->get_par() );
131 if( par ) {
132 mul[0] = par->get_wb_red();
133 mul[1] = par->get_wb_green();
134 mul[2] = par->get_wb_blue();
135 }
136 }
137
138
get_lf_maker()139 std::string PF::RawDeveloperV1Par::get_lf_maker()
140 {
141 std::string result;
142 LensFunPar* lfpar = dynamic_cast<LensFunPar*>( lensfun->get_par() );
143 if( !lfpar ) {
144 std::cout<<"RawDeveloperPar::build(): could not get LensFunPar object."<<std::endl;
145 return result;
146 }
147 return lfpar->camera_maker();
148 }
149
150
get_lf_model()151 std::string PF::RawDeveloperV1Par::get_lf_model()
152 {
153 std::string result;
154 LensFunPar* lfpar = dynamic_cast<LensFunPar*>( lensfun->get_par() );
155 if( !lfpar ) {
156 std::cout<<"RawDeveloperPar::build(): could not get LensFunPar object."<<std::endl;
157 return result;
158 }
159 return lfpar->camera_model();
160 }
161
162
get_lf_lens()163 std::string PF::RawDeveloperV1Par::get_lf_lens()
164 {
165 std::string result;
166 LensFunPar* lfpar = dynamic_cast<LensFunPar*>( lensfun->get_par() );
167 if( !lfpar ) {
168 std::cout<<"RawDeveloperPar::build(): could not get LensFunPar object."<<std::endl;
169 return result;
170 }
171 return lfpar->lens();
172 }
173
174
build(std::vector<VipsImage * > & in,int first,VipsImage * imap,VipsImage * omap,unsigned int & level)175 VipsImage* PF::RawDeveloperV1Par::build(std::vector<VipsImage*>& in, int first,
176 VipsImage* imap, VipsImage* omap,
177 unsigned int& level)
178 {
179 if( (in.size()<1) || (in[0]==NULL) )
180 return NULL;
181
182 VipsImage* out_demo;
183 std::vector<VipsImage*> in2;
184
185 size_t blobsz;
186 if( PF_VIPS_IMAGE_GET_BLOB( in[0], "raw_image_data", &image_data, &blobsz ) ) {
187 std::cout<<"RawDeveloperV1Par::build(): could not extract raw_image_data."<<std::endl;
188 return NULL;
189 }
190 //std::cout<<"RawDeveloperV1Par::build(): blobsz="<<blobsz<<std::endl;
191 if( blobsz != sizeof(dcraw_data_t) ) {
192 std::cout<<"RawDeveloperV1Par::build(): wrong raw_image_data size."<<std::endl;
193 return NULL;
194 }
195
196
197 LensFunPar* lfpar = dynamic_cast<LensFunPar*>( lensfun->get_par() );
198 if( !lfpar ) {
199 std::cout<<"RawDeveloperPar::build(): could not get LensFunPar object."<<std::endl;
200 return NULL;
201 }
202 int lf_modflags = lfpar->get_flags( in[0] );
203
204 VipsImage* input_img = in[0];
205 //std::cout<<"RawDeveloperV1Par::build(): input_img->Bands="<<input_img->Bands<<std::endl;
206 if( input_img->Bands != 3 ) {
207 raw_preprocessor->get_par()->set_image_hints( in[0] );
208 raw_preprocessor->get_par()->set_format( VIPS_FORMAT_FLOAT );
209 VipsImage* image = raw_preprocessor->get_par()->build( in, 0, NULL, NULL, level );
210 //VipsImage* image = in[0]; PF_REF( image, "");
211 if( !image )
212 return NULL;
213
214 VipsImage* out_ca = NULL;
215 PF::ProcessorBase* demo = NULL;
216 if( PF::check_xtrans(image_data->idata.filters) ) {
217 out_ca = image;
218 //PF_REF( out_ca, "RawDeveloperV1Par::build(): in[0] ref for xtrans");
219 //demo = fast_demosaic_xtrans;
220 demo = xtrans_demosaic;
221 } else {
222 in2.push_back( image );
223 hotpixels->get_par()->set_image_hints( image );
224 hotpixels->get_par()->set_format( VIPS_FORMAT_FLOAT );
225 HotPixelsPar* hppar = dynamic_cast<HotPixelsPar*>( hotpixels->get_par() );
226 hppar->set_pixels_fixed( 0 );
227 VipsImage* out_hotp = hotpixels->get_par()->build( in2, 0, NULL, NULL, level );
228 g_object_unref( image );
229 //VipsImage* out_hotp = image;
230
231 CACorrectPar* capar = dynamic_cast<CACorrectPar*>( ca_correct->get_par() );
232 if( !capar ) {
233 std::cout<<"RawDeveloperPar::build(): could not get CACorrectPar object."<<std::endl;
234 return NULL;
235 }
236
237 capar->set_enable_ca( false );
238 capar->set_auto_ca( false );
239 if( enable_tca.get() || enable_all.get() ) {
240 switch(tca_method.get_enum_value().first) {
241 case PF::PF_TCA_CORR_AUTO:
242 capar->set_enable_ca( true );
243 capar->set_auto_ca( true );
244 break;
245 case PF::PF_TCA_CORR_PROFILED_AUTO:
246 if( (lf_modflags & LF_MODIFY_TCA) == 0) {
247 capar->set_enable_ca( true );
248 capar->set_auto_ca( true );
249 }
250 break;
251 case PF::PF_TCA_CORR_MANUAL:
252 capar->set_enable_ca( true );
253 capar->set_auto_ca( false );
254 break;
255 default:
256 break;
257 }
258 }
259
260 in2.clear(); in2.push_back( out_hotp );
261 ca_correct->get_par()->set_image_hints( out_hotp );
262 ca_correct->get_par()->set_format( VIPS_FORMAT_FLOAT );
263 out_ca = ca_correct->get_par()->build( in2, 0, NULL, NULL, level );
264 g_object_unref( out_hotp );
265 //VipsImage* out_ca = out_hotp;
266
267 switch( demo_method.get_enum_value().first ) {
268 case PF::PF_DEMO_FAST: demo = fast_demosaic; break;
269 case PF::PF_DEMO_AMAZE: demo = amaze_demosaic; break;
270 case PF::PF_DEMO_LMMSE: demo = lmmse_demosaic; break;
271 case PF::PF_DEMO_IGV: demo = igv_demosaic; break;
272 default: break;
273 }
274 //PF::ProcessorBase* demo = amaze_demosaic;
275 //PF::ProcessorBase* demo = igv_demosaic;
276 //PF::ProcessorBase* demo = fast_demosaic;
277 }
278 if( !demo ) return NULL;
279 in2.clear(); in2.push_back( out_ca );
280 demo->get_par()->set_image_hints( out_ca );
281 demo->get_par()->set_format( VIPS_FORMAT_FLOAT );
282 out_demo = demo->get_par()->build( in2, 0, NULL, NULL, level );
283 g_object_unref( out_ca );
284
285 for(int ifcs = 0; ifcs < VIPS_MIN(fcs_steps.get(),4); ifcs++) {
286 VipsImage* temp = out_demo;
287 in2.clear(); in2.push_back( temp );
288 fcs[ifcs]->get_par()->set_image_hints( temp );
289 fcs[ifcs]->get_par()->set_format( VIPS_FORMAT_FLOAT );
290 out_demo = fcs[ifcs]->get_par()->build( in2, 0, NULL, NULL, level );
291 PF_UNREF( temp, "RawDeveloperV1Par::build(): temp unref");
292 }
293 } else {
294 raw_preprocessor->get_par()->set_image_hints( in[0] );
295 raw_preprocessor->get_par()->set_format( VIPS_FORMAT_FLOAT );
296 VipsImage* image = raw_preprocessor->get_par()->build( in, 0, NULL, NULL, level );
297 if( !image )
298 return NULL;
299
300 out_demo = image;
301 }
302
303 /**/
304 lensfun->get_par()->set_image_hints( out_demo );
305 lensfun->get_par()->set_format( VIPS_FORMAT_FLOAT );
306 lfpar->set_vignetting_enabled( enable_vignetting.get() || enable_all.get() );
307 lfpar->set_distortion_enabled( enable_distortion.get() || enable_all.get() );
308 lfpar->set_tca_enabled( false );
309 if( enable_tca.get() || enable_all.get() ) {
310 switch(tca_method.get_enum_value().first) {
311 case PF::PF_TCA_CORR_PROFILED:
312 lfpar->set_tca_enabled( true );
313 break;
314 case PF::PF_TCA_CORR_PROFILED_AUTO:
315 if( lf_modflags & LF_MODIFY_TCA )
316 lfpar->set_tca_enabled( true );
317 break;
318 default:
319 break;
320 }
321 }
322 in2.clear(); in2.push_back( out_demo );
323 VipsImage* out_lf = lensfun->get_par()->build( in2, 0, NULL, NULL, level );
324 g_object_unref( out_demo );
325
326
327 raw_output->get_par()->set_image_hints( out_lf );
328 raw_output->get_par()->set_format( VIPS_FORMAT_FLOAT );
329 RawPreprocessorV1Par* rppar = dynamic_cast<RawPreprocessorV1Par*>( raw_preprocessor->get_par() );
330 RawOutputV1Par* ropar = dynamic_cast<RawOutputV1Par*>( raw_output->get_par() );
331 if( rppar && ropar ) {
332 switch( rppar->get_wb_mode() ) {
333 case WB_SPOT:
334 case WB_COLOR_SPOT:
335 ropar->set_wb( rppar->get_wb_red(), rppar->get_wb_green(), rppar->get_wb_blue() );
336 break;
337 default:
338 ropar->set_wb( rppar->get_wb_red()*rppar->get_camwb_corr_red(),
339 rppar->get_wb_green()*rppar->get_camwb_corr_green(),
340 rppar->get_wb_blue()*rppar->get_camwb_corr_blue() );
341 break;
342 }
343 }
344
345 in2.clear(); in2.push_back( out_lf );
346 VipsImage* out = raw_output->get_par()->build( in2, 0, NULL, NULL, level );
347 g_object_unref( out_lf );
348 /**/
349
350 //VipsImage* gamma_in = out_demo;
351 VipsImage* gamma_in = out;
352 VipsImage* gamma = gamma_in;
353 /*
354 if( vips_gamma(gamma_in, &gamma, "exponent", (float)(2.2), NULL) ) {
355 g_object_unref(gamma_in);
356 return NULL;
357 }
358 */
359
360 /*
361 void *data;
362 size_t data_length;
363 cmsHPROFILE profile_in;
364 if( gamma ) {
365 if( !vips_image_get_blob( gamma, VIPS_META_ICC_NAME,
366 &data, &data_length ) ) {
367
368 profile_in = cmsOpenProfileFromMem( data, data_length );
369 if( profile_in ) {
370 char tstr[1024];
371 cmsGetProfileInfoASCII(profile_in, cmsInfoDescription, "en", "US", tstr, 1024);
372 std::cout<<"RawDeveloperV1::build(): convert_format input profile: "<<tstr<<std::endl;
373 cmsCloseProfile( profile_in );
374 }
375 }
376 }
377 */
378
379 VipsImage* out2;
380 std::vector<VipsImage*> in3;
381 in3.push_back( gamma );
382 convert_format->get_par()->set_image_hints( gamma );
383 convert_format->get_par()->set_format( get_format() );
384 out2 = convert_format->get_par()->build( in3, 0, NULL, NULL, level );
385 g_object_unref( gamma );
386
387 set_image_hints( out2 );
388 /*
389 if( out2 ) {
390 if( !vips_image_get_blob( out2, VIPS_META_ICC_NAME,
391 &data, &data_length ) ) {
392
393 profile_in = cmsOpenProfileFromMem( data, data_length );
394 if( profile_in ) {
395 char tstr[1024];
396 cmsGetProfileInfoASCII(profile_in, cmsInfoDescription, "en", "US", tstr, 1024);
397 std::cout<<"RawDeveloperV1::build(): convert_format output profile: "<<tstr<<std::endl;
398 cmsCloseProfile( profile_in );
399 }
400 }
401 }
402 */
403
404 //std::cout<<"RawDeveloperV1::build(): output image: "<<out2<<std::endl;
405 return out2;
406 }
407