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