Hugin trunk 0.1
Loading...
Searching...
No Matches
checkpto.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
12/* This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This software is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public
23 * License along with this software. If not, see
24 * <http://www.gnu.org/licenses/>.
25 *
26 */
27
28#include <hugin_config.h>
29
30#include <fstream>
31#include <sstream>
32#include <random>
33#include <getopt.h>
34
35#include <panodata/Panorama.h>
41#include <filesystem>
42#include "vigra/impexalpha.hxx"
43
44static void usage(const char* name)
45{
46 std::cout << name << ": report the number of image groups in a project" << std::endl
47 << name << " version " << hugin_utils::GetHuginVersion() << std::endl
48 << std::endl
49 << "Usage: " << name << " input.pto" << std::endl
50 << std::endl
51 << name << " examines the connections between images in a project and" << std::endl
52 << "reports back the number of parts or image groups in that project" << std::endl
53 << std::endl
54 << "Further switches:" << std::endl
55 << " --print-output-info Print more information about the output" << std::endl
56 << " --print-lens-info Print more information about lenses" << std::endl
57 << " --print-stack-info Print more information about assigned stacks" << std::endl
58 << " --print-image-info Print information about image files" << std::endl
59 << " --create-missing-images Creates placeholder images for non-existing" << std::endl
60 << " images in same directory as the pto file" << std::endl
61 << std::endl
62 << name << " is used by the assistant" << std::endl
63 << std::endl;
64}
65
66void PrintImageGroup(const std::vector<HuginBase::UIntSet>& imageGroup, const std::string& prefix=std::string())
67{
68 for (size_t i=0; i < imageGroup.size(); i++)
69 {
70 if (!prefix.empty())
71 {
72 std::cout << prefix << " " << i << ": ";
73 };
74 std::cout << "[";
75 size_t c=0;
76 for (HuginBase::UIntSet::const_iterator it = imageGroup[i].begin(); it != imageGroup[i].end(); ++it)
77 {
78 std::cout << (*it);
79 if (c+1 != imageGroup[i].size())
80 {
81 std::cout << ", ";
82 }
83 ++c;
84 }
85 std::cout << "]";
86 if (prefix.empty() && (i+1 != imageGroup.size()))
87 {
88 std::cout << ", ";
89 }
90 std::cout << std::endl;
91 }
92};
93
94void InspectRGBImage(const vigra::FRGBImage &image)
95{
96 vigra::FindMinMax<float> minmax;
97 vigra::inspectImage(srcImageRange(image, vigra::RedAccessor<vigra::RGBValue<float>>()), minmax);
98 std::cout << " Red channel: " << minmax.min << " - " << minmax.max << std::endl;
99 minmax.reset();
100 vigra::inspectImage(srcImageRange(image, vigra::GreenAccessor<vigra::RGBValue<float>>()), minmax);
101 std::cout << " Green channel: " << minmax.min << " - " << minmax.max << std::endl;
102 minmax.reset();
103 vigra::inspectImage(srcImageRange(image, vigra::BlueAccessor<vigra::RGBValue<float>>()), minmax);
104 std::cout << " Blue channel: " << minmax.min << " - " << minmax.max << std::endl;
105}
106
107void InspectGrayscaleImage(const vigra::FImage &image, const std::string text)
108{
109 vigra::FindMinMax<float> minmax;
110 vigra::inspectImage(srcImageRange(image), minmax);
111 std::cout << " " << text << ": " << minmax.min << " - " << minmax.max << std::endl;
112}
113
115{
116 // print info for all images
117 std::cout << std::endl;
118 for (int imgNr = 0; imgNr < pano.getNrOfImages(); ++imgNr)
119 {
120 const std::string filename = pano.getImage(imgNr).getFilename();
121 std::cout << "Image " << imgNr << ": " << filename << std::endl;
122 if (hugin_utils::FileExists(filename))
123 {
124 if (vigra::isImage(filename.c_str()))
125 {
126 vigra::ImageImportInfo info(filename.c_str());
127 std::filesystem::path file(filename);
128 std::cout << " File type: " << info.getFileType() << std::endl;
129 const auto fileSize = std::filesystem::file_size(file);
130 std::cout << " File size: ";
131 if (fileSize > 1000)
132 {
133 std::cout << fileSize / 1000 << " kB" << std::endl;
134 }
135 else
136 {
137 std::cout << fileSize << " B" << std::endl;
138 };
139 std::cout << " Pixel type: " << info.getPixelType() << std::endl
140 << " Pixel size: " << info.width() << "x" << info.height() << std::endl
141 << " Resolution: " << info.getXResolution() << "/" << info.getYResolution() << std::endl
142 << " Offset: " << info.getPosition() << std::endl
143 << " Canvas size: " << info.getCanvasSize() << std::endl
144 << " ICC profile: " << (info.getICCProfile().empty() ? "no" : hugin_utils::GetICCDesc(info.getICCProfile())) << std::endl
145 << " Bands: " << info.numBands() << std::endl
146 << " Extra bands: " << info.numExtraBands() << std::endl;
147 if (info.numImages() > 1)
148 {
149 std::cout << " Subimages: " << info.numImages() << " (reading index " << info.getImageIndex() << ")" << std::endl;
150 };
151 if (info.numExtraBands() == 0)
152 {
153 // no mask
154 if (info.numBands() == 3)
155 {
156 //RGB image
157 vigra::FRGBImage image(info.size());
158 vigra::importImage(info, destImage(image));
159 InspectRGBImage(image);
160 }
161 else
162 {
163 if (info.numBands() == 1)
164 {
165 // grayscale image
166 vigra::FImage image(info.size());
167 vigra::importImage(info, destImage(image));
168 InspectGrayscaleImage(image, "Grey channel");
169 }
170 else
171 {
172 std::cout << " Only RGB or grayscale images supported" << std::endl;
173 };
174 };
175 std::cout << std::endl;
176 }
177 else
178 {
179 if (info.numExtraBands() == 1)
180 {
181 // single mask
182 if (info.numBands() == 4)
183 {
184 // RGB image with mask
185 vigra::FRGBImage image(info.size());
186 vigra::FImage mask(info.size());
187 vigra::importImageAlpha(info, destImage(image), destImage(mask));
188 InspectRGBImage(image);
189 InspectGrayscaleImage(mask, "Mask");
190 }
191 else
192 {
193 if (info.numBands() == 2)
194 {
195 // grayscale image with mask
196 vigra::FImage image(info.size());
197 vigra::FImage mask(info.size());
198 vigra::importImageAlpha(info, destImage(image), destImage(mask));
199 InspectGrayscaleImage(image, "Grey channel");
200 InspectGrayscaleImage(mask, "Mask");
201 }
202 else
203 {
204 std::cout << " Only RGB or grayscale images supported" << std::endl;
205 };
206 };
207 std::cout << std::endl;
208 }
209 else
210 {
211 std::cout << " Only images with one or no alpha channel supported" << std::endl;
212 };
213 };
214 }
215 else
216 {
217 // no recognized image type
218 std::filesystem::path file(filename);
219 std::cout << std::endl << " not recognized by vigra as image file" << std::endl
220 << " File size: " << std::filesystem::file_size(file) / 1024 << " kiB" << std::endl << std::endl;
221 };
222 }
223 else
224 {
225 // file does not exists
226 std::cout << " does not exists." << std::endl <<std::endl;
227 };
228 };
229}
230
231void CreateMissingImages(HuginBase::Panorama& pano, const std::string& output)
232{
233 // init the random generator
234 std::mt19937 rng(0);
235 std::uniform_int_distribution<> distribIndex(0, 128);
236 auto randIndex = std::bind(distribIndex, rng);
237
238 bool requiresPTOrewrite = false;
239 // store path to pto file for easier access
241 const std::filesystem::path imagePath(ptoPath);
242 // check all images
243 for (int imgNr = 0; imgNr < pano.getNrOfImages(); ++imgNr)
244 {
245 std::filesystem::path srcFile(pano.getImage(imgNr).getFilename());
246 std::cout << "Image " << imgNr << ": " << srcFile.string();
247 if (std::filesystem::exists(srcFile))
248 {
249 std::cout << " exists." << std::endl;
250 }
251 else
252 {
253 // image does not exists
254 srcFile = std::filesystem::absolute(srcFile);
255 std::filesystem::path newImage(imagePath);
256 newImage /= srcFile.filename();
257 // file is not in the same directory as pto file, adjust path
258 if (newImage != srcFile)
259 {
260 requiresPTOrewrite = true;
261 pano.setImageFilename(imgNr, newImage.string());
262 };
263 std::cout << " does not exist. Creating " << newImage.filename() << std::endl;
264 // now create dummy image and save it to disc
265 vigra::UInt8RGBImage image(pano.getImage(imgNr).getWidth(), pano.getImage(imgNr).getHeight(),
266 vigra::RGBValue<vigra::UInt8>(64 + randIndex(), 64 + randIndex(), 64 + randIndex()));
267 vigra::ImageExportInfo imgExportInfo(newImage.string().c_str());
268 vigra::exportImage(vigra::srcImageRange(image), imgExportInfo);
269 };
270 };
272 {
273 // resave pto file in case path to some images has changed
274 if (pano.WritePTOFile(output, ptoPath))
275 {
276 std::cout << "Written output to " << output << std::endl;
277 };
278 };
279}
280
281int main(int argc, char* argv[])
282{
283 // parse arguments
284 const char* optstring = "h";
285 enum
286 {
288 PRINT_LENS_INFO=1004,
289 PRINT_STACK_INFO=1005,
292 };
293 static struct option longOptions[] =
294 {
295 { "print-output-info", no_argument, NULL, PRINT_OUTPUT_INFO },
296 { "print-lens-info", no_argument, NULL, PRINT_LENS_INFO },
297 { "print-stack-info", no_argument, NULL, PRINT_STACK_INFO },
298 { "print-image-info", no_argument, NULL, PRINT_IMAGE_INFO },
299 { "create-missing-images", no_argument, NULL, CREATE_DUMMY_IMAGES },
300 { "help", no_argument, NULL, 'h' },
301 0
302 };
303
304 int c;
305 bool printOutputInfo=false;
306 bool printLensInfo = false;
307 bool printStackInfo = false;
308 bool printImageInfo = false;
309 bool createDummyImages = false;
310 int optionIndex = 0;
311 while ((c = getopt_long (argc, argv, optstring, longOptions,nullptr)) != -1)
312 {
313 switch (c)
314 {
315 case 'h':
317 return 0;
319 printOutputInfo=true;
320 break;
321 case PRINT_LENS_INFO:
322 printLensInfo = true;
323 break;
324 case PRINT_STACK_INFO:
325 printStackInfo = true;
326 break;
327 case PRINT_IMAGE_INFO:
328 printImageInfo = true;
329 break;
331 createDummyImages = true;
332 break;
333 case '?':
334 case ':':
335 // missing argument or invalid switch
336 return 1;
337 break;
338 default:
339 // this should not happen
340 abort ();
341 }
342 }
343
344 if (argc - optind != 1)
345 {
346 if (argc - optind < 1)
347 {
348 std::cerr << hugin_utils::stripPath(argv[0]) << ": No project file given." << std::endl;
349 }
350 else
351 {
352 std::cerr << hugin_utils::stripPath(argv[0]) << ": Only one project file expected." << std::endl;
353 };
354 return -1;
355 }
356
357
358 std::string input=argv[optind];
359 // filename for output if needed
360 std::string output;
362 {
364 };
365
368 {
369 return -1;
370 };
371
373 std::cout << std::endl
374 << "Opened project " << input << std::endl << std::endl
375 << "Project contains" << std::endl
376 << pano.getNrOfImages() << " images" << std::endl
377 << variable_groups.getLenses().getNumberOfParts() << " lenses" << std::endl
378 << variable_groups.getStacks().getNumberOfParts() << " stacks" << std::endl
379 << pano.getNrOfCtrlPoints() << " control points" << std::endl << std::endl;
380 //cp statistics
381 if(pano.getNrOfCtrlPoints()>0)
382 {
383 double min;
384 double max;
385 double mean;
386 double var;
389 if(max>0)
390 {
391 std::ios oldstate(nullptr);
392 oldstate.copyfmt(std::cout);
393 std::cout << "Control points statistics" << std::endl
394 << std::fixed << std::setprecision(2)
395 << "\tMean error : " << mean << std::endl
396 << "\tStandard deviation: " << sqrt(var) << std::endl
397 << "\tMinimum : " << min << std::endl
398 << "\tMaximum : " << max << std::endl;
399 std::cout.copyfmt(oldstate);
400 };
401 };
403 const HuginGraph::ImageGraph::Components comps = graph.GetComponents();
404 int returnValue=0;
405 if(comps.size()==1)
406 {
407 std::cout << "All images are connected." << std::endl;
408 // return value must be 0, otherwise the assistant does not continue
409 returnValue=0;
410 }
411 else
412 {
413 std::cout << "Found unconnected images!" << std::endl
414 << "There are " << comps.size() << " image groups." << std::endl;
415
416 std::cout << "Image groups: " << std::endl;
417 for (size_t i=0; i < comps.size(); i++)
418 {
419 std::cout << "[";
420 HuginGraph::ImageGraph::Components::value_type::const_iterator it;
421 size_t c=0;
422 for (it = comps[i].begin(); it != comps[i].end(); ++it)
423 {
424 std::cout << (*it);
425 if (c+1 != comps[i].size())
426 {
427 std::cout << ", ";
428 }
429 c++;
430 }
431 std::cout << "]";
432 if (i+1 != comps.size())
433 {
434 std::cout << ", " << std::endl;
435 }
436 }
437 returnValue=comps.size();
438 };
439 std::cout << std::endl;
440 if (printLensInfo)
441 {
442 std::cout << std::endl << "Lenses:" << std::endl;
443 PrintImageGroup(variable_groups.getLenses().getPartsSet(), "Lens");
444 };
445 if (printStackInfo)
446 {
447 std::cout << std::endl << "Stacks:" << std::endl;
448 PrintImageGroup(variable_groups.getStacks().getPartsSet(), "Stack");
449 };
450 if (printOutputInfo)
451 {
453 std::vector<HuginBase::UIntSet> stacks=HuginBase::getHDRStacks(pano, outputImages, pano.getOptions());
454 std::cout << std::endl << "Output contains" << std::endl
455 << stacks.size() << " images stacks:" << std::endl;
456 PrintImageGroup(stacks);
457 std::vector<HuginBase::UIntSet> layers=HuginBase::getExposureLayers(pano, outputImages, pano.getOptions());
458 std::cout << std::endl << std::endl << "and " << layers.size() << " exposure layers:" << std::endl;
460 };
461 if (printImageInfo)
462 {
463 std::cout << "Supported file formats: " << vigra::impexListFormats() << std::endl
464 << "Supported extensions: " << vigra::impexListExtensions() << std::endl;
465 PrintImageInfo(pano);
466 };
468 {
470 };
471 return returnValue;
472}
declaration of functions to handle stacks and layers
static void usage()
Definition Main.cpp:32
Utility calls into PanoTools using CPP interface.
Somewhere to specify what variables belong to what.
int main(int argc, char *argv[])
Definition checkpto.cpp:281
void InspectRGBImage(const vigra::FRGBImage &image)
Definition checkpto.cpp:94
void InspectGrayscaleImage(const vigra::FImage &image, const std::string text)
Definition checkpto.cpp:107
void PrintImageInfo(const HuginBase::Panorama &pano)
Definition checkpto.cpp:114
void CreateMissingImages(HuginBase::Panorama &pano, const std::string &output)
Definition checkpto.cpp:231
void PrintImageGroup(const std::vector< HuginBase::UIntSet > &imageGroup, const std::string &prefix=std::string())
Definition checkpto.cpp:66
static void calcCtrlPntsErrorStats(const PanoramaData &pano, double &min, double &max, double &mean, double &var, const int &imgNr=-1, const bool onlyActive=false, const bool ignoreLineCp=false)
Make an ImageVariableGroup for lenses and other common concepts.
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
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition Panorama.h:481
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...
std::size_t getNrOfCtrlPoints() const
number of control points
Definition Panorama.h:306
void setImageFilename(unsigned int img, const std::string &fname)
set a new image filename
Definition Panorama.cpp:373
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
UIntSet getActiveImages() const
get active images
std::size_t getNrOfImages() const
number of images.
Definition Panorama.h:205
int getWidth() const
Get the width of the image in pixels.
int getHeight() const
Get the height of the image in pixels.
class to work with images graphs created from a HuginBase::Panorama class it creates a graph based on...
Definition ImageGraph.h:45
std::vector< HuginBase::UIntSet > Components
stores the components of the graph
Definition ImageGraph.h:50
class AlphaIterator class AlphaAccessor inline void importImageAlpha(const ImageImportInfo &import_info, ImageIterator image_iterator, ImageAccessor image_accessor, AlphaIterator alpha_iterator, AlphaAccessor alpha_accessor)
void calcCtrlPointErrors(PanoramaData &pano)
Update the Ctrl Point errors without optimizing.
UIntSet getImagesinROI(const PanoramaData &pano, const UIntSet activeImages)
returns set of images which are visible in output ROI
std::set< unsigned int > UIntSet
std::vector< UIntSet > getHDRStacks(const PanoramaData &pano, UIntSet allImgs, PanoramaOptions opts)
returns vector of set of output stacks
std::vector< UIntSet > getExposureLayers(const PanoramaData &pano, UIntSet allImgs, PanoramaOptions opts)
returns vector of set of output exposure layers
std::string GetAbsoluteFilename(const std::string &filename)
returns the full absolute filename
Definition utils.cpp:368
std::string GetICCDesc(const vigra::ImageImportInfo::ICCProfile &iccProfile)
returns description of given icc profile
Definition utils.cpp:912
std::string GetHuginVersion()
return a string with version numbers
Definition utils.cpp:907
bool FileExists(const std::string &filename)
checks if file exists
Definition utils.cpp:362
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
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