27 #include <vigra/distancetransform.hxx>
52 #define TRACE_IMG(X) {if (iPanoDetector.getVerbose() > 1) { TRACE_INFO("i" << ioImgInfo._number << " : " << X << std::endl);} }
53 #define TRACE_PAIR(X) {if (iPanoDetector.getVerbose() > 1){ TRACE_INFO("i" << ioMatchData._i1->_number << " <> " \
54 "i" << ioMatchData._i2->_number << " : " << X << std::endl)}}
123 template <
class SrcImageIterator,
class SrcAccessor>
126 vigra::Diff2D imgSize = img.second - img.first;
129 SrcImageIterator yd(img.first);
131 for(
int y=0; y < imgSize.y; ++y, ++yd.y)
134 SrcImageIterator xd(yd);
135 for(
int x=0; x < imgSize.x; ++x, ++xd.x)
137 if(!SrcImg.
isInside(vigra::Point2D(x,y)))
163 template <
class T2,
class A>
177 template <
class ImageType,
class PixelTransform>
179 size_t detectWidth,
size_t detectHeight,
181 const PixelTransform& pixelTransform,
182 ImageType*& finalImage, vigra::BImage*& finalMask)
187 finalImage =
new ImageType(detectWidth, detectHeight);
188 finalMask =
new vigra::BImage(detectWidth, detectHeight, vigra::UInt8(0));
194 mask =
new vigra::BImage(image->size(), vigra::UInt8(255));
216 template <
class ImageType>
218 size_t detectWidth,
size_t detectHeight,
bool downscale,
219 ImageType*& finalImage, vigra::BImage*& finalMask)
226 mask =
new vigra::BImage(image->size(), vigra::UInt8(255));
234 finalImage =
new ImageType(detectWidth, detectHeight);
241 finalMask =
new vigra::BImage(detectWidth, detectHeight);
262 vigra::DImage* final_img = NULL;
263 vigra::BImage* final_mask = NULL;
270 vigra::ImageImportInfo aImageInfo(ioImgInfo.
_name.c_str());
271 if (aImageInfo.numExtraBands() > 1)
273 TRACE_INFO(
"Image with multiple alpha channels are not supported");
282 if (aImageInfo.isGrayscale())
285 vigra::DImage* image =
new vigra::DImage(aImageInfo.size());
286 vigra::BImage* mask = NULL;
288 if (aImageInfo.numExtraBands() == 1)
290 mask=
new vigra::BImage(aImageInfo.size());
300 if (aImageInfo.getPixelType() == std::string(
"FLOAT") || aImageInfo.getPixelType() == std::string(
"DOUBLE"))
302 vigra::FindMinMax<float> minmax;
311 bool range255 = (fabs(maxVal - 255) < 0.01 && fabs(minVal) < 0.01);
312 if (aImageInfo.getICCProfile().empty())
319 vigra::linearRangeMapping(minVal, maxVal, 0.0, 255.0));
329 vigra::linearRangeMapping(minVal, maxVal, 0.0, 1.0));
341 final_img, final_mask);
348 final_img, final_mask);
355 TRACE_IMG(
"Downscale and transform to suitable grayscale...");
358 final_img, final_mask);
362 TRACE_IMG(
"Transform to suitable grayscale...");
365 final_img, final_mask);
371 TRACE_IMG(
"Celeste does not work with grayscale images. Skipping...");
376 if (aImageInfo.isColor())
393 switch (aImageInfo.pixelType())
395 case vigra::ImageImportInfo::UINT8:
398 vigra::BRGBImage* rgbImage=
new vigra::BRGBImage(aImageInfo.size());
399 vigra::BImage* mask = NULL;
401 if (aImageInfo.numExtraBands() == 1)
403 mask=
new vigra::BImage(aImageInfo.size());
411 if (!aImageInfo.getICCProfile().empty())
416 vigra::BRGBImage* scaled = NULL;
439 vigra::UInt16RGBImage* image16=
new vigra::UInt16RGBImage(scaled->size());
441 vigra::linearIntensityTransform<vigra::RGBValue<vigra::UInt16> >(255));
443 #ifdef DEBUG_LOADING_REMAPPING
445 std::ostringstream maskfilename;
446 maskfilename << ioImgInfo.
_name <<
"_celeste_mask.JPG";
447 vigra::ImageExportInfo maskexinfo(maskfilename.str().c_str());
457 final_mask = celeste_mask;
461 TRACE_IMG(
"Convert to greyscale double...");
462 final_img =
new vigra::DImage(scaled->size());
468 case vigra::ImageImportInfo::UINT16:
471 vigra::UInt16RGBImage* rgbImage =
new vigra::UInt16RGBImage(aImageInfo.size());
472 vigra::BImage* mask = NULL;
474 if (aImageInfo.numExtraBands() == 1)
476 mask =
new vigra::BImage(aImageInfo.size());
484 if (!aImageInfo.getICCProfile().empty())
489 vigra::UInt16RGBImage* scaled = NULL;
513 #ifdef DEBUG_LOADING_REMAPPING
515 std::ostringstream maskfilename;
516 maskfilename << ioImgInfo.
_name <<
"_celeste_mask.JPG";
517 vigra::ImageExportInfo maskexinfo(maskfilename.str().c_str());
526 final_mask = celeste_mask;
530 TRACE_IMG(
"Convert to greyscale double...");
531 final_img =
new vigra::DImage(scaled->size());
534 vigra::destImage(*final_img), vigra::functor::Arg1() / vigra::functor::Param(255.0));
541 vigra::DRGBImage* rgbImage =
new vigra::DRGBImage(aImageInfo.size());
542 vigra::BImage* mask = NULL;
544 if (aImageInfo.numExtraBands() == 1)
546 mask =
new vigra::BImage(aImageInfo.size());
556 const bool isDouble = aImageInfo.getPixelType() == std::string(
"FLOAT") || aImageInfo.getPixelType() == std::string(
"DOUBLE");
559 vigra::FindMinMax<float> minmax;
560 vigra::inspectImage(
vigra::srcImageRange(*rgbImage, vigra::RGBToGrayAccessor<vigra::RGBValue<double> >()), minmax);
568 bool range255 = (fabs(maxVal - 255) < 0.01 && fabs(minVal) < 0.01);
569 if (aImageInfo.getICCProfile().empty())
595 vigra::DRGBImage* scaled;
606 TRACE_IMG(
"Transform to suitable grayscale...");
614 vigra::UInt16RGBImage* image16 =
new vigra::UInt16RGBImage(scaled->size());
618 vigra::linearIntensityTransform<vigra::RGBValue<vigra::UInt16> >(255));
623 vigra::linearIntensityTransform<vigra::RGBValue<vigra::UInt16> >(65535));
626 #ifdef DEBUG_LOADING_REMAPPING
628 std::ostringstream maskfilename;
629 maskfilename << ioImgInfo.
_name <<
"_celeste_mask.JPG";
630 vigra::ImageExportInfo maskexinfo(maskfilename.str().c_str());
640 final_mask = celeste_mask;
644 TRACE_IMG(
"Convert to greyscale double...");
645 final_img =
new vigra::DImage(scaled->size());
654 vigra::destImage(*final_img), vigra::functor::Arg1() * vigra::functor::Param(255.0));
663 TRACE_INFO(
"Cpfind works only with grayscale or RGB images");
669 #ifdef DEBUG_LOADING_REMAPPING
671 std::ostringstream filename;
672 filename << ioImgInfo.
_name <<
"_grey.JPG";
673 vigra::ImageExportInfo exinfo(filename.str().c_str());
679 ioImgInfo.
_ii.
init(*final_img);
688 vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType>(1, 255, 0, 255));
689 ioImgInfo.
_distancemap.resize(final_mask->width(), final_mask->height(), 0);
691 #ifdef DEBUG_LOADING_REMAPPING
692 std::ostringstream maskfilename;
693 maskfilename << ioImgInfo.
_name <<
"_mask.JPG";
694 vigra::ImageExportInfo maskexinfo(maskfilename.str().c_str());
696 std::ostringstream distfilename;
697 distfilename << ioImgInfo.
_name <<
"_distancemap.JPG";
698 vigra::ImageExportInfo distexinfo(distfilename.str().c_str());
704 catch (std::exception& e)
706 TRACE_INFO(
"An error happened while loading image : caught exception: " << e.what() << std::endl);
726 TRACE_IMG(
"Found "<< ioImgInfo.
_kp.size() <<
" interest points.");
744 for (
size_t i = 0; i < ioImgInfo.
_kp.size(); ++i)
750 && ioImgInfo.
_distancemap((
int)(aK->_x),(
int)(aK->_y)) >aK->_scale*8)
753 aSieve.insert(aK, (
int)(aK->_x * aXF), (
int)(aK->_y * aYF));
758 aSieve.insert(aK, (
int)(aK->_x * aXF), (
int)(aK->_y * aYF));
763 ioImgInfo.
_kp.clear();
767 aSieve.extract(aSieveExt);
769 TRACE_IMG(
"Kept " << ioImgInfo.
_kp.size() <<
" interest points.");
777 TRACE_IMG(
"Make keypoint descriptors...");
784 for (
size_t j = 0; j < ioImgInfo.
_kp.size(); ++j)
789 for (
int i=0; i < nAngles; i++)
793 aKn->_ori = angles[i];
794 kp_new_ori.push_back(aKn);
797 ioImgInfo.
_kp.insert(ioImgInfo.
_kp.end(), kp_new_ori.begin(), kp_new_ori.end());
799 for (
size_t i = 0; i < ioImgInfo.
_kp.size(); ++i)
812 for (
size_t i = 0; i < ioImgInfo.
_kp.size(); ++i)
824 TRACE_IMG(
"Remapping back keypoints...");
832 for (
size_t i = 0; i < ioImgInfo.
_kp.size(); ++i)
853 if(ioImgInfo.
_kp.empty())
862 for (
size_t i = 0; i < ioImgInfo.
_kp.size(); ++i)
890 flann::Index<flann::L2<double> > * index2 = ioMatchData.
_i2->
_flann_index;
897 flann::Matrix<int> indices(
new int[query.rows*nn], query.rows, nn);
898 flann::Matrix<double> dists(
new double[query.rows*nn], query.rows, nn);
901 index2->knnSearch(query, indices, dists, nn, flann::SearchParams(iPanoDetector.
getKDTreeSearchSteps()));
909 std::set<int> aAlreadyMatched;
910 std::set<int> aBadMatch;
913 typedef std::pair<lfeat::KeyPointPtr, int> TmpPair_t;
914 std::vector<TmpPair_t> aUnfilteredMatches;
919 for (
unsigned aKIt = 0; aKIt < query.rows; ++aKIt)
929 if (aAlreadyMatched.find(indices[aKIt][0]) != aAlreadyMatched.end())
932 aBadMatch.insert(indices[aKIt][0]);
939 aAlreadyMatched.insert(indices[aKIt][0]);
942 aUnfilteredMatches.push_back(TmpPair_t(ioMatchData.
_i1->
_kp[aKIt], indices[aKIt][0]));
946 for (
size_t i = 0; i < aUnfilteredMatches.size(); ++i)
948 TmpPair_t& aP = aUnfilteredMatches[i];
950 if (aBadMatch.find(aP.second) != aBadMatch.end())
959 delete[] indices.ptr();
960 delete[] dists.ptr();
984 TRACE_PAIR(
"RANSAC Filtering with Panorama model...");
988 TRACE_PAIR(
"Too few matches ... removing all of them.");
993 if (ioMatchData.
_matches.size() < 6)
995 TRACE_PAIR(
"Not enough matches for RANSAC filtering.");
1004 imgs.insert(pano_i1);
1005 imgs.insert(pano_i2);
1006 int pano_local_i1 = 0;
1007 int pano_local_i2 = 1;
1008 if (pano_i1 > pano_i2)
1016 std::vector<int> inliers;
1017 #pragma omp critical
1023 for (
size_t i = 0; i < ioMatchData.
_matches.size(); ++i)
1027 pano_local_i2, aM->_img2_x, aM->_img2_y);
1045 PT_setProgressFcn(NULL);
1046 PT_setInfoDlgFcn(NULL);
1050 TRACE_PAIR(
"Removed " << ioMatchData.
_matches.size() - inliers.size() <<
" matches. " << inliers.size() <<
" remaining.");
1051 if (inliers.size() < 0.5 * ioMatchData.
_matches.size())
1054 TRACE_PAIR(
"RANSAC found more than 50% outliers, removing all matches");
1062 TRACE_PAIR(
"Too few matches ... removing all of them.");
1069 aInlierMatches.reserve(inliers.size());
1071 for (
size_t i = 0; i < inliers.size(); ++i)
1073 aInlierMatches.push_back(ioMatchData.
_matches[inliers[i]]);
1075 ioMatchData.
_matches = aInlierMatches;
1093 TRACE_PAIR(
"Too few matches ... removing all of them.");
1098 if (ioMatchData.
_matches.size() < 6)
1100 TRACE_PAIR(
"Not enough matches for RANSAC filtering.");
1113 thresholdDistance*=5;
1119 TRACE_PAIR(
"Removed " << aRemovedMatches.size() <<
" matches. " << ioMatchData.
_matches.size() <<
" remaining.");
1121 if (aRemovedMatches.size() > ioMatchData.
_matches.size())
1124 TRACE_PAIR(
"More than 50% outliers, removing all matches");
1131 aRemovedMatches, aRansacFilter, iPanoDetector.
getDownscale());
1142 if (ioMatchData.
_matches.size() < 2)
1154 for (
size_t i = 0; i < ioMatchData.
_matches.size(); ++i)
1157 if (aM->_img1_x < aMinX)
1159 aMinX = aM->_img1_x;
1161 if (aM->_img1_x > aMaxX)
1163 aMaxX = aM->_img1_x;
1166 if (aM->_img1_y < aMinY)
1168 aMinY = aM->_img1_y;
1170 if (aM->_img1_y > aMaxY)
1172 aMaxY = aM->_img1_y;
1176 double aSizeX = aMaxX - aMinX + 2;
1177 double aSizeY = aMaxY - aMinY + 2;
1188 for (
size_t i = 0; i < ioMatchData.
_matches.size(); ++i)
1192 ioMatchData.
_i2->
_number, aM->_img2_x, aM->_img2_y);
1198 aSieve.insert(aM, (
int)((aM->_img1_x - aMinX) * aXF), (
int)((aM->_img1_y - aMinY) * aYF));
1206 aSieve.extract(aSieveExt);
1217 std::cerr <<
"ERROR couldn't write to output file '" <<
_outputFile <<
"'!" << std::endl;
1225 std::ofstream aOut(imgInfo.
_keyfilename.c_str(), std::ios_base::trunc);
1234 writer.writeHeader ( img_info, imgInfo.
_kp.size(), imgInfo.
_descLength );
1236 for(
size_t i=0; i<imgInfo.
_kp.size(); ++i)
1239 writer.writeKeypoint ( aK->_x, aK->_y, aK->_scale, aK->_ori, aK->_score,
1242 writer.writeFooter();
int getSieve2Width() const
int getRansacIterations() const
Dummy progress display, without output.
double getMaxValForPixelType(const std::string &v)
int getSieve2Size() const
std::vector< PointMatchPtr > PointMatchVector_t
void HandleDownscaleImage(const HuginBase::SrcPanoImage &srcImage, ImageType *&image, vigra::BImage *&mask, size_t detectWidth, size_t detectHeight, bool downscale, ImageType *&finalImage, vigra::BImage *&finalMask)
downscale image if requested, optimized code for non-downscale version to prevent unnecessary copying...
vigra::BImage _distancemap
std::vector< KeyPointPtr > KeyPointVect_t
void setHeight(unsigned int h)
set panorama height
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.
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
virtual void setCtrlPoints(const CPVector &points)=0
set all control points (Ippei: Is this supposed to be 'add' method?)
vigra::BImage * getCelesteMask(struct svm_model *model, vigra::UInt16RGBImage &input, int radius, float threshold, int resize_dimension, bool adaptThreshold, bool verbose)
calculates the mask using SVM
PanoramaData * getNewSubset(const UIntSet &imgs) const
int getMinimumMatches() const
void copyImageIf(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, MaskImageIterator mask_upperleft, MaskAccessor mask_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
static const double A(-0.75)
static bool LoadKeypoints(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
static bool MakeKeyPointDescriptorsInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
void makeDescriptor(KeyPoint &ioKeyPoint) const
HuginBase::PanoramaOptions _projOpts
bool hasActiveMasks() const
returns true, if image has active masks
static std::vector< int > findInliers(PanoramaData &pano, int i1, int i2, double maxError, Mode mode=RPY)
T2 operator()(const T2 &a, const hugin_utils::FDiff2D &p) const
void setDistanceThreshold(int iDT)
Contains functions to transform whole images.
static int ptinfoDlg(int command, char *argument)
bool set_contains(const _Container &c, const typename _Container::key_type &key)
static int ptProgress(int command, char *argument)
int getHeight() const
Get the height of the image in pixels.
void setIterations(int iIters)
bool isInside(vigra::Point2D p, bool ignoreMasks=false) const
check if a coordinate is inside the source image
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
void applyMapping(vigra::triple< SrcIterator, SrcIterator, SrcAccessor > img, vigra::pair< DestIterator, DestAccessor > dest, T min, T max, int mapping)
represents a control point
functor to scale image on the fly during other operations
std::set< unsigned int > UIntSet
const std::string getCPString() const
returns string which contains all features of a control point used for detecting duplicate control po...
static bool RansacMatchesInPairCam(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
const vigra::Rect2D & getROI() const
static bool FilterKeyPointsInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
int getSieve1Height() const
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
int getSieve1Size() const
void filter(std::vector< PointMatchPtr > &ioMatches, std::vector< PointMatchPtr > &ioRemovedMatches)
vigra::FRGBImage ImageType
std::set< std::string > _cpsHashSet
int getWidth() const
Get the width of the image in pixels.
static bool FindMatchesInPair(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
lfeat::KeyPointVect_t & _v
static bool RansacMatchesInPair(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
void RemapImage(const HuginBase::SrcPanoImage &srcImage, const HuginBase::PanoramaOptions &options, size_t detectWidth, size_t detectHeight, ImageType *&image, vigra::BImage *&mask, const PixelTransform &pixelTransform, ImageType *&finalImage, vigra::BImage *&finalMask)
helper function to remap image to given projection, you can supply a pixelTransform, which will be applied during remapping, this is intended for scaling a image during remapping, but this means also, that no photometric corrections are applied, if this is wanted you need to supply a suitable pixelTransform
virtual const SrcPanoImage & getImage(std::size_t nr) const =0
get a panorama image, counting starts with 0
static bool RemapBackKeypoints(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
void init(vigra::DImage &img)
static void drawRansacMatches(std::string &i1, std::string &i2, lfeat::PointMatchVector_t &iOK, lfeat::PointMatchVector_t &iNOK, lfeat::Ransac &iRansac, bool iHalf)
bool NeedsRemapping() const
static bool FreeMemoryInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
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
!! from PTOptimise.h 1951
lfeat::PointMatchVector_t _matches
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
ScaleFunctor(double scale)
flann::Matrix< double > _flann_descriptors
void importImageAlpha(const ImageImportInfo &import_info, ImageIterator image_iterator, ImageAccessor image_accessor, AlphaIterator alpha_iterator, AlphaAccessor alpha_accessor)
Read the image specified by the given vigra::ImageImportInfo object including its alpha channel...
HuginBase::Panorama _panoramaInfoCopy
T operator()(const T &a) const
struct celeste::svm_model * svmModel
HuginBase::RANSACOptimizer::Mode _ransacMode
int getKDTreeSearchSteps() const
static bool FilterMatchesInPair(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
lfeat::KeyPointVect_t _kp
void transformImageAlpha(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, std::pair< SrcAlphaIterator, SrcAlphaAccessor > srcAlpha, 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 image, and respect a possible alpha channel.
static bool AnalyzeImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
KeyPointVectInsertor(lfeat::KeyPointVect_t &iVect)
int getDescriptorLength() const
bool getDownscale() const
flann::Index< flann::L2< double > > * _flann_index
double getCelesteThreshold() const
int getSieve2Height() const
void applyMaskAndCrop(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > img, const HuginBase::SrcPanoImage &SrcImg)
apply the mask and the crop of the given SrcImg to given mask image
std::shared_ptr< KeyPoint > KeyPointPtr
std::vector< ControlPoint > CPVector
double getKDTreeSecondDistance() const
vigra::triple< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImageRange(ROIImage< Image, Alpha > &img)
void copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
int assignOrientation(KeyPoint &ioKeyPoint, double angles[4]) const
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
static void info(const char *fmt,...)
HuginBase::Panorama * _panoramaInfo
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
virtual void operator()(const lfeat::KeyPoint &k)
int getCelesteRadius() const
A hdrWeight(T2 v, A a) const
void writeKeyfile(ImgData &imgInfo)
int getSieve1Width() const
All variables of a source image.
std::shared_ptr< PointMatch > PointMatchPtr
functions to handle icc profiles in images
ImageInfo loadKeypoints(const std::string &filename, KeyPointVect_t &vec)
void detectKeypoints(Image &iImage, KeyPointInsertor &iInsertor)
static bool FindKeyPointsInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
void ApplyICCProfile(ImageType &image, const vigra::ImageImportInfo::ICCProfile &iccProfile, const cmsUInt32Number imageFormat)
converts given image with iccProfile to sRGB/gray space, need to give pixel type in lcms2 format work...
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
static bool BuildKDTreesInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
static bool RansacMatchesInPairHomography(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
int getRansacDistanceThreshold() const