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 "../base/new_operation.hh"
35 #include "convert_colorspace.hh"
36 #include "icc_transform.hh"
37 #include "gaussblur.hh"
38 #include "defringe.hh"
39
40
DefringePar()41 PF::DefringePar::DefringePar():
42 OpParBase(),
43 op_mode("op_mode",this,PF::MODE_LOCAL_AVERAGE,"MODE_LOCAL_AVERAGE","local average (slow)"),
44 radius("radius",this,4.0),
45 threshold("threshold",this,20.0),
46 in_profile( NULL )
47 {
48 //op_mode("op_mode",this,PF::MODE_GLOBAL_AVERAGE,"MODE_GLOBAL_AVERAGE","global average (fast)");
49 op_mode.add_enum_value(PF::MODE_STATIC,"MODE_STATIC","static threshold (fast)");
50
51 gauss = new_gaussblur();
52 convert2lab = PF::new_convert_colorspace();
53 PF::ConvertColorspacePar* csconvpar = dynamic_cast<PF::ConvertColorspacePar*>(convert2lab->get_par());
54 if(csconvpar) {
55 csconvpar->set_out_profile_mode( PF::PROF_MODE_DEFAULT );
56 csconvpar->set_out_profile_type( PF::PROF_TYPE_LAB );
57 }
58 convert2input = new_icc_transform();
59 defringe_algo = new_defringe_algo();
60
61 set_type("defringe" );
62
63 set_default_name( _("defringe") );
64 }
65
66
needs_caching()67 bool PF::DefringePar::needs_caching()
68 {
69 return false;
70 }
71
72
73
74
compute_padding(VipsImage * full_res,unsigned int id,unsigned int level)75 void PF::DefringePar::compute_padding( VipsImage* full_res, unsigned int id, unsigned int level )
76 {
77 double radius2 = radius.get();
78 for( unsigned int l = 1; l <= level; l++ )
79 radius2 /= 2;
80
81 DefringeAlgoPar* defringepar = dynamic_cast<DefringeAlgoPar*>( defringe_algo->get_par() );
82 defringepar->set_sigma( radius2 );
83 defringepar->set_threshold( threshold.get() );
84 defringepar->set_op_mode( (defringe_method_t)(op_mode.get_enum_value().first) );
85 defringepar->fb_init();
86
87 int padding = defringepar->get_padding();
88
89 set_padding( padding, id );
90 }
91
92
build(std::vector<VipsImage * > & in,int first,VipsImage * imap,VipsImage * omap,unsigned int & level)93 VipsImage* PF::DefringePar::build(std::vector<VipsImage*>& in, int first,
94 VipsImage* imap, VipsImage* omap,
95 unsigned int& level)
96 {
97 if( (in.size()<1) || (in[0]==NULL) )
98 return NULL;
99
100 VipsImage* srcimg = in[0];
101
102 double radius2 = radius.get();
103 for( unsigned int l = 1; l <= level; l++ )
104 radius2 /= 2;
105
106 std::vector<VipsImage*> in2;
107
108 in_profile = PF::get_icc_profile( in[0] );
109
110 DefringeAlgoPar* defringepar = dynamic_cast<DefringeAlgoPar*>( defringe_algo->get_par() );
111 //defringepar->set_sigma( radius2 );
112 //defringepar->set_threshold( threshold.get() );
113 //defringepar->set_op_mode( (defringe_method_t)(op_mode.get_enum_value().first) );
114 //defringepar->fb_init();
115
116 int padding = defringepar->get_padding();
117
118 // std::cout<<"padding: "<<padding<<std::endl;
119 // std::cout<<"srcimg->Xsize: "<<srcimg->Xsize<<std::endl;
120
121 bool do_conversion = true;
122 if( get_colorspace() == PF::PF_COLORSPACE_LAB ) do_conversion = false;
123
124 // Extend the image by two pixels to account for the pixel averaging window
125 // of the impulse noise reduction algorithm
126 VipsImage* extended;
127 VipsExtend extend = VIPS_EXTEND_COPY;
128 if( vips_embed(srcimg, &extended, padding, padding,
129 srcimg->Xsize+padding*2, srcimg->Ysize+padding*2,
130 "extend", extend, NULL) ) {
131 std::cout<<"DefringePar::build(): vips_embed() failed."<<std::endl;
132 PF_REF( in[0], "DefringePar::build(): vips_embed() failed." );
133 return NULL;
134 }
135 // std::cout<<"extended->Xsize: "<<extended->Xsize<<std::endl;
136
137 VipsImage* labimg;
138 if( do_conversion ) {
139 convert2lab->get_par()->set_image_hints( extended );
140 convert2lab->get_par()->set_format( get_format() );
141 in2.clear(); in2.push_back( extended );
142 labimg = convert2lab->get_par()->build( in2, 0, NULL, NULL, level );
143 if( !labimg ) {
144 std::cout<<"DefringePar::build(): null Lab image"<<std::endl;
145 PF_REF( in[0], "DefringePar::build(): null Lab image" );
146 return in[0];
147 }
148 PF_UNREF( extended, "DefringePar::build(): extended unref after convert2lab" );
149 } else {
150 labimg = extended;
151 }
152
153
154 VipsImage* blurred = NULL;
155
156 GaussBlurPar* gausspar = dynamic_cast<GaussBlurPar*>( gauss->get_par() );
157 if( gausspar ) {
158 gausspar->set_radius( radius.get() ); // TODO: should this be radius2?
159 gausspar->set_image_hints( labimg );
160 gausspar->set_format( get_format() );
161 in2.clear(); in2.push_back( labimg );
162 blurred = gausspar->build( in2, 0, NULL, NULL, level );
163 PF_UNREF( labimg, "ImageReaderPar::build(): extended unref after convert2lab" );
164 }
165
166 if( !blurred ) {
167 std::cout<<"DefringePar::build(): null Lab image"<<std::endl;
168 PF_REF( in[0], "DefringePar::build(): null Lab image" );
169 return in[0];
170 }
171
172 defringepar->set_image_hints( labimg );
173 defringepar->set_format( get_format() );
174 in2.clear();
175 in2.push_back( labimg );
176 in2.push_back(blurred);
177 VipsImage* defr = defringepar->build( in2, 0, NULL, NULL, level );
178 PF_UNREF( blurred, "DefringePar::build(): extended unref after convert2lab" );
179
180 // std::cout<<"defr->Xsize: "<<defr->Xsize<<std::endl;
181
182 // Final cropping to remove the padding pixels
183 VipsImage* cropped;
184 if( vips_crop(defr, &cropped, padding, padding,
185 srcimg->Xsize, srcimg->Ysize, NULL) ) {
186 std::cout<<"DefringePar::build(): vips_crop() failed."<<std::endl;
187 PF_UNREF( defr, "DefringePar::build(): defr unref" );
188 PF_REF( in[0], "DefringePar::build(): vips_crop() failed" );
189 return in[0];
190 }
191 PF_UNREF( defr, "DefringePar::build(): defr unref" );
192
193 // std::cout<<"cropped->Xsize: "<<cropped->Xsize<<std::endl;
194
195 VipsImage* out;
196 if( do_conversion ) {
197 PF::ICCTransformPar* icc_par = dynamic_cast<PF::ICCTransformPar*>( convert2input->get_par() );
198 if( icc_par ) {
199 icc_par->set_out_profile( in_profile );
200 }
201 convert2input->get_par()->set_image_hints( cropped );
202 convert2input->get_par()->set_format( get_format() );
203 in2.clear(); in2.push_back( cropped );
204 std::cout<<"DefringePar::build(): calling convert2input->get_par()->build()"<<std::endl;
205 out = convert2input->get_par()->build(in2, 0, NULL, NULL, level );
206 PF_UNREF( cropped, "DefringePar::update() cropped unref" );
207 } else {
208 out = cropped;
209 }
210
211 // std::cout<<"out->Xsize: "<<out->Xsize<<std::endl;
212
213 set_image_hints( out );
214
215 return out;
216 }
217