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 <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
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
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
00093 if (origType == "FLOAT" || origType == "DOUBLE")
00094 {
00098 vigra::RGBToGrayAccessor<vigra::RGBValue<float> > ga;
00099 vigra::FindMinMax<float> minmax;
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
00119 if (origType == "FLOAT" || origType == "DOUBLE")
00120 {
00124 vigra::FindMinMax<float> minmax;
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
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
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
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
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
00376 for(size_t i=0;i<pano.getNrOfImages();i++)
00377 {
00378 imagesToProcess.push_back(i);
00379 };
00380 }
00381 else
00382 {
00383
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
00405
00406
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
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
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
00457 UIntSet imgs;
00458 fill_set(imgs,0, pano.getNrOfImages()-1);
00459
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 }