1 // -*- c-basic-offset: 4 -*-
2
3 /** @file vig_optimize.cpp
4 *
5 * @brief a simple test stitcher
6 *
7 * @author Pablo d'Angelo <pablo.dangelo@web.de>
8 *
9 * $Id$
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This software is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public
22 * License along with this software. If not, see
23 * <http://www.gnu.org/licenses/>.
24 *
25 */
26
27 #include <hugin_config.h>
28 #include <fstream>
29 #include <sstream>
30
31 #include <algorithms/optimizer/PhotometricOptimizer.h>
32 #include "ExtractPoints.h"
33 #include <getopt.h>
34 #include <hugin_basic.h>
35 #include <nona/Stitcher.h>
36
37 #include <tiff.h>
38
usage(const char * name)39 static void usage(const char* name)
40 {
41 std::cout << name << ": Try to determine the radial vignetting" << std::endl
42 << "vig_optimize version " << hugin_utils::GetHuginVersion() << std::endl
43 << std::endl
44 << "Usage: " << name << " [options] -o output.pto input.pto" << std::endl
45 << "Valid options are:" << std::endl
46 << " -o|--output file write results to output project" << std::endl
47 << " -v|--verbose Verbose, print progress messages" << std::endl
48 << " -p n Number of points to extract" << std::endl
49 << " -s level Work on downscaled images, every step halves width and height" << std::endl
50 << " -h|--help Display help (this text)" << std::endl
51 << std::endl
52 << " Expert and debugging options:" << std::endl
53 << " -i file Read corresponding points from file" << std::endl
54 << " -w file Dump corresponding points to file" << std::endl;
55 }
56
57
58 /*
59 template<class RIMG>
60 void importROIImage(ImageImportInfo & info, RIMG & img)
61 {
62 vigra::Rect2D roi(Point2D(info.getPosition()), info.size());
63 img.resize(roi);
64 importImageAlpha(info, destImage(img.m_image), destImage(img.m_mask));
65 }
66 */
67
68
loadPointsC(FILE * f,std::vector<vigra_ext::PointPairRGB> & vec)69 void loadPointsC(FILE* f, std::vector<vigra_ext::PointPairRGB>& vec)
70 {
71 double dummy1, dummy2;
72 vigra_ext::PointPairRGB point;
73 double i1, i2;
74
75 int n=0;
76 do
77 {
78 n = fscanf(f, " %lf %lf %lf %lf %lf %lf %f %f %f %f %f %f %lf %f %f %lf",
79 &i1, &i2, &(point.p1.x), &(point.p1.y),
80 &(point.p2.x), &(point.p2.y),
81 &(point.i1.red()), &(point.i1.green()), &(point.i1.blue()),
82 &(point.i2.red()), &(point.i2.green()), &(point.i2.blue()),
83 // matlab index.. set to zero
84 &dummy1,
85 &(point.r1), &(point.r2),
86 // edge score at this point, zero so far
87 &(dummy2) );
88
89
90 point.imgNr1 = hugin_utils::roundi(i1);
91 point.imgNr2 = hugin_utils::roundi(i2);
92 if (n==16)
93 {
94 vec.push_back(point);
95 }
96 }
97 while (n == 16);
98 }
99
loadPoints(std::istream & i,std::vector<vigra_ext::PointPairRGB> & vec)100 void loadPoints(std::istream& i, std::vector<vigra_ext::PointPairRGB>& vec )
101 {
102 while(!i.eof() && i.good())
103 {
104 double dummy1, dummy2;
105 vigra_ext::PointPairRGB point;
106 double i1, i2;
107 i >> i1 >> i2
108 >> point.p1.x >> point.p1.y
109 >> point.p2.x >> point.p2.y
110 >> point.i1.red() >> point.i1.green() >> point.i1.blue()
111 >> point.i2.red() >> point.i2.green() >> point.i2.blue()
112 // matlab index.. set to zero
113 >> dummy1
114 >> point.r1 >> point.r2
115 // edge score at this point, zero so far
116 >> dummy2;
117 point.imgNr1 = hugin_utils::roundi(i1);
118 point.imgNr2 = hugin_utils::roundi(i2);
119 if (i.good())
120 {
121 vec.push_back(point);
122 }
123 }
124 }
125
hasphotometricParams(HuginBase::Panorama & pano)126 bool hasphotometricParams(HuginBase::Panorama& pano)
127 {
128 HuginBase::OptimizeVector vars = pano.getOptimizeVector();
129
130 for (HuginBase::OptimizeVector::const_iterator it = vars.begin(); it != vars.end(); ++it)
131 {
132 for (std::set<std::string>::const_iterator itv = (*it).begin();
133 itv != (*it).end(); ++itv)
134 {
135 if ((*itv)[0] == 'E' || (*itv)[0] == 'R' || (*itv)[0] == 'V')
136 {
137 return true;
138 }
139 }
140 }
141 return false;
142 }
143
144
main(int argc,char * argv[])145 int main(int argc, char* argv[])
146 {
147 AppBase::StreamProgressDisplay progressDisplay(std::cout);
148
149 // parse arguments
150 const char* optstring = "hi:o:p:s:vw:";
151 static struct option longOptions[] =
152 {
153 { "output", required_argument, NULL, 'o' },
154 { "verbose", no_argument, NULL, 'v' },
155 { "help", no_argument, NULL, 'h' },
156 0
157 };
158 int c;
159
160 int pyrLevel=3;
161 int verbose = 0;
162 int nPoints = 200;
163 std::string outputFile;
164 std::string outputPointsFile;
165 std::string inputPointsFile;
166 while ((c = getopt_long(argc, argv, optstring, longOptions, nullptr)) != -1)
167 {
168 switch (c)
169 {
170 case 'i':
171 inputPointsFile = optarg;
172 break;
173 case 'o':
174 outputFile = optarg;
175 break;
176 case 'p':
177 nPoints = atoi(optarg);
178 break;
179 case 's':
180 pyrLevel = atoi(optarg);
181 break;
182 case 'v':
183 verbose++;
184 break;
185 case 'h':
186 usage(hugin_utils::stripPath(argv[0]).c_str());
187 return 1;
188 case 'w':
189 outputPointsFile = optarg;
190 break;
191 case ':':
192 case '?':
193 // missing argument or invalid switch
194 return 1;
195 break;
196 default:
197 // this should not happen
198 abort();
199 }
200 };
201
202 unsigned nFiles = argc - optind;
203 if (nFiles != 1)
204 {
205 if (nFiles< 1)
206 {
207 std::cerr << hugin_utils::stripPath(argv[0]) << ": No project file given." << std::endl;
208 }
209 else
210 {
211 std::cerr << hugin_utils::stripPath(argv[0]) << ": Only one project file expected." << std::endl;
212 };
213 return 1;
214 };
215
216 const char* scriptFile = argv[optind];
217 HuginBase::Panorama pano;
218 std::ifstream prjfile(scriptFile);
219 if (!prjfile.good())
220 {
221 std::cerr << "could not open script : " << scriptFile << std::endl;
222 return 1;
223 }
224 pano.setFilePrefix(hugin_utils::getPathPrefix(scriptFile));
225 AppBase::DocumentData::ReadWriteError err = pano.readData(prjfile);
226 if (err != AppBase::DocumentData::SUCCESSFUL)
227 {
228 std::cerr << "error while parsing panos tool script: " << scriptFile << std::endl;
229 std::cerr << "AppBase::DocumentData::ReadWriteError code: " << err << std::endl;
230 return 1;
231 }
232
233 // Ensure photometric parameters are selected for optimizaion
234 if (!hasphotometricParams(pano))
235 {
236 std::cerr << "ERROR:no photometric parameters were selected for optimization" << std::endl;
237 std::cerr << "please update 'v' line in .pto script and try again." << std::endl;
238 return 1;
239 }
240
241 // suppress tiff warnings
242 TIFFSetWarningHandler(0);
243
244 // todo: handle images with alpha masks
245 try
246 {
247 std::vector<vigra_ext::PointPairRGB> points;
248
249 float imageStepSize = 1 / 255.0f;
250 if (inputPointsFile != "" )
251 {
252 //ifstream ifs(inputPointsFile.c_str());
253 //loadPoints(ifs, points);
254 FILE* f = fopen(inputPointsFile.c_str(), "r");
255 if (f == 0)
256 {
257 perror("Could not open input point file");
258 return 1;
259 }
260 loadPointsC(f, points);
261 fclose(f);
262 }
263 else
264 {
265 loadImgsAndExtractPoints(pano, nPoints, pyrLevel, true, progressDisplay, points, verbose, imageStepSize);
266 }
267 if (verbose)
268 {
269 std::cout << "\rSelected " << points.size() << " points" << std::endl;
270 }
271 if (points.empty())
272 {
273 std::cerr << "Error: no overlapping points found, exiting" << std::endl;
274 return 1;
275 }
276
277 if (!outputPointsFile.empty())
278 {
279 std::ofstream of(outputPointsFile.c_str());
280 for (std::vector<vigra_ext::PointPairRGB>::iterator it = points.begin(); it != points.end(); ++it)
281 {
282 of << (*it).imgNr1 << " " << (*it).imgNr2 << " "
283 << (*it).p1.x << " " << (*it).p1.y<< " "
284 << (*it).p2.x << " " << (*it).p2.y<< " "
285 << (*it).i1.red() << " " << (*it).i1.green() << " " << (*it).i1.blue() << " "
286 << (*it).i2.red() << " " << (*it).i2.green() << " " << (*it).i2.blue() << " "
287 // matlab index.. set to zero
288 << 0 << " "
289 << (*it).r1 << " " << (*it).r2 << " "
290 // edge score at this point, zero so far
291 << 0 << std::endl;
292 }
293 }
294
295
296 progressDisplay.setMessage("Vignetting Optimization");
297 HuginBase::PhotometricOptimizer photoopt(pano, &progressDisplay, pano.getOptimizeVector(), points, imageStepSize);
298 photoopt.run();
299 // double error = photoopt.getResultError();
300
301 progressDisplay.taskFinished();
302
303 HuginBase::UIntSet allImgs;
304 fill_set(allImgs,0, pano.getNrOfImages()-1);
305 // save project
306 if (outputFile == "" || outputFile == "-")
307 {
308 pano.printPanoramaScript(std::cout, pano.getOptimizeVector(), pano.getOptions(), allImgs, false, hugin_utils::getPathPrefix(scriptFile));
309 }
310 else
311 {
312 std::ofstream of(outputFile.c_str());
313 pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), allImgs, false, hugin_utils::getPathPrefix(scriptFile));
314 }
315
316 }
317 catch (std::exception& e)
318 {
319 std::cerr << "caught exception: " << e.what() << std::endl;
320 return 1;
321 }
322 return 0;
323 }
324