linefind.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, write to the Free Software
00023  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 <lines/FindLines.h>
00037 #include <vigra/impex.hxx>
00038 #include <vigra_ext/impexalpha.hxx>
00039 #include <vigra/functorexpression.hxx>
00040 #include <vigra_ext/utils.h>
00041 
00042 extern "C"
00043 {
00044 #include <pano13/filter.h>
00045 }
00046 #if defined _MSC_VER && _MSC_VER>=1600
00047 #include <ppl.h>
00048 #define HAS_PPL
00049 #endif
00050 
00051 using namespace std;
00052 using namespace HuginBase;
00053 using namespace AppBase;
00054 
00055 static void usage(const char* name)
00056 {
00057     cout << name << ": find vertical lines in images" << endl
00058          << name << " version " << DISPLAY_VERSION << endl
00059          << endl
00060          << "Usage:  " << name << " [options] input.pto" << endl
00061          << endl
00062          << "  Options:" << endl
00063          << "     -o, --output=file.pto  Output Hugin PTO file. Default: <filename>_lines.pto" << endl
00064          << "     -i, --image=IMGNR      Work only on given image numbers" << endl
00065          << "     -l, --lines=COUNT      Save maximal COUNT lines (default: 5)" << endl
00066          << "     -h, --help             Shows this help" << endl
00067          << endl;
00068 }
00069 
00070 // dummy panotools progress functions
00071 static int ptProgress( int command, char* argument )
00072 {
00073     return 1;
00074 }
00075 static int ptinfoDlg( int command, char* argument )
00076 {
00077     return 1;
00078 }
00079 
00086 // 2 versions: one for color images, the other for gray images
00087 template <class SrcIMG>
00088 void convertToUInt8(SrcIMG & src, const std::string & origType, vigra::UInt8RGBImage & dest)
00089 {
00090     dest.resize(src.size());
00091     long newMax=vigra_ext::getMaxValForPixelType("UINT8");
00092     // float needs to be from min ... max.
00093     if (origType == "FLOAT" || origType == "DOUBLE")
00094     {
00098         vigra::RGBToGrayAccessor<vigra::RGBValue<float> > ga;
00099         vigra::FindMinMax<float> minmax;   // init functor
00100         vigra::inspectImage(srcImageRange(src, ga),
00101                             minmax);
00102         double minVal = minmax.min;
00103         double maxVal = minmax.max;
00104         vigra_ext::applyMapping(srcImageRange(src), destImage(dest), minVal, maxVal, 0);
00105     }
00106     else
00107     {
00108         vigra::transformImage(srcImageRange(src), destImage(dest),
00109             vigra::functor::Arg1()*vigra::functor::Param( newMax/ vigra_ext::getMaxValForPixelType(origType)));
00110     };
00111 }
00112 
00113 template <class SrcIMG>
00114 void convertGrayToUInt8(SrcIMG & src, const std::string & origType, vigra::BImage & dest)
00115 {
00116     dest.resize(src.size());
00117     long newMax=vigra_ext::getMaxValForPixelType("UINT8");
00118     // float needs to be from min ... max.
00119     if (origType == "FLOAT" || origType == "DOUBLE")
00120     {
00124         vigra::FindMinMax<float> minmax;   // init functor
00125         vigra::inspectImage(srcImageRange(src), minmax);
00126         double minVal = minmax.min;
00127         double maxVal = minmax.max;
00128         vigra_ext::applyMapping(srcImageRange(src), destImage(dest), minVal, maxVal, 0);
00129     }
00130     else
00131     {
00132         vigra::transformImage(srcImageRange(src), destImage(dest),
00133             vigra::functor::Arg1()*vigra::functor::Param( newMax/ vigra_ext::getMaxValForPixelType(origType)));
00134     };
00135 }
00136 
00137 template <class SrcIMG>
00138 vigra::BImage LoadGrayImageAndConvert(vigra::ImageImportInfo & info)
00139 {
00140     vigra::BImage image;
00141     SrcIMG imageIn(info.width(),info.height());
00142     if(info.numExtraBands()==1)
00143     {
00144         vigra::BImage mask(info.size());
00145         vigra::importImageAlpha(info,destImage(imageIn),destImage(mask));
00146         mask.resize(0,0);
00147     }
00148     else
00149     {
00150         importImage(info,destImage(imageIn));
00151     };
00152     convertGrayToUInt8(imageIn,info.getPixelType(),image);
00153     imageIn.resize(0,0);
00154     return image;
00155 };
00156 
00157 template <class SrcIMG>
00158 vigra::UInt8RGBImage LoadImageAndConvert(vigra::ImageImportInfo & info)
00159 {
00160     vigra::UInt8RGBImage image;
00161     SrcIMG imageIn(info.width(),info.height());
00162     if(info.numExtraBands()==1)
00163     {
00164         vigra::BImage mask(info.size());
00165         vigra::importImageAlpha(info,destImage(imageIn),destImage(mask));
00166         mask.resize(0,0);
00167     }
00168     else
00169     {
00170         importImage(info,destImage(imageIn));
00171     };
00172     convertToUInt8(imageIn,info.getPixelType(),image);
00173     imageIn.resize(0,0);
00174     return image;
00175 };
00176 
00177 // loads the gray images and finds vertical lines, returns a CPVector with found vertical lines
00178 HuginBase::CPVector LoadGrayImageAndFindLines(vigra::ImageImportInfo info, Panorama & pano, size_t imgNr, int nrLines)
00179 {
00180     vigra::BImage image;
00181     HuginBase::CPVector lineCp;
00182     std::string pixelType=info.getPixelType();
00183     if(pixelType=="UINT8")
00184     {
00185         image.resize(info.width(),info.height());
00186         if(info.numExtraBands()==1)
00187         {
00188             vigra::BImage mask(info.size());
00189             vigra::importImageAlpha(info,destImage(image),destImage(mask));
00190             mask.resize(0,0);
00191         }
00192         else
00193         {
00194             importImage(info,destImage(image));
00195         };
00196     }
00197     else
00198     {
00199         if(pixelType=="UINT16" || pixelType=="INT16")
00200         {
00201             image=LoadGrayImageAndConvert<vigra::UInt16Image>(info);
00202         }
00203         else
00204         {
00205             if(pixelType=="INT32" || pixelType=="UINT32")
00206             {
00207                 image=LoadGrayImageAndConvert<vigra::UInt32Image>(info);
00208             }
00209             else
00210             {
00211                 if(pixelType=="FLOAT" || pixelType=="DOUBLE")
00212                 {
00213                     image=LoadGrayImageAndConvert<vigra::FImage>(info);
00214                 }
00215                 else
00216                 {
00217                     std::cerr << "Unsupported pixel type" << std::endl;
00218                 };
00219             };
00220         };
00221     };
00222     if(image.width()>0 && image.height()>0)
00223     {
00224         lineCp=HuginLines::GetVerticalLines(pano, imgNr, image, nrLines);
00225     };
00226     return lineCp;
00227 };
00228 
00229 // loads the color images and finds vertical lines, returns a CPVector with found vertical lines
00230 HuginBase::CPVector LoadImageAndFindLines(vigra::ImageImportInfo info, Panorama & pano, size_t imgNr, int nrLines)
00231 {
00232     vigra::UInt8RGBImage image;
00233     HuginBase::CPVector lineCp;
00234     std::string pixelType=info.getPixelType();
00235     if(pixelType=="UINT8")
00236     {
00237         image.resize(info.width(),info.height());
00238         if(info.numExtraBands()==1)
00239         {
00240             vigra::BImage mask(info.size());
00241             vigra::importImageAlpha(info,destImage(image),destImage(mask));
00242             mask.resize(0,0);
00243         }
00244         else
00245         {
00246             importImage(info,destImage(image));
00247         };
00248     }
00249     else
00250     {
00251         if(pixelType=="UINT16" || pixelType=="INT16")
00252         {
00253             image=LoadImageAndConvert<vigra::UInt16RGBImage>(info);
00254         }
00255         else
00256         {
00257             if(pixelType=="INT32" || pixelType=="UINT32")
00258             {
00259                 image=LoadImageAndConvert<vigra::UInt32RGBImage>(info);
00260             }
00261             else
00262             {
00263                 if(pixelType=="FLOAT" || pixelType=="DOUBLE")
00264                 {
00265                     image=LoadImageAndConvert<vigra::FRGBImage>(info);
00266                 }
00267                 else
00268                 {
00269                     std::cerr << "Unsupported pixel type" << std::endl;
00270                 };
00271             };
00272         };
00273     };
00274     if(image.width()>0 && image.height()>0)
00275     {
00276         lineCp=HuginLines::GetVerticalLines(pano, imgNr, image, nrLines);
00277     };
00278     return lineCp;
00279 };
00280 
00281 int main(int argc, char* argv[])
00282 {
00283     // parse arguments
00284     const char* optstring = "o:i:l:h";
00285 
00286     static struct option longOptions[] =
00287     {
00288         {"output", required_argument, NULL, 'o' },
00289         {"image", required_argument, NULL, 'i' },
00290         {"lines", required_argument, NULL, 'l' },
00291         {"help", no_argument, NULL, 'h' },
00292         0
00293     };
00294 
00295     UIntSet cmdlineImages;
00296     int c;
00297     int optionIndex = 0;
00298     int nrLines = 5;
00299     string output;
00300     while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1)
00301     {
00302         switch (c)
00303         {
00304             case 'o':
00305                 output = optarg;
00306                 break;
00307             case 'h':
00308                 usage(argv[0]);
00309                 return 0;
00310             case 'i':
00311                 {
00312                     int imgNr=atoi(optarg);
00313                     if((imgNr==0) && (strcmp(optarg,"0")!=0))
00314                     {
00315                         cerr << "Could not parse image number.";
00316                         return 1;
00317                     };
00318                     cmdlineImages.insert(imgNr);
00319                 };
00320                 break;
00321             case 'l':
00322                 nrLines=atoi(optarg);
00323                 if(nrLines<1)
00324                 {
00325                     cerr << "Could not parse number of lines.";
00326                     return 1;
00327                 };
00328                 break;
00329             case ':':
00330                 cerr <<"Option " << longOptions[optionIndex].name << " requires a number" << endl;
00331                 return 1;
00332                 break;
00333             case '?':
00334                 break;
00335             default:
00336                 abort ();
00337         }
00338     }
00339 
00340     if (argc - optind != 1)
00341     {
00342         cout << "Warning: " << argv[0] << " can only work on one project file at one time" << endl << endl;
00343         usage(argv[0]);
00344         return 1;
00345     };
00346 
00347     string input=argv[optind];
00348     // read panorama
00349     Panorama pano;
00350     ifstream prjfile(input.c_str());
00351     if (!prjfile.good())
00352     {
00353         cerr << "could not open script : " << input << endl;
00354         return 1;
00355     }
00356     pano.setFilePrefix(hugin_utils::getPathPrefix(input));
00357     DocumentData::ReadWriteError err = pano.readData(prjfile);
00358     if (err != DocumentData::SUCCESSFUL)
00359     {
00360         cerr << "error while parsing panos tool script: " << input << endl;
00361         cerr << "DocumentData::ReadWriteError code: " << err << endl;
00362         return 1;
00363     }
00364 
00365     if(pano.getNrOfImages()==0)
00366     {
00367         cerr << "error: project file does not contains any image" << endl;
00368         cerr << "aborting processing" << endl;
00369         return 1;
00370     };
00371 
00372     std::vector<size_t> imagesToProcess;
00373     if(cmdlineImages.size()==0)
00374     {
00375         //no image given, process all
00376         for(size_t i=0;i<pano.getNrOfImages();i++)
00377         {
00378             imagesToProcess.push_back(i);
00379         };
00380     }
00381     else
00382     {
00383         //check, if given image numbers are valid
00384         for(UIntSet::const_iterator it=cmdlineImages.begin();it!=cmdlineImages.end();it++)
00385         {
00386             if((*it)>=0 && (*it)<pano.getNrOfImages())
00387             {
00388                 imagesToProcess.push_back(*it);
00389             };
00390         };
00391     };
00392 
00393     if(imagesToProcess.size()==0)
00394     {
00395         cerr << "No image to process found" << endl << "Stopping processing" << endl;
00396         return 1;
00397     };
00398 
00399     PT_setProgressFcn(ptProgress);
00400     PT_setInfoDlgFcn(ptinfoDlg);
00401 
00402     cout << argv[0] << " is searching for vertical lines" << endl;
00403 #if _WINDOWS
00404     //multi threading of image loading results sometime in a race condition
00405     //try to prevent this by initialisation of codecManager before
00406     //running multi threading part
00407     std::string s=vigra::impexListExtensions();
00408 #endif
00409 #ifdef HAS_PPL
00410     size_t nrCPS=pano.getNrOfCtrlPoints();
00411     Concurrency::parallel_for<size_t>(0,imagesToProcess.size(),[&pano,imagesToProcess,nrLines](size_t i)
00412 #else
00413     for(size_t i=0;i<imagesToProcess.size();i++)
00414 #endif
00415     {
00416         unsigned int imgNr=imagesToProcess[i];
00417         cout << "Working on image " << pano.getImage(imgNr).getFilename() << endl;
00418         // now load and process all images
00419         vigra::ImageImportInfo info(pano.getImage(imgNr).getFilename().c_str());
00420         HuginBase::CPVector foundLines;
00421         if(info.isGrayscale())
00422         {
00423             foundLines=LoadGrayImageAndFindLines(info, pano, imgNr, nrLines);
00424         }
00425         else
00426         {
00427             if(info.isColor())
00428             {
00429                 //colour images
00430                 foundLines=LoadImageAndFindLines(info, pano, imgNr, nrLines);
00431             }
00432             else
00433             {
00434                 std::cerr << "Image " << pano.getImage(imgNr).getFilename().c_str() << " has " 
00435                     << info.numBands() << " channels." << std::endl
00436                     << "Linefind works only with grayscale or color images." << std::endl
00437                     << "Skipping image." << std::endl;
00438             };
00439         };
00440 #ifndef HAS_PPL
00441         cout << "Found " << foundLines.size() << " vertical lines" << endl;
00442 #endif
00443         if(foundLines.size()>0)
00444         {
00445             for(CPVector::const_iterator cpIt=foundLines.begin(); cpIt!=foundLines.end(); cpIt++)
00446             {
00447                 pano.addCtrlPoint(*cpIt);
00448             };
00449         };
00450     }
00451 #ifdef HAS_PPL
00452     );
00453     cout << endl << "Found " << pano.getNrOfCtrlPoints() - nrCPS << " vertical lines" << endl << endl;
00454 #endif
00455 
00456     //write output
00457     UIntSet imgs;
00458     fill_set(imgs,0, pano.getNrOfImages()-1);
00459     // Set output .pto filename if not given
00460     if (output=="")
00461     {
00462         output=input.substr(0,input.length()-4).append("_lines.pto");
00463     }
00464     ofstream of(output.c_str());
00465     pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input));
00466 
00467     cout << endl << "Written output to " << output << endl;
00468     return 0;
00469 }

Generated on 21 Oct 2014 for Hugintrunk by  doxygen 1.4.7