27 #include <hugin_config.h>
36 #include <vigra/error.hxx>
37 #include <vigra/functorexpression.hxx>
38 #include <vigra/transformimage.hxx>
48 #include "../deghosting/deghosting.h"
49 #include "../deghosting/khan.h"
64 bool mergeWeightedAverage(std::vector<std::string> inputFiles, vigra::FRGBImage& output, vigra::BImage& alpha, vigra::Rect2D& outputROI)
67 std::vector<ImagePtr> images;
68 std::vector<deghosting::BImagePtr> weightImages;
69 std::vector<vigra::ImageImportInfo> imageInfo;
72 for (
size_t i = 0; i < inputFiles.size(); i++)
74 vigra::ImageImportInfo
info(inputFiles[i].c_str());
75 imageInfo.push_back(info);
78 outputROI = vigra::Rect2D(vigra::Point2D(info.getPosition()), info.size());
82 outputROI |= vigra::Rect2D(vigra::Point2D(info.getPosition()), info.size());
86 for (
size_t i=0; i < imageInfo.size(); i++)
93 std::cout <<
"Loading image: " << inputFiles[i] << std::endl;
96 vigra::Point2D offset = vigra::Point2D(imageInfo[i].getPosition());
97 offset -= outputROI.upperLeft();
99 img->resize(outputROI.size());
100 weight->resize(img->size().width(), img->size().height(), 0);
101 if (imageInfo[i].numBands() == 4)
107 importImage(imageInfo[i],
destImage(*img, offset));
110 images.push_back(img);
111 weightImages.push_back(weight);
114 output.resize(outputROI.size());
115 alpha.resize(output.width(), output.height(), 0);
118 std::cout <<
"Calculating weighted average " << std::endl;
125 for (
int y=0; y < output.height(); y++)
127 for (
int x=0; x < output.width(); x++)
131 bool hasValues =
false;
132 for (
unsigned imgNr=0; imgNr < images.size(); imgNr++)
135 const vigra::UInt8 weight = (*weightImages[imgNr])(x, y);
136 waverage( (*images[imgNr])(x,y), weight);
137 hasValues |= (weight > 0);
142 output(x,y) = waverage();
152 const std::vector<deghosting::FImagePtr>& weights,
153 vigra::FRGBImage& output,
154 vigra::BImage& alpha,
155 const vigra::Rect2D outputROI)
159 std::cout <<
"Merging input images" << std::endl;
161 int width = (weights[0])->width();
162 int height = (weights[0])->height();
164 assert(inputFiles.size() == weights.size());
166 vigra::BasicImage<vigra::NumericTraits<vigra::FRGBImage::PixelType>::Promote> weightedImg(width, height);
167 vigra::BasicImage<vigra::NumericTraits<vigra::FImage::PixelType>::Promote> weightAdded(width, height);
168 for(
unsigned i = 0; i < inputFiles.size(); i++)
170 vigra::ImageImportInfo inputInfo(inputFiles[i].c_str());
171 vigra::BasicImage<vigra::NumericTraits<vigra::FRGBImage::PixelType>::Promote> tmpImg(outputROI.size());
174 vigra::Point2D offset = vigra::Point2D(inputInfo.getPosition());
175 offset -= outputROI.upperLeft();
176 if (inputInfo.numBands() == 4)
178 vigra::BImage tmpMask(tmpImg.size());
190 output.resize(width, height);
191 alpha.resize(width, height, 0);
194 vigra::Threshold<vigra::FImage::PixelType, vigra::BImage::PixelType>(1e-7f, FLT_MAX, 0, 255));
200 std::cout << name <<
": merge overlapping images" << std::endl
204 <<
"Usage: " << name <<
" [options] -o output.exr <input-files>" << std::endl
205 <<
"Valid options are:" << std::endl
206 <<
" -o|--output prefix output file" << std::endl
207 <<
" -m mode merge mode, can be one of: avg (default), avg_slow, khan, if avg, no" << std::endl
208 <<
" -i and -s options apply" << std::endl
209 <<
" -i iter number of iterations to execute (default is 4). Khan only" << std::endl
210 <<
" -s sigma standard deviation of Gaussian weighting" << std::endl
211 <<
" function (sigma > 0); default: 30. Khan only" << std::endl
212 <<
" -a set advanced settings. Possible options are:" << std::endl
213 <<
" f use gray images for computation. It's about two times faster" << std::endl
214 <<
" but it usually returns worse results." << std::endl
215 <<
" g use gamma 2.2 correction instead of logarithm" << std::endl
216 <<
" m do not scale image, NOTE: slows down process" << std::endl
217 <<
" -c Only consider pixels that are defined in all images (avg mode only)" << std::endl
218 <<
" -v|--verbose Verbose, print progress messages, repeat for" << std::endl
219 <<
" even more verbose output" << std::endl
220 <<
" -h|help Display help (this text)" << std::endl
225 int main(
int argc,
char* argv[])
229 const char* optstring =
"chvo:m:i:s:a:el";
230 static struct option longOptions[] =
232 {
"output", required_argument, NULL,
'o' },
233 {
"verbose", no_argument, NULL,
'v' },
234 {
"help", no_argument, NULL,
'h' },
240 std::string outputFile =
"merged.exr";
241 std::string mode =
"avg";
242 bool onlyCompleteOverlap =
false;
248 while ((c = getopt_long(argc, argv, optstring, longOptions,
nullptr)) != -1)
256 iterations = atoi(optarg);
259 sigma = atof(optarg);
262 for(
char* c = optarg; *c; c++)
281 onlyCompleteOverlap =
true;
303 unsigned nFiles = argc - optind;
309 else if (nFiles == 1)
311 std::cout << std::endl <<
"Only one input image given. Copying input image to output image." << std::endl;
313 std::ifstream infile(argv[optind], std::ios_base::binary);
314 std::ofstream outfile(outputFile.c_str(), std::ios_base::binary);
315 outfile << infile.rdbuf();
320 std::vector<std::string> inputFiles;
321 for (
size_t i=optind; i < (size_t)argc; i++)
323 inputFiles.push_back(argv[i]);
330 if (mode ==
"avg_slow")
336 std::cout <<
"Running simple weighted avg algorithm" << std::endl;
339 vigra::Rect2D outputROI;
344 std::cout <<
"Writing " << outputFile << std::endl;
346 vigra::ImageExportInfo exinfo(outputFile.c_str());
347 exinfo.setPixelType(
"FLOAT");
348 exinfo.setPosition(outputROI.upperLeft());
349 exinfo.setCanvasSize(vigra::Size2D(outputROI.lowerRight().x, outputROI.lowerRight().y));
352 else if (mode ==
"avg")
360 else if (mode ==
"khan")
364 std::cout <<
"Running Khan deghosting algorithm" << std::endl;
366 vigra::Rect2D outputROI;
367 std::vector<deghosting::FImagePtr> weights;
385 std::cout <<
"Writing " << outputFile << std::endl;
387 vigra::ImageExportInfo exinfo(outputFile.c_str());
388 exinfo.setPixelType(
"FLOAT");
389 exinfo.setPosition(outputROI.upperLeft());
390 exinfo.setCanvasSize(vigra::Size2D(outputROI.lowerRight().x, outputROI.lowerRight().y));
395 std::cerr <<
"Unknown merge mode, see help for a list of possible modes" << std::endl;
399 catch (std::exception& e)
401 std::cerr <<
"caught exception: " << e.what() << std::endl;
const uint16_t ADV_MULTIRES
std::shared_ptr< vigra::BImage > BImagePtr
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.
bool mergeWeightedAverage(std::vector< std::string > inputFiles, vigra::FRGBImage &output, vigra::BImage &alpha, vigra::Rect2D &outputROI)
bool weightedAverageOfImageFiles(const std::vector< std::string > &inputFiles, const std::vector< deghosting::FImagePtr > &weights, vigra::FRGBImage &output, vigra::BImage &alpha, const vigra::Rect2D outputROI)
compute output image when given source images
void exportImageAlpha(ImageIterator image_upper_left, ImageIterator image_lower_right, ImageAccessor image_accessor, AlphaIterator alpha_upper_left, AlphaAccessor alpha_accessor, const ImageExportInfo &export_info)
Write the image and its alpha channel to a file.
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
const uint16_t OTHER_GRAY
virtual std::vector< FImagePtr > createWeightMasks() override
create weight masks create weight masks for masking out ghosting regions
void combineThreeImages(SrcImageIterator1 src1_upperleft, SrcImageIterator1 src1_lowerright, SrcAccessor1 src1_acc, SrcImageIterator2 src2_upperleft, SrcAccessor2 src2_acc, SrcImageIterator3 src3_upperleft, SrcAccessor3 src3_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc, const Functor &func)
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 importImageAlpha(const ImageImportInfo &import_info, ImageIterator image_iterator, ImageAccessor image_accessor, AlphaIterator alpha_iterator, AlphaAccessor alpha_accessor, VigraTrueType)
vigra::FRGBImage ImageType
std::shared_ptr< ImageType > ImagePtr
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
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...
static uint16_t otherFlags
std::string GetHuginVersion()
return a string with version numbers
vigra::triple< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImageRange(ROIImage< Image, Alpha > &img)
static void info(const char *fmt,...)
vigra::Rect2D getOutputROI() const
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
void reduceFilesToHDR(std::vector< std::string > input, std::string output, bool onlyCompleteOverlap, Functor &reduce)
int main(int argc, char *argv[])