wxPanoCommand.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00027 #include "hugin_config.h"
00028 
00029 #include "panoinc_WX.h"
00030 #include "panoinc.h"
00031 #include <wx/window.h> 
00032 #include "wxPlatform.h"
00033 #include "LensTools.h"
00034 
00035 #include "wxImageCache.h"
00036 #include "platform.h"
00037 #include "wxPanoCommand.h"
00038 #include "HFOVDialog.h"
00039 #include <panodata/OptimizerSwitches.h>
00040 
00041 #include <vigra/cornerdetection.hxx>
00042 #include <vigra/localminmax.hxx>
00043 #include <panodata/StandardImageVariableGroups.h>
00044 
00045 #include <hugin_utils/alphanum.h>
00046 
00047 #ifdef HUGIN_HSI
00048 #include "hugin_script_interface/hpi.h"
00049 #endif
00050 
00051 namespace PanoCommand
00052 {
00053 
00054 bool wxAddCtrlPointGridCmd::processPanorama(HuginBase::Panorama& pano)
00055 {
00056     // TODO: rewrite, and use same function for modular image creation.
00057     const HuginBase::SrcPanoImage & i1 = pano.getImage(img1);
00058     const HuginBase::SrcPanoImage & i2 = pano.getImage(img1);
00059 
00060     // run both images through the harris corner detector
00061     ImageCache::EntryPtr eptr = ImageCache::getInstance().getSmallImage(i1.getFilename());
00062 
00063     vigra::BImage leftImg(eptr->get8BitImage()->size());
00064 
00065     vigra::GreenAccessor<vigra::RGBValue<vigra::UInt8> > ga;
00066     vigra::copyImage(srcImageRange(*(eptr->get8BitImage()), ga ),
00067                      destImage(leftImg));
00068 
00069     double scale = i1.getSize().width() / (double) leftImg.width();
00070 
00071     //const vigra::BImage & leftImg = ImageCache::getInstance().getPyramidImage(
00072     //    i1.getFilename(),1);
00073 
00074     vigra::BImage leftCorners(leftImg.size());
00075     vigra::FImage leftCornerResponse(leftImg.size());
00076 
00077     // empty corner image
00078     leftCorners.init(0);
00079 
00080     DEBUG_DEBUG("running corner detector threshold: " << cornerThreshold << "  scale: " << scale );
00081 
00082     // find corner response at scale scale
00083     vigra::cornerResponseFunction(srcImageRange(leftImg),
00084         destImage(leftCornerResponse),
00085         scale);
00086 
00087     //    saveScaledImage(leftCornerResponse,"corner_response.png");
00088     DEBUG_DEBUG("finding local maxima");
00089     // find local maxima of corner response, mark with 1
00090     vigra::localMaxima(vigra::srcImageRange(leftCornerResponse), vigra::destImage(leftCorners), 255);
00091 
00092 //    exportImage(srcImageRange(leftCorners), vigra::ImageExportInfo("c:/corner_response_maxima.png"));
00093 
00094     DEBUG_DEBUG("thresholding corner response");
00095     // threshold corner response to keep only strong corners (above 400.0)
00096     vigra::transformImage(vigra::srcImageRange(leftCornerResponse), vigra::destImage(leftCornerResponse),
00097         vigra::Threshold<double, double>(
00098         cornerThreshold, DBL_MAX, 0.0, 1.0));
00099 
00100     vigra::combineTwoImages(srcImageRange(leftCorners), srcImage(leftCornerResponse),
00101         destImage(leftCorners), std::multiplies<float>());
00102 
00103 //    exportImage(srcImageRange(leftCorners), vigra::ImageExportInfo("c:/corner_response_threshold.png"));
00104 
00105     // create transform from img1 -> sphere
00106     HuginBase::PTools::Transform img1ToSphere;
00107     HuginBase::PTools::Transform sphereToImg2;
00108 
00109     HuginBase::PanoramaOptions opts;
00110     opts.setProjection(HuginBase::PanoramaOptions::EQUIRECTANGULAR);
00111     opts.setHFOV(360);
00112     opts.setWidth(360);
00113     opts.setVFOV(180);
00114 
00115     img1ToSphere.createInvTransform(pano, img1, opts);
00116     sphereToImg2.createTransform(pano, img2, opts);
00117 
00118 
00119     int border = 5;
00120     double sphx, sphy;
00121     double img2x, img2y;
00122     // need to scale the images.
00123     // sample grid on img1 and try to add ctrl points
00124     for (unsigned int x=0; x < (unsigned int)leftImg.width(); x++ ) {
00125         for (unsigned int y=0; y < (unsigned int)leftImg.height(); y++) {
00126             if (leftCorners(x,y) > 0) {
00127                 img1ToSphere.transformImgCoord(sphx, sphy, scale*x, scale*y);
00128                 sphereToImg2.transformImgCoord(img2x, img2y, sphx, sphy);
00129                 // check if it is inside..
00130                 if (   img2x > border && img2x < i2.getWidth() - border
00131                     && img2y > border && img2y < i2.getHeight() - border )
00132                 {
00133                     // add control point
00134                     HuginBase::ControlPoint p(img1, scale*x, scale*y, img2, img2x, img2y);
00135                     pano.addCtrlPoint(p);
00136                 }
00137             }
00138         }
00139     }
00140     return true;
00141 }
00142 
00143 void applyColorBalanceValue(HuginBase::SrcPanoImage& srcImg, HuginBase::Panorama& pano)
00144 {
00145     double redBal=1;
00146     double blueBal=1;
00147     if(pano.getNrOfImages()>=1)
00148     {
00149         const HuginBase::SrcPanoImage &anchor = pano.getImage(pano.getOptions().colorReferenceImage);
00150         // use EXIF Red/BlueBalance data only if image and anchor image are from the same camera
00151         if(srcImg.getExifMake() == anchor.getExifMake() &&
00152             srcImg.getExifModel() == anchor.getExifModel())
00153         {
00154             double redBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifRedBalance();
00155             double blueBalanceAnchor=pano.getImage(pano.getOptions().colorReferenceImage).getExifBlueBalance();
00156             if(fabs(redBalanceAnchor)<1e-2)
00157             {
00158                 redBalanceAnchor=1;
00159             };
00160             if(fabs(blueBalanceAnchor)<1e-2)
00161             {
00162                 blueBalanceAnchor=1;
00163             };
00164             redBal=fabs(srcImg.getExifRedBalance()/redBalanceAnchor);
00165             blueBal=fabs(srcImg.getExifBlueBalance()/blueBalanceAnchor);
00166             if(redBal<1e-2)
00167             {
00168                 redBal=1;
00169             };
00170             if(blueBal<1e-2)
00171             {
00172                 blueBal=1;
00173             };
00174         };
00175     }
00176     srcImg.setWhiteBalanceRed(redBal);
00177     srcImg.setWhiteBalanceBlue(blueBal);
00178 };
00179 
00180 void copySrcImageExif(HuginBase::SrcPanoImage& destImg, HuginBase::SrcPanoImage srcImg)
00181 {
00182     destImg.setExifExposureTime(srcImg.getExifExposureTime());
00183     destImg.setExifAperture(srcImg.getExifAperture());
00184     destImg.setExifExposureMode(srcImg.getExifExposureMode());
00185     destImg.setExifISO(srcImg.getExifISO());
00186     destImg.setExifMake(srcImg.getExifMake());
00187     destImg.setExifModel(srcImg.getExifModel());
00188     destImg.setExifLens(srcImg.getExifLens());
00189     destImg.setExifOrientation(srcImg.getExifOrientation());
00190     destImg.setExifFocalLength(srcImg.getExifFocalLength());
00191     destImg.setExifFocalLength35(srcImg.getExifFocalLength35());
00192     destImg.setExifCropFactor(srcImg.getExifCropFactor());
00193     destImg.setExifDistance(srcImg.getExifDistance());
00194     destImg.setExifDate(srcImg.getExifDate());
00195     destImg.setExifRedBalance(srcImg.getExifRedBalance());
00196     destImg.setExifBlueBalance(srcImg.getExifBlueBalance());
00197     destImg.setFileMetadata(srcImg.getFileMetadata());
00198 };
00199 
00200 bool getLensDataFromUser(wxWindow * parent, HuginBase::SrcPanoImage & srcImg)
00201 {
00202     // display lens dialog
00203     HFOVDialog dlg(parent, srcImg);
00204     dlg.CenterOnParent();
00205     int ret = dlg.ShowModal();
00206     if (ret == wxID_OK)
00207     {
00208         // assume a cancel dialog.
00209         srcImg = dlg.GetSrcImage();
00210         if (dlg.GetCropFactor() <= 0)
00211         {
00212             srcImg.setCropFactor(1);
00213         }
00214         return true;
00215     }
00216     else {
00217         return false;
00218     }
00219 }
00220 
00221 bool wxAddImagesCmd::processPanorama(HuginBase::Panorama& pano)
00222 {
00223     // check if the files should be sorted by date
00224     long sort = wxConfigBase::Get()->Read(wxT("General/SortNewImgOnAdd"), HUGIN_GUI_SORT_NEW_IMG_ON_ADD);
00225 
00226     switch (sort) {
00227         case 1:
00228                 // sort by filename
00229             std::sort(files.begin(), files.end(), doj::alphanum_less());
00230             break;
00231         case 2:
00232                 // sort by date
00233             std::sort(files.begin(), files.end(), FileIsNewer());
00234             break;
00235         default:
00236                 // no or unknown sort method
00237             break;
00238     }
00239 
00240     std::vector<std::string>::const_iterator it;
00241     HuginBase::Lens lens;
00242     HuginBase::SrcPanoImage srcImg;
00243     HuginBase::SrcPanoImage srcImgExif;
00244     HuginBase::StandardImageVariableGroups variable_groups(pano);
00245     HuginBase::ImageVariableGroup & lenses = variable_groups.getLenses();
00246     const size_t oldImgCount = pano.getNrOfImages();
00247 
00248     // load additional images...
00249     for (it = files.begin(); it != files.end(); ++it) {
00250         const std::string &filename = *it;
00251         wxString fname(filename.c_str(), HUGIN_CONV_FILENAME);
00252 
00253         // try to read settings automatically.
00254         srcImg.setFilename(filename);
00255         try
00256         {
00257             vigra::ImageImportInfo info(filename.c_str());
00258             if(info.width()==0 || info.height()==0)
00259             {
00260                 wxMessageBox(wxString::Format(_("Could not decode image:\n%s\nAbort"), fname.c_str()), _("Unsupported image file format"));
00261                 return false;
00262             };
00263             srcImg.setSize(info.size());
00264             const std::string pixelType=info.getPixelType();
00265             // refuse black/white images
00266             if (pixelType == "BILEVEL")
00267             {
00268                 wxMessageBox(wxString::Format(_("File \"%s\" is a black/white image.\nHugin does not support this image type. Skipping this image.\nConvert image to grayscale image and try loading again."), fname.c_str()),
00269                     _("Warning"), wxOK|wxICON_EXCLAMATION);
00270                 continue;
00271             }
00272             // check if images is grayscale or RGB image, maybe with alpha channel
00273             // reject CMYK or other images
00274             const int bands = info.numBands();
00275             const int extraBands = info.numExtraBands();
00276             if (bands != 1 && bands != 3 && !(bands == 2 && extraBands == 1) && !(bands == 4 && extraBands == 1))
00277             {
00278                 wxMessageBox(wxString::Format(_("Hugin supports only grayscale and RGB images (without and with alpha channel).\nBut file \"%s\" has %d channels and %d extra channels (probably alpha channels).\nHugin does not support this image type. Skipping this image.\nConvert this image to grayscale or RGB image and try loading again."), fname.c_str(), bands, extraBands),
00279                     _("Warning"), wxOK | wxICON_EXCLAMATION);
00280                 continue;
00281             };
00282             if (pano.getNrOfImages() == 0)
00283             {
00284                 pano.setNrOfBands(bands - extraBands);
00285             };
00286             if (pano.getNrOfBands() != bands - extraBands)
00287             {
00288                 wxString s(_("Hugin supports only grayscale or RGB images (without and with alpha channel)."));
00289                 s.Append(wxT("\n"));
00290                 if (pano.getNrOfBands() == 3)
00291                 {
00292                     s.Append(wxString::Format(_("File \"%s\" is a grayscale image, but other images in project are color images."), fname.c_str()));
00293                 }
00294                 else
00295                 {
00296                     s.Append(wxString::Format(_("File \"%s\" is a color image, but other images in project are grayscale images."), fname.c_str()));
00297                 };
00298                 s.Append(wxT("\n"));
00299                 s.Append(_("Hugin does not support this mixing. Skipping this image.\nConvert this image to grayscale or RGB image respectively and try loading again."));
00300                 wxMessageBox(s, _("Warning"), wxOK | wxICON_EXCLAMATION);
00301                 continue;
00302             };
00303             if((pixelType=="UINT8") || (pixelType=="UINT16") || (pixelType=="INT16"))
00304                 srcImg.setResponseType(HuginBase::SrcPanoImage::RESPONSE_EMOR);
00305             else
00306                 srcImg.setResponseType(HuginBase::SrcPanoImage::RESPONSE_LINEAR);
00307             if (pano.getNrOfImages() > 0)
00308             {
00309                 const std::string newICCProfileDesc = hugin_utils::GetICCDesc(info.getICCProfile());
00310                 if (newICCProfileDesc != pano.getICCProfileDesc())
00311                 {
00312                     // icc profiles does not match
00313                     wxString warning;
00314                     if (newICCProfileDesc.empty())
00315                     { 
00316                         warning = wxString::Format(_("File \"%s\" has no embedded icc profile, but other images in project have profile \"%s\" embedded."), fname.c_str(), wxString(pano.getICCProfileDesc().c_str(), wxConvLocal).c_str());
00317                     }
00318                     else
00319                     {
00320                         if (pano.getICCProfileDesc().empty())
00321                         {
00322                             warning = wxString::Format(_("File \"%s\" has icc profile \"%s\" embedded, but other images in project have no embedded color profile."), fname.c_str(), wxString(newICCProfileDesc.c_str(), wxConvLocal).c_str());
00323                         }
00324                         else
00325                         {
00326                             warning = wxString::Format(_("File \"%s\" has icc profile \"%s\" embedded, but other images in project have color profile \"%s\" embedded."), fname.c_str(), wxString(newICCProfileDesc.c_str(), wxConvLocal).c_str(), wxString(pano.getICCProfileDesc().c_str(), wxConvLocal).c_str());
00327                         }
00328                     }
00329                     warning.Append(wxT("\n"));
00330                     warning.Append(_("Hugin expects all images in the same color profile.\nPlease convert all images to same color profile and try again."));
00331                     wxMessageBox(warning, _("Warning"), wxOK | wxICON_EXCLAMATION);
00332                     continue;
00333                 }
00334             }
00335             else
00336             {
00337                 // remember icc profile name
00338                 if (!info.getICCProfile().empty())
00339                 {
00340                     pano.setICCProfileDesc(hugin_utils::GetICCDesc(info.getICCProfile()));
00341                 }
00342                 else
00343                 {
00344                     pano.setICCProfileDesc("");
00345                 };
00346             }
00347         }
00348         catch(std::exception & e)
00349         {
00350             std::cerr << "ERROR: caught exception: " << e.what() << std::endl;
00351             std::cerr << "Could not get pixel type for file " << filename << std::endl;
00352              wxMessageBox(wxString::Format(_("Could not decode image:\n%s\nAbort"), fname.c_str()), _("Unsupported image file format"));
00353              return false;
00354         };
00355         bool ok = srcImg.readEXIF();
00356         if(ok)
00357         {
00358             ok = srcImg.applyEXIFValues();
00359             if (srcImg.getProjection() != HuginBase::BaseSrcPanoImage::EQUIRECTANGULAR)
00360             {
00361                 // if projection is equirectangular, we loaded info from gpano tags
00362                 // in this case we don't need to look up the database
00363                 srcImg.readProjectionFromDB();
00364             };
00365         };
00366         // save EXIF data for later to prevent double loading of EXIF data
00367         srcImgExif=srcImg;
00368         applyColorBalanceValue(srcImg, pano);
00369         double redBal=srcImg.getWhiteBalanceRed();
00370         double blueBal=srcImg.getWhiteBalanceBlue();
00371         if(srcImg.getCropFactor()<0.1)
00372         {
00373             srcImg.readCropfactorFromDB();
00374             ok=(srcImg.getExifFocalLength()>0 && srcImg.getCropFactor()>0.1);
00375         };
00376         if (! ok ) {
00377                 // search for image with matching size and exif data
00378                 // and re-use it.
00379                 bool added = false;
00380                 for (unsigned int i=0; i < pano.getNrOfImages(); i++) {
00381                     HuginBase::SrcPanoImage other = pano.getSrcImage(i);
00382                     if ( other.getSize() == srcImg.getSize() &&
00383                          other.getExifModel() == srcImg.getExifModel() &&
00384                          other.getExifMake()  == srcImg.getExifMake() &&
00385                          other.getExifFocalLength() == srcImg.getExifFocalLength()
00386                        )
00387                     {
00388                         double ev = srcImg.getExposureValue();
00389                         srcImg = pano.getSrcImage(i);
00390                         srcImg.setFilename(filename);
00391                         srcImg.deleteAllMasks();
00392                         copySrcImageExif(srcImg, srcImgExif);
00393                         // add image
00394                         int imgNr = pano.addImage(srcImg);
00395                         variable_groups.update();
00396                         lenses.switchParts(imgNr, lenses.getPartNumber(i));
00397                         lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_ExposureValue, i);
00398                         srcImg.setExposureValue(ev);
00399                         lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceRed, i);
00400                         lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceBlue, i);
00401                         applyColorBalanceValue(srcImg, pano);
00402                         pano.setSrcImage(imgNr, srcImg);
00403                         added=true;
00404                         break;
00405                     }
00406                 }
00407                 if (added) continue;
00408         }
00409         int matchingLensNr=-1;
00410         // if no similar image found, ask user
00411         if (! ok) {
00412             if (!getLensDataFromUser(wxGetActiveWindow(), srcImg)) {
00413                 // assume a standart lens
00414                 srcImg.setHFOV(50);
00415                 srcImg.setCropFactor(1);
00416             }
00417         }
00418 
00419         // check the image hasn't disappeared on us since the HFOV dialog was
00420         // opened
00421         wxString fn(srcImg.getFilename().c_str(),HUGIN_CONV_FILENAME);
00422         if (!wxFileName::FileExists(fn)) {
00423             DEBUG_INFO("Image: " << fn.mb_str() << " has disappeared, skipping...");
00424             continue;
00425         }
00426 
00427         // FIXME: check if the exif information
00428         // indicates this image matches a already used lens
00429         variable_groups.update();
00430         double ev = 0;
00431         bool set_exposure = false;
00432         for (unsigned int i=0; i < pano.getNrOfImages(); i++) {
00433             HuginBase::SrcPanoImage other = pano.getSrcImage(i);
00434             if (other.getExifFocalLength()>0) {
00435                 if (other.getSize() == srcImg.getSize()
00436                     && other.getExifModel() == srcImg.getExifModel()
00437                     && other.getExifMake()  == srcImg.getExifMake()
00438                     && other.getExifFocalLength() == srcImg.getExifFocalLength()
00439                    )
00440                 {
00441                     matchingLensNr = lenses.getPartNumber(i);
00442                     // copy data from other image, just keep
00443                     // the file name and reload the exif data (for exposure)
00444                     ev = srcImg.getExposureValue();
00445                     redBal = srcImg.getWhiteBalanceRed();
00446                     blueBal = srcImg.getWhiteBalanceBlue();
00447                     set_exposure = true;
00448                     srcImg = pano.getSrcImage(i);
00449                     srcImg.setFilename(filename);
00450                     srcImg.deleteAllMasks();
00451                     copySrcImageExif(srcImg, srcImgExif);
00452                     srcImg.setExposureValue(ev);
00453                     srcImg.setWhiteBalanceRed(redBal);
00454                     srcImg.setWhiteBalanceBlue(blueBal);
00455                     break;
00456                 }
00457             }
00458             else
00459             {
00460                 // no exiv information, just check image size.
00461                 if (other.getSize() == srcImg.getSize() )
00462                 {
00463                     matchingLensNr = lenses.getPartNumber(i);
00464                     // copy data from other image, just keep
00465                     // the file name
00466                     srcImg = pano.getSrcImage(i);
00467                     srcImg.setFilename(filename);
00468                     srcImg.deleteAllMasks();
00469                     copySrcImageExif(srcImg, srcImgExif);
00470                     break;
00471                 }
00472             }
00473         }
00474 
00475         // If matchingLensNr == -1 still, we haven't found a good lens to use.
00476         // We shouldn't attach the image to a lens in this case, it will have
00477         // its own new lens.
00478         int imgNr = pano.addImage(srcImg);
00479         variable_groups.update();
00480         if (matchingLensNr != -1)
00481         {
00482             lenses.switchParts(imgNr, matchingLensNr);
00483             // unlink and set exposure value, if wanted.
00484             if (set_exposure)
00485             {
00486                 lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_ExposureValue, imgNr);
00487                 lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceRed, imgNr);
00488                 lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceBlue, imgNr);
00489                 //don't link image size, this will foul the photometric optimizer
00490                 lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_Size, imgNr);
00492                 HuginBase::SrcPanoImage t = pano.getSrcImage(imgNr);
00493                 t.setExposureValue(ev);
00494                 t.setWhiteBalanceRed(redBal);
00495                 t.setWhiteBalanceBlue(blueBal);
00496                 pano.setSrcImage(imgNr, t);
00497             }
00498         }
00499         if (imgNr == 0) {
00500             // get initial value for output exposure
00501             HuginBase::PanoramaOptions opts = pano.getOptions();
00502             opts.outputExposureValue = srcImg.getExposureValue();
00503             pano.setOptions(opts);
00504             // set the exposure, but there isn't anything to link to so don't try unlinking.
00505             // links are made by default when adding new images.
00506             if (set_exposure)
00507             {
00509                 HuginBase::SrcPanoImage t = pano.getSrcImage(imgNr);
00510                 t.setExposureValue(ev);
00511                 t.setWhiteBalanceRed(redBal);
00512                 t.setWhiteBalanceBlue(blueBal);
00513                 pano.setSrcImage(imgNr, t);
00514             }
00515         }
00516     }
00517     if (pano.hasPossibleStacks())
00518     {
00519         wxString message;
00520         if (oldImgCount == 0)
00521         {
00522             // all images added
00523             message = _("Hugin has image stacks detected in the added images and will assign corresponding stack numbers to the images.");
00524         }
00525         else
00526         {
00527             message = _("Hugin has image stacks detected in the whole project. Stack numbers will be re-assigned on base of this detection. Existing stack assignments will be overwritten.");
00528         };
00529         message.append(wxT("\n"));
00530         message.append(_("Should the position of images in each stack be linked?"));
00531         wxMessageDialog dialog(wxGetActiveWindow(), message,
00532 #ifdef _WIN32
00533             _("Hugin"),
00534 #else
00535             wxT(""),
00536 #endif
00537             wxICON_EXCLAMATION | wxYES_NO | wxCANCEL);
00538         dialog.SetExtendedMessage(_("When shooting bracketed image stacks from a sturdy tripod the position of the images in each stack can be linked to help Hugin to process the panorama. But if the images in each stack require a fine tune of the position (e. g. when shooting hand held), then don't link the position."));
00539         if (oldImgCount == 0)
00540         {
00541             dialog.SetYesNoCancelLabels(_("Link position"), _("Don't link position"), _("Don't assign stacks"));
00542         }
00543         else
00544         {
00545             dialog.SetYesNoCancelLabels(_("Link position"), _("Don't link position"), _("Keep existing stacks"));
00546         };
00547         switch (dialog.ShowModal())
00548         {
00549             case wxID_OK:
00550             case wxID_YES:
00551                 pano.linkPossibleStacks(true);
00552                 break;
00553             case wxID_NO:
00554                 pano.linkPossibleStacks(false);
00555                 break;
00556         };
00557     }
00558     else
00559     {
00560         bool hasStacks = false;
00561         for (size_t i = 0; i<pano.getNrOfImages(); i++)
00562         {
00563             if (pano.getImage(i).StackisLinked())
00564             {
00565                 hasStacks = true;
00566                 break;
00567             };
00568         };
00569         wxConfigBase* config = wxConfigBase::Get();
00570         bool showExposureWarning = config->Read(wxT("/ShowExposureWarning"), 1l) == 1l;
00571         if (!hasStacks && pano.getMaxExposureDifference() > 2 && showExposureWarning)
00572         {
00573             wxDialog dlg;
00574             wxXmlResource::Get()->LoadDialog(&dlg, NULL, wxT("warning_exposure_dlg"));
00575             if (dlg.ShowModal() == wxID_OK)
00576             {
00577                 if (XRCCTRL(dlg, "dont_show_again_checkbox", wxCheckBox)->GetValue())
00578                 {
00579                     config->Write(wxT("/ShowExposureWarning"), 0l);
00580                 }
00581                 else
00582                 {
00583                     config->Write(wxT("/ShowExposureWarning"), 1l);
00584                 };
00585                 config->Flush();
00586             }
00587         };
00588     };
00589     return true;
00590 }
00591 
00592 
00593 bool wxLoadPTProjectCmd::processPanorama(HuginBase::Panorama& pano)
00594 {
00595     HuginBase::PanoramaMemento newPano;
00596     int ptoVersion = 0;
00597     std::ifstream in(filename.c_str());
00598     if (newPano.loadPTScript(in, ptoVersion, prefix))
00599     {
00600         pano.setMemento(newPano);
00601         HuginBase::PanoramaOptions opts = pano.getOptions();
00602         // always reset to TIFF_m ...
00603         opts.outputFormat = HuginBase::PanoramaOptions::TIFF_m;
00604         // get enblend and enfuse options from preferences
00605         if (ptoVersion < 2)
00606         {
00607             // no options stored in file, use default arguments in config file
00608             opts.enblendOptions = wxConfigBase::Get()->Read(wxT("/Enblend/Args"), wxT(HUGIN_ENBLEND_ARGS)).mb_str(wxConvLocal);
00609             opts.enfuseOptions = wxConfigBase::Get()->Read(wxT("/Enfuse/Args"), wxT(HUGIN_ENFUSE_ARGS)).mb_str(wxConvLocal);
00610         }
00611         // Set the nona gpu flag base on what is in preferences as it is not
00612         // stored in the file.
00613         opts.remapUsingGPU = wxConfigBase::Get()->Read(wxT("/Nona/UseGPU"),HUGIN_NONA_USEGPU) == 1;
00614         pano.setOptions(opts);
00615 
00616         HuginBase::StandardImageVariableGroups variableGroups(pano);
00617         HuginBase::ImageVariableGroup & lenses = variableGroups.getLenses();
00618 
00619         unsigned int nImg = pano.getNrOfImages();
00620         wxString basedir;
00621         bool autopanoSiftFile=false;
00622         HuginBase::SrcPanoImage autopanoSiftRefImg;
00623         for (unsigned int i = 0; i < nImg; i++) {
00624             wxFileName fname(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
00625             while (! fname.FileExists()){
00626                         // Is file in the new path
00627                 if (basedir != wxT("")) {
00628                     DEBUG_DEBUG("Old filename: " << pano.getImage(i).getFilename());
00629                     std::string fn = hugin_utils::stripPath(pano.getImage(i).getFilename());
00630                     DEBUG_DEBUG("Old filename, without path): " << fn);
00631                     wxString newname(fn.c_str(), HUGIN_CONV_FILENAME);
00632                             // GetFullName does only work with local paths (not compatible across platforms)
00633 //                            wxString newname = fname.GetFullName();
00634                     fname.AssignDir(basedir);
00635                     fname.SetFullName(newname);
00636                     DEBUG_TRACE("filename with new path: " << fname.GetFullPath().mb_str(wxConvLocal));
00637                     if (fname.FileExists()) {
00638                         pano.setImageFilename(i, (const char *)fname.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
00639                         DEBUG_TRACE("New filename set: " << fname.GetFullPath().mb_str(wxConvLocal));
00640                                 // TODO - set pano dirty flag so that new paths are saved
00641                         continue;
00642                     }
00643                 }
00644 
00645                 wxMessageBox(wxString::Format(_("The project file \"%s\" refers to image \"%s\" which was not found.\nPlease manually select the correct image."), filename, fname.GetFullPath()), _("Image file not found"));
00646 
00647                 if (basedir == wxT("")) {
00648                     basedir = fname.GetPath();
00649                 }
00650 
00651                 // open file dialog
00652                 wxFileDialog dlg(wxGetActiveWindow(), wxString::Format(_("Select image %s"), fname.GetFullName()),
00653                                  basedir, fname.GetFullName(),
00654                                  GetFileDialogImageFilters(), wxFD_OPEN  | wxFD_FILE_MUST_EXIST | wxFD_PREVIEW, wxDefaultPosition);
00655                 dlg.SetDirectory(basedir);
00656                 if (dlg.ShowModal() == wxID_OK) {
00657                     pano.setImageFilename(i, (const char *)dlg.GetPath().mb_str(HUGIN_CONV_FILENAME));
00658                             // save used path
00659                     basedir = dlg.GetDirectory();
00660                     DEBUG_INFO("basedir is: " << basedir.mb_str(wxConvLocal));
00661                 } else {
00662                     HuginBase::PanoramaMemento emptyPano;
00663                     pano.setMemento(emptyPano);
00664                             // set an empty panorama
00665                     return true;
00666                 }
00667                 fname.Assign(dlg.GetPath());
00668             }
00669             // check if image size is correct
00670             HuginBase::SrcPanoImage srcImg = pano.getSrcImage(i);
00671             //
00672             vigra::ImageImportInfo imginfo(srcImg.getFilename().c_str());
00673             if (srcImg.getSize() != imginfo.size()) {
00674                 // adjust size properly.
00675                 srcImg.resize(imginfo.size());
00676             }
00677             // check if script contains invalid HFOV
00678             double hfov = pano.getImage(i).getHFOV();
00679             if (pano.getImage(i).getProjection() == HuginBase::SrcPanoImage::RECTILINEAR
00680                 && hfov >= 180 && autopanoSiftFile == false)
00681             {
00682                 autopanoSiftFile = true;
00683                 // something is wrong here, try to read from exif data (all images)
00684                 bool ok = srcImg.readEXIF();
00685                 if(ok) {
00686                     ok = srcImg.applyEXIFValues();
00687                 };
00688                 if (! ok) {
00689                     getLensDataFromUser(wxGetActiveWindow(), srcImg);
00690                 }
00691                 autopanoSiftRefImg = srcImg;
00692             }
00693             else 
00694             {
00695                 // load exif data
00696                 srcImg.readEXIF();
00697                 if (autopanoSiftFile)
00698                 {
00699                 // need to copy the lens parameters from the first lens.
00700                     srcImg.setHFOV(autopanoSiftRefImg.getHFOV());
00701                 };
00702             };
00703             // remember icc profile, only from first image
00704             if (i == 0)
00705             {
00706                 pano.setNrOfBands(imginfo.numBands() - imginfo.numExtraBands());
00707                 pano.setICCProfileDesc(hugin_utils::GetICCDesc(imginfo.getICCProfile()));
00708             }
00709             pano.setSrcImage(i, srcImg);
00710         }
00711         // Link image projection across each lens, since it is not saved.
00712         const HuginBase::UIntSetVector imgSetLens = lenses.getPartsSet();
00713         for (size_t i = 0; i < imgSetLens.size(); ++i)
00714         {
00715             const HuginBase::UIntSet imgLens = imgSetLens[i];
00716             if (imgLens.size()>1)
00717             {
00718                 HuginBase::UIntSet::const_iterator it = imgLens.begin();
00719                 const size_t img1 = *it;
00720                 ++it;
00721                 do
00722                 {
00723                     pano.linkImageVariableProjection(img1, *it);
00724                     ++it;
00725                 } while (it != imgLens.end());
00726             };
00727         };
00728     } else {
00729         DEBUG_ERROR("could not load panotools script");
00730     }
00731     in.close();
00732 
00733     // Verify control points are valid
00734     // loop through entire list of points, confirming they are inside the
00735     // bounding box of their images
00736     const HuginBase::CPVector & oldCPs = pano.getCtrlPoints();
00737     HuginBase::CPVector goodCPs;
00738     int bad_cp_count = 0;
00739     for (HuginBase::CPVector::const_iterator it = oldCPs.begin();
00740             it != oldCPs.end(); ++it)
00741     {
00742         HuginBase::ControlPoint point = *it;
00743         const HuginBase::SrcPanoImage & img1 = pano.getImage(point.image1Nr);
00744         const HuginBase::SrcPanoImage & img2 = pano.getImage(point.image2Nr);
00745         if (0 > point.x1 || point.x1 > img1.getSize().x ||
00746             0 > point.y1 || point.y1 > img1.getSize().y ||
00747             0 > point.x2 || point.x2 > img2.getSize().x ||
00748             0 > point.y2 || point.y2 > img2.getSize().y)
00749         {
00750             bad_cp_count++;
00751         } else
00752         {
00753             goodCPs.push_back(point);
00754         }
00755     }
00756 
00757     if (bad_cp_count > 0)
00758     {
00759         wxString errMsg = wxString::Format(_("%d invalid control point(s) found.\n\nPress OK to remove."), bad_cp_count);
00760         wxMessageBox(errMsg, _("Error Detected"), wxICON_ERROR);
00761         pano.setCtrlPoints(goodCPs);
00762     }
00763 
00764     // check stacks and warn users in case
00765     CheckLensStacks(&pano, false);
00766     // Update control point error values
00767     HuginBase::PTools::calcCtrlPointErrors(pano);
00768     if(markAsOptimized)
00769     {
00770         pano.markAsOptimized();
00771     };
00772     return true;
00773 }
00774 
00775 bool wxNewProjectCmd::processPanorama(HuginBase::Panorama& pano)
00776 {
00777     pano.reset();
00778 
00779     // Setup pano with options from preferences
00780     HuginBase::PanoramaOptions opts = pano.getOptions();
00781     wxConfigBase* config = wxConfigBase::Get();
00782     opts.quality = config->Read(wxT("/output/jpeg_quality"),HUGIN_JPEG_QUALITY);
00783     switch(config->Read(wxT("/output/tiff_compression"), HUGIN_TIFF_COMPRESSION))
00784     {
00785         case 0:
00786         default:
00787             opts.outputImageTypeCompression = "NONE";
00788             opts.tiffCompression = "NONE";
00789             break;
00790         case 1:
00791             opts.outputImageTypeCompression = "PACKBITS";
00792             opts.tiffCompression = "PACKBITS";
00793             break;
00794         case 2:
00795             opts.outputImageTypeCompression = "LZW";
00796             opts.tiffCompression = "LZW";
00797             break;
00798         case 3:
00799             opts.outputImageTypeCompression = "DEFLATE";
00800             opts.tiffCompression = "DEFLATE";
00801             break;
00802     }
00803     switch (config->Read(wxT("/output/ldr_format"), HUGIN_LDR_OUTPUT_FORMAT)) {
00804     case 1:
00805         opts.outputImageType ="jpg";
00806         break;
00807     case 2:
00808         opts.outputImageType ="png";
00809         break;
00810     case 3:
00811         opts.outputImageType ="exr";
00812         break;
00813     default:
00814     case 0:
00815         opts.outputImageType ="tif";
00816         break;
00817     }
00818     // HDR disabled because there is no real choice at the moment:  HDR TIFF is broken and there is only EXR
00819     // opts.outputImageTypeHDR = config->Read(wxT("/output/hdr_format"), HUGIN_HDR_OUTPUT_FORMAT);
00820     opts.outputFormat = HuginBase::PanoramaOptions::TIFF_m;
00821     opts.blendMode = static_cast<HuginBase::PanoramaOptions::BlendingMechanism>(config->Read(wxT("/default_blender"), HUGIN_DEFAULT_BLENDER));
00822     opts.enblendOptions = config->Read(wxT("Enblend/Args"),wxT(HUGIN_ENBLEND_ARGS)).mb_str(wxConvLocal);
00823     opts.enfuseOptions = config->Read(wxT("Enfuse/Args"),wxT(HUGIN_ENFUSE_ARGS)).mb_str(wxConvLocal);
00824     opts.verdandiOptions = config->Read(wxT("/VerdandiDefaultArgs"), wxEmptyString).mb_str(wxConvLocal);
00825     opts.interpolator = (vigra_ext::Interpolator)config->Read(wxT("Nona/Interpolator"),HUGIN_NONA_INTERPOLATOR);
00826     opts.remapUsingGPU = config->Read(wxT("Nona/useGPU"),HUGIN_NONA_USEGPU)!=0;
00827     opts.tiff_saveROI = config->Read(wxT("Nona/CroppedImages"),HUGIN_NONA_CROPPEDIMAGES)!=0;
00828     opts.hdrMergeMode = HuginBase::PanoramaOptions::HDRMERGE_AVERAGE;
00829     opts.hdrmergeOptions = HUGIN_HDRMERGE_ARGS;
00830     pano.setOptions(opts);
00831 
00832     pano.setOptimizerSwitch(HuginBase::OPT_PAIR);
00833     pano.setPhotometricOptimizerSwitch(HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE);
00834     return true;
00835 }
00836 
00837 
00838 bool wxApplyTemplateCmd::processPanorama(HuginBase::Panorama& pano)
00839 {
00840     wxConfigBase* config = wxConfigBase::Get();
00841 
00842     if (pano.getNrOfImages() == 0) {
00843         // TODO: prompt for images!
00844         wxString path = config->Read(wxT("actualPath"), wxT(""));
00845         wxFileDialog dlg(wxGetActiveWindow(), _("Add images"),
00846                 path, wxT(""),
00847                 GetFileDialogImageFilters(), wxFD_OPEN|wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST | wxFD_PREVIEW , wxDefaultPosition);
00848         dlg.SetDirectory(path);
00849 
00850         // remember the image extension
00851         wxString img_ext;
00852         if (config->HasEntry(wxT("lastImageType"))){
00853             img_ext = config->Read(wxT("lastImageType")).c_str();
00854         }
00855         if (img_ext == wxT("all images"))
00856             dlg.SetFilterIndex(0);
00857         else if (img_ext == wxT("jpg"))
00858             dlg.SetFilterIndex(1);
00859         else if (img_ext == wxT("tiff"))
00860             dlg.SetFilterIndex(2);
00861         else if (img_ext == wxT("png"))
00862             dlg.SetFilterIndex(3);
00863         else if (img_ext == wxT("hdr"))
00864             dlg.SetFilterIndex(4);
00865         else if (img_ext == wxT("exr"))
00866             dlg.SetFilterIndex(5);
00867         else if (img_ext == wxT("all files"))
00868             dlg.SetFilterIndex(6);
00869         DEBUG_INFO ( "Image extention: " << img_ext.mb_str(wxConvLocal) );
00870 
00871         // call the file dialog
00872         if (dlg.ShowModal() == wxID_OK) {
00873             // get the selections
00874             wxArrayString Pathnames;
00875             dlg.GetPaths(Pathnames);
00876 
00877             // save the current path to config
00878 #ifdef __WXGTK__
00879             //workaround a bug in GTK, see https://bugzilla.redhat.com/show_bug.cgi?id=849692 and http://trac.wxwidgets.org/ticket/14525
00880             config->Write(wxT("/actualPath"), wxPathOnly(Pathnames[0]));
00881 #else
00882             config->Write(wxT("/actualPath"), dlg.GetDirectory());
00883 #endif
00884             DEBUG_INFO ( wxString::Format(wxT("img_ext: %d"), dlg.GetFilterIndex()).mb_str(wxConvLocal) );
00885             // save the image extension
00886             switch ( dlg.GetFilterIndex() ) {
00887                 case 0: config->Write(wxT("lastImageType"), wxT("all images")); break;
00888                 case 1: config->Write(wxT("lastImageType"), wxT("jpg")); break;
00889                 case 2: config->Write(wxT("lastImageType"), wxT("tiff")); break;
00890                 case 3: config->Write(wxT("lastImageType"), wxT("png")); break;
00891                 case 4: config->Write(wxT("lastImageType"), wxT("hdr")); break;
00892                 case 5: config->Write(wxT("lastImageType"), wxT("exr")); break;
00893                 case 6: config->Write(wxT("lastImageType"), wxT("all files")); break;
00894             }
00895 
00896             HuginBase::StandardImageVariableGroups variable_groups(pano);
00897             HuginBase::ImageVariableGroup & lenses = variable_groups.getLenses();
00898             // add images.
00899             for (unsigned int i=0; i< Pathnames.GetCount(); i++) {
00900                 std::string filename = (const char *)Pathnames[i].mb_str(HUGIN_CONV_FILENAME);
00901                 vigra::ImageImportInfo inf(filename.c_str());
00902                 HuginBase::SrcPanoImage img;
00903                 img.setFilename(filename);
00904                 img.setSize(inf.size());
00905                 img.readEXIF();
00906                 img.applyEXIFValues();
00907                 int imgNr = pano.addImage(img);
00908                 lenses.updatePartNumbers();
00909                 if (i > 0) lenses.switchParts(imgNr, 0);
00910             }
00911 
00912         }
00913     }
00914 
00915     unsigned int nOldImg = pano.getNrOfImages();
00916     HuginBase::PanoramaMemento newPanoMem;
00917 
00918     int ptoVersion = 0;
00919     if (newPanoMem.loadPTScript(in, ptoVersion, "")) {
00920         HuginBase::Panorama newPano;
00921         newPano.setMemento(newPanoMem);
00922 
00923         unsigned int nNewImg = newPano.getNrOfImages();
00924         if (nOldImg != nNewImg) {
00925             wxString errMsg = wxString::Format(_("Error, template expects %d images,\ncurrent project contains %d images\n"), nNewImg, nOldImg);
00926             wxMessageBox(errMsg, _("Could not apply template"), wxICON_ERROR);
00927             return false;
00928         }
00929 
00930         // check image sizes, and correct parameters if required.
00931         for (unsigned int i = 0; i < nNewImg; i++) {
00932 
00933             // check if image size is correct
00934             const HuginBase::SrcPanoImage & oldSrcImg = pano.getImage(i);
00935             HuginBase::SrcPanoImage newSrcImg = newPano.getSrcImage(i);
00936 
00937             // just keep the file name
00938             DEBUG_DEBUG("apply template fn:" <<  newSrcImg.getFilename() << " real fn: " << oldSrcImg.getFilename());
00939             newSrcImg.setFilename(oldSrcImg.getFilename());
00940             if (oldSrcImg.getSize() != newSrcImg.getSize()) {
00941                 // adjust size properly.
00942                 newSrcImg.resize(oldSrcImg.getSize());
00943             }
00944             newPano.setSrcImage(i, newSrcImg);
00945         }
00946         // keep old control points.
00947         newPano.setCtrlPoints(pano.getCtrlPoints());
00948         newPanoMem = newPano.getMemento();
00949         pano.setMemento(newPanoMem);
00950     } else {
00951         wxMessageBox(_("Error loading project file"), _("Could not apply template"), wxICON_ERROR);
00952     }
00953     return true;
00954 }
00955 
00956 #ifdef HUGIN_HSI
00957 bool PythonScriptPanoCmd::processPanorama(HuginBase::Panorama& pano)
00958 {
00959     std::cout << "run python script: " << m_scriptFile.c_str() << std::endl;
00960 
00961     int success = hpi::callhpi ( m_scriptFile.c_str() , 1 ,
00962                    "HuginBase::Panorama*" , &pano ) ;
00963 
00964     if(success!=0)
00965         wxMessageBox(wxString::Format(wxT("Script returned %d"),success),_("Result"), wxICON_INFORMATION);
00966     std::cout << "Python interface returned " << success << endl ;
00967     // notify other of change in panorama
00968     if(pano.getNrOfImages()>0)
00969     {
00970         for(unsigned int i=0;i<pano.getNrOfImages();i++)
00971         {
00972             pano.imageChanged(i);
00973         };
00974     };
00975 
00976     return true;
00977 }
00978 #endif
00979 
00980 } // namespace
00981 

Generated on 25 Apr 2018 for Hugintrunk by  doxygen 1.4.7