Hugin trunk 0.1
Loading...
Searching...
No Matches
linefind.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
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 <fstream>
28#include <sstream>
29#include <getopt.h>
30#include <panodata/Panorama.h>
32#include <lines/FindLines.h>
33#include <vigra/impex.hxx>
35#include <vigra/functorexpression.hxx>
36#include <vigra_ext/utils.h>
39
40extern "C"
41{
42#include <pano13/filter.h>
43}
44
45static void usage(const char* name)
46{
47 std::cout << name << ": find vertical lines in images" << std::endl
48 << name << " version " << hugin_utils::GetHuginVersion() << std::endl
49 << std::endl
50 << "Usage: " << name << " [options] input.pto" << std::endl
51 << std::endl
52 << " Options:" << std::endl
53 << " -o, --output=file.pto Output Hugin PTO file. Default: <filename>_lines.pto" << std::endl
54 << " -i, --image=IMGNR Work only on given image numbers" << std::endl
55 << " -l, --lines=COUNT Save maximal COUNT lines (default: 5)" << std::endl
56 << " -h, --help Shows this help" << std::endl
57 << std::endl;
58}
59
60// dummy panotools progress functions
61static int ptProgress( int command, char* argument )
62{
63 return 1;
64}
65static int ptinfoDlg( int command, char* argument )
66{
67 return 1;
68}
69
76// 2 versions: one for color images, the other for gray images
77template <class SrcIMG>
78void convertToUInt8(SrcIMG& src, const std::string& origType, vigra::UInt8RGBImage& dest)
79{
80 dest.resize(src.size());
82 // float needs to be from min ... max.
83 if (origType == "FLOAT" || origType == "DOUBLE" || origType == "UINT32" || origType == "INT32")
84 {
88 vigra::FindAverageAndVariance<float> mean; // init functor
89 vigra::inspectImage(srcImageRange(src, vigra::RGBToGrayAccessor<typename SrcIMG::PixelType>()), mean);
90 const double minVal = std::max(mean.average() - 3 * sqrt(mean.variance()), 1e-6f);
91 const double maxVal = mean.average() + 3 * sqrt(mean.variance());
92 vigra_ext::applyMapping(srcImageRange(src), destImage(dest), minVal, maxVal, 1);
93 }
94 else
95 {
96 vigra::transformImage(srcImageRange(src), destImage(dest),
97 vigra::functor::Arg1()*vigra::functor::Param( newMax/ vigra_ext::getMaxValForPixelType(origType)));
98 };
99}
100
101template <class SrcIMG>
102void convertGrayToUInt8(SrcIMG& src, const std::string& origType, vigra::BImage& dest)
103{
104 dest.resize(src.size());
106 // float needs to be from min ... max.
107 if (origType == "FLOAT" || origType == "DOUBLE" || origType == "UINT32" || origType == "INT32")
108 {
112 vigra::FindAverageAndVariance<float> mean; // init functor
113 vigra::inspectImage(srcImageRange(src), mean);
114 const double minVal = std::max(mean.average() - 3 * sqrt(mean.variance()), 1e-6f);
115 const double maxVal = mean.average() + 3 * sqrt(mean.variance());
116 vigra_ext::applyMapping(srcImageRange(src), destImage(dest), minVal, maxVal, 1);
117 }
118 else
119 {
120 vigra::transformImage(srcImageRange(src), destImage(dest),
121 vigra::functor::Arg1()*vigra::functor::Param( newMax/ vigra_ext::getMaxValForPixelType(origType)));
122 };
123}
124
125template <class SrcIMG>
126vigra::BImage LoadGrayImageAndConvert(vigra::ImageImportInfo& info, vigra::BImage& mask)
127{
128 vigra::BImage image;
129 SrcIMG imageIn(info.width(),info.height());
130 if(info.numExtraBands()==1)
131 {
132 mask.resize(info.width(), info.height());
133 vigra::importImageAlpha(info,destImage(imageIn),destImage(mask));
134 }
135 else
136 {
137 importImage(info,destImage(imageIn));
138 };
139 convertGrayToUInt8(imageIn,info.getPixelType(),image);
140 imageIn.resize(0,0);
141 return image;
142};
143
144template <class SrcIMG>
145vigra::UInt8RGBImage LoadImageAndConvert(vigra::ImageImportInfo& info, vigra::BImage& mask)
146{
147 vigra::UInt8RGBImage image;
148 SrcIMG imageIn(info.width(),info.height());
149 if(info.numExtraBands()==1)
150 {
151 mask.resize(info.width(), info.height());
152 vigra::importImageAlpha(info,destImage(imageIn),destImage(mask));
153 }
154 else
155 {
156 importImage(info,destImage(imageIn));
157 };
158 convertToUInt8(imageIn,info.getPixelType(),image);
159 imageIn.resize(0,0);
160 return image;
161};
162
163// loads the gray images and finds vertical lines, returns a CPVector with found vertical lines
164HuginBase::CPVector LoadGrayImageAndFindLines(vigra::ImageImportInfo info, HuginBase::Panorama& pano, size_t imgNr, int nrLines)
165{
166 vigra::BImage image;
167 vigra::BImage mask;
169 std::string pixelType=info.getPixelType();
170 if(pixelType=="UINT8")
171 {
172 image.resize(info.width(),info.height());
173 if(info.numExtraBands()==1)
174 {
175 mask.resize(info.width(), info.height());
176 vigra::importImageAlpha(info,destImage(image),destImage(mask));
177 }
178 else
179 {
180 importImage(info,destImage(image));
181 };
182 }
183 else
184 {
185 if(pixelType=="UINT16" || pixelType=="INT16")
186 {
188 }
189 else
190 {
191 if(pixelType=="INT32" || pixelType=="UINT32")
192 {
194 }
195 else
196 {
197 if(pixelType=="FLOAT" || pixelType=="DOUBLE")
198 {
200 }
201 else
202 {
203 std::cerr << "Unsupported pixel type" << std::endl;
204 };
205 };
206 };
207 };
208 if(image.width()>0 && image.height()>0)
209 {
210 lineCp=HuginLines::GetVerticalLines(pano, imgNr, image, mask, nrLines);
211 };
212 return lineCp;
213};
214
215// loads the color images and finds vertical lines, returns a CPVector with found vertical lines
216HuginBase::CPVector LoadImageAndFindLines(vigra::ImageImportInfo info, HuginBase::Panorama& pano, size_t imgNr, int nrLines)
217{
218 vigra::UInt8RGBImage image;
219 vigra::BImage mask;
221 std::string pixelType=info.getPixelType();
222 if(pixelType=="UINT8")
223 {
224 image.resize(info.width(),info.height());
225 if(info.numExtraBands()==1)
226 {
227 mask.resize(info.width(), info.height());
228 vigra::importImageAlpha(info,destImage(image),destImage(mask));
229 }
230 else
231 {
232 importImage(info,destImage(image));
233 };
234 }
235 else
236 {
237 if(pixelType=="UINT16" || pixelType=="INT16")
238 {
240 }
241 else
242 {
243 if(pixelType=="INT32" || pixelType=="UINT32")
244 {
246 }
247 else
248 {
249 if(pixelType=="FLOAT" || pixelType=="DOUBLE")
250 {
252 }
253 else
254 {
255 std::cerr << "Unsupported pixel type" << std::endl;
256 };
257 };
258 };
259 };
260 if(image.width()>0 && image.height()>0)
261 {
262 lineCp=HuginLines::GetVerticalLines(pano, imgNr, image, mask, nrLines);
263 }
264 return lineCp;
265};
266
268{
269 explicit SortVectorByExposure(const HuginBase::Panorama& pano) : m_pano(pano) {};
270 bool operator()(const size_t& img1, const size_t& img2)
271 {
272 return m_pano.getImage(img1).getExposureValue() < m_pano.getImage(img2).getExposureValue();
273 }
274private:
276};
277
279
280int main(int argc, char* argv[])
281{
282 // parse arguments
283 const char* optstring = "o:i:l:h";
284
285 static struct option longOptions[] =
286 {
287 {"output", required_argument, NULL, 'o' },
288 {"image", required_argument, NULL, 'i' },
289 {"lines", required_argument, NULL, 'l' },
290 {"help", no_argument, NULL, 'h' },
291 0
292 };
293
295 int c;
296 int nrLines = 5;
297 std::string output;
298 while ((c = getopt_long (argc, argv, optstring, longOptions,nullptr)) != -1)
299 {
300 switch (c)
301 {
302 case 'o':
303 output = optarg;
304 break;
305 case 'h':
307 return 0;
308 case 'i':
309 {
310 int imgNr=atoi(optarg);
311 if((imgNr==0) && (strcmp(optarg,"0")!=0))
312 {
313 std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse image number." << std::endl;
314 return 1;
315 };
316 cmdlineImages.insert(imgNr);
317 };
318 break;
319 case 'l':
321 if(nrLines<1)
322 {
323 std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse number of lines." << std::endl;
324 return 1;
325 };
326 break;
327 case ':':
328 case '?':
329 // missing argument or invalid switch
330 return 1;
331 break;
332 default:
333 // this should not happen
334 abort();
335 }
336 }
337
338 if (argc - optind != 1)
339 {
340 if (argc - optind < 1)
341 {
342 std::cerr << hugin_utils::stripPath(argv[0]) << ": No project file given." << std::endl;
343 }
344 else
345 {
346 std::cerr << hugin_utils::stripPath(argv[0]) << ": Only one project file expected." << std::endl;
347 };
348 return 1;
349 };
350
351
352 std::string input=argv[optind];
353 // read panorama
356 {
357 return 1;
358 };
359
360 // disable progress messages from libpano optimizer
363
364 std::vector<size_t> imagesToProcess;
365 if(cmdlineImages.empty())
366 {
367 //no image given, process one image of each stack
369 HuginBase::UIntSetVector imageGroups = variable_groups.getStacks().getPartsSet();
370 //get image with median exposure for search for lines
371 for (size_t imgGroup = 0; imgGroup < imageGroups.size(); ++imgGroup)
372 {
374 if (pano.getImage(stackImages[0]).YawisLinked())
375 {
376 // position is linked, take only image with median exposure for search
377 std::sort(stackImages.begin(), stackImages.end(), SortVectorByExposure(pano));
378 size_t index = 0;
379 if (pano.getImage(*(stackImages.begin())).getExposureValue() != pano.getImage(*(stackImages.rbegin())).getExposureValue())
380 {
381 index = stackImages.size() / 2;
382 };
383 imagesToProcess.push_back(stackImages[index]);
384 }
385 else
386 {
387 // stacks are unlinked, search all images
388 std::copy(stackImages.begin(), stackImages.end(), std::back_inserter(imagesToProcess));
389 };
390 };
391 if (pano.getNrOfCtrlPoints())
392 {
393 // pano has already control points, so do a pair-wise optimisation to get
394 // rough positions of the images, so we can decide which images are near
395 // the zenit/nadir and ignore these images
397 // reset translation parameters
399 for (size_t i = 0; i < varMapVec.size(); i++)
400 {
401 map_get(varMapVec[i], "TrX").setValue(0);
402 map_get(varMapVec[i], "TrY").setValue(0);
403 map_get(varMapVec[i], "TrZ").setValue(0);
404 };
405 optPano.updateVariables(varMapVec);
406 // now do a pairwise optimisation
408 std::vector<size_t> imagesToCheck;
409 std::swap(imagesToProcess, imagesToCheck);
410 for (auto& img:imagesToCheck)
411 {
412 // now remove all images from list where pitch > 50 or < -50 -> images near zenit/nadir
413 if (std::abs(optPano.getImage(img).getPitch()) < 50)
414 {
415 imagesToProcess.push_back(img);
416 };
417 };
418 }
419 }
420 else
421 {
422 //check, if given image numbers are valid
423 for (HuginBase::UIntSet::const_iterator it = cmdlineImages.begin(); it != cmdlineImages.end(); ++it)
424 {
425 if((*it)>=0 && (*it)<pano.getNrOfImages())
426 {
427 imagesToProcess.push_back(*it);
428 };
429 };
430 };
431
432 if(imagesToProcess.empty())
433 {
434 std::cerr << "No image to process found" << std::endl << "Stopping processing" << std::endl;
435 return 1;
436 };
437
438 std::cout << hugin_utils::stripPath(argv[0]) << " is searching for vertical lines" << std::endl;
439#if _WIN32
440 //multi threading of image loading results sometime in a race condition
441 //try to prevent this by initialisation of codecManager before
442 //running multi threading part
443 std::string s=vigra::impexListExtensions();
444#endif
445
446 const size_t nrCPS=pano.getNrOfCtrlPoints();
447#pragma omp parallel for schedule(dynamic)
448 for(int i=0; i < imagesToProcess.size(); ++i)
449 {
450 const size_t imgNr = imagesToProcess[i];
451 std::ostringstream buf;
452 buf << "Working on image " << pano.getImage(imgNr).getFilename() << std::endl;
453 std::cout << buf.str();
454 // now load and process all images
455 vigra::ImageImportInfo info(pano.getImage(imgNr).getFilename().c_str());
457 if(info.isGrayscale())
458 {
459 foundLines=LoadGrayImageAndFindLines(info, pano, imgNr, nrLines);
460 }
461 else
462 {
463 if(info.isColor())
464 {
465 //colour images
466 foundLines=LoadImageAndFindLines(info, pano, imgNr, nrLines);
467 }
468 else
469 {
470 std::cerr << "Image " << pano.getImage(imgNr).getFilename().c_str() << " has "
471 << info.numBands() << " channels." << std::endl
472 << "Linefind works only with grayscale or color images." << std::endl
473 << "Skipping image." << std::endl;
474 };
475 };
476 if(!foundLines.empty())
477 {
478 for (HuginBase::CPVector::const_iterator cpIt = foundLines.begin(); cpIt != foundLines.end(); ++cpIt)
479 {
481 pano.addCtrlPoint(*cpIt);
482 };
483 };
484 }
485 std::cout << std::endl << "Found " << pano.getNrOfCtrlPoints() - nrCPS << " vertical lines" << std::endl << std::endl;
486
487 //write output
488 // Set output .pto filename if not given
491 {
492 std::cout << std::endl << "Written output to " << output << std::endl;
493 };
494 return 0;
495}
declaration of functions for finding lines
static void usage()
Definition Main.cpp:32
!! from PTOptimise.h 1951
Somewhere to specify what variables belong to what.
Make an ImageVariableGroup for lenses and other common concepts.
virtual void run()
runs the algorithm.
Model for a panorama.
Definition Panorama.h:153
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition Panorama.h:211
bool ReadPTOFile(const std::string &filename, const std::string &prefix="")
read pto file from the given filename into Panorama object it does some checks on the file and issues...
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
Definition Panorama.cpp:381
std::size_t getNrOfCtrlPoints() const
number of control points
Definition Panorama.h:306
VariableMapVector getVariables() const
get variables of this panorama
Definition Panorama.cpp:118
Panorama duplicate() const
duplicate the panorama
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
std::size_t getNrOfImages() const
number of images.
Definition Panorama.h:205
class AlphaIterator class AlphaAccessor inline void importImageAlpha(const ImageImportInfo &import_info, ImageIterator image_iterator, ImageAccessor image_accessor, AlphaIterator alpha_iterator, AlphaAccessor alpha_accessor)
static int ptProgress(int command, char *argument)
Definition linefind.cpp:61
int main(int argc, char *argv[])
Definition linefind.cpp:280
void convertToUInt8(SrcIMG &src, const std::string &origType, vigra::UInt8RGBImage &dest)
converts the given image to UInt8RGBImage only this image is correctly processed by linefind
Definition linefind.cpp:78
static int ptinfoDlg(int command, char *argument)
Definition linefind.cpp:65
HuginBase::CPVector LoadGrayImageAndFindLines(vigra::ImageImportInfo info, HuginBase::Panorama &pano, size_t imgNr, int nrLines)
Definition linefind.cpp:164
vigra::UInt8RGBImage LoadImageAndConvert(vigra::ImageImportInfo &info, vigra::BImage &mask)
Definition linefind.cpp:145
void convertGrayToUInt8(SrcIMG &src, const std::string &origType, vigra::BImage &dest)
Definition linefind.cpp:102
vigra::BImage LoadGrayImageAndConvert(vigra::ImageImportInfo &info, vigra::BImage &mask)
Definition linefind.cpp:126
static hugin_omp::Lock lock
Definition linefind.cpp:278
HuginBase::CPVector LoadImageAndFindLines(vigra::ImageImportInfo info, HuginBase::Panorama &pano, size_t imgNr, int nrLines)
Definition linefind.cpp:216
std::vector< unsigned int > UIntVector
std::vector< VariableMap > VariableMapVector
std::vector< ControlPoint > CPVector
std::vector< UIntSet > UIntSetVector
std::set< unsigned int > UIntSet
HuginBase::CPVector GetVerticalLines(const HuginBase::Panorama &pano, const unsigned int imgNr, vigra::UInt8RGBImage &image, vigra::BImage &mask, const unsigned int nrLines)
searches for vertical control points in given image
std::string GetHuginVersion()
return a string with version numbers
Definition utils.cpp:907
std::string GetOutputFilename(const std::string &out, const std::string &in, const std::string &suffix)
construct output filename, if ouput is known return this value otherwise use the input filename and a...
Definition utils.cpp:420
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
Definition utils.cpp:160
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition utils.cpp:184
double getMaxValForPixelType(const std::string &v)
Definition utils.h:89
void applyMapping(vigra::triple< SrcIterator, SrcIterator, SrcAccessor > img, vigra::pair< DestIterator, DestAccessor > dest, T min, T max, int mapping)
Definition utils.h:685
helper for OpenMP
Map::mapped_type & map_get(Map &m, const typename Map::key_type &key)
get a map element.
Definition stl_utils.h:98
const HuginBase::Panorama & m_pano
Definition linefind.cpp:275
SortVectorByExposure(const HuginBase::Panorama &pano)
Definition linefind.cpp:269
bool operator()(const size_t &img1, const size_t &img2)
Definition linefind.cpp:270
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41
functions to manage ROI's