00001
00002
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <hugin_version.h>
00028
00029 #include <fstream>
00030 #include <sstream>
00031 #include <getopt.h>
00032 #ifndef WIN32
00033 #include <unistd.h>
00034 #endif
00035 #include <panodata/Panorama.h>
00036 #include <algorithms/basic/CalculateOverlap.h>
00037 #include <algorithms/nona/ComputeImageROI.h>
00038
00039 using namespace std;
00040 using namespace HuginBase;
00041 using namespace AppBase;
00042
00043
00044
00045 bool CheckAndAddPoint(Panorama& pano, size_t img1, size_t img2, PTools::Transform& transform1, PTools::Transform& transform2, double x, double y)
00046 {
00047 double x1, y1, x2, y2;
00048 if(!transform1.transformImgCoord(x1, y1, x, y))
00049 {
00050 return false;
00051 };
00052 if(!pano.getImage(img1).isInside(vigra::Point2D(x1,y1), true))
00053 {
00054 return false;
00055 };
00056 if(!transform2.transformImgCoord(x2, y2, x, y))
00057 {
00058 return false;
00059 };
00060 if(!pano.getImage(img2).isInside(vigra::Point2D(x2,y2), true))
00061 {
00062 return false;
00063 };
00064 pano.addCtrlPoint(ControlPoint(img1, x1, y1, img2, x2, y2));
00065 return true;
00066 };
00067
00068
00069 bool sortByDistance(FDiff2D p1, FDiff2D p2)
00070 {
00071 return p1.squareLength()<p2.squareLength();
00072 };
00073
00074
00075 void AddGeometricControlPoint(Panorama& pano, size_t img1, size_t img2)
00076 {
00077 PanoramaOptions opts=pano.getOptions();
00078
00079 opts.setROI(vigra::Rect2D(0, 0, opts.getWidth(), opts.getHeight()));
00080 vigra::Rect2D rect1=estimateOutputROI(pano, opts, img1);
00081 vigra::Rect2D rect2=estimateOutputROI(pano, opts, img2);
00082
00083 rect1=rect1 & rect2;
00084 if(rect1.area()>0)
00085 {
00086 PTools::Transform transform1, transform2;
00087 transform1.createTransform(pano.getImage(img1), opts);
00088 transform2.createTransform(pano.getImage(img2), opts);
00089
00090 FDiff2D mid=(rect1.upperLeft()+rect1.lowerRight())/2.0;
00091
00092 vector<FDiff2D> points;
00093 for(int dx=-5; dx<=5; dx++)
00094 {
00095 for(int dy=-5; dy<=5; dy++)
00096 {
00097 points.push_back(FDiff2D(dx*rect1.width()/10.0, dy*rect1.height()/10.0));
00098 };
00099 };
00100
00101 sort(points.begin(), points.end(),sortByDistance);
00102
00103 for(size_t i=0; i<points.size(); i++)
00104 {
00105 if(CheckAndAddPoint(pano, img1, img2, transform1, transform2, mid.x+points[i].x, mid.y+points[i].y))
00106 {
00107 return;
00108 };
00109 };
00110 };
00111 };
00112
00113
00114 void SetGeometricControlPointsUnconnected(Panorama& pano, const int minOverlap)
00115 {
00116
00117 CPVector cp=pano.getCtrlPoints();
00118 UIntSet imgsWithCp;
00119 UIntSet imgsWithoutCp;
00120 for(size_t i=0; i<pano.getNrOfImages(); i++)
00121 {
00122 bool hasControlPoints=false;
00123 for(CPVector::const_iterator it=cp.begin(); it!=cp.end(); it++)
00124 {
00125 if((it->image1Nr==i || it->image2Nr==i) && (it->mode==ControlPoint::X_Y))
00126 {
00127 hasControlPoints=true;
00128 break;
00129 };
00130 };
00131 if(hasControlPoints)
00132 {
00133 imgsWithCp.insert(i);
00134 }
00135 else
00136 {
00137 imgsWithoutCp.insert(i);
00138 };
00139 };
00140
00141 UIntSet imgsToTest;
00142 for(UIntSet::const_iterator img=imgsWithoutCp.begin(); img!=imgsWithoutCp.end(); img++)
00143 {
00144 const SrcPanoImage& img1=pano.getImage(*img);
00145 bool connected=false;
00146 if(img1.YawisLinked())
00147 {
00148 for(UIntSet::const_iterator img2=imgsWithCp.begin(); img2!=imgsWithCp.end(); img2++)
00149 {
00150 if(img1.YawisLinkedWith(pano.getImage(*img2)))
00151 {
00152 imgsWithCp.insert(*img);
00153 connected=true;
00154 break;
00155 };
00156 };
00157 };
00158 if(!connected)
00159 {
00160 imgsToTest.insert(*img);
00161 };
00162 };
00163
00164
00165 if(imgsToTest.size()==0)
00166 {
00167 cout << "No unconnected images found." << endl
00168 << "No control point added." << endl;
00169 return;
00170 };
00171 cout << endl << "Found " << imgsToTest.size() << " unconnected images." << endl;
00172
00173
00174 CalculateImageOverlap overlap(&pano);
00175 overlap.limitToImages(imgsToTest);
00176 overlap.calculate(10);
00177 vector<UIntSet> checkedImgPairs(pano.getNrOfImages());
00178 for(UIntSet::const_iterator img=imgsToTest.begin(); img!=imgsToTest.end(); img++)
00179 {
00180 UIntSet overlappingImgs;
00181 const SrcPanoImage& img1=pano.getImage(*img);
00182
00183 for(size_t i=0; i<pano.getNrOfImages(); i++)
00184 {
00185 if(i==*img)
00186 {
00187 continue;
00188 };
00189 if(overlap.getOverlap(*img, i)>minOverlap/100.0f)
00190 {
00191
00192 bool ignoreImage=false;
00193 const SrcPanoImage& img2=pano.getImage(i);
00194 if(img2.YawisLinked())
00195 {
00196 for(UIntSet::const_iterator it=overlappingImgs.begin(); it!=overlappingImgs.end(); it++)
00197 {
00198 if(img2.YawisLinkedWith(pano.getImage(*it)))
00199 {
00200 ignoreImage=true;
00201 break;
00202 }
00203 };
00204 };
00205 if(set_contains(checkedImgPairs[*img], i) || set_contains(checkedImgPairs[i], *img))
00206 {
00207 ignoreImage=true;
00208 };
00209 if(!ignoreImage)
00210 {
00211 overlappingImgs.insert(i);
00212 checkedImgPairs[*img].insert(i);
00213 checkedImgPairs[i].insert(*img);
00214 };
00215 };
00216 };
00217
00218 for(UIntSet::const_iterator overlapImg=overlappingImgs.begin(); overlapImg!=overlappingImgs.end(); overlapImg++)
00219 {
00220 AddGeometricControlPoint(pano, *img, *overlapImg);
00221 };
00222 };
00223 cout << "Added " << pano.getCtrlPoints().size() - cp.size() << " control points." << endl;
00224 };
00225
00226
00227 void SetGeometricControlPointsOverlap(Panorama& pano, const int minOverlap)
00228 {
00229 CPVector cp=pano.getCtrlPoints();
00230
00231 CalculateImageOverlap overlap(&pano);
00232 overlap.calculate(10);
00233 for(size_t i=0; i<pano.getNrOfImages()-1; i++)
00234 {
00235 UIntSet overlappingImgs;
00236 const SrcPanoImage& img1=pano.getImage(i);
00237
00238 for(size_t j=i+1; j<pano.getNrOfImages(); j++)
00239 {
00240
00241 if(img1.YawisLinked())
00242 {
00243 if(img1.YawisLinkedWith(pano.getImage(j)))
00244 {
00245 continue;
00246 };
00247 };
00248 if(overlap.getOverlap(i, j)>=minOverlap/100.0f)
00249 {
00250
00251 bool hasControlPoints=false;
00252 for(CPVector::const_iterator it=cp.begin(); it!=cp.end(); it++)
00253 {
00254 if(((it->image1Nr==i && it->image2Nr==j) ||
00255 (it->image1Nr==j && it->image2Nr==i) ) &&
00256 (it->mode==ControlPoint::X_Y))
00257 {
00258 hasControlPoints=true;
00259 break;
00260 };
00261 };
00262 if(!hasControlPoints)
00263 {
00264
00265 bool ignoreImage=false;
00266 const SrcPanoImage& img2=pano.getImage(j);
00267 if(img2.YawisLinked())
00268 {
00269 for(UIntSet::const_iterator it=overlappingImgs.begin(); it!=overlappingImgs.end(); it++)
00270 {
00271 if(img2.YawisLinkedWith(pano.getImage(*it)))
00272 {
00273 ignoreImage=true;
00274 break;
00275 };
00276 };
00277 };
00278 if(!ignoreImage)
00279 {
00280 overlappingImgs.insert(j);
00281 };
00282 };
00283 };
00284 };
00285
00286 for(UIntSet::const_iterator overlapImg=overlappingImgs.begin(); overlapImg!=overlappingImgs.end(); overlapImg++)
00287 {
00288 AddGeometricControlPoint(pano, i, *overlapImg);
00289 };
00290 };
00291 cout << endl << "Added " << pano.getCtrlPoints().size() - cp.size() << " control points." << endl;
00292 };
00293
00294 static void usage(const char* name)
00295 {
00296 cout << name << ": set geometric control points" << endl
00297 << name << " version " << DISPLAY_VERSION << endl
00298 << endl
00299 << "Usage: " << name << " [options] input.pto" << endl
00300 << endl
00301 << " Options:" << endl
00302 << " -o, --output=file.pto Output Hugin PTO file. Default: <filename>_geo.pto" << endl
00303 << " -e, --each-overlap By default, geocpset will only work on the overlap" << endl
00304 << " of unconnected images. With this switch it will" << endl
00305 << " work on all overlaps without control points." << endl
00306 << " --minimum-overlap=NUM Take only these images into accout where the" << endl
00307 << " overlap is bigger than NUM percent (default 10)." << endl
00308 << " -h, --help Shows this help" << endl
00309 << endl;
00310 }
00311
00312 int main(int argc, char* argv[])
00313 {
00314
00315 const char* optstring = "o:eh";
00316 enum
00317 {
00318 MINOVERLAP=1000
00319 };
00320
00321 static struct option longOptions[] =
00322 {
00323 {"output", required_argument, NULL, 'o' },
00324 {"each-overlap", no_argument, NULL, 'e' },
00325 {"min-overlap", required_argument, NULL, MINOVERLAP},
00326 {"help", no_argument, NULL, 'h' },
00327 0
00328 };
00329
00330 int c;
00331 int optionIndex = 0;
00332 bool eachOverlap=false;
00333 int minOverlap=10;
00334 string output;
00335 while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1)
00336 {
00337 switch (c)
00338 {
00339 case 'o':
00340 output = optarg;
00341 break;
00342 case 'e':
00343 eachOverlap = true;
00344 break;
00345 case MINOVERLAP:
00346 minOverlap=atoi(optarg);
00347 if(minOverlap<1 || minOverlap>99)
00348 {
00349 cerr << "Invalid minimum overlap: " << optarg << endl
00350 << "Minimum overlap have to be between 1 and 99." << endl;
00351 return 1;
00352 };
00353 break;
00354 case 'h':
00355 usage(argv[0]);
00356 return 0;
00357 case ':':
00358 cerr <<"Option " << longOptions[optionIndex].name << " requires a parameter" << endl;
00359 return 1;
00360 break;
00361 case '?':
00362 break;
00363 default:
00364 abort ();
00365 }
00366 }
00367
00368 if (argc - optind == 0)
00369 {
00370 cout << "Error: No project file given." << endl << endl;
00371 return 1;
00372 };
00373 if (argc - optind != 1)
00374 {
00375 cout << "Error: geocpset can only work on one project file at one time" << endl << endl;
00376 return 1;
00377 };
00378
00379 string input=argv[optind];
00380
00381 Panorama pano;
00382 ifstream prjfile(input.c_str());
00383 if (!prjfile.good())
00384 {
00385 cerr << "could not open script : " << input << endl;
00386 return 1;
00387 }
00388 pano.setFilePrefix(hugin_utils::getPathPrefix(input));
00389 DocumentData::ReadWriteError err = pano.readData(prjfile);
00390 if (err != DocumentData::SUCCESSFUL)
00391 {
00392 cerr << "error while parsing panos tool script: " << input << endl;
00393 cerr << "DocumentData::ReadWriteError code: " << err << endl;
00394 return 1;
00395 }
00396
00397 if(pano.getNrOfImages()==0)
00398 {
00399 cerr << "error: project file does not contains any image" << endl;
00400 cerr << "aborting processing" << endl;
00401 return 1;
00402 };
00403 if(pano.getNrOfImages()==1)
00404 {
00405 cerr << "error: project file contains only one image" << endl;
00406 cerr << "aborting processing" << endl;
00407 return 1;
00408 };
00409
00410 cout << "Adding geometric control points..." << endl;
00411 if(eachOverlap)
00412 {
00413 SetGeometricControlPointsOverlap(pano, minOverlap);
00414 }
00415 else
00416 {
00417 SetGeometricControlPointsUnconnected(pano, minOverlap);
00418 };
00419
00420
00421 UIntSet imgs;
00422 fill_set(imgs, 0, pano.getNrOfImages()-1);
00423
00424 if (output=="")
00425 {
00426 output=input.substr(0,input.length()-4).append("_geo.pto");
00427 }
00428 ofstream of(output.c_str());
00429 pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input));
00430
00431 cout << endl << "Written output to " << output << endl;
00432 return 0;
00433 }