27 #include <hugin_config.h>
32 #include <vigra/error.hxx>
34 #include <vigra/cornerdetection.hxx>
35 #include <vigra/localminmax.hxx>
39 #include "vigra/stdimage.hxx"
40 #include "vigra/stdimagefunctions.hxx"
41 #include "vigra/functorexpression.hxx"
42 #include "vigra/transformimage.hxx"
54 #include <foreign/levmar/levmar.h>
65 #define DEFAULT_OPTIMISATION_PARAMETER "abcvde"
122 double mEstimatorSigma,
int maxIter)
129 for (
unsigned int i = 0; i<3; i++)
131 const std::set<std::string> vars =
m_optvars[i];
132 for (std::set<std::string>::const_iterator it = vars.begin(); it != vars.end(); ++it)
134 const char var = (*it)[0];
135 if ((var >=
'a') && (var <=
'c'))
139 else if ((var ==
'd') || (var ==
'e'))
149 std::cerr <<
"Unknown parameter detected, ignoring!" << std::endl;
158 for (
size_t i=0; i <
m_mapping.size(); i++)
167 for (
size_t i=0; i <
m_mapping.size(); i++)
175 for (
unsigned int i = 0; i < 3; i++)
178 m_hfov[i] = img.getHFOV();
179 m_dist[i][0] = img.getRadialDistortion()[0];
180 m_dist[i][1] = img.getRadialDistortion()[1];
181 m_dist[i][2] = img.getRadialDistortion()[2];
184 m_shift[0] = img.getRadialDistortionCenterShift().x;
185 m_shift[1] = img.getRadialDistortionCenterShift().y;
186 m_center[0] = img.getSize().width() / 2.0;
187 m_center[1] = img.getSize().height() / 2.0;
193 for (
unsigned int i = 0; i < 3; i++)
197 std::vector<double> radialDist(4);
198 radialDist[0] =
m_dist[i][0];
199 radialDist[1] =
m_dist[i][1];
200 radialDist[2] =
m_dist[i][2];
201 radialDist[3] = 1 - radialDist[0] - radialDist[1] - radialDist[2];
202 img.setRadialDistortion(radialDist);
212 std::set<std::string> vars = g_param.
optvars;
213 optvars.push_back(vars);
214 optvars.push_back(std::set<std::string>());
219 optvars.push_back(vars);
255 x = sqrt(sigma*(2.0*fabs(x) - sigma));
267 for (
unsigned int i = 0; i<3; i++)
270 for (
unsigned int j = 0; j<3; j++)
272 dist[i][j] = dat->
m_dist[i][j] *
pow(scale, (
int)(4 - j));
287 for (
unsigned int ptIdx = 0; ptIdx < noPts; ptIdx++)
291 double dist_p1 = vigra::hypot(cp.
x1 - center[0], cp.
y1 - center[1]);
292 double dist_p2 = vigra::hypot(cp.
x2 - center[0], cp.
y2 - center[1]);
296 double base_dist = dist_p1 / base_size;
297 double corr_dist_p1 = dist[cp.
image2Nr][0] *
pow(base_dist, 4) +
301 corr_dist_p1 *= base_size;
302 x[ptIdx] = corr_dist_p1 - dist_p2;
306 double base_dist = dist_p2 / base_size;
307 double corr_dist_p2 = dist[cp.
image1Nr][0] *
pow(base_dist, 4) +
311 corr_dist_p2 *= base_size;
312 x[ptIdx] = corr_dist_p2 - dist_p1;
316 newcp.
error = fabs(x[ptIdx]);
317 newCPs.push_back(newcp);
330 int optVis(
double* p,
double* x,
int m,
int n,
int iter,
double sqerror,
void*
data)
353 double info[LM_INFO_SZ];
357 vigra::ArrayVector<double> p(m, 0.0);
361 vigra::ArrayVector<double> x(n, 0.0);
366 fprintf(stderr,
"Parameters before optimization: ");
367 for (
int i = 0; i<m; ++i)
369 fprintf(stderr,
"%.7g ", p[i]);
371 fprintf(stderr,
"\n");
374 ret = dlevmar_dif(&
optGetError, &
optVis, &(p[0]), &(x[0]), m, n, nMaxIter, NULL, info, NULL, NULL, &data);
381 for (
int i = 0; i<n; i++)
383 error += x[i] * x[i];
385 error = sqrt(error / n);
389 fprintf(stderr,
"Levenberg-Marquardt returned %d in %g iter, reason %g\nSolution: ", ret, info[5], info[6]);
390 for (
int i = 0; i<m; ++i)
392 fprintf(stderr,
"%.7g ", p[i]);
394 fprintf(stderr,
"\n\nMinimization info:\n");
395 for (
int i = 0; i<LM_INFO_SZ; ++i)
397 fprintf(stderr,
"%g ", info[i]);
399 fprintf(stderr,
"\n");
405 std::cout << name <<
": Parameter estimation of transverse chromatic abberations" << std::endl
408 <<
"Usage: " << name <<
" [options] <inputfile>" << std::endl
409 <<
" option are: " << std::endl
410 <<
" -h Display help (this text)" << std::endl
411 <<
" -l input file is PTO file instead of image" << std::endl
412 <<
" -m method optimization method (0 normal, 1 newfit)" << std::endl
413 <<
" -o optvars string of variables to optimize (\"abcvde\")" << std::endl
414 <<
" -r reset values (this will zero a,b,c,d,e params and set v to 10)" << std::endl
415 <<
" makes sense only with -l option" << std::endl
416 <<
" -s <scale> Scale for corner detection" << std::endl
417 <<
" -n <number> number of points per grid cell (default: 10)" << std::endl
418 <<
" -g <number> divide image in <number>x<number> grid cells (default: 10)" << std::endl
419 <<
" -t num Remove all control points with an error higher than num pixels (default: 1.5)" << std::endl
420 <<
" -v Verbose" << std::endl
421 <<
" --save-into-database Saves the tca data into Hugin lens database" << std::endl
422 <<
" -w filename write PTO file" << std::endl
423 <<
" -R <r> Use this file as red channel" << std::endl
424 <<
" -G <g> Use this file as green channel" << std::endl
425 <<
" -B <b> Use this file as blue channel" << std::endl
427 <<
" <inputfile> is the base name of 4 image files:" << std::endl
428 <<
" <inputfile> Colour file to compute TCA parameters" << std::endl
429 <<
" red_<inputfile> Red channel of <inputfile>" << std::endl
430 <<
" green_<inputfile> Green channel of <inputfile>" << std::endl
431 <<
" blue_<inputfile> Blue channel of <inputfile>" << std::endl
432 <<
" The channel images must be colour images with 3 identical channels." << std::endl
433 <<
" If any of -R, -G, or -B is given, this file name is used instead of the derived name." << std::endl
435 <<
" Output:" << std::endl
436 <<
" commandline arguments for fulla" << std::endl;
442 template <
class ImageType>
445 vigra::BasicImage<vigra::RGBValue<vigra::UInt8> > img8(img.size());
449 vigra::functor::Arg1()*vigra::functor::Param(ratio));
452 std::cout <<
"image8 size:" << img8.size() << std::endl;
459 std::cout <<
"Finding control points... " << std::endl;
461 const long templWidth = 29;
462 const long sWidth = 29 + 11;
465 vigra::Size2D size(img8.width(), img8.height());
466 std::vector<vigra::Rect2D> rects;
467 for (
unsigned party = 0; party < grid; party++)
469 for (
unsigned partx = 0; partx < grid; partx++)
472 vigra::Rect2D rect(partx*size.x / grid, party*size.y / grid,
473 (partx + 1)*size.x / grid, (party + 1)*size.y / grid);
474 rect &= vigra::Rect2D(size);
475 if (rect.width()>0 && rect.height()>0)
477 rects.push_back(rect);
482 #pragma omp parallel for schedule(dynamic)
483 for (
int i = 0; i < rects.size(); ++i)
486 vigra::Rect2D rect(rects[i]);
492 for (MapPoints::const_reverse_iterator it = points.rbegin(); it != points.rend(); ++it)
494 if (cps.size() >= nPoints)
506 img8, vigra::GreenAccessor<vigra::RGBValue<vigra::UInt8> >(),
508 img8, vigra::RedAccessor<vigra::RGBValue<vigra::UInt8> >(),
531 img8, vigra::GreenAccessor<vigra::RGBValue<vigra::UInt8> >(), roundP1, templWidth,
532 img8, vigra::BlueAccessor<vigra::RGBValue<vigra::UInt8> >(), roundP2, sWidth);
550 std::ostringstream buf;
551 buf <<
"Number of good matches: " << cps.size() <<
", bad matches: " << nBad << std::endl;
552 std::cout << buf.str();
557 for (HuginBase::CPVector::const_iterator it = cps.begin(); it != cps.end(); ++it)
567 template <
class PixelType>
570 typedef vigra::BasicImage<PixelType>
ImageType;
574 vigra::ImageImportInfo imgInfo(filename);
575 ImageType imgOrig(imgInfo.size());
577 const int bands = imgInfo.numBands();
578 const int extraBands = imgInfo.numExtraBands();
580 if (!(bands == 3 || (bands == 4 && extraBands == 1)))
582 std::cerr <<
"Unsupported number of bands!";
592 vigra::BImage alpha(imgInfo.size());
600 std::string red_name;
607 red_name=std::string(
"red_")+filename;
611 srcRedImg.
setSize(imgInfo.size());
613 srcRedImg.setHFOV(10);
614 srcRedImg.setCropFactor(1);
615 srcRedImg.setFilename(red_name);
616 int imgRedNr = pano.
addImage(srcRedImg);
620 std::string green_name;
627 green_name=std::string(
"green_")+filename;
631 srcGreenImg.
setSize(imgInfo.size());
633 srcGreenImg.setHFOV(10);
634 srcGreenImg.setCropFactor(1);
635 srcGreenImg.setFilename(green_name);
636 int imgGreenNr = pano.
addImage(srcGreenImg);
640 std::string blue_name;
647 blue_name=std::string(
"blue_")+filename;
651 srcBlueImg.
setSize(imgInfo.size());
653 srcBlueImg.setHFOV(10);
654 srcBlueImg.setCropFactor(1);
655 srcBlueImg.setFilename(blue_name);
656 int imgBlueNr = pano.
addImage(srcBlueImg);
668 opts.
setHFOV(srcGreenImg.getHFOV(),
false);
669 opts.
setWidth(srcGreenImg.getSize().x,
false);
683 catch (std::exception& e)
685 std::cerr <<
"ERROR: caught exception: " << e.what() << std::endl;
695 const std::string filenameString(filename);
706 for (
unsigned int i=0; i < 3; i++)
712 std::vector<double> radialDist(4);
717 img.setRadialDistortion(radialDist);
731 for (
unsigned int i=0; i < 3; i++)
734 hfov[i] = img.getHFOV();
735 dist[i][0] = img.getRadialDistortion()[0];
736 dist[i][1] = img.getRadialDistortion()[1];
737 dist[i][2] = img.getRadialDistortion()[2];
740 shift[0] = img.getRadialDistortionCenterShift().x;
741 shift[1] = img.getRadialDistortionCenterShift().y;
746 double distnew[3][4];
747 for (
unsigned int i=0 ; i<3 ; i++)
749 double scale = hfov[1] / hfov[i];
750 for (
unsigned int j=0 ; j<3 ; j++)
752 distnew[i][j] = dist[i][j]*
pow(scale, (
int)(4-j));
754 distnew[i][3] = scale*(1 - dist[i][0] - dist[i][1] - dist[i][2]);
759 fprintf(stdout,
"-r %.7f:%.7f:%.7f:%.7f "
760 "-b %.7f:%.7f:%.7f:%.7f ",
761 distnew[0][0], distnew[0][1], distnew[0][2], distnew[0][3],
762 distnew[2][0], distnew[2][1], distnew[2][2], distnew[2][3]);
766 fprintf(stdout,
"-r %.7f:%.7f:%.7f:%.7f "
767 "-b %.7f:%.7f:%.7f:%.7f "
769 distnew[0][0], distnew[0][1], distnew[0][2], distnew[0][3],
770 distnew[2][0], distnew[2][1], distnew[2][2], distnew[2][3],
781 if (lensname.empty())
784 std::cout << std::endl <<
"For saving information tca data into database no suitable information" << std::endl
785 <<
"found in EXIF data." << std::endl
786 <<
"For fixed lens cameras leave lensname empty." << std::endl << std::endl <<
"Lensname: ";
788 std::cin.getline(input, 255);
790 if (lensname.empty())
792 std::string camMaker;
793 std::string camModel;
794 std::cout <<
"Camera maker: ";
795 while (camMaker.empty())
797 std::cin.getline(input, 255);
800 std::cout <<
"Camera model: ";
801 while (camModel.empty())
803 std::cin.getline(input, 255);
806 lensname = camMaker.append(
"|").append(camModel);
809 double focal = img.getExifFocalLength();
810 if (fabs(focal) < 0.1f)
812 std::cout <<
"Real focal length (in mm): ";
813 while (fabs(focal) < 0.1f)
820 std::vector<double> redDistData(4, 0.0f);
821 std::vector<double> blueDistData(4, 0.0f);
822 redDistData[0] = distnew[0][0];
823 redDistData[1] = distnew[0][1];
824 redDistData[2] = distnew[0][2];
825 redDistData[3] = distnew[0][3];
826 blueDistData[0] = distnew[2][0];
827 blueDistData[1] = distnew[2][1];
828 blueDistData[2] = distnew[2][2];
829 blueDistData[3] = distnew[2][3];
830 if (lensDB.
SaveTCA(lensname, focal, redDistData, blueDistData))
832 std::cout << std::endl << std::endl <<
"TCA data for " << lensname <<
" @ " << focal <<
" mm successful saved into database." << std::endl;
836 std::cout << std::endl << std::endl <<
"Could not save data into database." << std::endl;
849 for (
int i = 0; i < 10; i++)
861 std::cerr <<
"Unknown optimizer strategy." << std::endl
862 <<
"Using newfit method." << std::endl;
869 for (HuginBase::CPVector::const_iterator it = cps.begin(); it != cps.end(); ++it)
873 newCPs.push_back(*it);
878 std::cerr <<
"Ctrl points before pruning: " << cps.size() <<
", after: " << newCPs.size() << std::endl;
882 if (cps.size() == newCPs.size())
903 int main(
int argc,
char* argv[])
906 const char* optstring =
"hlm:o:rt:vw:R:G:B:s:g:n:";
911 static struct option longOptions[] =
913 {
"save-into-database", no_argument, NULL, SAVEDATABASE },
914 {
"help", no_argument, NULL,
'h' },
918 bool parameter_request_seen=
false;
920 while ((c = getopt_long(argc, argv, optstring, longOptions,
nullptr)) != -1)
935 char* optptr = optarg;
938 if ((*optptr ==
'a') || (*optptr ==
'b') ||
939 (*optptr ==
'c') || (*optptr ==
'v') ||
940 (*optptr ==
'd') || (*optptr ==
'e'))
942 g_param.
optvars.insert(std::string(optptr, 1));
946 parameter_request_seen=
true;
950 g_param.
reset =
true;
956 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": Invalid parameter: control point error threshold (-t) must be greater than 0" << std::endl;
976 g_param.
scale=atof( optarg);
982 g_param.
grid=atoi(optarg);
998 if (argc - optind != 1)
1000 if (argc - optind < 1)
1013 if ( !parameter_request_seen)
1018 g_param.
optvars.insert( std::string( dop, 1));
1032 vigra::ImageImportInfo firstImgInfo(argv[optind]);
1033 std::string pixelType = firstImgInfo.getPixelType();
1034 if (pixelType ==
"UINT8")
1036 return processImg<vigra::RGBValue<vigra::UInt8> >(argv[optind]);
1038 else if (pixelType ==
"INT16")
1040 return processImg<vigra::RGBValue<vigra::Int16> >(argv[optind]);
1042 else if (pixelType ==
"UINT16")
1044 return processImg<vigra::RGBValue<vigra::UInt16> >(argv[optind]);
1048 std::cerr <<
" ERROR: unsupported pixel type: " << pixelType << std::endl;
std::set< std::string > optvars
int optimize_old(HuginBase::Panorama &pano)
void setHeight(unsigned int h)
set panorama height
std::string StrTrim(const std::string &str)
remove trailing and leading white spaces and tabs
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.
static LensDB & GetSingleton()
returns the static LensDB instance
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
virtual void setSrcImage(unsigned int nr, const SrcPanoImage &img)=0
set input image parameters TODO: Propagate changes to linked images.
void FromX(double *x)
copy new values from x to internal optimization variables
void optGetError(double *p, double *x, int m, int n, void *data)
void resetValues(HuginBase::Panorama &pano)
misc math function & classes used by other parts of the program
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 getDBLensName() const
constructs the lens name for the database it is the lensname if known, for compact cameras it is cons...
Somewhere to specify what variables belong to what.
const CPVector & getCtrlPoints() const
get all control point of this Panorama
represents a control point
functions to manage ROI's
void setOptimizeVector(const OptimizeVector &optvec)
set optimize setting
void findInterestPointsPartial(vigra::triple< ImageIter, ImageIter, ImageAcc > img, const vigra::Rect2D &rect, double scale, unsigned nPoints, std::multimap< double, vigra::Diff2D > &points)
static void Clean()
cleanup the static LensDB instance, must be called at the end of the program
#define DEFAULT_OPTIMISATION_PARAMETER
std::set< unsigned int > UIntSet
class to access Hugins camera and lens database
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
void print_result(HuginBase::Panorama &pano)
virtual void updateCtrlPointErrors(const CPVector &controlPoints)=0
update control points distances.
bool SaveTCA(const std::string &lens, const double focal, const std::vector< double > &tca_red, const std::vector< double > &tca_blue, const int weight=10)
saves the tca distortion parameters of the lens
std::size_t getNrOfImages() const
number of images.
void setCtrlPoints(const CPVector &points)
set all control points (Ippei: Is this supposed to be 'add' method?)
vigra::FRGBImage ImageType
float pow(float a, double b)
OptimData(HuginBase::PanoramaData &pano, const HuginBase::OptimizeVector &optvars, double mEstimatorSigma, int maxIter)
static int ptinfoDlg(int command, char *argument)
bool ReadPTOFile(const std::string &filename, const std::string &prefix="")
read pto file from the given filename into Panorama object it does some checks on the file and issues...
Maximum of correlation, position and value.
void ToX(double *x)
copy internal optimization variables into x
ImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
std::vector< double * > m_mapping
std::multimap< double, vigra::Diff2D > MapPoints
int processPTO(const char *filename)
std::string ptoOutputFile
virtual const ControlPoint & getCtrlPoint(std::size_t nr) const =0
get a control point, counting starts with 0
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
static int ptProgress(int command, char *argument)
void unlinkVariablePart(ImageVariableEnum variable, unsigned int partNr)
unlink one of the variables across a given part.
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
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
int processImg(const char *filename)
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...
Same as above, but use a non const panorama.
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 setHFOV(double h, bool keepView=true)
set the horizontal field of view.
Contains various routines used for stitching panoramas.
std::string alignedPrefix
const PanoramaOptions & getOptions() const
returns the options for this panorama
options wxIntPtr wxIntPtr sortData std::vector< PanoInfo > * data
static hugin_omp::Lock lock
void updatePartNumbers()
Update the part numbers, call this when the panorama changes.
const HuginBase::OptimizeVector & m_optvars
bool readEXIF()
try to fill out information about the image, by examining the exif data
void setSize(vigra::Size2D val)
Set the image size in pixels.
std::string GetHuginVersion()
return a string with version numbers
int main2(std::vector< std::string > files, Parameters param)
int optVis(double *p, double *x, int m, int n, int iter, double sqerror, void *data)
hugin_utils::FDiff2D maxpos
std::vector< ControlPoint > CPVector
virtual std::size_t getNrOfCtrlPoints() const =0
number of control points
static void info(const char *fmt,...)
std::vector< std::set< std::string > > OptimizeVector
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
HuginBase::PanoramaData & m_pano
void printPanoramaScript(std::ostream &o, const OptimizeVector &optvars, const PanoramaOptions &options, const UIntSet &imgs, bool forPTOptimizer, const std::string &stripPrefix="") const
create an optimizer script
virtual SrcPanoImage getSrcImage(unsigned imgNr) const =0
get a complete description of a source image
void setSrcImage(unsigned int nr, const SrcPanoImage &img)
set input image parameters
virtual std::size_t getNrOfImages() const =0
number of images.
void optimize_new(HuginBase::PanoramaData &pano)
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.
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
void get_optvars(HuginBase::OptimizeVector &_retval)
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
double weightHuber(double x, double sigma)
int main(int argc, char *argv[])