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

Generated on 7 Dec 2016 for Hugintrunk by  doxygen 1.4.7