geocpset.cpp

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

Generated on 29 Jun 2016 for Hugintrunk by  doxygen 1.4.7