vector<UIntSet> getHDRStacks(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; CalculateImageOverlap overlap(&pano); overlap.calculate(10); // we are testing 10*10=100 points do { unsigned srcImg = *(allImgs.begin()); stack.insert(srcImg); allImgs.erase(srcImg); // find all images that have a suitable overlap. for (UIntSet::iterator it = allImgs.begin(); it != allImgs.end(); ) { unsigned srcImg2 = *it; ++it; if(overlap.getOverlap(srcImg,srcImg2)>opts.outputStacksMinOverlap) { stack.insert(srcImg2); allImgs.erase(srcImg2); } } result.push_back(stack); stack.clear(); } while (allImgs.size() > 0); return result; }
EStatusCode CFFEmbeddedFontWriter::AddDependentGlyphs(UIntVector& ioSubsetGlyphIDs) { EStatusCode status = PDFHummus::eSuccess; UIntSet glyphsSet; UIntVector::iterator it = ioSubsetGlyphIDs.begin(); bool hasCompositeGlyphs = false; for(;it != ioSubsetGlyphIDs.end() && PDFHummus::eSuccess == status; ++it) { bool localHasCompositeGlyphs; status = AddComponentGlyphs(*it,glyphsSet,localHasCompositeGlyphs); hasCompositeGlyphs |= localHasCompositeGlyphs; } if(hasCompositeGlyphs) { UIntSet::iterator itNewGlyphs; for(it = ioSubsetGlyphIDs.begin();it != ioSubsetGlyphIDs.end(); ++it) glyphsSet.insert(*it); ioSubsetGlyphIDs.clear(); for(itNewGlyphs = glyphsSet.begin(); itNewGlyphs != glyphsSet.end(); ++itNewGlyphs) ioSubsetGlyphIDs.push_back(*itNewGlyphs); sort(ioSubsetGlyphIDs.begin(),ioSubsetGlyphIDs.end()); } return status; }
//now you can do dynamic programming, look thinks up on fly bool CalculateOptimalROI::stackPixel(int i, int j, UIntSet &stack) { bool inside = intersection; // start with true for intersection mode and with false for union mode //check that pixel at each place for(UIntSet::const_iterator it=stack.begin();it!=stack.end();it++) { double xd,yd; if(transfMap[*it]->transformImgCoord(xd,yd,(double)i,(double)j)) { if(o_panorama.getImage(*it).isInside(vigra::Point2D(xd,yd))) { if (!intersection) { //if found in a single image, short cut out inside=true; break; } } else { if (intersection) { //outside of at least one image - return false inside=false; break; } } } } return inside; }
UIntSet getImagesinROI (const PanoramaData& pano, const UIntSet activeImages) { UIntSet images; PanoramaOptions opts = pano.getOptions(); for (UIntSet::const_iterator it = activeImages.begin(); it != activeImages.end(); ++it) { vigra::Rect2D roi = estimateOutputROI(pano, opts, *it); if (! (roi.isEmpty())) { images.insert(*it); } } return images; }
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; }
void TrueTypeEmbeddedFontWriter::AddDependentGlyphs(UIntVector& ioSubsetGlyphIDs) { UIntSet glyphsSet; UIntVector::iterator it = ioSubsetGlyphIDs.begin(); bool hasCompositeGlyphs = false; for(;it != ioSubsetGlyphIDs.end(); ++it) hasCompositeGlyphs |= AddComponentGlyphs(*it,glyphsSet); if(hasCompositeGlyphs) { UIntSet::iterator itNewGlyphs; for(it = ioSubsetGlyphIDs.begin();it != ioSubsetGlyphIDs.end(); ++it) glyphsSet.insert(*it); ioSubsetGlyphIDs.clear(); for(itNewGlyphs = glyphsSet.begin(); itNewGlyphs != glyphsSet.end(); ++itNewGlyphs) ioSubsetGlyphIDs.push_back(*itNewGlyphs); sort(ioSubsetGlyphIDs.begin(),ioSubsetGlyphIDs.end()); } }
int main(int argc, char* argv[]) { // parse arguments const char* optstring = "o:i:l:h"; static struct option longOptions[] = { {"output", required_argument, NULL, 'o' }, {"image", required_argument, NULL, 'i' }, {"lines", required_argument, NULL, 'l' }, {"help", no_argument, NULL, 'h' }, 0 }; UIntSet cmdlineImages; int c; int optionIndex = 0; int nrLines = 5; string output; 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 'i': { int imgNr=atoi(optarg); if((imgNr==0) && (strcmp(optarg,"0")!=0)) { cerr << "Could not parse image number."; return 1; }; cmdlineImages.insert(imgNr); }; break; case 'l': nrLines=atoi(optarg); if(nrLines<1) { cerr << "Could not parse number of lines."; return 1; }; break; case ':': cerr <<"Option " << longOptions[optionIndex].name << " requires a number" << endl; return 1; break; case '?': break; default: abort (); } } if (argc - optind != 1) { cout << "Warning: " << argv[0] << " can only work on one project file at one time" << endl << endl; usage(argv[0]); return 1; }; string input=argv[optind]; // read panorama Panorama pano; ifstream prjfile(input.c_str()); if (!prjfile.good()) { cerr << "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; }; std::vector<size_t> imagesToProcess; if(cmdlineImages.size()==0) { //no image given, process all for(size_t i=0;i<pano.getNrOfImages();i++) { imagesToProcess.push_back(i); }; } else { //check, if given image numbers are valid for(UIntSet::const_iterator it=cmdlineImages.begin();it!=cmdlineImages.end();it++) { if((*it)>=0 && (*it)<pano.getNrOfImages()) { imagesToProcess.push_back(*it); }; }; }; if(imagesToProcess.size()==0) { cerr << "No image to process found" << endl << "Stopping processing" << endl; return 1; }; PT_setProgressFcn(ptProgress); PT_setInfoDlgFcn(ptinfoDlg); cout << argv[0] << " is searching for vertical lines" << endl; #if _WINDOWS //multi threading of image loading results sometime in a race condition //try to prevent this by initialisation of codecManager before //running multi threading part std::string s=vigra::impexListExtensions(); #endif #ifdef HAS_PPL size_t nrCPS=pano.getNrOfCtrlPoints(); Concurrency::parallel_for<size_t>(0,imagesToProcess.size(),[&pano,imagesToProcess,nrLines](size_t i) #else for(size_t i=0;i<imagesToProcess.size();i++) #endif { unsigned int imgNr=imagesToProcess[i]; cout << "Working on image " << pano.getImage(imgNr).getFilename() << endl; // now load and process all images vigra::ImageImportInfo info(pano.getImage(imgNr).getFilename().c_str()); HuginBase::CPVector foundLines; if(info.isGrayscale()) { foundLines=LoadGrayImageAndFindLines(info, pano, imgNr, nrLines); } else { if(info.isColor()) { //colour images foundLines=LoadImageAndFindLines(info, pano, imgNr, nrLines); } else { std::cerr << "Image " << pano.getImage(imgNr).getFilename().c_str() << " has " << info.numBands() << " channels." << std::endl << "Linefind works only with grayscale or color images." << std::endl << "Skipping image." << std::endl; }; }; #ifndef HAS_PPL cout << "Found " << foundLines.size() << " vertical lines" << endl; #endif if(foundLines.size()>0) { for(CPVector::const_iterator cpIt=foundLines.begin(); cpIt!=foundLines.end(); cpIt++) { pano.addCtrlPoint(*cpIt); }; }; } #ifdef HAS_PPL );
void OptimizePhotometricPanel::runOptimizer(const UIntSet & imgs) { DEBUG_TRACE(""); int mode = m_mode_cb->GetSelection(); // check if vignetting and response are linked, display a warning if they are not // The variables to check: 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 }; // keep a list of commands needed to fix it: std::vector<PT::PanoCommand *> commands; HuginBase::ConstImageVariableGroup & 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()) { commands.push_back(new PT::LinkLensVarsCmd(*m_pano, i, links_needed)); } } // if the list of commands is empty, all is good and we don't need a warning. if (!commands.empty()) { int ok = wxMessageBox(_("The same vignetting and response parameters should\nbe applied for all images of a lens.\nCurrently each image can have different parameters.\nLink parameters?"), _("Link parameters"), wxYES_NO | wxICON_INFORMATION); if (ok == wxYES) { // perform all the commands we stocked up earilier. for (std::vector<PT::PanoCommand *>::iterator it = commands.begin(); it != commands.end(); it++) { GlobalCmdHist::getInstance().addCommand(*it); } } else { // free all the commands, the user doesn't want them used. for (std::vector<PT::PanoCommand *>::iterator it = commands.begin(); it != commands.end(); it++) { delete *it; } } } Panorama optPano = m_pano->getSubset(imgs); PanoramaOptions opts = optPano.getOptions(); OptimizeVector optvars; if(mode==OPT_CUSTOM) { optvars = getOptimizeVector(); if (optPano.getNrOfImages() != m_pano->getNrOfImages()) { OptimizeVector o = optvars; optvars.clear(); for (UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it) { optvars.push_back(o[*it]); } } unsigned int countVar=0; for(unsigned int i=0;i<optvars.size();i++) { countVar+=optvars[i].size(); }; if(countVar==0) { wxMessageBox(_("You selected no parameters to optimize.\nTherefore optimization will be canceled."), _("Exposure optimization"), wxOK | wxICON_INFORMATION); return; }; }; std::vector<vigra_ext::PointPairRGB> m_points; // extract points only if not done previously long nPoints = 200; wxConfigBase::Get()->Read(wxT("/OptimizePhotometric/nRandomPointsPerImage"), & nPoints); // get parameters for estimation. nPoints = wxGetNumberFromUser(_("The vignetting and exposure correction is determined by analysing color values in the overlapping areas.\nTo speed up the computation, only a random subset of points is used."), _("Number of points per image"), _("Photometric optimization"), nPoints, 0, 32000, this); if (nPoints < 0) { return; } wxConfigBase::Get()->Write(wxT("/OptimizePhotometric/nRandomPointsPerImage"),nPoints); ProgressReporterDialog progress(5.0, _("Photometric alignment"), _("Loading images")); progress.Show(); nPoints = nPoints * optPano.getNrOfImages(); // get the small images std::vector<vigra::FRGBImage *> srcImgs; for (size_t i=0; i < optPano.getNrOfImages(); i++) { ImageCache::EntryPtr e = ImageCache::getInstance().getSmallImage(optPano.getImage(i).getFilename()); vigra::FRGBImage * img = new FRGBImage; if (!e) { wxMessageBox(_("Error: could not load all images"), _("Error")); return; } if (e->image8 && e->image8->width() > 0) { reduceToNextLevel(*(e->image8), *img); transformImage(vigra::srcImageRange(*img), vigra::destImage(*img), vigra::functor::Arg1()/vigra::functor::Param(255.0)); } else if (e->image16 && e->image16->width() > 0) { reduceToNextLevel(*(e->image16), *img); transformImage(vigra::srcImageRange(*img), vigra::destImage(*img), vigra::functor::Arg1()/vigra::functor::Param(65535.0)); } else { reduceToNextLevel(*(e->imageFloat), *img); } srcImgs.push_back(img); } bool randomPoints = true; extractPoints(optPano, srcImgs, nPoints, randomPoints, progress, m_points); if (m_points.size() == 0) { wxMessageBox(_("Error: no overlapping points found, Photometric optimization aborted"), _("Error")); return; } double error = 0; try { //wxBusyCursor busyc; if (mode != OPT_CUSTOM) { // run automatic optimisation // ensure that we have a valid anchor. PanoramaOptions opts = optPano.getOptions(); if (opts.colorReferenceImage >= optPano.getNrOfImages()) { opts.colorReferenceImage = 0; optPano.setOptions(opts); } smartOptimizePhotometric(optPano, PhotometricOptimizeMode(mode), m_points, progress, error); } else { // optimize selected parameters optimizePhotometric(optPano, optvars, m_points, progress, error); } } catch (std::exception & error) { wxMessageBox(_("Internal error during photometric optimization:\n") + wxString(error.what(), wxConvLocal), _("Internal error")); } progress.Close(); // display information about the estimation process: int ret = wxMessageBox(wxString::Format(_("Photometric optimization results:\nAverage difference (RMSE) between overlapping pixels: %.2f gray values (0..255)\n\nApply results?"), error*255), _("Photometric optimization finished"), wxYES_NO | wxICON_INFORMATION,this); if (ret == wxYES) { DEBUG_DEBUG("Applying vignetting corr"); // TODO: merge into a single update command const VariableMapVector & vars = optPano.getVariables(); GlobalCmdHist::getInstance().addCommand( new PT::UpdateImagesVariablesCmd(*m_pano, imgs, vars) ); //now update panorama exposure value PanoramaOptions opts = m_pano->getOptions(); opts.outputExposureValue = calcMeanExposure(*m_pano); GlobalCmdHist::getInstance().addCommand( new PT::SetPanoOptionsCmd(*m_pano, opts) ); } }
FDiff2D CalculateFOV::calcFOV(const PanoramaData& panorama) { if (panorama.getNrOfImages() == 0) { // no change return FDiff2D(panorama.getOptions().getHFOV(), panorama.getOptions().getVFOV()); } vigra::Size2D panoSize(360*2,180*2); // remap into minature pano. PanoramaOptions opts; opts.setHFOV(360); opts.setProjection(PanoramaOptions::EQUIRECTANGULAR); opts.setWidth(panoSize.x); opts.setHeight(panoSize.y); // remap image // DGSW - make sure the type is correct vigra::BImage panoAlpha(panoSize.x, panoSize.y,static_cast< unsigned char >(0)); // vigra::BImage panoAlpha(panoSize.x, panoSize.y,0); Nona::RemappedPanoImage<vigra::BImage, vigra::BImage> remapped; UIntSet activeImgs = panorama.getActiveImages(); for (UIntSet::iterator it = activeImgs.begin(); it != activeImgs.end(); ++it) { // for (unsigned int imgNr=0; imgNr < getNrOfImages(); imgNr++) { // DGSW FIXME - Unreferenced // const PanoImage & img = getImage(*it); remapped.setPanoImage(panorama.getSrcImage(*it), opts, vigra::Rect2D(0,0,panoSize.x,panoSize.y)); //remapped.setPanoImage(*this, *it, vigra::Size2D(img.getWidth(), img.getHeight()), opts); // calculate alpha channel remapped.calcAlpha(); // copy into global alpha channel. vigra::copyImageIf(vigra_ext::applyRect(remapped.boundingBox(), vigra_ext::srcMaskRange(remapped)), vigra_ext::applyRect(remapped.boundingBox(), vigra_ext::srcMask(remapped)), vigra_ext::applyRect(remapped.boundingBox(), destImage(panoAlpha))); // vigra::ImageExportInfo imge2("c:/hugin_calcfov_alpha.png"); // exportImage(vigra::srcImageRange(panoAlpha), imge2); } // get field of view FDiff2D ul,lr; bool found = false; ul.x = DBL_MAX; ul.y = DBL_MAX; lr.x = -DBL_MAX; lr.y = -DBL_MAX; for (int v=0; v< panoSize.y; v++) { for (int h=0; h < panoSize.x; h++) { if (panoAlpha(h,v)) { // pixel is valid if ( ul.x > h ) { found=true; ul.x = h; } if ( ul.y > v ) { found=true; ul.y = v; } if ( lr.x < h) { found=true; lr.x = h; } if ( lr.y < v) { found=true; lr.y = v; } } } } if (!found) { // if nothing found, return current fov return FDiff2D(panorama.getOptions().getHFOV(), panorama.getOptions().getVFOV()); } ul=ul/2.0; lr=lr/2.0; ul.x = ul.x - 180; ul.y = ul.y - 90; lr.x = lr.x - 180; lr.y = lr.y - 90; FDiff2D fov (2*std::max(fabs(ul.x), fabs(lr.x)), 2*std::max(fabs(ul.y), fabs(lr.y))); if(fov.x<40) { fov.x+=1; }; return fov; }
CPVector AutoPanoSiftMultiRow::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, int & ret_value, wxWindow *parent) { CPVector cps; if (imgs.size() < 2) { return cps; }; std::vector<wxString> keyFiles(pano.getNrOfImages()); //generate cp for every consecutive image pair unsigned int counter=0; for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ) { if(counter==imgs.size()-1) break; counter++; UIntSet ImagePair; ImagePair.clear(); ImagePair.insert(*it); it++; ImagePair.insert(*it); AutoPanoSift matcher; CPVector new_cps; new_cps.clear(); if(setting.IsTwoStepDetector()) new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, keyFiles, ret_value, parent); else new_cps=matcher.automatch(setting, pano, ImagePair, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps); if(ret_value!=0) { Cleanup(setting, pano, imgs, keyFiles, parent); return cps; }; }; // now connect all image groups // generate temporary panorama to add all found cps UIntSet allImgs; fill_set(allImgs, 0, pano.getNrOfImages()-1); Panorama optPano=pano.getSubset(allImgs); for (CPVector::const_iterator it=cps.begin();it!=cps.end();++it) optPano.addCtrlPoint(*it); CPGraph graph; createCPGraph(optPano, graph); CPComponents comps; int n = findCPComponents(graph, comps); if(n>1) { UIntSet ImagesGroups; for(unsigned int i=0;i<n;i++) { ImagesGroups.insert(*(comps[i].begin())); if(comps[i].size()>1) ImagesGroups.insert(*(comps[i].rbegin())); }; AutoPanoSift matcher; CPVector new_cps; if(setting.IsTwoStepDetector()) new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, keyFiles, ret_value, parent); else new_cps=matcher.automatch(setting, optPano, ImagesGroups, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps,&optPano); if(ret_value!=0) { Cleanup(setting, pano, imgs, keyFiles, parent); return cps; }; createCPGraph(optPano,graph); n=findCPComponents(graph, comps); }; if(n==1 && setting.GetOption()) { //next steps happens only when all images are connected; //now optimize panorama PanoramaOptions opts = pano.getOptions(); opts.setProjection(PanoramaOptions::EQUIRECTANGULAR); // calculate proper scaling, 1:1 resolution. // Otherwise optimizer distances are meaningless. opts.setWidth(30000, false); opts.setHeight(15000); optPano.setOptions(opts); int w = optPano.calcOptimalWidth(); opts.setWidth(w); opts.setHeight(w/2); optPano.setOptions(opts); //generate optimize vector, optimize only yaw and pitch OptimizeVector optvars; const SrcPanoImage & anchorImage = optPano.getImage(opts.optimizeReferenceImage); for (unsigned i=0; i < optPano.getNrOfImages(); i++) { std::set<std::string> imgopt; if(i==opts.optimizeReferenceImage) { //optimize only anchors pitch, not yaw imgopt.insert("p"); } else { // do not optimize anchor image's stack for position. if(!optPano.getImage(i).YawisLinkedWith(anchorImage)) { imgopt.insert("p"); imgopt.insert("y"); }; }; optvars.push_back(imgopt); } optPano.setOptimizeVector(optvars); // remove vertical and horizontal control points CPVector backupOldCPS = optPano.getCtrlPoints(); CPVector backupNewCPS; for (CPVector::const_iterator it = backupOldCPS.begin(); it != backupOldCPS.end(); it++) { if (it->mode == ControlPoint::X_Y) { backupNewCPS.push_back(*it); } } optPano.setCtrlPoints(backupNewCPS); // do a first pairwise optimisation step HuginBase::AutoOptimise::autoOptimise(optPano,false); HuginBase::PTools::optimize(optPano); optPano.setCtrlPoints(backupOldCPS); //and find cp on overlapping images //work only on image pairs, which are not yet connected AutoPanoSiftPreAlign matcher; CPDetectorSetting newSetting; newSetting.SetProg(setting.GetProg()); newSetting.SetArgs(setting.GetArgs()); if(setting.IsTwoStepDetector()) { newSetting.SetProgMatcher(setting.GetProgMatcher()); newSetting.SetArgsMatcher(setting.GetArgsMatcher()); }; newSetting.SetOption(true); CPVector new_cps; if(setting.IsTwoStepDetector()) new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, keyFiles, ret_value, parent); else new_cps=matcher.automatch(newSetting, optPano, imgs, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps); }; Cleanup(setting, pano, imgs, keyFiles, parent); return cps; };
CPVector AutoPanoSiftStack::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, int & ret_value, wxWindow *parent) { CPVector cps; if (imgs.size() == 0) { return cps; }; std::vector<stack_img> stack_images; HuginBase::StandardImageVariableGroups* variable_groups = new HuginBase::StandardImageVariableGroups(pano); for(UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); it++) { unsigned int stack_nr=variable_groups->getStacks().getPartNumber(*it); //check, if this stack is already in list bool found=false; unsigned int index=0; for(index=0;index<stack_images.size();index++) { found=(stack_images[index].layer_nr==stack_nr); if(found) break; }; if(!found) { //new stack stack_images.resize(stack_images.size()+1); index=stack_images.size()-1; //add new stack stack_images[index].layer_nr=stack_nr; }; //add new image unsigned int new_image_index=stack_images[index].images.size(); stack_images[index].images.resize(new_image_index+1); stack_images[index].images[new_image_index].img_nr=*it; stack_images[index].images[new_image_index].ev=pano.getImage(*it).getExposure(); }; delete variable_groups; //get image with median exposure for search with cp generator UIntSet images_layer; for(unsigned int i=0;i<stack_images.size();i++) { std::sort(stack_images[i].images.begin(),stack_images[i].images.end(),sort_img_ev); unsigned int index=0; if(stack_images[i].images[0].ev!=stack_images[i].images[stack_images[i].images.size()-1].ev) { index=stack_images[i].images.size() / 2; }; images_layer.insert(stack_images[i].images[index].img_nr); }; //generate cp for median exposure ret_value=0; if(images_layer.size()>1) { AutoPanoSift matcher; cps=matcher.automatch(setting, pano, images_layer, nFeatures, ret_value, parent); if(ret_value!=0) return cps; }; //now work on all stacks if(!setting.GetProgStack().IsEmpty()) { CPDetectorSetting stack_setting; stack_setting.SetType(CPDetector_AutoPanoSift); stack_setting.SetProg(setting.GetProgStack()); stack_setting.SetArgs(setting.GetArgsStack()); for(unsigned int i=0;i<stack_images.size();i++) { UIntSet images_stack; images_stack.clear(); for(unsigned int j=0;j<stack_images[i].images.size();j++) images_stack.insert(stack_images[i].images[j].img_nr); if(images_stack.size()>1) { AutoPanoSift matcher; CPVector new_cps=matcher.automatch(stack_setting, pano, images_stack, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps); if(ret_value!=0) return cps; }; }; } return cps; };
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, 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; }
CPVector AutoPanoSiftPreAlign::automatch(CPDetectorSetting &setting, Panorama & pano, const UIntSet & imgs, int nFeatures, std::vector<wxString> &keyFiles, int & ret_value, wxWindow *parent) { CPVector cps; if (imgs.size()<2) return cps; DEBUG_ASSERT(keyFiles.size()==pano.getNrOfImages()); vector<UIntSet> usedImages; usedImages.resize(pano.getNrOfImages()); if(setting.GetOption()) { //only work on not connected image pairs CPVector oldCps=pano.getCtrlPoints(); for(unsigned i=0;i<oldCps.size();i++) { if(oldCps[i].mode==ControlPoint::X_Y) { usedImages[oldCps[i].image1Nr].insert(oldCps[i].image2Nr); usedImages[oldCps[i].image2Nr].insert(oldCps[i].image1Nr); }; }; }; HuginBase::CalculateImageOverlap overlap(&pano); overlap.calculate(10); for(UIntSet::const_iterator it=imgs.begin();it!=imgs.end();it++) { UIntSet images; images.clear(); images.insert(*it); UIntSet::const_iterator it2=it; for(++it2;it2!=imgs.end();it2++) { //check if this image pair was yet used if(set_contains(usedImages[*it2],*it)) continue; //now check position if(overlap.getOverlap(*it,*it2)>0) { images.insert(*it2); }; }; if(images.size()<2) continue; //remember image pairs for later for(UIntSet::const_iterator img_it=images.begin();img_it!=images.end();img_it++) for(UIntSet::const_iterator img_it2=images.begin();img_it2!=images.end();img_it2++) usedImages[*img_it].insert(*img_it2); AutoPanoSift matcher; CPVector new_cps; if(setting.IsTwoStepDetector()) new_cps=matcher.automatch(setting, pano, images, nFeatures, keyFiles, ret_value, parent); else new_cps=matcher.automatch(setting, pano, images, nFeatures, ret_value, parent); if(new_cps.size()>0) AddControlPointsWithCheck(cps,new_cps); if(ret_value!=0) { Cleanup(setting, pano, imgs, keyFiles, parent); return cps; }; }; Cleanup(setting, pano, imgs, keyFiles, parent); return cps; };
void CenterHorizontally::centerHorizontically(PanoramaData& panorama) { vigra::Size2D panoSize(360,180); // remap into minature pano. PanoramaOptions opts; opts.setHFOV(360); opts.setProjection(PanoramaOptions::EQUIRECTANGULAR); opts.setWidth(360); opts.setHeight(180); // remap image vigra::BImage panoAlpha(panoSize); Nona::RemappedPanoImage<vigra::BImage, vigra::BImage> remapped; // use selected images. const UIntSet allActiveImgs(panorama.getActiveImages()); if (allActiveImgs.empty()) { // do nothing if there are no images return; } //only check unlinked images UIntSet activeImgs; for (UIntSet::const_iterator it = allActiveImgs.begin(); it!= allActiveImgs.end(); ++it) { const SrcPanoImage & img=panorama.getImage(*it); bool consider=true; if(img.YawisLinked()) { for(UIntSet::const_iterator it2=activeImgs.begin(); it2!=activeImgs.end(); ++it2) { if(img.YawisLinkedWith(panorama.getSrcImage(*it2))) { consider=false; break; }; }; }; if(consider) activeImgs.insert(*it); }; for (UIntSet::iterator it = activeImgs.begin(); it != activeImgs.end(); ++it) { remapped.setPanoImage(panorama.getSrcImage(*it), opts, vigra::Rect2D(0,0,360,180)); // calculate alpha channel remapped.calcAlpha(); // copy into global alpha channel. vigra::copyImageIf(vigra_ext::applyRect(remapped.boundingBox(), vigra_ext::srcMaskRange(remapped)), vigra_ext::applyRect(remapped.boundingBox(), vigra_ext::srcMask(remapped)), vigra_ext::applyRect(remapped.boundingBox(), destImage(panoAlpha))); } // get field of view std::vector<int> borders; bool colOccupied = false; for (int h=0; h < 360; h++) { bool curColOccupied = false; for (int v=0; v< 180; v++) { if (panoAlpha(h,v)) { // pixel is valid curColOccupied = true; } } if ((colOccupied && !curColOccupied) || (!colOccupied && curColOccupied)) { // change in position, save point. borders.push_back(h-180); colOccupied = curColOccupied; } } int lastidx = borders.size() -1; if (lastidx == -1) { // empty pano return; } if (colOccupied) { // we have reached the right border, and the pano is still valid // shift right fragments by 360 deg // |11 2222| -> | 222211 | std::vector<int> newBorders; newBorders.push_back(borders[lastidx]); for (int i = 0; i < lastidx; i++) { newBorders.push_back(borders[i]+360); } borders = newBorders; } const double dYaw=(borders[0] + borders[lastidx])/2; // apply yaw shift, takes also translation parameters into account RotatePanorama(panorama, -dYaw, 0, 0).run(); }