27 #include "hugin_config.h"
31 #include <wx/window.h>
42 #include <vigra/cornerdetection.hxx>
43 #include <vigra/localminmax.hxx>
62 ImageCache::EntryPtr eptr = ImageCache::getInstance().getSmallImage(i1.getFilename());
64 vigra::BImage leftImg(eptr->get8BitImage()->size());
66 vigra::GreenAccessor<vigra::RGBValue<vigra::UInt8> > ga;
70 double scale = i1.getSize().width() / (double) leftImg.width();
75 vigra::BImage leftCorners(leftImg.size());
76 vigra::FImage leftCornerResponse(leftImg.size());
98 vigra::Threshold<double, double>(
102 destImage(leftCorners), std::multiplies<float>());
125 for (
unsigned int x=0; x < (
unsigned int)leftImg.width(); x++ ) {
126 for (
unsigned int y=0; y < (
unsigned int)leftImg.height(); y++) {
127 if (leftCorners(x,y) > 0) {
131 if ( img2x > border && img2x < i2.
getWidth() - border
132 && img2y > border && img2y < i2.
getHeight() - border )
153 if(srcImg.getExifMake() == anchor.getExifMake() &&
154 srcImg.getExifModel() == anchor.getExifModel())
158 if(fabs(redBalanceAnchor)<1e-2)
162 if(fabs(blueBalanceAnchor)<1e-2)
166 redBal=fabs(srcImg.getExifRedBalance()/redBalanceAnchor);
167 blueBal=fabs(srcImg.getExifBlueBalance()/blueBalanceAnchor);
178 srcImg.setWhiteBalanceRed(redBal);
179 srcImg.setWhiteBalanceBlue(blueBal);
186 dlg.CenterOnParent();
187 int ret = dlg.ShowModal();
194 srcImg.setCropFactor(1);
213 if (iccName.compare(0, 4,
"sRGB") == 0)
244 for (
const auto& filename:
files)
250 srcImg.setFilename(filename);
253 vigra::ImageImportInfo
info(filename.c_str());
254 if(
info.width()==0 ||
info.height()==0)
256 hugin_utils::HuginMessageBox(wxString::Format(_(
"Could not decode image:\n%s\nAbort"), fname.c_str()), _(
"Hugin"), wxOK | wxICON_HAND, wxGetActiveWindow());
260 const std::string pixelType=
info.getPixelType();
262 if (pixelType ==
"BILEVEL")
264 hugin_utils::HuginMessageBox(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()),
265 _(
"Hugin"), wxOK|wxICON_EXCLAMATION, wxGetActiveWindow());
270 const int bands =
info.numBands();
271 const int extraBands =
info.numExtraBands();
272 if (bands != 1 && bands != 3 && !(bands == 2 && extraBands == 1) && !(bands == 4 && extraBands == 1))
274 hugin_utils::HuginMessageBox(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),
275 _(
"Hugin"), wxOK | wxICON_EXCLAMATION, wxGetActiveWindow());
284 wxString s(_(
"Hugin supports only grayscale or RGB images (without and with alpha channel)."));
288 s.Append(wxString::Format(_(
"File \"%s\" is a grayscale image, but other images in project are color images."), fname.c_str()));
292 s.Append(wxString::Format(_(
"File \"%s\" is a color image, but other images in project are grayscale images."), fname.c_str()));
295 s.Append(_(
"Hugin does not support this mixing. Skipping this image.\nConvert this image to grayscale or RGB image respectively and try loading again."));
299 if ((pixelType ==
"UINT8") || (pixelType ==
"UINT16") || (pixelType ==
"INT16"))
319 if (newICCProfileDesc.empty())
321 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());
327 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());
331 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());
334 warning.Append(
"\n");
335 warning.Append(_(
"Hugin expects all images in the same color profile.\nPlease convert all images to same color profile and try again."));
343 if (!
info.getICCProfile().empty())
353 catch(std::exception & e)
355 std::cerr <<
"ERROR: caught exception: " << e.what() << std::endl;
356 std::cerr <<
"Could not get pixel type for file " << filename << std::endl;
357 hugin_utils::HuginMessageBox(wxString::Format(_(
"Could not decode image:\n%s\nAbort"), fname.c_str()), _(
"Hugin"), wxOK | wxICON_EXCLAMATION, wxGetActiveWindow());
365 if (srcImg.getCropFactor()<0.1)
368 ok=(srcImg.getExifFocalLength()>0 && srcImg.getCropFactor()>0.1);
374 const bool ignoreFovRectilinear = wxConfigBase::Get()->Read(
"/General/IgnoreFovRectilinearOnAdd", 1l) == 1l;
381 srcImg.setProjection(static_cast<HuginBase::BaseSrcPanoImage::Projection>(
m_preferredLensType));
391 if ( other.getSize() == srcImg.getSize() &&
392 other.getExifModel() == srcImg.getExifModel() &&
393 other.getExifMake() == srcImg.getExifMake() &&
394 other.getExifFocalLength() == srcImg.getExifFocalLength()
398 if (srcImg.getCropFactor() <= 0.1)
401 srcImg.setCropFactor(other.getCropFactor());
412 int matchingLensNr=-1;
418 srcImg.setCropFactor(1);
426 DEBUG_INFO(
"Image: " << fn.mb_str() <<
" has disappeared, skipping...");
434 bool set_exposure =
false;
437 if (other.getExifFocalLength()>0) {
438 if (other.getSize() == srcImg.getSize()
439 && other.getExifModel() == srcImg.getExifModel()
440 && other.getExifMake() == srcImg.getExifMake()
441 && other.getExifFocalLength() == srcImg.getExifFocalLength()
443 && other.getCropFactor() == srcImg.getCropFactor()
453 if (other.getSize() == srcImg.getSize() )
466 if (matchingLensNr != -1)
480 if (oldImgCount == 0)
483 message = _(
"Hugin has image stacks detected in the added images and will assign corresponding stack numbers to the images.");
487 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.");
489 message.append(
"\n");
490 message.append(_(
"Should the position of images in each stack be linked?"));
492 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."));
493 if (oldImgCount == 0)
495 dialog->SetYesNoCancelLabels(_(
"Link position"), _(
"Don't link position"), _(
"Don't assign stacks"));
499 dialog->SetYesNoCancelLabels(_(
"Link position"), _(
"Don't link position"), _(
"Keep existing stacks"));
501 switch (dialog->ShowModal())
514 bool hasStacks =
false;
517 if (pano.
getImage(i).StackisLinked())
523 wxConfigBase* config = wxConfigBase::Get();
524 bool showExposureWarning = config->Read(
"/ShowExposureWarning", 1l) == 1l;
528 wxXmlResource::Get()->LoadDialog(&dlg, NULL,
"warning_exposure_dlg");
529 if (dlg.ShowModal() == wxID_OK)
531 if (XRCCTRL(dlg,
"dont_show_again_checkbox", wxCheckBox)->GetValue())
533 config->Write(
"/ShowExposureWarning", 0l);
537 config->Write(
"/ShowExposureWarning", 1l);
575 bool autopanoSiftFile=
false;
578 for (
unsigned int i = 0; i < nImg; i++) {
580 while (! fname.FileExists()){
582 if (basedir != wxEmptyString) {
585 DEBUG_DEBUG(
"Old filename, without path): " << fn);
589 fname.AssignDir(basedir);
590 fname.SetFullName(newname);
591 DEBUG_TRACE(
"filename with new path: " << fname.GetFullPath().mb_str(wxConvLocal));
592 if (fname.FileExists()) {
594 DEBUG_TRACE(
"New filename set: " << fname.GetFullPath().mb_str(wxConvLocal));
600 hugin_utils::HuginMessageBox(wxString::Format(_(
"The project file \"%s\" refers to image \"%s\" which was not found.\nPlease manually select the correct image."),
filename, fname.GetFullPath()), _(
"Hugin"), wxOK | wxICON_INFORMATION, wxGetActiveWindow());
602 if (basedir == wxEmptyString) {
603 basedir = fname.GetPath();
607 wxFileDialog dlg(wxGetActiveWindow(), wxString::Format(_(
"Select image %s"), fname.GetFullName()),
608 basedir, fname.GetFullName(),
610 dlg.SetDirectory(basedir);
611 if (dlg.ShowModal() == wxID_OK) {
614 basedir = dlg.GetDirectory();
615 DEBUG_INFO(
"basedir is: " << basedir.mb_str(wxConvLocal));
622 fname.Assign(dlg.GetPath());
627 vigra::ImageImportInfo imginfo(srcImg.getFilename().c_str());
628 if (srcImg.getSize() != imginfo.size()) {
630 srcImg.
resize(imginfo.size(), &vars[i]);
633 double hfov = pano.
getImage(i).getHFOV();
635 && hfov >= 180 && autopanoSiftFile ==
false)
637 autopanoSiftFile =
true;
646 autopanoSiftRefImg = srcImg;
652 if (autopanoSiftFile)
655 srcImg.setHFOV(autopanoSiftRefImg.getHFOV());
661 pano.
setNrOfBands(imginfo.numBands() - imginfo.numExtraBands());
668 for (
unsigned i = 0; i < nImg; ++i)
670 if (!vars[i].empty())
677 for (
size_t i = 0; i < imgSetLens.size(); ++i)
680 if (imgLens.size()>1)
682 HuginBase::UIntSet::const_iterator it = imgLens.begin();
683 const size_t img1 = *it;
687 pano.linkImageVariableProjection(img1, *it);
689 }
while (it != imgLens.end());
704 int bad_cp_count = 0;
705 for (HuginBase::CPVector::const_iterator it = oldCPs.begin();
706 it != oldCPs.end(); ++it)
711 if (0 > point.
x1 || point.
x1 > img1.getSize().x ||
712 0 > point.
y1 || point.
y1 > img1.getSize().y ||
713 0 > point.
x2 || point.
x2 > img2.getSize().x ||
714 0 > point.
y2 || point.
y2 > img2.getSize().y)
719 goodCPs.push_back(point);
723 if (bad_cp_count > 0)
725 wxString errMsg = wxString::Format(_(
"%d invalid control point(s) found.\n\nPress OK to remove."), bad_cp_count);
747 wxConfigBase* config = wxConfigBase::Get();
790 opts.
verdandiOptions = config->Read(
"/VerdandiDefaultArgs", wxEmptyString).mb_str(wxConvLocal);
806 wxConfigBase* config = wxConfigBase::Get();
810 wxString path = config->Read(
"actualPath", wxEmptyString);
811 wxFileDialog dlg(wxGetActiveWindow(), _(
"Add images"),
814 dlg.SetDirectory(path);
818 if (config->HasEntry(
"lastImageType")){
819 img_ext = config->Read(
"lastImageType").c_str();
821 if (img_ext ==
"all images")
822 dlg.SetFilterIndex(0);
823 else if (img_ext ==
"jpg")
824 dlg.SetFilterIndex(1);
825 else if (img_ext ==
"tiff")
826 dlg.SetFilterIndex(2);
827 else if (img_ext ==
"png")
828 dlg.SetFilterIndex(3);
829 else if (img_ext ==
"hdr")
830 dlg.SetFilterIndex(4);
831 else if (img_ext ==
"exr")
832 dlg.SetFilterIndex(5);
833 else if (img_ext ==
"all files")
834 dlg.SetFilterIndex(6);
835 DEBUG_INFO (
"Image extention: " << img_ext.mb_str(wxConvLocal) );
838 if (dlg.ShowModal() == wxID_OK) {
840 wxArrayString Pathnames;
841 dlg.GetPaths(Pathnames);
846 config->Write(
"/actualPath", wxPathOnly(Pathnames[0]));
848 config->Write(
"/actualPath", dlg.GetDirectory());
850 DEBUG_INFO ( wxString::Format(
"img_ext: %d", dlg.GetFilterIndex()).mb_str(wxConvLocal) );
852 switch ( dlg.GetFilterIndex() ) {
853 case 0: config->Write(
"lastImageType",
"all images");
break;
854 case 1: config->Write(
"lastImageType",
"jpg");
break;
855 case 2: config->Write(
"lastImageType",
"tiff");
break;
856 case 3: config->Write(
"lastImageType",
"png");
break;
857 case 4: config->Write(
"lastImageType",
"hdr");
break;
858 case 5: config->Write(
"lastImageType",
"exr");
break;
859 case 6: config->Write(
"lastImageType",
"all files");
break;
865 for (
unsigned int i=0; i< Pathnames.GetCount(); i++) {
867 vigra::ImageImportInfo inf(filename.c_str());
869 img.setFilename(filename);
872 img.applyEXIFValues();
890 if (nOldImg != nNewImg) {
891 wxString errMsg = wxString::Format(_(
"Error, template expects %d images,\ncurrent project contains %d images\n"), nNewImg, nOldImg);
898 for (
unsigned int i = 0; i < nNewImg; i++) {
905 DEBUG_DEBUG(
"apply template fn:" << newSrcImg.getFilename() <<
" real fn: " << oldSrcImg.getFilename());
906 newSrcImg.setFilename(oldSrcImg.getFilename());
907 if (oldSrcImg.getSize() != newSrcImg.getSize()) {
909 newSrcImg.
resize(oldSrcImg.getSize(), &(vars[i]));
916 for (
unsigned int i = 0; i < nNewImg; ++i)
918 if (!vars[i].empty())
942 std::cout <<
"run python script: " << m_scriptFile.c_str() << std::endl;
945 "HuginBase::Panorama*" , &pano ) ;
948 hugin_utils::HuginMessageBox(wxString::Format(
"Script returned %d",success),_(
"Hugin"), wxOK | wxICON_INFORMATION, wxGetActiveWindow());
949 std::cout <<
"Python interface returned " << success << endl ;
std::string GetICCDesc(const vigra::ImageImportInfo::ICCProfile &iccProfile)
returns description of given icc profile
bool FileExists(const std::string &filename)
checks if file exists
void imageChanged(unsigned int imgNr)
mark image for change notification.
std::vector< UIntSet > UIntSetVector
const int getNrOfBands() const
return number of bands of first image (without alpha channel) so it can be 1 for grayscale or 3 for r...
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().
#define HUGIN_NONA_CROPPEDIMAGES
bool applyEXIFValues(bool applyEVValue=true)
apply values found in EXIF data to SrcPanoImage class, call readEXIF() before to initialize some valu...
void setMemento(const PanoramaMemento &memento)
set the internal state
unsigned int getPartNumber(unsigned int imageNr) const
Get a part number from an image number.
void transformImage(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, vigra::Diff2D destUL, TRANSFORM &transform, PixelTransform &pixelTransform, bool warparound, Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
Transform an image into the panorama.
std::vector< std::string > files
BlendingMechanism
blenders
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
bool IsLinearICCProfile(const vigra::ImageImportInfo::ICCProfile &iccProfile)
return true if icc profile is linear one, otherwise return false
std::unique_ptr< wxMessageDialogBase > MessageDialog
#define HUGIN_JPEG_QUALITY
void setPhotometricOptimizerSwitch(const int newSwitch)
sets the photometric optimizer master switch
Somewhere to specify what variables belong to what.
std::string GetICCProfileNameChecked(const std::string &iccName)
return name of icc profile with same checks for comparision
Functor class to compare two objects with the "Alphanum Algorithm".
std::string enfuseOptions
include file for the hugin project
#define HUGIN_GUI_SORT_NEW_IMG_ON_ADD
const CPVector & getCtrlPoints() const
get all control point of this Panorama
int getHeight() const
Get the height of the image in pixels.
std::string outputImageTypeCompression
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
const std::string filename
void setOptimizerSwitch(const int newSwitch)
set optimizer master switch
represents a control point
virtual void updateVariables(const VariableMapVector &vars)
Set the variables.
unsigned int colorReferenceImage
MessageDialog GetMessageDialog(const wxString &message, const wxString &caption, int style, wxWindow *parent)
bool readProjectionFromDB(const bool ignoreFovRectilinear=true)
tries to read projection and crop area from lens database you need to call SrcPanoImage::readEXIF bef...
const bool markAsOptimized
std::set< unsigned int > UIntSet
std::vector< VariableMap > VariableMapVector
void linkPossibleStacks(bool linkPosition)
create automatically stacks as indicated by metadata
empirical model of response
C++ call interface to hpi.
UIntSetVector getPartsSet() const
return a vector which contains a HuginBase::UIntSet for each group with the corresponding images numb...
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
bool loadPTScript(std::istream &i, int &ptoVersion, const std::string &prefix="")
load a Hugin file
some definitions to work with optimizer master switches
std::size_t getNrOfImages() const
number of images.
void combineTwoImages(SrcImageIterator1 src1_upperleft, SrcImageIterator1 src1_lowerright, SrcAccessor1 src1_acc, SrcImageIterator2 src2_upperleft, SrcAccessor2 src2_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc, const Functor &func)
void setCtrlPoints(const CPVector &points)
set all control points (Ippei: Is this supposed to be 'add' method?)
vigra_ext::Interpolator interpolator
int callhpi(const char *plugin_name, int argc,...)
simplified call interface to the Python Plugin facility.
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().
int getWidth() const
Get the width of the image in pixels.
bool getLensDataFromUser(wxWindow *parent, HuginBase::SrcPanoImage &srcImg)
void resize(const vigra::Size2D &size, VariableMap *potentialLinkedVars)
"resize" image, adjusts all distortion coefficients for usage with a source image of size size potent...
ImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
#define HUGIN_NONA_INTERPOLATOR
#define HUGIN_TIFF_COMPRESSION
wxwindows specific panorama commands
void setImageFilename(unsigned int img, const std::string &fname)
set a new image filename
#define HUGIN_NONA_USEGPU
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
#define HUGIN_HDRMERGE_ARGS
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().
#define HUGIN_LDR_OUTPUT_FORMAT
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
const std::string getICCProfileDesc() const
return description of icc profile used for pano
std::string tiffCompression
std::string verdandiOptions
Same as above, but use a non const panorama.
PanoramaMemento getMemento() const
get the internal state
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
include file for the hugin project
std::string enblendOptions
void setICCProfileDesc(const std::string &newDesc)
sets the icc profile description for check of same profile
const PanoramaOptions & getOptions() const
returns the options for this panorama
HDRMergeType hdrMergeMode
void markAsOptimized(bool optimized=true)
Memento class for a Panorama object.
void updatePartNumbers()
Update the part numbers, call this when the panorama changes.
#define HUGIN_ENFUSE_ARGS
bool readEXIF()
try to fill out information about the image, by examining the exif data
std::string outputImageType
void setSize(vigra::Size2D val)
Set the image size in pixels.
void update()
Update part numbers for each variable group.
std::vector< ControlPoint > CPVector
void copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
void applyColorBalanceValue(HuginBase::SrcPanoImage &srcImg, HuginBase::Panorama &pano)
static void info(const char *fmt,...)
std::string hdrmergeOptions
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
void setSrcImage(unsigned int nr, const SrcPanoImage &img)
set input image parameters
void setNrOfBands(const int nrBands)
sets the number of bands
Interpolator
enum with all interpolation methods
HuginBase::SrcPanoImage GetSrcImage()
All variables of a source image.
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
void switchParts(unsigned int ImageNr, unsigned int partNr)
switch a given image to a different part number.
const bool hasPossibleStacks() const
return true, if the metadata indicates that the projects is a bracketet project
#define HUGIN_ENBLEND_ARGS
const double getMaxExposureDifference() const
returns the maximum exposure value difference of all images in the project
#define HUGIN_DEFAULT_BLENDER
bool readCropfactorFromDB()
tries to read cropfactor from lens database you need to call SrcPanoImage::readEXIF before to fill so...
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
void reset()
clear the internal state.
BlendingMechanism blendMode
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
double outputExposureValue
virtual bool processPanorama(HuginBase::Panorama &pano)
Called by execute().