27#include <hugin_config.h>
32#include <vigra/error.hxx>
33#include <vigra/cornerdetection.hxx>
34#include <vigra/localminmax.hxx>
56#include <hugin_config.h>
57#include <mach-o/dyld.h>
64static void usage(
const char* name)
66 std::cout << name <<
": align overlapping images for HDR creation" << std::endl
69 <<
"Usage: " << name <<
" [options] input files" << std::endl
70 <<
"Valid options are:" << std::endl
71 <<
" Modes of operation:" << std::endl
72 <<
" -p file Output .pto file (useful for debugging, or further refinement)" << std::endl
73 <<
" -a prefix align images, output as prefix_xxxx.tif" << std::endl
74 <<
" -o output merge images to HDR, generate output.hdr" << std::endl
75 <<
" Modifiers" << std::endl
76 <<
" -v Verbose, print progress messages. Repeat for higher verbosity" << std::endl
77 <<
" -e Assume input images are full frame fish eye (default: rectilinear)" << std::endl
78 <<
" -t num Remove all control points with an error higher than num pixels" << std::endl
79 <<
" (default: 3)" << std::endl
80 <<
" --corr=num Correlation threshold for identifing control points" << std::endl
81 <<
" (default: 0.9)" << std::endl
82 <<
" -f HFOV approximate horizontal field of view of input images," << std::endl
83 <<
" use if EXIF info not complete" << std::endl
84 <<
" -m Optimize field of view for all images, except for first." << std::endl
85 <<
" Useful for aligning focus stacks with slightly" << std::endl
86 <<
" different magnification." << std::endl
87 <<
" -d Optimize radial distortion for all images, except for first." << std::endl
88 <<
" -i Optimize image center shift for all images, except for first." << std::endl
89 <<
" -x Optimize X coordinate of the camera position." << std::endl
90 <<
" -y Optimize Y coordinate of the camera position." << std::endl
91 <<
" -z Optimize Z coordinate of the camera position." << std::endl
92 <<
" Useful for aligning more distorted images." << std::endl
93 <<
" -S Assume stereo images - allow horizontal shift of control points." << std::endl
94 <<
" -A Align stereo window - assumes -S." << std::endl
95 <<
" -P Align stereo window with pop-out effect - assumes -S." << std::endl
96 <<
" -C Auto crop the image to the area covered by all images." << std::endl
97 <<
" -c num number of control points (per grid) to create" << std::endl
98 <<
" between adjacent images (default: 8)" << std::endl
99 <<
" -l Assume linear input files" << std::endl
100 <<
" -s scale Scale down image by 2^scale (default: 1 [2x downsampling])" << std::endl
101 <<
" -g gsize Break image into a rectangular grid (gsize x gsize) and attempt" << std::endl
102 <<
" to find num control points in each section" << std::endl
103 <<
" (default: 5 [5x5 grid] )" << std::endl
104 <<
" --distortion Try to load distortion information from lens database" << std::endl
105 <<
" --use-given-order Use the image order as given from command line" << std::endl
106 <<
" (By default images will be sorted by exposure values.)" << std::endl
107 <<
" --align-to-first Align all images to the first one. By default" << std::endl
108 <<
" align_image_stack matches all image pairs" << std::endl
109 <<
" consecutive." << std::endl
110 <<
" This implies also the --use-given-order option" << std::endl
111 <<
" --dont-remap-ref Don't output the remapped reference image" << std::endl
112 <<
" --gpu Use GPU for remapping" << std::endl
113 <<
" -h Display help (this text)" << std::endl
122 template <
class ImageType>
132 template <
class ImageType>
137 vigra::RGBToGrayAccessor<typename ImageType::value_type>(),
139 rightImg, vigra::RGBToGrayAccessor<typename ImageType::value_type>(),
143template <
class ImageType>
150 typedef typename vigra::NumericTraits<ImageValueType>::isScalar
is_scalar;
154 for (MapPoints::const_reverse_iterator
it =
points.rbegin();
it !=
points.rend(); ++
it)
156 if (
nGood >= nPoints)
166 std::ostringstream
buf;
167 buf <<
"I :" << (*it).second.x* scaleFactor <<
"," << (*it).second.y* scaleFactor <<
" -> "
168 << res.
maxpos.
x* scaleFactor <<
"," << res.
maxpos.
y* scaleFactor <<
": corr coeff: " << res.
maxi
169 <<
" curv:" << res.
curv.
x <<
" " << res.
curv.
y << std::endl;
170 std::cout <<
buf.str();
172 if (res.
maxi < corrThresh)
186 std::ostringstream
buf;
187 buf <<
"II>" << (*it).second.x* scaleFactor <<
"," << (*it).second.y* scaleFactor <<
" -> "
189 <<
" curv:" << res.
curv.
x <<
" " << res.
curv.
y << std::endl;
190 std::cout <<
buf.str();
192 if (res.
maxi < corrThresh)
202 (*it).second.y * scaleFactor,
213 std::ostringstream
buf;
214 buf <<
"Number of good matches: " <<
nGood <<
", bad matches: " <<
points.size() -
nGood << std::endl;
215 std::cout <<
buf.str();
221 template <
class ImageType>
223 unsigned nPoints, std::multimap<double, vigra::Diff2D> &
points, vigra::VigraTrueType)
228 template <
class ImageType>
230 unsigned nPoints, std::multimap<double, vigra::Diff2D> &
points, vigra::VigraFalseType)
237template <
class ImageType>
238void createCtrlPoints(
HuginBase::Panorama& pano,
int img1,
const ImageType&
leftImg,
const ImageType&
leftImgOrig,
int img2,
const ImageType&
rightImg,
const ImageType&
rightImgOrig,
int pyrLevel,
double scale,
unsigned nPoints,
unsigned grid,
double corrThresh = 0.9,
bool stereo =
false)
241 typedef typename vigra::NumericTraits<ImageValueType>::isScalar
is_scalar;
254 std::cout <<
"Trying to find " << nPoints <<
" corners... " << std::endl;
258 std::vector<vigra::Rect2D>
rects;
265 (
partx + 1)*size.x / grid, (
party + 1)*size.y / grid);
266 rect &= vigra::Rect2D(size);
267 if (
rect.width()>0 &&
rect.height()>0)
274 const double scaleFactor = 1 << pyrLevel;
278 #pragma omp parallel for schedule(dynamic)
279 for (
int i = 0;
i <
rects.size(); ++
i)
284 FineTuneInterestPoints(pano, img1,
leftImg,
leftImgOrig, img2,
rightImg,
rightImgOrig,
points, nPoints, pyrLevel,
templWidth,
sWidth, scaleFactor, corrThresh, stereo);
299 for (
int k = 6;
k >= 0; --
k)
301 for (
int j = 0;
j < 2; ++
j)
303 for (
unsigned int i = 0;
i < nPoints; ++
i)
305 up.insert(std::make_pair(0, vigra::Diff2D(
j *
xstep / 2 +
i *
xstep, 1 +
k * 10)));
306 down.insert(std::make_pair(0, vigra::Diff2D(
j *
xstep / 2 +
i *
xstep,
leftImg.size().y - 2 -
k * 10)));
307 left.insert(std::make_pair(0, vigra::Diff2D(1 +
k * 10,
j *
ystep / 2 +
i *
ystep)));
308 right.insert(std::make_pair(0, vigra::Diff2D(
leftImg.size().x - 2 -
k * 10,
j *
ystep / 2 +
i *
ystep)));
313 #pragma omp parallel sections
317 FineTuneInterestPoints(pano, img1,
leftImg,
leftImgOrig, img2,
rightImg,
rightImgOrig,
up, nPoints, pyrLevel,
templWidth,
sWidth, corrThresh, scaleFactor, stereo);
321 FineTuneInterestPoints(pano, img1,
leftImg,
leftImgOrig, img2,
rightImg,
rightImgOrig, down, nPoints, pyrLevel,
templWidth,
sWidth, corrThresh, scaleFactor, stereo);
325 FineTuneInterestPoints(pano, img1,
leftImg,
leftImgOrig, img2,
rightImg,
rightImgOrig, left, nPoints, pyrLevel,
templWidth,
sWidth, corrThresh, scaleFactor, stereo);
329 FineTuneInterestPoints(pano, img1,
leftImg,
leftImgOrig, img2,
rightImg,
rightImgOrig, right, nPoints, pyrLevel,
templWidth,
sWidth, corrThresh, scaleFactor, stereo);
353 for (
int i=0;
i < (
int)cps.size();
i++)
391 if (!(
rect1.contains(vigra::Point2D(cps[
i].x1, cps[
i].y1)) &&
392 rect2.contains(vigra::Point2D(cps[
i].x2, cps[
i].y2))))
426 for (
int i=0;
i < (
int)cps.size();
i++)
450 std::cout <<
"Set crop size to " <<
roi.left() <<
"," <<
roi.top() <<
"," <<
roi.right() <<
"," <<
roi.bottom() << std::endl;
454 std::cout <<
"Could not find best crop rectangle for image" << std::endl;
538template <
class PixelType>
541 typedef vigra::BasicImage<PixelType>
ImageType;
549 srcImg.setFilename(files[0]);
577 std::cerr <<
"Could not decode image: " << files[0] <<
"Unsupported image file format" << std::endl;
583 if(
srcImg.readDistortionFromDB())
585 std::cout <<
"\tRead distortion data from lens database." << std::endl;
589 std::cout <<
"\tNo valid distortion data found in lens database." << std::endl;
598 else if (
srcImg.getCropFactor() == 0)
609 std::cout <<
"Using linear response" << std::endl;
641 std::vector<unsigned int> images;
647 for (
int i = 1;
i < (
int) files.size();
i++)
652 srcImg.setSize(vigra::Size2D());
657 std::cerr <<
"Could not decode image: " << files[
i] <<
"Unsupported image file format" << std::endl;
662 std::cerr <<
"Images have different sizes." << std::endl
663 << files[0] <<
" has " << pano.
getImage(0).getSize() <<
" pixel, while " << std::endl
664 << files[
i] <<
" has " <<
srcImg.getSize() <<
" pixel." << std::endl
665 <<
"This is not supported. Align_image_stack works only with images of the same size." << std::endl;
683 if(
srcImg.readDistortionFromDB())
685 std::cout <<
"\tRead distortion data from lens database." << std::endl;
689 std::cout <<
"\tNo valid distortion data found in lens database." << std::endl;
697 else if (
srcImg.getCropFactor() == 0)
710 pano.unlinkImageVariableHFOV(0);
714 pano.unlinkImageVariableRadialDistortion(0);
718 pano.unlinkImageVariableRadialDistortionCenterShift(0);
721 pano.linkImageVariableStack(0, imgNr);
724 std::set<std::string> vars;
755 optvars.push_back(vars);
771 std::cout <<
"WARNING: Spread of exposure values is very small." << std::endl
772 <<
" Disabling sorting images by exposure value." << std::endl << std::endl;
795 vigra_fail(
"Images with multiple extra (alpha) channels not supported");
804 for (
int i = 1;
i < (
int) images.size();
i++)
810 std::cout <<
"Creating control points between " << pano.
getSrcImage(images[0]).getFilename().c_str() <<
" and " <<
811 pano.
getSrcImage(images[
i]).getFilename().c_str() << std::endl;
815 std::cout <<
"Creating control points between " << pano.
getSrcImage(images[
i - 1]).getFilename().c_str() <<
" and " <<
816 pano.
getSrcImage(images[
i]).getFilename().c_str() << std::endl;
835 vigra_fail(
"Images with multiple extra (alpha) channels not supported");
845 createCtrlPoints(pano, 0, *
leftImg, *
leftImgOrig, images[
i], *
rightImg, *
rightImgOrig, param.
pyrLevel, 2, param.
nPoints, param.
grid, param.
corrThresh, param.
stereo);
846 vigra::initImage(vigra::destImageRange(*
rightImg), vigra::NumericTraits<PixelType>::zero());
847 vigra::initImage(vigra::destImageRange(*
rightImgOrig), vigra::NumericTraits<PixelType>::zero());
851 createCtrlPoints(pano, images[
i - 1], *
leftImg, *
leftImgOrig, images[
i], *
rightImg, *
rightImgOrig, param.
pyrLevel, 2, param.
nPoints, param.
grid, param.
corrThresh, param.
stereo);
883 for (
int i=0;
i < (
int)cps.size();
i++)
893 std::cout <<
"Ctrl points before pruning: " << cps.size() <<
", after: " <<
newCPs.size() << std::endl;
906 std::cerr << std::endl <<
"After control points pruning reference images has no control" << std::endl
907 <<
"points Optimizing field of view in this case results in undefined" << std::endl
908 <<
"behaviour. Increase error distance (-t parameter), tweak cp" << std::endl
909 <<
"detection parameters or don't optimize HFOV." << std::endl
911 <<
"Exiting..." << std::endl;
919 std::cerr << std::endl <<
"After control points pruning there are only " << pano.
getNrOfCtrlPoints() <<
" control points" << std::endl
920 <<
"left, but you selected " << pano.
getOptimizeVector().size() <<
" parameters to optimize." << std::endl
921 <<
"This will give strange results." << std::endl
922 <<
"Increase error distance (-t parameter), tweak cp" << std::endl
923 <<
"detection parameters or select less parameters to optimize." << std::endl
925 <<
"Exiting..." << std::endl;
950 std::cerr <<
"An error occurred during optimization." << std::endl;
953 std::cerr <<
"Try adding \"-p debug.pto\" and checking output." << std::endl;
957 std::cerr <<
"Check output file " << param.
ptoFile <<
" for details." << std::endl;
959 std::cerr <<
"Exiting..." << std::endl;
989 std::cout <<
"Written HDR output to " << param.
hdrFile << std::endl;
1017 std::cout <<
"Written aligned images to files with prefix \"" << param.
alignedPrefix <<
"\"" << std::endl;
1025 std::cout <<
"Written output to " << param.
ptoFile << std::endl;
1031 catch (std::exception& e)
1033 std::cerr <<
"ERROR: caught exception: " << e.what() << std::endl;
1042 const char*
optstring =
"a:ef:g:hlmdiSAPCp:vo:s:t:c:xyz";
1083 std::cerr <<
hugin_utils::stripPath(
argv[0]) <<
": Invalid parameter: Number of points/grid (-c) must be at least 1" << std::endl;
1092 if (param.
hfov <= 0)
1100 if (param.
grid < 1 || param.
grid>50)
1102 std::cerr <<
hugin_utils::stripPath(
argv[0]) <<
": Invalid parameter: number of grid cells (-g) should be between 1 and 50" << std::endl;
1146 std::cerr <<
hugin_utils::stripPath(
argv[0]) <<
": Invalid parameter: control point error threshold (-t) must be greater than 0" << std::endl;
1179 std::cout <<
"WARNING: Switch --threads is deprecated. Set environment variable OMP_NUM_THREADS instead" << std::endl;
1182#if defined __APPLE__ && defined __aarch64__
1185 std::cout <<
"WARNING: GPU remapping is not supported on ARM Macs. Switching back to CPU remapping." << std::endl;
1233 std::vector<std::string> files;
1240 std::cerr <<
"Ignoring raw file " << filename << std::endl;
1244 if (!vigra::isImage(filename.c_str()))
1246 std::cerr <<
"Could not read file " << filename << std::endl;
1249 files.push_back(filename);
1253 std::cerr <<
"ERROR: No valid files given. Nothing to do." << std::endl;
1267 std::cerr <<
"ERROR: images with several alpha channels are not supported." << std::endl;
1272 catch (std::exception& e)
1274 std::cerr <<
"ERROR: caught exception: " << e.what() << std::endl;
1302 std::cerr <<
" ERROR: unsupported pixel type: " <<
pixelType << std::endl;
1325 std::cerr <<
" ERROR: unsupported pixel type: " <<
pixelType << std::endl;
std::multimap< double, vigra::Diff2D > MapPoints
class to access Hugins camera and lens database
!! from PTOptimise.h 1951
Somewhere to specify what variables belong to what.
Contains various routines used for stitching panoramas.
static int ptProgress(int command, char *argument)
int main(int argc, char *argv[])
void FineTuneInterestPoints(HuginBase::Panorama &pano, int img1, const ImageType &leftImg, const ImageType &leftImgOrig, int img2, const ImageType &rightImg, const ImageType &rightImgOrig, const MapPoints &points, unsigned nPoints, int pyrLevel, int templWidth, int sWidth, double scaleFactor, double corrThresh, bool stereo)
static int ptinfoDlg(int command, char *argument)
int main2(std::vector< std::string > files, Parameters param)
std::multimap< double, vigra::Diff2D > MapPoints
static hugin_omp::Lock lock
void autoCrop(HuginBase::Panorama &pano)
void createCtrlPoints(HuginBase::Panorama &pano, int img1, const ImageType &leftImg, const ImageType &leftImgOrig, int img2, const ImageType &rightImg, const ImageType &rightImgOrig, int pyrLevel, double scale, unsigned nPoints, unsigned grid, double corrThresh=0.9, bool stereo=false)
void alignStereoWindow(HuginBase::Panorama &pano, bool pop_out)
Dummy progress display, without output.
a progress display to print progress reports to a stream
@ RESPONSE_LINEAR
linear response
represents a control point
@ X
evaluate x, points are on a vertical line
@ Y
evaluate y, points are on a horizontal line
static void Clean()
cleanup the static LensDB instance, must be called at the end of the program
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
void setHeight(unsigned int h)
set panorama height
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
void setROI(const vigra::Rect2D &val)
double outputExposureValue
std::string outputPixelType
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
const PanoramaOptions & getOptions() const
returns the options for this panorama
void setOptimizeVector(const OptimizeVector &optvec)
set optimize setting
std::vector< unsigned int > getCtrlPointsForImage(unsigned int imgNr) const
return all control points for a given image.
void setCtrlPoints(const CPVector &points)
set all control points (Ippei: Is this supposed to be 'add' method?)
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
std::size_t getNrOfCtrlPoints() const
number of control points
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
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 activateImage(unsigned int imgNr, bool active=true)
mark an image as active or inactive.
const CPVector & getCtrlPoints() const
get all control point of this Panorama
const OptimizeVector & getOptimizeVector() const
return the optimize settings stored inside panorama
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
UIntSet getActiveImages() const
get active images
std::size_t getNrOfImages() const
number of images.
All variables of a source image.
bool readEXIF()
try to fill out information about the image, by examining the exif data
class AlphaIterator class AlphaAccessor inline void importImageAlpha(const ImageImportInfo &import_info, ImageIterator image_iterator, ImageAccessor image_accessor, AlphaIterator alpha_iterator, AlphaAccessor alpha_accessor)
vigra::FRGBImage ImageType
std::map< std::string, std::string > AdvancedOptions
void stitchPanorama(const PanoramaData &pano, const PanoramaOptions &opt, AppBase::ProgressDisplay *progress, const std::string &basename, const UIntSet &usedImgs, const AdvancedOptions &advOptions)
The main stitching function.
void SetAdvancedOption(AdvancedOptions &opts, const std::string &name, const bool value)
store the option with name in AdvancedOptions
std::vector< ControlPoint > CPVector
std::vector< std::set< std::string > > OptimizeVector
UIntSet getImagesinROI(const PanoramaData &pano, const UIntSet activeImages)
returns set of images which are visible in output ROI
std::set< unsigned int > UIntSet
void FindInterestPointsPartial(const ImageType &image, const vigra::Rect2D &rect, double scale, unsigned nPoints, std::multimap< double, vigra::Diff2D > &points, vigra::VigraTrueType)
vigra_ext::CorrelationResult FineTunePoint(const ImageType &leftImg, const vigra::Diff2D templPos, const int templSize, const ImageType &rightImg, const vigra::Diff2D searchPos, const int searchWidth, vigra::VigraTrueType)
bool initGPU(int *argcp, char **argv)
Try to initalise GLUT and GLEW, and create an OpenGL context for GPU stitching.
std::string getExtension(const std::string &basename2)
Get extension of a filename.
bool wrapupGPU()
cleanup GPU settings
bool IsRawExtension(const std::string testExt)
return true if extension belongs to a raw file
std::string GetHuginVersion()
return a string with version numbers
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
void findInterestPointsPartial(vigra::triple< ImageIter, ImageIter, ImageAcc > img, const vigra::Rect2D &rect, double scale, unsigned nPoints, std::multimap< double, vigra::Diff2D > &points)
void reduceNTimes(ImageIn &in, Image &out, int n)
CorrelationResult PointFineTune(const IMAGET &templImg, ACCESSORT access_t, vigra::Diff2D templPos, int templSize, const IMAGES &searchImg, ACCESSORS access_s, vigra::Diff2D searchPos, int sWidth)
fine tune a point with normalized cross correlation
std::string alignedPrefix
bool operator()(const unsigned int i, const unsigned int j)
SortImageVectorEV(const HuginBase::Panorama *pano)
const HuginBase::Panorama * m_pano
Maximum of correlation, position and value.
hugin_utils::FDiff2D curv
hugin_utils::FDiff2D maxpos
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.