void AssistantPanel::OnExifToggle (wxCommandEvent & e) { if (m_exifToggle->GetValue()) { unsigned int imgNr = 0; // if activated, load exif info double cropFactor = 0; double focalLength = 0; SrcPanoImage srcImg = m_pano->getSrcImage(imgNr); bool ok = initImageFromFile(srcImg, focalLength, cropFactor, true); if (! ok) { if (!getLensDataFromUser(this, srcImg, focalLength, cropFactor)) { // hmm, we don't know anything, assume a standart lens. srcImg.setHFOV(50); } } GlobalCmdHist::getInstance().addCommand( new PT::UpdateSrcImageCmd( *m_pano, imgNr, srcImg) ); XRCCTRL(*this, "ass_lens_group", wxPanel)->Disable(); } else { // exif disabled XRCCTRL(*this, "ass_lens_group", wxPanel)->Enable(); } }
vector<UIntSet> getExposureLayers(const PanoramaData & pano, UIntSet allImgs, PanoramaOptions opts) { vector<UIntSet> result; // if no images are available, return empty result vector if ( allImgs.empty() ) { return result; } UIntSet stack; do { unsigned srcImg = *(allImgs.begin()); stack.insert(srcImg); allImgs.erase(srcImg); // find all images that have a suitable overlap. SrcPanoImage simg = pano.getSrcImage(srcImg); double maxEVDiff = opts.outputLayersExposureDiff; for (UIntSet::iterator it = allImgs.begin(); it != allImgs.end(); ) { unsigned srcImg2 = *it; ++it; SrcPanoImage simg2 = pano.getSrcImage(srcImg2); if ( fabs(simg.getExposureValue() - simg2.getExposureValue()) < maxEVDiff ) { stack.insert(srcImg2); allImgs.erase(srcImg2); } } result.push_back(stack); stack.clear(); } while (allImgs.size() > 0); return result; }
Matrix3 StraightenPanorama::calcStraighteningRotation(const PanoramaData& panorama) { // landscape/non rotated portrait detection is not working correctly // should use the exif rotation tag but thats not stored anywhere currently... // 1: use y axis (image x axis), for normal image // 0: use z axis (image y axis), for non rotated portrait images // (usually rotation is just stored in EXIF tag) std::vector<int> coord_idx; for (unsigned int i = 0; i < panorama.getNrOfImages(); i++) { SrcPanoImage img = panorama.getSrcImage(i); // BUG: need to read exif data here, since exif orientation is not // stored in Panorama data model double fl=0; double crop=0; img.readEXIF(fl, crop, false, false); double roll = img.getExifOrientation(); if (roll == 90 || roll == 270 ) { coord_idx.push_back(2); } else { coord_idx.push_back(1); } } // build covariance matrix of X Matrix3 cov; unsigned int nrOfVariableImages=0; for (unsigned int i = 0; i < panorama.getNrOfImages(); i++) { const SrcPanoImage & img=panorama.getImage(i); if(img.YawisLinked()) { //only consider images which are not linked with the previous ones bool consider=true; for(unsigned int j=0; j<i; j++) { if(img.YawisLinkedWith(panorama.getImage(j))) { consider=false; break; }; }; if(!consider) continue; }; double y = const_map_get(panorama.getImageVariables(i), "y").getValue(); double p = const_map_get(panorama.getImageVariables(i), "p").getValue(); double r = const_map_get(panorama.getImageVariables(i), "r").getValue(); Matrix3 mat; mat.SetRotationPT(DEG_TO_RAD(y), DEG_TO_RAD(p), DEG_TO_RAD(r)); nrOfVariableImages++; DEBUG_DEBUG("mat = " << mat); for (int j=0; j<3; j++) { for (int k=0; k<3; k++) { cov.m[j][k] += mat.m[j][coord_idx[i]] * mat.m[k][coord_idx[i]]; } } } cov /= nrOfVariableImages; DEBUG_DEBUG("cov = " << cov); // calculate eigenvalues and vectors Matrix3 eigvectors; double eigval[3]; int eigvalIdx[3]; int maxsweep = 100; int maxannil = 0; double eps = 1e-16; hugin_utils::eig_jacobi(3, cov.m, eigvectors.m, eigval, eigvalIdx, &maxsweep, &maxannil, &eps); DEBUG_DEBUG("Eigenvectors & eigenvalues:" << std::endl << "V = " << eigvectors << std::endl << "D = [" << eigval[0] << ", " << eigval[1] << ", " << eigval[2] << " ]" << "idx = [" << eigvalIdx[0] << ", " << eigvalIdx[1] << ", " << eigvalIdx[2] << " ]"); // get up vector, eigenvector with smallest eigenvalue Vector3 up; up.x = eigvectors.m[eigvalIdx[2]][0]; up.y = eigvectors.m[eigvalIdx[2]][1]; up.z = eigvectors.m[eigvalIdx[2]][2]; // normalize vector up.Normalize(); DEBUG_DEBUG("Up vector: up = " << up ); double rotAngle = acos(up.Dot(Vector3(0,0,1))); if (rotAngle > M_PI/2) { // turn in shorter direction up *= -1; rotAngle = acos(up.Dot(Vector3(0,0,1))); } DEBUG_DEBUG("rotation Angle: " << rotAngle); // get rotation axis Vector3 rotAxis = up.Cross(Vector3(0,0,1)); DEBUG_DEBUG("rotAxis = " << rotAngle); // calculate rotation matrix Matrix3 rotMat = GetRotationAroundU(rotAxis, -rotAngle); DEBUG_DEBUG("rotMat = " << rotMat); return rotMat; }
int main(int argc, char *argv[]) { // parse arguments const char * optstring = "alho:npqsv:m"; int c; string output; bool doPairwise = false; bool doAutoOpt = false; bool doNormalOpt = false; bool doLevel = false; bool chooseProj = false; bool quiet = false; bool doPhotometric = false; double hfov = 0.0; while ((c = getopt (argc, argv, optstring)) != -1) { switch (c) { case 'o': output = optarg; break; case 'h': usage(argv[0]); return 0; case 'p': doPairwise = true; break; case 'a': doAutoOpt = true; break; case 'n': doNormalOpt = true; break; case 'l': doLevel = true; break; case 's': chooseProj = true; break; case 'q': quiet = true; break; case 'v': hfov = atof(optarg); break; case 'm': doPhotometric = true; break; default: abort (); } } if (argc - optind != 1) { usage(argv[0]); return 1; } const char * scriptFile = argv[optind]; Panorama pano; if (scriptFile[0] == '-') { DocumentData::ReadWriteError err = pano.readData(std::cin); if (err != DocumentData::SUCCESSFUL) { cerr << "error while reading script file from stdin." << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } } else { ifstream prjfile(scriptFile); if (!prjfile.good()) { cerr << "could not open script : " << scriptFile << endl; return 1; } pano.setFilePrefix(hugin_utils::getPathPrefix(scriptFile)); DocumentData::ReadWriteError err = pano.readData(prjfile); if (err != DocumentData::SUCCESSFUL) { cerr << "error while parsing panos tool script: " << scriptFile << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } } if (pano.getNrOfImages() == 0) { cerr << "Panorama should consist of at least one image" << endl; return 1; } // for bad HFOV (from autopano-SIFT) for (unsigned i=0; i < pano.getNrOfImages(); i++) { SrcPanoImage img = pano.getSrcImage(i); if (img.getProjection() == SrcPanoImage::RECTILINEAR && img.getHFOV() >= 180) { // something is wrong here, try to read from exif data double focalLength = 0; double cropFactor = 0; cerr << "HFOV of image " << img.getFilename() << " invalid, trying to read EXIF tags" << endl; bool ok = img.readEXIF(focalLength, cropFactor, true, false); if (! ok) { if (hfov) { img.setHFOV(hfov); } else { cerr << "EXIF reading failed, please specify HFOV with -v" << endl; return 1; } } pano.setSrcImage(i, img); } } if(pano.getNrOfCtrlPoints()==0 && (doPairwise || doAutoOpt || doNormalOpt)) { cerr << "Panorama have to have control points to optimise positions" << endl; return 1; }; if (doPairwise && ! doAutoOpt) { // do pairwise optimisation set<string> optvars; optvars.insert("r"); optvars.insert("p"); optvars.insert("y"); AutoOptimise::autoOptimise(pano); // do global optimisation if (!quiet) std::cerr << "*** Pairwise position optimisation" << endl; PTools::optimize(pano); } else if (doAutoOpt) { if (!quiet) std::cerr << "*** Adaptive geometric optimisation" << endl; SmartOptimise::smartOptimize(pano); } else if (doNormalOpt) { if (!quiet) std::cerr << "*** Optimising parameters specified in PTO file" << endl; PTools::optimize(pano); } else { if (!quiet) std::cerr << "*** Geometric parameters not optimized" << endl; } if (doLevel) { bool hasVerticalLines=false; CPVector allCP=pano.getCtrlPoints(); if(allCP.size()>0 && (doPairwise || doAutoOpt || doNormalOpt)) { for(size_t i=0;i<allCP.size() && !hasVerticalLines;i++) { hasVerticalLines=(allCP[i].mode==ControlPoint::X); }; }; // straighten only if there are no vertical control points if(hasVerticalLines) { cout << "Skipping automatic leveling because of existing vertical control points." << endl; } else { StraightenPanorama(pano).run(); CenterHorizontally(pano).run(); }; } if (chooseProj) { PanoramaOptions opts = pano.getOptions(); double hfov, vfov; CalculateFitPanorama fitPano = CalculateFitPanorama(pano); fitPano.run(); opts.setHFOV(fitPano.getResultHorizontalFOV()); opts.setHeight(roundi(fitPano.getResultHeight())); vfov = opts.getVFOV(); hfov = opts.getHFOV(); // avoid perspective projection if field of view > 100 deg double mf = 100; if (vfov < mf) { // cylindrical or rectilinear if (hfov < mf) { opts.setProjection(PanoramaOptions::RECTILINEAR); } else { opts.setProjection(PanoramaOptions::CYLINDRICAL); } } // downscale pano a little double sizeFactor = 0.7; pano.setOptions(opts); double w = CalculateOptimalScale::calcOptimalScale(pano); opts.setWidth(roundi(opts.getWidth()*w*sizeFactor), true); pano.setOptions(opts); } if(doPhotometric) { // photometric estimation PanoramaOptions opts = pano.getOptions(); int nPoints = 200; int pyrLevel=3; bool randomPoints = true; nPoints = nPoints * pano.getNrOfImages(); std::vector<vigra_ext::PointPairRGB> points; ProgressDisplay *progressDisplay; if(!quiet) progressDisplay=new StreamProgressDisplay(std::cout); else progressDisplay=new DummyProgressDisplay(); try { loadImgsAndExtractPoints(pano, nPoints, pyrLevel, randomPoints, *progressDisplay, points, !quiet); } catch (std::exception & e) { cerr << "caught exception: " << e.what() << endl; return 1; }; if(!quiet) cout << "\rSelected " << points.size() << " points" << endl; if (points.size() == 0) { cerr << "Error: no overlapping points found, exiting" << endl; return 1; } progressDisplay->startSubtask("Photometric Optimization", 0.0); // first, ensure that vignetting and response coefficients are linked const HuginBase::ImageVariableGroup::ImageVariableEnum vars[] = { HuginBase::ImageVariableGroup::IVE_EMoRParams, HuginBase::ImageVariableGroup::IVE_ResponseType, HuginBase::ImageVariableGroup::IVE_VigCorrMode, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift }; HuginBase::StandardImageVariableGroups variable_groups(pano); HuginBase::ImageVariableGroup & lenses = variable_groups.getLenses(); for (size_t i = 0; i < lenses.getNumberOfParts(); i++) { std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> links_needed; links_needed.clear(); for (int v = 0; v < 5; v++) { if (!lenses.getVarLinkedInPart(vars[v], i)) { links_needed.insert(vars[v]); } }; if (!links_needed.empty()) { std::set<HuginBase::ImageVariableGroup::ImageVariableEnum>::iterator it; for (it = links_needed.begin(); it != links_needed.end(); it++) { lenses.linkVariablePart(*it, i); } } } HuginBase::SmartPhotometricOptimizer::PhotometricOptimizeMode optmode = HuginBase::SmartPhotometricOptimizer::OPT_PHOTOMETRIC_LDR; if (opts.outputMode == PanoramaOptions::OUTPUT_HDR) { optmode = HuginBase::SmartPhotometricOptimizer::OPT_PHOTOMETRIC_HDR; } SmartPhotometricOptimizer photoOpt(pano, progressDisplay, pano.getOptimizeVector(), points, optmode); photoOpt.run(); // calculate the mean exposure. opts.outputExposureValue = CalculateMeanExposure::calcMeanExposure(pano); pano.setOptions(opts); progressDisplay->finishSubtask(); delete progressDisplay; }; // write result OptimizeVector optvec = pano.getOptimizeVector(); UIntSet imgs; fill_set(imgs,0, pano.getNrOfImages()-1); if (output != "") { ofstream of(output.c_str()); pano.printPanoramaScript(of, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(scriptFile)); } else { pano.printPanoramaScript(cout, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(scriptFile)); } return 0; }
bool PanoDetector::loadProject() { ifstream ptoFile(_inputFile.c_str()); if (ptoFile.bad()) { cerr << "ERROR: could not open file: '" << _inputFile << "'!" << endl; return false; } _prefix=hugin_utils::getPathPrefix(_inputFile); if(_prefix.empty()) { // Get the current working directory: char* buffer; #ifdef _WINDOWS #define getcwd _getcwd #endif if((buffer=getcwd(NULL,0))!=NULL) { _prefix.append(buffer); free(buffer); _prefix=includeTrailingPathSep(_prefix); } }; _panoramaInfo->setFilePrefix(_prefix); AppBase::DocumentData::ReadWriteError err = _panoramaInfo->readData(ptoFile); if (err != AppBase::DocumentData::SUCCESSFUL) { cerr << "ERROR: couldn't parse panos tool script: '" << _inputFile << "'!" << endl; return false; } // Create a copy of panoramaInfo that will be used to define // image options _panoramaInfoCopy=_panoramaInfo->duplicate(); // Add images found in the project file to _filesData unsigned int nImg = _panoramaInfo->getNrOfImages(); unsigned int imgWithKeyfile=0; for (unsigned int imgNr = 0; imgNr < nImg; ++imgNr) { // insert the image in the map _filesData.insert(make_pair(imgNr, ImgData())); // get the data ImgData& aImgData = _filesData[imgNr]; // get a copy of image info SrcPanoImage img = _panoramaInfoCopy.getSrcImage(imgNr); // set the name aImgData._name = img.getFilename(); // modify image position in the copy img.setYaw(0); img.setRoll(0); img.setPitch(0); img.setX(0); img.setY(0); img.setZ(0); img.setActive(true); img.setResponseType(SrcPanoImage::RESPONSE_LINEAR); img.setExposureValue(0); _panoramaInfoCopy.setImage(imgNr,img); // Number pointing to image info in _panoramaInfo aImgData._number = imgNr; aImgData._needsremap=(img.getHFOV()>=65 && img.getProjection() != SrcPanoImage::FISHEYE_STEREOGRAPHIC); // set image detection size if(aImgData._needsremap) { _filesData[imgNr]._detectWidth = max(img.getSize().width(),img.getSize().height()); _filesData[imgNr]._detectHeight = max(img.getSize().width(),img.getSize().height()); } else { _filesData[imgNr]._detectWidth = img.getSize().width(); _filesData[imgNr]._detectHeight = img.getSize().height(); }; if (_downscale) { _filesData[imgNr]._detectWidth >>= 1; _filesData[imgNr]._detectHeight >>= 1; } // set image remapping options if(aImgData._needsremap) { aImgData._projOpts.setProjection(PanoramaOptions::STEREOGRAPHIC); aImgData._projOpts.setHFOV(250); aImgData._projOpts.setVFOV(250); aImgData._projOpts.setWidth(250); aImgData._projOpts.setHeight(250); // determine size of output image. // The old code did not work with images with images with a FOV // approaching 180 degrees vigra::Rect2D roi=estimateOutputROI(_panoramaInfoCopy,aImgData._projOpts,imgNr); double scalefactor = max((double)_filesData[imgNr]._detectWidth / roi.width(), (double)_filesData[imgNr]._detectHeight / roi.height() ); // resize output canvas vigra::Size2D canvasSize((int)aImgData._projOpts.getWidth() * scalefactor, (int)aImgData._projOpts.getHeight() * scalefactor); aImgData._projOpts.setWidth(canvasSize.width(), false); aImgData._projOpts.setHeight(canvasSize.height()); // set roi to cover the remapped input image roi = roi * scalefactor; _filesData[imgNr]._detectWidth = roi.width(); _filesData[imgNr]._detectHeight = roi.height(); aImgData._projOpts.setROI(roi); } // Specify if the image has an associated keypoint file aImgData._keyfilename = getKeyfilenameFor(_keypath,aImgData._name); ifstream keyfile(aImgData._keyfilename.c_str()); aImgData._hasakeyfile = keyfile.good(); if(aImgData._hasakeyfile) { imgWithKeyfile++; }; } //update masks, convert positive masks into negative masks //because positive masks works only if the images are on the final positions _panoramaInfoCopy.updateMasks(true); //if all images has keyfile, we don't need to load celeste model file if(nImg==imgWithKeyfile) { _celeste=false; }; return true; }
SmallRemappedImageCache::MRemappedImage * SmallRemappedImageCache::getRemapped(const PanoramaData& pano, const PanoramaOptions & popts, unsigned int imgNr, vigra::Rect2D outputROI, AppBase::MultiProgressDisplay& progress) { // always map to HDR mode. curve and exposure is applied in preview window, for speed PanoramaOptions opts = popts; opts.outputMode = PanoramaOptions::OUTPUT_HDR; opts.outputExposureValue = 0.0; // return old image, if already in cache and if it has changed since the last rendering if (set_contains(m_images, imgNr)) { // return cached image if the parameters of the image have not changed SrcPanoImage oldParam = m_imagesParam[imgNr]; if (oldParam == pano.getSrcImage(imgNr) && m_panoOpts[imgNr].getHFOV() == opts.getHFOV() && m_panoOpts[imgNr].getWidth() == opts.getWidth() && m_panoOpts[imgNr].getHeight() == opts.getHeight() && m_panoOpts[imgNr].getProjection() == opts.getProjection() && m_panoOpts[imgNr].getProjectionParameters() == opts.getProjectionParameters() ) { DEBUG_DEBUG("using cached remapped image " << imgNr); return m_images[imgNr]; } } ImageCache::getInstance().softFlush(); typedef BasicImageView<RGBValue<unsigned char> > BRGBImageView; // typedef NumericTraits<PixelType>::RealPromote RPixelType; // remap image DEBUG_DEBUG("remapping image " << imgNr); // load image const SrcPanoImage & img = pano.getImage(imgNr); ImageCache::EntryPtr e = ImageCache::getInstance().getSmallImage(img.getFilename().c_str()); if ( (e->image8->width() == 0) && (e->image16->width() == 0) && (e->imageFloat->width() == 0) ) { throw std::runtime_error("could not retrieve small source image for preview generation"); } Size2D srcImgSize; if (e->image8->width() > 0) srcImgSize = e->image8->size(); else if (e->image16->width() > 0) srcImgSize = e->image16->size(); else srcImgSize = e->imageFloat->size(); MRemappedImage *remapped = new MRemappedImage; SrcPanoImage srcPanoImg = pano.getSrcImage(imgNr); // adjust distortion parameters for small preview image srcPanoImg.resize(srcImgSize); FImage srcFlat; // use complete image, by supplying an empty mask image BImage srcMask; if (img.getVigCorrMode() & SrcPanoImage::VIGCORR_FLATFIELD) { ImageCache::EntryPtr e = ImageCache::getInstance().getSmallImage(img.getFlatfieldFilename().c_str()); if (!e) { throw std::runtime_error("could not retrieve flatfield image for preview generation"); } if (e->image8->width()) { srcFlat.resize(e->image8->size()); copyImage(srcImageRange(*(e->image8), RGBToGrayAccessor<RGBValue<UInt8> >()), destImage(srcFlat)); } else if (e->image16->width()) { srcFlat.resize(e->image16->size()); copyImage(srcImageRange(*(e->image16), RGBToGrayAccessor<RGBValue<vigra::UInt16> >()), destImage(srcFlat)); } else { srcFlat.resize(e->imageFloat->size()); copyImage(srcImageRange(*(e->imageFloat), RGBToGrayAccessor<RGBValue<float> >()), destImage(srcFlat)); } } progress.pushTask(AppBase::ProgressTask("remapping", "", 0)); // compute the bounding output rectangle here! vigra::Rect2D outROI = estimateOutputROI(pano, opts, imgNr); DEBUG_DEBUG("srcPanoImg size: " << srcPanoImg.getSize() << " pano roi:" << outROI); if (e->imageFloat->width()) { // remap image remapImage(*(e->imageFloat), srcMask, srcFlat, srcPanoImg, opts, outROI, *remapped, progress); } else if (e->image16->width()) { // remap image remapImage(*(e->image16), srcMask, srcFlat, srcPanoImg, opts, outROI, *remapped, progress); } else { remapImage(*(e->image8), srcMask, srcFlat, srcPanoImg, opts, outROI, *remapped, progress); } progress.popTask(); m_images[imgNr] = remapped; m_imagesParam[imgNr] = pano.getSrcImage(imgNr); m_panoOpts[imgNr] = opts; return remapped; }
CPVector AutoPanoKolor::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, int & ret_value, wxWindow *parent) { CPVector cps; wxString autopanoExe = setting.GetProg(); // write default autopano.kolor.com flags wxString autopanoArgs = setting.GetArgs(); string imgFiles; for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++) { imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename())); } wxString ptofilepath = wxFileName::CreateTempFileName(wxT("ap_res")); wxFileName ptofn(ptofilepath); wxString ptofile = ptofn.GetFullName(); autopanoArgs.Replace(wxT("%o"), ptofile); wxString tmp; tmp.Printf(wxT("%d"), nFeatures); autopanoArgs.Replace(wxT("%p"), tmp); SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin()); tmp.Printf(wxT("%f"), firstImg.getHFOV()); autopanoArgs.Replace(wxT("%v"), tmp); tmp.Printf(wxT("%d"), (int) firstImg.getProjection()); autopanoArgs.Replace(wxT("%f"), tmp); autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME)); wxString tempdir = ptofn.GetPath(); autopanoArgs.Replace(wxT("%d"), ptofn.GetPath()); wxString cmd; cmd.Printf(wxT("%s %s"), wxQuoteFilename(autopanoExe).c_str(), autopanoArgs.c_str()); #ifdef __WXMSW__ if (cmd.size() > 32766) { CPMessage(_("Command line for control point detector too long.\nThis is a Windows limitation\nPlease select less images, or place the images in a folder with\na shorter pathname"), _("Too many images selected"), parent); return cps; } #endif DEBUG_DEBUG("Executing: " << cmd.c_str()); wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(cmd); if (arguments.GetCount() > 127) { DEBUG_ERROR("Too many arguments for call to wxExecute()"); DEBUG_ERROR("Try using the %s parameter in preferences"); CPMessage(wxString::Format(_("Too many arguments (images). Try using the %%s parameter in preferences.\n\n Could not execute command: %s"), autopanoExe.c_str()), _("wxExecute Error"), parent); return cps; } ret_value = 0; // use MyExternalCmdExecDialog ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent); if (ret_value == HUGIN_EXIT_CODE_CANCELLED) { return cps; } else if (ret_value == -1) { CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent); return cps; } else if (ret_value > 0) { CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value), _("wxExecute Error"), parent); return cps; } ptofile = ptofn.GetFullPath(); ptofile.append(wxT("0.oto")); if (! wxFileExists(ptofile.c_str()) ) { CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor incorrect command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()), _("Control point detector failure"), parent ); return cps; } // read and update control points cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano); if (!wxRemoveFile(ptofile)) { DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str()); } return cps; }
CPVector AutoPanoSift::automatch(CPDetectorSetting &setting, PT::Panorama & pano, const PT::UIntSet & imgs, int nFeatures, vector<wxString> &keyFiles, int & ret_value, wxWindow *parent) { CPVector cps; if (imgs.size() == 0) { return cps; } DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages()); // create suitable command line.. wxString generateKeysExe=GetProgPath(setting.GetProg()); wxString matcherExe = GetProgPath(setting.GetProgMatcher()); wxString generateKeysArgs=setting.GetArgs(); wxString matcherArgs = setting.GetArgsMatcher(); wxString tempDir= wxConfigBase::Get()->Read(wxT("tempDir"),wxT("")); if(!tempDir.IsEmpty()) if(tempDir.Last()!=wxFileName::GetPathSeparator()) tempDir.Append(wxFileName::GetPathSeparator()); //check arguments if(generateKeysArgs.Find(wxT("%i"))==wxNOT_FOUND || generateKeysArgs.Find(wxT("%k"))==wxNOT_FOUND) { CPMessage(_("Please use %i to specify the input files and %k to specify the keypoint file for the generate keys step"), _("Error in control point detector command"), parent); return cps; }; if(matcherArgs.Find(wxT("%k"))==wxNOT_FOUND || matcherArgs.Find(wxT("%o"))==wxNOT_FOUND) { CPMessage(_("Please use %k to specify the keypoint files and %o to specify the output project file for the matching step"), _("Error in control point detector command"), parent); return cps; }; ret_value=0; for(UIntSet::const_iterator img=imgs.begin();img!=imgs.end();img++) { if(keyFiles[*img].IsEmpty()) { //no key files exists, so generate it wxString keyfile=wxFileName::CreateTempFileName(tempDir+wxT("apk_")); keyFiles[*img]=keyfile; wxString cmd=generateKeysArgs; wxString tmp; tmp.Printf(wxT("%d"), nFeatures); cmd.Replace(wxT("%p"), tmp); SrcPanoImage srcImg = pano.getSrcImage(*img); tmp.Printf(wxT("%f"), srcImg.getHFOV()); cmd.Replace(wxT("%v"), tmp); tmp.Printf(wxT("%d"), (int) srcImg.getProjection()); cmd.Replace(wxT("%f"), tmp); cmd.Replace(wxT("%i"),wxQuoteFilename(wxString(srcImg.getFilename().c_str(), HUGIN_CONV_FILENAME))); cmd.Replace(wxT("%k"),wxQuoteFilename(keyfile)); // use MyExternalCmdExecDialog ret_value = CPExecute(generateKeysExe, cmd, _("generating key file"), parent); cmd=generateKeysExe+wxT(" ")+cmd; if (ret_value == HUGIN_EXIT_CODE_CANCELLED) return cps; else if (ret_value == -1) { CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent); return cps; } else if (ret_value > 0) { CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value), _("wxExecute Error"), parent); return cps; }; }; }; // TODO: create a secure temporary filename here wxString ptofile = wxFileName::CreateTempFileName(wxT("ap_res")); matcherArgs.Replace(wxT("%o"), ptofile); wxString tmp; tmp.Printf(wxT("%d"), nFeatures); matcherArgs.Replace(wxT("%p"), tmp); SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin()); tmp.Printf(wxT("%f"), firstImg.getHFOV()); matcherArgs.Replace(wxT("%v"), tmp); tmp.Printf(wxT("%d"), (int) firstImg.getProjection()); matcherArgs.Replace(wxT("%f"), tmp); wxString imgFiles; for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++) { imgFiles.append(wxT(" ")).append(wxQuoteFilename(keyFiles[*it])); }; matcherArgs.Replace(wxT("%k"), wxString (imgFiles.wc_str(), HUGIN_CONV_FILENAME)); #ifdef __WXMSW__ if (matcherArgs.size() > 32000) { CPMessage(_("Command line for control point detector too long.\nThis is a Windows limitation\nPlease select less images, or place the images in a folder with\na shorter pathname"), _("Too many images selected"), parent ); return cps; } #endif wxString cmd = matcherExe + wxT(" ") + matcherArgs; DEBUG_DEBUG("Executing: " << matcherExe.mb_str(wxConvLocal) << " " << matcherArgs.mb_str(wxConvLocal)); wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(matcherArgs); if (arguments.GetCount() > 127) { DEBUG_ERROR("Too many arguments for call to wxExecute()"); CPMessage(wxString::Format(_("Too many arguments (images). Try using a cp generator setting which supports the %%s parameter in preferences.\n\n Could not execute command: %s"), matcherExe.c_str()), _("wxExecute Error"), parent); return cps; } // use MyExternalCmdExecDialog ret_value = CPExecute(matcherExe, matcherArgs, _("finding control points"), parent); if (ret_value == HUGIN_EXIT_CODE_CANCELLED) return cps; else if (ret_value == -1) { CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent); return cps; } else if (ret_value > 0) { CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value), _("wxExecute Error"), parent); return cps; }; if (! wxFileExists(ptofile.c_str())) { CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor incorrect command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()), _("Control point detector failure"), parent ); return cps; } // read and update control points cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano); if (!wxRemoveFile(ptofile)) { DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str()); } return cps; };
CPVector AutoPanoSift::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, int & ret_value, wxWindow *parent) { CPVector cps; if (imgs.size() == 0) { return cps; } // create suitable command line.. wxString autopanoExe = GetProgPath(setting.GetProg()); if(setting.IsTwoStepDetector()) { std::vector<wxString> keyFiles(pano.getNrOfImages()); cps=automatch(setting, pano, imgs, nFeatures, keyFiles, ret_value, parent); Cleanup(setting, pano, imgs, keyFiles, parent); return cps; }; wxString autopanoArgs = setting.GetArgs(); // TODO: create a secure temporary filename here wxString ptofile = wxFileName::CreateTempFileName(wxT("ap_res")); autopanoArgs.Replace(wxT("%o"), ptofile); wxString tmp; tmp.Printf(wxT("%d"), nFeatures); autopanoArgs.Replace(wxT("%p"), tmp); SrcPanoImage firstImg = pano.getSrcImage(*imgs.begin()); tmp.Printf(wxT("%f"), firstImg.getHFOV()); autopanoArgs.Replace(wxT("%v"), tmp); tmp.Printf(wxT("%d"), (int) firstImg.getProjection()); autopanoArgs.Replace(wxT("%f"), tmp); long idx = autopanoArgs.Find(wxT("%namefile")) ; DEBUG_DEBUG("find %namefile in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx); bool use_namefile = idx >=0; idx = autopanoArgs.Find(wxT("%i")); DEBUG_DEBUG("find %i in '"<< autopanoArgs.mb_str(wxConvLocal) << "' returned: " << idx); bool use_params = idx >=0; idx = autopanoArgs.Find(wxT("%s")); bool use_inputscript = idx >=0; if (! (use_namefile || use_params || use_inputscript)) { CPMessage(_("Please use %namefile, %i or %s to specify the input files for the control point detector"), _("Error in control point detector command"), parent); return cps; } wxFile namefile; wxString namefile_name; if (use_namefile) { // create temporary file with image names. namefile_name = wxFileName::CreateTempFileName(wxT("ap_imgnames"), &namefile); DEBUG_DEBUG("before replace %namefile: " << autopanoArgs.mb_str(wxConvLocal)); autopanoArgs.Replace(wxT("%namefile"), namefile_name); DEBUG_DEBUG("after replace %namefile: " << autopanoArgs.mb_str(wxConvLocal)); for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++) { namefile.Write(wxString(pano.getImage(*it).getFilename().c_str(), HUGIN_CONV_FILENAME)); namefile.Write(wxT("\r\n")); } // close namefile if (namefile_name != wxString(wxT(""))) { namefile.Close(); } } else { string imgFiles; for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++) { imgFiles.append(" ").append(quoteFilename(pano.getImage(*it).getFilename())); } autopanoArgs.Replace(wxT("%i"), wxString (imgFiles.c_str(), HUGIN_CONV_FILENAME)); } wxString ptoinfile_name; if (use_inputscript) { wxFile ptoinfile; ptoinfile_name = wxFileName::CreateTempFileName(wxT("ap_inproj")); autopanoArgs.Replace(wxT("%s"), ptoinfile_name); ofstream ptoinstream(ptoinfile_name.mb_str(wxConvFile)); //delete all existing control points in temp project //otherwise the existing control points will be loaded again Panorama tempPano=pano.duplicate(); CPVector emptyCPV; tempPano.setCtrlPoints(emptyCPV); tempPano.printPanoramaScript(ptoinstream, tempPano.getOptimizeVector(), tempPano.getOptions(), imgs, false); } #ifdef __WXMSW__ if (autopanoArgs.size() > 32000) { CPMessage(_("Command line for control point detector too long.\nThis is a Windows limitation\nPlease select less images, or place the images in a folder with\na shorter pathname"), _("Too many images selected"), parent ); return cps; } #endif wxString cmd = autopanoExe + wxT(" ") + autopanoArgs; DEBUG_DEBUG("Executing: " << autopanoExe.mb_str(wxConvLocal) << " " << autopanoArgs.mb_str(wxConvLocal)); wxArrayString arguments = wxCmdLineParser::ConvertStringToArgs(autopanoArgs); if (arguments.GetCount() > 127) { DEBUG_ERROR("Too many arguments for call to wxExecute()"); DEBUG_ERROR("Try using the %%s parameter in preferences"); CPMessage(wxString::Format(_("Too many arguments (images). Try using the %%s parameter in preferences.\n\n Could not execute command: %s"), autopanoExe.c_str()), _("wxExecute Error"), parent); return cps; } ret_value = 0; // use MyExternalCmdExecDialog ret_value = CPExecute(autopanoExe, autopanoArgs, _("finding control points"), parent); if (ret_value == HUGIN_EXIT_CODE_CANCELLED) { return cps; } else if (ret_value == -1) { CPMessage( wxString::Format(_("Could not execute command: %s"),cmd.c_str()), _("wxExecute Error"), parent); return cps; } else if (ret_value > 0) { CPMessage(wxString::Format(_("Command: %s\nfailed with error code: %d"),cmd.c_str(),ret_value), _("wxExecute Error"), parent); return cps; } if (! wxFileExists(ptofile.c_str())) { CPMessage(wxString::Format(_("Could not open %s for reading\nThis is an indicator that the control point detector call failed,\nor incorrect command line parameters have been used.\n\nExecuted command: %s"),ptofile.c_str(),cmd.c_str()), _("Control point detector failure"), parent ); return cps; } // read and update control points if(use_inputscript) { cps = readUpdatedControlPoints((const char*)ptofile.mb_str(HUGIN_CONV_FILENAME), pano, imgs); } else { cps = readUpdatedControlPoints((const char *)ptofile.mb_str(HUGIN_CONV_FILENAME), pano); }; if (namefile_name != wxString(wxT(""))) { namefile.Close(); wxRemoveFile(namefile_name); } if (ptoinfile_name != wxString(wxT(""))) { wxRemoveFile(ptoinfile_name); } if (!wxRemoveFile(ptofile)) { DEBUG_DEBUG("could not remove temporary file: " << ptofile.c_str()); } return cps; }
int main(int argc, char* argv[]) { // parse arguments const char* optstring = "o:p:f:c:s:lh"; static struct option longOptions[] = { {"output", required_argument, NULL, 'o' }, {"projection", required_argument, NULL, 'p' }, {"fov", required_argument, NULL, 'f' }, {"crop", required_argument, NULL, 'c' }, {"stacklength", required_argument, NULL, 's' }, {"linkstacks", no_argument, NULL, 'l' }, {"distortion", no_argument, NULL, 300 }, {"vignetting", no_argument, NULL, 301 }, {"help", no_argument, NULL, 'h' }, 0 }; int c; int optionIndex = 0; string output; int projection=-1; float fov=-1; int stackLength=1; bool linkStacks=false; vigra::Rect2D cropRect(0,0,0,0); bool loadDistortion=false; bool loadVignetting=false; while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1) { switch (c) { case 'o': output = optarg; break; case 'h': usage(argv[0]); return 0; case 'p': { projection=atoi(optarg); if((projection==0) && (strcmp(optarg,"0")!=0)) { cerr << "Could not parse image number."; return 1; }; if(projection<0) { cerr << "Invalid projection number." << endl; return 1; }; }; break; case 'f': fov=atof(optarg); if(fov<1 || fov>360) { cerr << "Invalid field of view"; return 1; }; break; case 'c': { int left, right, top, bottom; int n=sscanf(optarg, "%d,%d,%d,%d", &left, &right, &top, &bottom); if (n==4) { if(right>left && bottom>top) { cropRect.setUpperLeft(vigra::Point2D(left,top)); cropRect.setLowerRight(vigra::Point2D(right,bottom)); } else { cerr << "Invalid crop area" << endl; return 1; }; } else { cerr << "Could not parse crop values" << endl; return 1; }; }; break; case 's': stackLength=atoi(optarg); if(stackLength<1) { cerr << "Could not parse stack length." << endl; return 1; }; break; case 'l': linkStacks=true; break; case 300: loadDistortion=true; break; case 301: loadVignetting=true; break; case ':': cerr <<"Option " << longOptions[optionIndex].name << " requires a number" << endl; return 1; break; case '?': break; default: abort (); } } if (argc - optind < 1) { usage(argv[0]); return 1; }; cout << "Generating pto file..." << endl; cout.flush(); std::vector<string> filelist; while(optind<argc) { string input; #ifdef _WINDOWS //do globbing input=GetAbsoluteFilename(argv[optind]); char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; char newFile[_MAX_PATH]; _splitpath(input.c_str(), drive, dir, NULL, NULL); struct _finddata_t finddata; intptr_t findhandle = _findfirst(input.c_str(), &finddata); if (findhandle != -1) { do { //ignore folder, can be happen when using *.* if((finddata.attrib & _A_SUBDIR)==0) { _splitpath(finddata.name, NULL, NULL, fname, ext); _makepath(newFile, drive, dir, fname, ext); //check if valid image file if(vigra::isImage(newFile)) { filelist.push_back(std::string(newFile)); }; }; } while (_findnext(findhandle, &finddata) == 0); _findclose(findhandle); } #else input=argv[optind]; if(hugin_utils::FileExists(input)) { if(vigra::isImage(input.c_str())) { filelist.push_back(GetAbsoluteFilename(input)); }; }; #endif optind++; }; if(filelist.size()==0) { cerr << "No valid image files given." << endl; return 1; }; //sort filenames sort(filelist.begin(),filelist.end(),doj::alphanum_less()); if(projection<0) { InitLensDB(); }; Panorama pano; for(size_t i=0; i<filelist.size();i++) { SrcPanoImage srcImage; cout << "Reading " << filelist[i] << "..." << endl; srcImage.setFilename(filelist[i]); try { vigra::ImageImportInfo info(filelist[i].c_str()); if(info.width()==0 || info.height()==0) { cerr << "ERROR: Could not decode image " << filelist[i] << endl << "Skipping this image." << endl << endl; continue; } srcImage.setSize(info.size()); std::string pixelType=info.getPixelType(); if((pixelType=="UINT8") || (pixelType=="UINT16") || (pixelType=="INT16")) { srcImage.setResponseType(HuginBase::SrcPanoImage::RESPONSE_EMOR); } else { srcImage.setResponseType(HuginBase::SrcPanoImage::RESPONSE_LINEAR); }; } catch(std::exception & e) { cerr << "ERROR: caught exception: " << e.what() << endl; cerr << "Could not read image information for file " << filelist[i] << endl; cerr << "Skipping this image." << endl << endl; continue; }; srcImage.readEXIF(); srcImage.applyEXIFValues(); if(projection>=0) { srcImage.setProjection((HuginBase::BaseSrcPanoImage::Projection)projection); } else { srcImage.readProjectionFromDB(); }; if(fov>0) { srcImage.setHFOV(fov); if(srcImage.getCropFactor()==0) { srcImage.setCropFactor(1.0); }; } else { //set plausible default value if they could not read from exif if(srcImage.getExifFocalLength()==0 || srcImage.getCropFactor()==0) { cout << "\tNo value for field of view found in EXIF data. " << endl << "\tAssuming a HFOV of 50 degrees. " << endl; srcImage.setHFOV(50); srcImage.setCropFactor(1.0); }; }; if(cropRect.width()>0 && cropRect.height()>0) { if(srcImage.isCircularCrop()) { srcImage.setCropMode(SrcPanoImage::CROP_CIRCLE); } else { srcImage.setCropMode(SrcPanoImage::CROP_RECTANGLE); }; srcImage.setAutoCenterCrop(false); srcImage.setCropRect(cropRect); }; if(loadDistortion) { if(srcImage.readDistortionFromDB()) { cout << "\tRead distortion data from lensfun database." << endl; } else { cout << "\tNo valid distortion data found in lensfun database." << endl; }; }; if(loadVignetting) { if(srcImage.readVignettingFromDB()) { cout << "\tRead vignetting data from lensfun database." << endl; } else { cout << "\tNo valid vignetting data found in lensfun database." << endl; }; }; pano.addImage(srcImage); }; if(pano.getNrOfImages()==0) { cerr << "Adding images to project files failed." << endl; HuginBase::LensDB::LensDB::Clean(); return 1; }; //link lenses if(pano.getNrOfImages()>1) { double redBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifRedBalance(); double blueBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifBlueBalance(); if(fabs(redBalanceAnchor)<1e-2) { redBalanceAnchor=1; }; if(fabs(blueBalanceAnchor)<1e-2) { blueBalanceAnchor=1; }; StandardImageVariableGroups variable_groups(pano); ImageVariableGroup& lenses = variable_groups.getLenses(); for(size_t i=1;i<pano.getNrOfImages();i++) { int image=-1; const SrcPanoImage & srcImg=pano.getImage(i); for(size_t j=0;j<i;j++) { const SrcPanoImage & compareImg=pano.getImage(j); if(srcImg.getHFOV()==compareImg.getHFOV() && srcImg.getProjection()==compareImg.getProjection() && srcImg.getExifModel()==compareImg.getExifModel() && srcImg.getExifMake()==compareImg.getExifMake() && srcImg.getSize()==compareImg.getSize()) { image=j; break; }; }; if(image!=-1) { SrcPanoImage img=pano.getSrcImage(i); double ev=img.getExposureValue(); lenses.switchParts(i,lenses.getPartNumber(image)); lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_ExposureValue, i); img.setExposureValue(ev); lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceRed, i); lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceBlue, i); img.setWhiteBalanceRed(img.getExifRedBalance()/redBalanceAnchor); img.setWhiteBalanceBlue(img.getExifBlueBalance()/blueBalanceAnchor); pano.setSrcImage(i, img); }; }; cout << endl << "Assigned " << lenses.getNumberOfParts() << " lenses." << endl; if(lenses.getNumberOfParts()>1 && stackLength>1) { cout << "Project contains more than one lens, but you requested to assign" << endl << "stacks. This is not supported. Therefore stacks will not be" << endl << "assigned." << endl << endl; stackLength=1; }; }; //link stacks if(pano.getNrOfImages()>1 && stackLength>1) { stackLength=std::min<int>(stackLength,pano.getNrOfImages()); int stackCount=pano.getNrOfImages() / stackLength; if(pano.getNrOfImages() % stackLength > 0) { stackCount++; }; if(stackCount<pano.getNrOfImages()) { for(size_t stackNr=0;stackNr<stackCount;stackNr++) { size_t firstImgStack=stackNr*stackLength; for(size_t i=0;i<stackLength;i++) { if(firstImgStack+i<pano.getNrOfImages()) { pano.linkImageVariableStack(firstImgStack,firstImgStack+i); if(linkStacks) { pano.linkImageVariableYaw(firstImgStack,firstImgStack+i); pano.linkImageVariablePitch(firstImgStack,firstImgStack+i); pano.linkImageVariableRoll(firstImgStack,firstImgStack+i); }; }; }; }; cout << "Assigned " << stackCount << " stacks." << endl; }; }; //set output exposure value PanoramaOptions opt = pano.getOptions(); opt.outputExposureValue = CalculateMeanExposure::calcMeanExposure(pano); pano.setOptions(opt); // set optimizer switches pano.setOptimizerSwitch(HuginBase::OPT_PAIR); pano.setPhotometricOptimizerSwitch(HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE); //output if(output=="") { output=hugin_utils::stripExtension(pano.getImage(0).getFilename()); if(pano.getNrOfImages()>1) { output.append("-"); output.append(hugin_utils::stripExtension(hugin_utils::stripPath(pano.getImage(pano.getNrOfImages()-1).getFilename()))); }; output=output.append(".pto"); }; output=GetAbsoluteFilename(output); //write output UIntSet imgs; fill_set(imgs,0, pano.getNrOfImages()-1); ofstream of(output.c_str()); pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(output)); cout << endl << "Written output to " << output << endl; HuginBase::LensDB::LensDB::Clean(); return 0; }
int main(int argc, char* argv[]) { // parse arguments const char* optstring = "o:t:h"; enum { MINOVERLAP=1000 }; static struct option longOptions[] = { {"output", required_argument, NULL, 'o' }, {"template", required_argument, NULL, 't'}, {"help", no_argument, NULL, 'h' }, 0 }; int c; int optionIndex = 0; string output; string templateFile; while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1) { switch (c) { case 'o': output = optarg; break; case 't': templateFile = optarg; if(!hugin_utils::FileExists(templateFile)) { cerr << "Error: Template \"" << templateFile << "\" not found." << endl; return 1; }; break; case 'h': usage(argv[0]); return 0; case ':': cerr <<"Option " << longOptions[optionIndex].name << " requires a parameter" << endl; return 1; break; case '?': break; default: abort (); } } if (argc - optind == 0) { cout << "Error: No project file given." << endl; return 1; }; if (argc - optind != 1) { cout << "Error: pto_template can only work on one project file at one time" << endl; return 1; }; if (templateFile.length()==0) { cerr << "Error: No template given." << endl; return 1; }; string input=argv[optind]; // read panorama Panorama pano; ifstream prjfile(input.c_str()); if (!prjfile.good()) { cerr << "Error: could not open script : " << input << endl; return 1; } pano.setFilePrefix(hugin_utils::getPathPrefix(input)); DocumentData::ReadWriteError err = pano.readData(prjfile); if (err != DocumentData::SUCCESSFUL) { cerr << "Error while parsing panos tool script: " << input << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } if(pano.getNrOfImages()==0) { cerr << "Error: project file does not contains any image" << endl; cerr << "aborting processing" << endl; return 1; }; Panorama newPano; ifstream templateStream(templateFile.c_str()); if (!templateStream.good()) { cerr << "Error: could not open template script : " << templateFile << endl; return 1; } newPano.setFilePrefix(hugin_utils::getPathPrefix(templateFile)); err = newPano.readData(templateStream); if (err != DocumentData::SUCCESSFUL) { cerr << "Error while parsing template script: " << templateFile << endl; cerr << "DocumentData::ReadWriteError code: " << err << endl; return 1; } if (pano.getNrOfImages() != newPano.getNrOfImages()) { cerr << "Error: template expects " << newPano.getNrOfImages() << " images," << endl << " current project contains " << pano.getNrOfImages() << " images" << endl << " Could not apply template" << endl; return false; } // check image sizes, and correct parameters if required. for (unsigned int i = 0; i < newPano.getNrOfImages(); i++) { // check if image size is correct const SrcPanoImage & oldSrcImg = pano.getImage(i); SrcPanoImage newSrcImg = newPano.getSrcImage(i); // just keep the file name newSrcImg.setFilename(oldSrcImg.getFilename()); if (oldSrcImg.getSize() != newSrcImg.getSize()) { // adjust size properly. newSrcImg.resize(oldSrcImg.getSize()); } newPano.setSrcImage(i, newSrcImg); } // keep old control points. newPano.setCtrlPoints(pano.getCtrlPoints()); //write output UIntSet imgs; fill_set(imgs, 0, newPano.getNrOfImages()-1); // Set output .pto filename if not given if (output=="") { output=input.substr(0,input.length()-4).append("_template.pto"); } ofstream of(output.c_str()); newPano.printPanoramaScript(of, newPano.getOptimizeVector(), newPano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input)); cout << endl << "Written output to " << output << endl; return 0; }