Hugin trunk 0.1
Loading...
Searching...
No Matches
geocpset.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>
33
34// check if given point x,y is inside both images img1 and img2,
35// using PTools::Tranform object to prevent creating of this transform for each point
37{
38 double x1, y1, x2, y2;
39 if(!transform1.transformImgCoord(x1, y1, x, y))
40 {
41 return false;
42 };
43 if(!pano.getImage(img1).isInside(vigra::Point2D(x1,y1), true))
44 {
45 return false;
46 };
47 if(!transform2.transformImgCoord(x2, y2, x, y))
48 {
49 return false;
50 };
51 if(!pano.getImage(img2).isInside(vigra::Point2D(x2,y2), true))
52 {
53 return false;
54 };
55 pano.addCtrlPoint(HuginBase::ControlPoint(img1, x1, y1, img2, x2, y2));
56 return true;
57};
58
59//helper class for sort
64
65// add geometric control point to overlap of images img1 and img2
66void AddGeometricControlPoint(HuginBase::Panorama& pano, size_t img1, size_t img2)
67{
69 //reset ROI to prevent unwanted clipping in this algorithm
70 opts.setROI(vigra::Rect2D(0, 0, opts.getWidth(), opts.getHeight()));
71 vigra::Rect2D rect1=estimateOutputROI(pano, opts, img1);
72 vigra::Rect2D rect2=estimateOutputROI(pano, opts, img2);
73 //get union of both outputs
75 if(rect1.area()>0)
76 {
78 transform1.createTransform(pano.getImage(img1), opts);
79 transform2.createTransform(pano.getImage(img2), opts);
80
81 hugin_utils::FDiff2D mid=(rect1.upperLeft()+rect1.lowerRight())/2.0;
82 //create grid of points to check
83 std::vector<hugin_utils::FDiff2D> points;
84 for(int dx=-5; dx<=5; dx++)
85 {
86 for(int dy=-5; dy<=5; dy++)
87 {
88 points.push_back(hugin_utils::FDiff2D(dx*rect1.width()/10.0, dy*rect1.height()/10.0));
89 };
90 };
91 //sort by distance
92 sort(points.begin(), points.end(),sortByDistance);
93 //now check all points in the grid
94 for(size_t i=0; i<points.size(); i++)
95 {
96 if(CheckAndAddPoint(pano, img1, img2, transform1, transform2, mid.x+points[i].x, mid.y+points[i].y))
97 {
98 return;
99 };
100 };
101 };
102};
103
104// only add control points for images without control points
106{
107 //first test: have image control points?
111 for(size_t i=0; i<pano.getNrOfImages(); i++)
112 {
113 bool hasControlPoints=false;
114 for (HuginBase::CPVector::const_iterator it = cp.begin(); it != cp.end(); ++it)
115 {
116 if ((it->image1Nr == i || it->image2Nr == i) && (it->mode == HuginBase::ControlPoint::X_Y))
117 {
118 hasControlPoints=true;
119 break;
120 };
121 };
123 {
124 imgsWithCp.insert(i);
125 }
126 else
127 {
128 imgsWithoutCp.insert(i);
129 };
130 };
131 // now test if images without control points have a linked position with an image with control point
133 for (HuginBase::UIntSet::const_iterator img = imgsWithoutCp.begin(); img != imgsWithoutCp.end(); ++img)
134 {
135 const HuginBase::SrcPanoImage& img1 = pano.getImage(*img);
136 bool connected=false;
137 if(img1.YawisLinked())
138 {
139 for (HuginBase::UIntSet::const_iterator img2 = imgsWithCp.begin(); img2 != imgsWithCp.end(); ++img2)
140 {
141 if(img1.YawisLinkedWith(pano.getImage(*img2)))
142 {
143 imgsWithCp.insert(*img);
144 connected=true;
145 break;
146 };
147 };
148 };
149 if(!connected)
150 {
151 imgsToTest.insert(*img);
152 };
153 };
154
155 // have we found unconnected images?
156 if(imgsToTest.empty())
157 {
158 std::cout << "No unconnected images found." << std::endl
159 << "No control point added." << std::endl;
160 return;
161 };
162 std::cout << std::endl << "Found " << imgsToTest.size() << " unconnected images." << std::endl;
163
164 // now find overlapping images
166 overlap.limitToImages(imgsToTest);
167 overlap.calculate(10);
168 std::vector<HuginBase::UIntSet> checkedImgPairs(pano.getNrOfImages());
169 for (HuginBase::UIntSet::const_iterator img = imgsToTest.begin(); img != imgsToTest.end(); ++img)
170 {
172 // search overlapping images, take linked positions into account
173 for(size_t i=0; i<pano.getNrOfImages(); i++)
174 {
175 if(i==*img)
176 {
177 continue;
178 };
179 if(overlap.getOverlap(*img, i)>minOverlap/100.0f)
180 {
181 //ignore overlap for linked images
182 bool ignoreImage=false;
183 const HuginBase::SrcPanoImage& img2 = pano.getImage(i);
184 if(img2.YawisLinked())
185 {
186 for (HuginBase::UIntSet::const_iterator it = overlappingImgs.begin(); it != overlappingImgs.end(); ++it)
187 {
188 if(img2.YawisLinkedWith(pano.getImage(*it)))
189 {
190 ignoreImage=true;
191 break;
192 }
193 };
194 };
196 {
197 ignoreImage=true;
198 };
199 if(!ignoreImage)
200 {
201 overlappingImgs.insert(i);
202 checkedImgPairs[*img].insert(i);
203 checkedImgPairs[i].insert(*img);
204 };
205 };
206 };
207 // now add control points
208 for (HuginBase::UIntSet::const_iterator overlapImg = overlappingImgs.begin(); overlapImg != overlappingImgs.end(); ++overlapImg)
209 {
211 };
212 };
213 std::cout << "Added " << pano.getCtrlPoints().size() - cp.size() << " control points." << std::endl;
214};
215
216// only add control points for images without control points
218{
220 // find overlapping images
222 overlap.calculate(10);
223 for(size_t i=0; i<pano.getNrOfImages()-1; i++)
224 {
226 const HuginBase::SrcPanoImage& img1 = pano.getImage(i);
227 // search overlapping images, take linked positions into account
228 for(size_t j=i+1; j<pano.getNrOfImages(); j++)
229 {
230 //skip linked images
231 if(img1.YawisLinked())
232 {
233 if(img1.YawisLinkedWith(pano.getImage(j)))
234 {
235 continue;
236 };
237 };
238 if(overlap.getOverlap(i, j)>=minOverlap/100.0f)
239 {
240 // we have an overlap, now check if there are control points
241 bool hasControlPoints=false;
242 for (HuginBase::CPVector::const_iterator it = cp.begin(); it != cp.end(); ++it)
243 {
244 if(((it->image1Nr==i && it->image2Nr==j) ||
245 (it->image1Nr==j && it->image2Nr==i) ) &&
247 {
248 hasControlPoints=true;
249 break;
250 };
251 };
253 {
254 //ignore overlap for linked images
255 bool ignoreImage=false;
256 const HuginBase::SrcPanoImage& img2 = pano.getImage(j);
257 if(img2.YawisLinked())
258 {
259 for (HuginBase::UIntSet::const_iterator it = overlappingImgs.begin(); it != overlappingImgs.end(); ++it)
260 {
261 if(img2.YawisLinkedWith(pano.getImage(*it)))
262 {
263 ignoreImage=true;
264 break;
265 };
266 };
267 };
268 if(!ignoreImage)
269 {
270 overlappingImgs.insert(j);
271 };
272 };
273 };
274 };
275 // now add control points
276 for (HuginBase::UIntSet::const_iterator overlapImg = overlappingImgs.begin(); overlapImg != overlappingImgs.end(); ++overlapImg)
277 {
279 };
280 };
281 std::cout << std::endl << "Added " << pano.getCtrlPoints().size() - cp.size() << " control points." << std::endl;
282};
283
284static void usage(const char* name)
285{
286 std::cout << name << ": set geometric control points" << std::endl
287 << name << " version " << hugin_utils::GetHuginVersion() << std::endl
288 << std::endl
289 << "Usage: " << name << " [options] input.pto" << std::endl
290 << std::endl
291 << " Options:" << std::endl
292 << " -o, --output=file.pto Output Hugin PTO file. Default: <filename>_geo.pto" << std::endl
293 << " -e, --each-overlap By default, geocpset will only work on the overlap" << std::endl
294 << " of unconnected images. With this switch it will" << std::endl
295 << " work on all overlaps without control points." << std::endl
296 << " --minimum-overlap=NUM Take only these images into account where the" << std::endl
297 << " overlap is bigger than NUM percent (default 10)." << std::endl
298 << " -h, --help Shows this help" << std::endl
299 << std::endl;
300}
301
302int main(int argc, char* argv[])
303{
304 // parse arguments
305 const char* optstring = "o:eh";
306 enum
307 {
308 MINOVERLAP=1000
309 };
310
311 static struct option longOptions[] =
312 {
313 {"output", required_argument, NULL, 'o' },
314 {"each-overlap", no_argument, NULL, 'e' },
315 {"min-overlap", required_argument, NULL, MINOVERLAP},
316 {"help", no_argument, NULL, 'h' },
317 0
318 };
319
320 int c;
321 bool eachOverlap=false;
322 int minOverlap=10;
323 std::string output;
324 while ((c = getopt_long (argc, argv, optstring, longOptions,nullptr)) != -1)
325 {
326 switch (c)
327 {
328 case 'o':
329 output = optarg;
330 break;
331 case 'e':
332 eachOverlap = true;
333 break;
334 case MINOVERLAP:
337 {
338 std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid minimum overlap: " << optarg << std::endl
339 << "Minimum overlap have to be between 1 and 99." << std::endl;
340 return 1;
341 };
342 break;
343 case 'h':
345 return 0;
346 case ':':
347 case '?':
348 // missing argument or invalid switch
349 return 1;
350 break;
351 default:
352 // this should not happen
353 abort ();
354 }
355 }
356
357 if (argc - optind != 1)
358 {
359 if (argc - optind < 1)
360 {
361 std::cerr << hugin_utils::stripPath(argv[0]) << ": No project file given." << std::endl;
362 }
363 else
364 {
365 std::cerr << hugin_utils::stripPath(argv[0]) << ": Only one project file expected." << std::endl;
366 };
367 return 1;
368 };
369
370 std::string input=argv[optind];
371 // read panorama
374 {
375 return 1;
376 };
377
378 if(pano.getNrOfImages()==1)
379 {
380 std::cerr << "error: project file contains only one image" << std::endl
381 << "aborting processing" << std::endl;
382 return 1;
383 };
384
385 std::cout << "Adding geometric control points..." << std::endl;
386 if(eachOverlap)
387 {
389 }
390 else
391 {
393 };
394
395 //write output
396 // Set output .pto filename if not given
399 {
400 std::cout << std::endl << "Written output to " << output << std::endl;
401 };
402 return 0;
403}
definitions of classes to calculate overlap between different images
static void usage()
Definition Main.cpp:32
class for calculating overlap of images
represents a control point
Holds transformations for Image -> Pano and the other way.
void createTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
initialize pano->image transformation
Panorama image options.
void setROI(const vigra::Rect2D &val)
unsigned int getWidth() const
unsigned int getHeight() const
get panorama height
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...
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
Definition Panorama.cpp:381
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition Panorama.h:319
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
All variables of a source image.
bool isInside(vigra::Point2D p, bool ignoreMasks=false) const
check if a coordinate is inside the source image
bool sortByDistance(hugin_utils::FDiff2D p1, hugin_utils::FDiff2D p2)
Definition geocpset.cpp:60
int main(int argc, char *argv[])
Definition geocpset.cpp:302
bool CheckAndAddPoint(HuginBase::Panorama &pano, size_t img1, size_t img2, HuginBase::PTools::Transform &transform1, HuginBase::PTools::Transform &transform2, double x, double y)
Definition geocpset.cpp:36
void SetGeometricControlPointsOverlap(HuginBase::Panorama &pano, const int minOverlap)
Definition geocpset.cpp:217
void SetGeometricControlPointsUnconnected(HuginBase::Panorama &pano, const int minOverlap)
Definition geocpset.cpp:105
void AddGeometricControlPoint(HuginBase::Panorama &pano, size_t img1, size_t img2)
Definition geocpset.cpp:66
std::vector< ControlPoint > CPVector
std::set< unsigned int > UIntSet
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
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition stl_utils.h:74
T squareLength() const
Return the square of the length of the vector.
Definition hugin_math.h:153
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