33 #include <vigra/imageinfo.hxx>
34 #include <vigra/codec.hxx>
35 #include <vigra/stdimage.hxx>
37 #include <vigra/tiff.hxx>
42 void SetCompression(vigra::ImageExportInfo& output,
const std::string& compression)
45 if (!compression.empty())
47 if (ext ==
"JPEG" || ext ==
"JPG")
49 output.setCompression(std::string(
"JPEG QUALITY=" + compression).c_str());
53 output.setCompression(compression.c_str());
59 template <
class ImageType,
class MaskType>
60 bool SaveImage(
ImageType& image, MaskType& mask, vigra::ImageExportInfo& exportImageInfo, std::string filetype, std::string pixelType)
62 typedef typename vigra::NumericTraits<typename ImageType::value_type>::isScalar scalar;
63 const int numberChannels = scalar().asBool ? 1 : 3;
64 exportImageInfo.setPixelType(pixelType.c_str());
65 if (vigra::isBandNumberSupported(filetype, numberChannels +1))
71 catch (std::exception& e)
73 std::cerr <<
"ERROR: Could not save " << exportImageInfo.getFileName() << std::endl
74 <<
"Cause: " << e.what() << std::endl;
81 if (vigra::isBandNumberSupported(filetype, numberChannels))
83 std::cout <<
"Warning: Filetype " << filetype <<
" does not support alpha channels." << std::endl
84 <<
"Saving image without alpha channel." << std::endl;
89 catch (std::exception& e)
91 std::cerr <<
"ERROR: Could not save " << exportImageInfo.getFileName() << std::endl
92 <<
"Cause: " << e.what() << std::endl;
99 std::cerr <<
"ERROR: Output filetype " << filetype <<
" does not support " << numberChannels <<
" channels." << std::endl
100 <<
"Can't save image." << std::endl;
107 template <
class ImageType,
class MaskType>
110 VIGRA_UNIQUE_PTR<vigra::Encoder> encoder(vigra::encoder(output));
111 if (vigra::isPixelTypeSupported(encoder->getFileType(), inputPixelType))
113 return SaveImage(image, mask, output, encoder->getFileType(), inputPixelType);
117 if (vigra::isPixelTypeSupported(encoder->getFileType(),
"UINT8"))
120 output.setForcedRangeMapping(0, vigra::NumericTraits<
typename vigra::NumericTraits<typename ImageType::PixelType>::ValueType>::
max(), 0, 255);
121 return SaveImage(image, mask, output, encoder->getFileType(),
"UINT8");
125 std::cerr <<
"ERROR: Output file type " << encoder->getFileType() <<
" does not support" << std::endl
126 <<
"requested pixeltype " << inputPixelType <<
"." << std::endl
127 <<
"Save output in other file format." << std::endl;
136 std::cout << name <<
": stack images" << std::endl
139 <<
"Usage: " << name <<
" [options] images" << std::endl
141 <<
" --output=FILE Set the filename for the output file." << std::endl
142 <<
" --compression=value Compression of the output files" << std::endl
143 <<
" For jpeg output: 0-100" << std::endl
144 <<
" For tiff output: PACKBITS, DEFLATE, LZW" << std::endl
145 <<
" --mode=STRING Select the mode for stacking" << std::endl
146 <<
" Possible names are described below." << std::endl
148 <<
" min|minimum|darkest Select the darkest pixel" << std::endl
149 <<
" max|maximum|brightest Select the brightest pixel" << std::endl
150 <<
" avg|average|mean Calculate the mean for each position" << std::endl
151 <<
" median Calculate the median for each position" << std::endl
152 <<
" winsor Calculate the Winsor trimmed mean" << std::endl
153 <<
" for each position. The parameter can be" << std::endl
154 <<
" set with --winsor-trim=NUMBER (default: 0.2)" << std::endl
155 <<
" sigma Calculate the sigma clipped mean for" << std::endl
156 <<
" each position. Fine-tune with" << std::endl
157 <<
" --max-sigma=NUMBER (default: 2) and" << std::endl
158 <<
" --max-iterations=NUMBER (default: 5)" << std::endl
160 <<
" --mask-input Mask input images" << std::endl
161 <<
" Only pixel which differ more than" << std::endl
162 <<
" mask-sigma * standard deviation" << std::endl
163 <<
" are visible in output" << std::endl
164 <<
" available for modes median, winsor or sigma" << std::endl
165 <<
" --mask-suffix=STRING Suffix for the masked input images" << std::endl
166 <<
" (default: _mask)" << std::endl
167 <<
" --mask-sigma=NUMBER Sigma parameter for input images masking" << std::endl
168 <<
" (default: 2)" << std::endl
169 <<
" --multi-layer-output Output layered TIFF instead of single images" << std::endl
170 <<
" (has only effect with --mask-input)" << std::endl
171 <<
" --bigtiff Write output in BigTIFF format" << std::endl
172 <<
" (only with TIFF output)" << std::endl
173 <<
" -h, --help Shows this help" << std::endl
175 <<
"The images to process can also be read from a text file. In this case specify the name" << std::endl
176 <<
"of the text file after an at sign + space (@ FILE.TXT)." << std::endl
270 template<
class ValueType>
271 void getValue(
const int x, vigra::RGBValue<ValueType>& value, ValueType& mask)
275 mask = vigra::NumericTraits<ValueType>::zero();
281 mask = vigra::NumericTraits<ValueType>::zero();
287 const ValueType* band0=
static_cast<const ValueType*
>(
m_decoder->currentScanlineOfBand(0));
288 const ValueType* band1 =
static_cast<const ValueType*
>(
m_decoder->currentScanlineOfBand(1));
289 const ValueType* band2 =
static_cast<const ValueType*
>(
m_decoder->currentScanlineOfBand(2));
295 const ValueType* band3 =
static_cast<const ValueType*
>(
m_decoder->currentScanlineOfBand(3));
303 value = vigra::RGBValue<ValueType>(*band0, *band1, *band2);
307 mask = vigra::NumericTraits<ValueType>::zero();
312 template<
class ValueType>
313 void getValue(
const int x, ValueType& value, ValueType& mask)
317 mask = vigra::NumericTraits<ValueType>::zero();
323 mask = vigra::NumericTraits<ValueType>::zero();
329 const ValueType* band0 =
static_cast<const ValueType*
>(
m_decoder->currentScanlineOfBand(0));
333 const ValueType* band1 =
static_cast<const ValueType*
>(
m_decoder->currentScanlineOfBand(1));
345 mask = vigra::NumericTraits<ValueType>::zero();
361 template<
class ValueType>
362 void getMean(
const std::vector<ValueType>& values, ValueType& val)
365 typedef vigra::NumericTraits<ValueType> RealTraits;
366 typename RealTraits::RealPromote mean = RealTraits::zero();
367 for (
auto& x : values)
370 mean += (x - mean) / n;
372 val = RealTraits::fromRealPromote(mean);
375 template<
class ValueType>
376 void getMeanSigma(
const std::vector<ValueType>& values, ValueType& val,
typename vigra::NumericTraits<ValueType>::RealPromote&
sigma)
378 typedef vigra::NumericTraits<ValueType> RealTraits;
379 typedef typename RealTraits::RealPromote RealType;
381 RealType mean = RealTraits::zero();
382 RealType m2 = RealTraits::zero();
383 for (
auto& x : values)
386 const RealType delta = x - mean;
388 const RealType delta2 = x - mean;
391 val = RealTraits::fromRealPromote(mean);
394 sigma = sqrt(m2 / n);
398 sigma = vigra::NumericTraits<RealType>::zero();
402 template<
class ValueType>
408 void operator()(
const ValueType& val, vigra::VigraFalseType) {
if (val.luminance() <
m_min.luminance())
m_min = val; }
411 typedef typename vigra::NumericTraits<ValueType>::isScalar is_scalar;
420 template<
class ValueType>
426 void operator()(
const ValueType& val, vigra::VigraFalseType) {
if (val.luminance() >
m_max.luminance())
m_max = val;}
429 typedef typename vigra::NumericTraits<ValueType>::isScalar is_scalar;
438 template<
class ValueType>
447 const std::string
getName()
const {
return "mean"; };
452 template<
class ValueType>
465 const int index = this->
m_values.size() / 2;
475 const std::string
getName()
const {
return "median"; };
478 void sort(vigra::VigraTrueType)
483 void sort(vigra::VigraFalseType)
486 [](
const ValueType & a,
const ValueType & b) {
return a.luminance() < b.luminance(); });
491 typedef typename vigra::NumericTraits<ValueType>::isScalar is_scalar;
496 template<
class ValueType>
510 const std::string
getName()
const {
return "Winsor clipped mean"; };
516 for (
size_t i = 0; i < indexTrim; ++i)
520 for (
size_t i = this->
m_values.size() - indexTrim; i < this->
m_values.size(); ++i)
527 template<
class ValueType>
536 typedef typename vigra::NumericTraits<ValueType>::isScalar is_scalar;
541 size_t iteration = 0;
567 size_t iteration = 0;
570 double grayMean, graySigma;
592 const std::string
getName()
const {
return "sigma clipped mean"; };
599 bool CheckInput(
const std::vector<InputImage*>& images, vigra::Rect2D& outputROI, vigra::Size2D& canvasSize)
606 outputROI = images[0]->getROI();
607 canvasSize = images[0]->getCanvasSize();
608 for (
size_t i = 1; i < images.size(); ++i)
610 outputROI |= images[i]->getROI();
611 if (images[i]->getCanvasSize().width() > canvasSize.width())
613 canvasSize.setWidth(images[i]->getCanvasSize().width());
615 if (images[i]->getCanvasSize().height() > canvasSize.height())
617 canvasSize.setHeight(images[i]->getCanvasSize().height());
620 if (outputROI.area() == 0)
622 std::cerr <<
"ERROR: You can't stack non-overlapping images." << std::endl;
629 template <
class PixelType,
class Functor>
630 bool StackImages(std::vector<InputImage*>& images, Functor& stacker)
632 typedef typename vigra::NumericTraits<PixelType>::ValueType ChannelType;
633 vigra::Rect2D outputROI;
634 vigra::Size2D canvasSize;
635 if (!
CheckInput(images, outputROI, canvasSize))
640 vigra::ImageExportInfo exportImageInfo(
Parameters.outputFilename.c_str(),
Parameters.useBigTIFF ?
"w8" :
"w");
641 exportImageInfo.setXResolution(images[0]->getXResolution());
642 exportImageInfo.setYResolution(images[0]->getYResolution());
643 exportImageInfo.setPosition(outputROI.upperLeft());
644 exportImageInfo.setCanvasSize(canvasSize);
645 exportImageInfo.setICCProfile(images[0]->getICCProfile());
647 vigra::BasicImage<PixelType> output(outputROI.size());
648 vigra::BImage mask(output.size(),vigra::UInt8(0));
650 for (
size_t y = outputROI.top(); y < outputROI.bottom(); ++y)
653 #pragma omp parallel for
654 for (
int i = 0; i < images.size(); ++i)
656 images[i]->readLine(y);
659 #pragma omp parallel for schedule(static, 100)
660 for (
int x = outputROI.left(); x < outputROI.right(); ++x)
663 Functor privateStacker(stacker);
664 privateStacker.reset();
665 for (
size_t i = 0; i < images.size(); ++i)
668 ChannelType maskValue;
669 images[i]->getValue(x, value, maskValue);
672 privateStacker(value);
675 if (privateStacker.IsValid())
677 privateStacker.getResult(output(x - outputROI.left(), y - outputROI.top()));
678 mask(x-outputROI.left(), y-outputROI.top()) = 255;
682 std::cout <<
"Write result to " <<
Parameters.outputFilename << std::endl;
683 return SaveFinalImage(output, mask, images[0]->getPixelType(), exportImageInfo);
686 template <
class PixelType>
690 typedef typename vigra::NumericTraits<PixelType>::RealPromote
realPixelType;
695 vigra::UInt8
operator()(
const vigra::TinyVector<realPixelType, 2>& limits,
const PixelType& color,
const vigra::UInt8& mask, vigra::VigraFalseType)
const
697 if (mask > 0 && (color.red() < limits[0].red() || color.red()>limits[1].red() ||
698 color.green() < limits[0].green() || color.green() > limits[1].green() ||
699 color.blue() < limits[0].blue() || color.blue() > limits[1].blue()))
709 vigra::UInt8
operator()(
const vigra::TinyVector<realPixelType, 2>& limits,
const PixelType& gray,
const vigra::UInt8& mask, vigra::VigraTrueType)
const
711 if (mask > 0 && (gray < limits[0] || gray>limits[1]))
721 vigra::UInt8
operator()(
const vigra::TinyVector<realPixelType, 2>& limits,
const PixelType& pixel,
const vigra::UInt8& mask)
const
723 typedef typename vigra::NumericTraits<PixelType>::isScalar is_scalar;
724 return (*
this)(limits, pixel, mask, is_scalar());
729 template <
class PixelType,
class Functor>
732 typedef typename vigra::NumericTraits<PixelType>::ValueType ChannelType;
733 vigra::Rect2D outputROI;
734 vigra::Size2D canvasSize;
735 if (!
CheckInput(images, outputROI, canvasSize))
740 vigra::ImageExportInfo exportImageInfo(
Parameters.outputFilename.c_str(),
Parameters.useBigTIFF ?
"w8" :
"w");
741 exportImageInfo.setXResolution(images[0]->getXResolution());
742 exportImageInfo.setYResolution(images[0]->getYResolution());
743 exportImageInfo.setPosition(outputROI.upperLeft());
744 exportImageInfo.setCanvasSize(canvasSize);
745 exportImageInfo.setICCProfile(images[0]->getICCProfile());
748 vigra::TiffImage* tiffImage;
749 vigra::BasicImage<PixelType> output(outputROI.size());
750 vigra::BImage mask(output.size(), vigra::UInt8(0));
751 vigra::BasicImage<vigra::TinyVector<typename vigra::NumericTraits<PixelType>::RealPromote, 2>> limits(output.size());
753 for (
size_t y = outputROI.top(); y < outputROI.bottom(); ++y)
756 #pragma omp parallel for
757 for (
int i = 0; i < images.size(); ++i)
759 images[i]->readLine(y);
762 #pragma omp parallel for schedule(static, 100)
763 for (
int x = outputROI.left(); x < outputROI.right(); ++x)
766 Functor privateStacker(stacker);
767 privateStacker.reset();
768 for (
size_t i = 0; i < images.size(); ++i)
771 ChannelType maskValue;
772 images[i]->getValue(x, value, maskValue);
775 privateStacker(value);
778 if (privateStacker.IsValid())
781 typename vigra::NumericTraits<PixelType>::RealPromote
sigma;
782 privateStacker.getResultAndSigma(mean, sigma);
783 output(x - outputROI.left(), y - outputROI.top()) = mean;
784 mask(x - outputROI.left(), y - outputROI.top()) = 255;
785 limits(x - outputROI.left(), y - outputROI.top()) = vigra::TinyVector<PixelType, 2>(mean -
Parameters.maskSigma*sigma, mean +
Parameters.maskSigma*sigma);
789 std::cout <<
"Write result to " <<
Parameters.outputFilename << std::endl;
792 tiffImage = TIFFOpen(
Parameters.outputFilename.c_str(),
"w");
795 outputROI.upperLeft(), canvasSize, images[0]->getICCProfile());
797 TIFFFlush(tiffImage);
801 if (!
SaveFinalImage(output, mask, images[0]->getPixelType(), exportImageInfo))
808 std::cout <<
"Masking input images with sigma=" <<
Parameters.maskSigma;
811 std::cout << std::endl;
815 std::cout <<
" and suffix " <<
Parameters.maskSuffix <<
".tif" << std::endl;
817 for (
size_t i = 0; i < images.size(); ++i)
819 std::cout <<
"Masking " << images[i]->getFilename();
822 std::cout << std::endl;
826 std::cout <<
" -> " << images[i]->getMaskFilename() << std::endl;
828 vigra::BasicImage<PixelType> image(images[i]->getROI().size());
829 vigra::BImage mask(image.size(), 255);
830 if (images[i]->numExtraBands() == 1)
836 vigra::importImage(images[i]->getImageImportInfo(),
vigra::destImage(image));
838 vigra::Rect2D roi = images[i]->getROI();
839 roi.moveBy(-outputROI.upperLeft());
845 images[i]->getROI().upperLeft(), images[i]->getCanvasSize(), images[i]->getICCProfile());
847 TIFFFlush(tiffImage);
853 std::cout <<
"Masked file \"" << images[i]->getMaskFilename() <<
"\" already exists." << std::endl
854 <<
"Processing aborted." << std::endl;
857 vigra::ImageExportInfo exportMaskImage(images[i]->getMaskFilename().c_str(),
Parameters.useBigTIFF ?
"w8" :
"w");
858 exportMaskImage.setXResolution(images[i]->getXResolution());
859 exportMaskImage.setYResolution(images[i]->getYResolution());
860 exportMaskImage.setPosition(images[i]->getROI().upperLeft());
861 exportMaskImage.setCanvasSize(images[i]->getCanvasSize());
862 exportMaskImage.setICCProfile(images[i]->getICCProfile());
863 exportMaskImage.setPixelType(images[i]->getPixelType().c_str());
864 exportMaskImage.setCompression(
"LZW");
869 catch (std::exception& e)
871 std::cerr <<
"Could not save masked images \"" << exportMaskImage.getFileName() <<
"\"." << std::endl
872 <<
"Error code: " << e.what() << std::endl
873 <<
"Processing aborted." << std::endl;
880 TIFFClose(tiffImage);
885 void CleanUp(std::vector<InputImage*>& images)
887 for (
auto& img : images)
893 template <
class PixelType>
898 std::cout <<
"Merging stack with minimum operator." << std::endl;
900 return StackImages<PixelType>(images, stacker);
906 std::cout <<
"Merging stack with maximum operator." << std::endl;
908 return StackImages<PixelType>(images, stacker);
914 std::cout <<
"Merging stack with average operator." << std::endl;
918 return StackImagesAndMask<PixelType>(images, stacker);
922 return StackImages<PixelType>(images, stacker);
930 std::cout <<
"Merging stack with median operator." << std::endl;
933 return StackImagesAndMask<PixelType>(images, stacker);
937 return StackImages<PixelType>(images, stacker);
945 std::cout <<
"Merging stack with Winsor clipping operator (trim=" <<
Parameters.winsorTrim <<
")." << std::endl;
948 return StackImagesAndMask<PixelType>(images, stacker);
952 return StackImages<PixelType>(images, stacker);
960 std::cout <<
"Merging stack with sigma clipping operator (max sigma=" <<
Parameters.sigma <<
", max " <<
Parameters.maxIterations <<
" iterations)." << std::endl;
963 return StackImagesAndMask<PixelType>(images, stacker);
967 return StackImages<PixelType>(images, stacker);
974 std::cerr <<
"ERROR: No stacking mode given. Please specify a stacking mode with --mode=STACK_MODE" << std::endl
975 <<
" Allowed values for STACK_MODE are min|max|average|median|winsor|sigma" << std::endl;
979 std::cerr <<
"ERROR: " <<
"\"" <<
Parameters.stackMode <<
"\" is not a valid stack mode." << std::endl
980 <<
" Allowed values are min|max|average|median|winsor|sigma" << std::endl;
991 int main(
int argc,
char* argv[])
994 const char* optstring =
"o:h";
998 OPT_COMPRESSION = 1000,
1009 static struct option longOptions[] =
1011 {
"output", required_argument, NULL,
'o' },
1012 {
"compression", required_argument, NULL, OPT_COMPRESSION },
1013 {
"mode", required_argument, NULL, OPT_STACKMODE },
1014 {
"winsor-trim", required_argument, NULL, OPT_WINSOR_TRIM},
1015 {
"max-sigma", required_argument, NULL, OPT_SIGMA_MAX},
1016 {
"max-iterations", required_argument, NULL, OPT_MAX_ITER},
1017 {
"mask-input", no_argument, NULL, OPT_MASK_INPUT},
1018 {
"mask-suffix", required_argument, NULL, OPT_MASK_SUFFIX},
1019 {
"mask-sigma", required_argument, NULL, OPT_MASK_SIGMA },
1020 {
"multi-layer-output", no_argument, NULL, OPT_MULTILAYER },
1021 {
"bigtiff", no_argument, NULL, OPT_BIGTIFF },
1022 {
"help", no_argument, NULL,
'h' },
1027 while ((c = getopt_long(argc, argv, optstring, longOptions,
nullptr)) != -1)
1038 case OPT_COMPRESSION:
1045 case OPT_WINSOR_TRIM:
1047 std::string text(optarg);
1048 int pos = text.find(
"%");
1049 if (pos != std::string::npos)
1051 text = text.substr(0, pos);
1054 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": No valid number for Winsor trim factor given." << std::endl;
1063 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": No valid number for Winsor trim factor given." << std::endl;
1076 std::string text(optarg);
1079 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": No valid number for maximal sigma value." << std::endl;
1084 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": Maximal sigma value have to be positive." << std::endl;
1091 std::string text(optarg);
1094 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": No valid number for maximal iterations." << std::endl;
1099 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": Maximal iterations values have to be at least 1." << std::endl;
1104 case OPT_MASK_INPUT:
1107 case OPT_MASK_SUFFIX:
1110 case OPT_MASK_SIGMA:
1112 std::string text(optarg);
1115 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": No valid number for maximal sigma value." << std::endl;
1120 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": Maximal sigma value have to be positive." << std::endl;
1125 case OPT_MULTILAYER:
1142 unsigned nFiles = argc - optind;
1145 std::cerr <<
hugin_utils::stripPath(argv[0]) <<
": at least one image need to be specified" << std::endl;
1150 std::vector<std::string> files;
1152 bool isResponseFile =
false;
1156 if (argv[optind + i][0] ==
'@')
1159 isResponseFile =
true;
1165 std::string currentFile(argv[optind + i]);
1169 std::ifstream textfile(currentFile);
1170 if (textfile.is_open())
1174 while (std::getline(textfile, line))
1176 const size_t pos = line.find_first_not_of(
" \t");
1177 if (line.empty() || (pos != std::string::npos && line[pos] ==
'#'))
1186 files.push_back(line);
1193 std::cerr <<
"ERROR: Could not open file " << currentFile << std::endl;
1195 isResponseFile =
false;
1202 if (vigra::isImage(currentFile.c_str()))
1205 files.push_back(currentFile);
1209 std::cerr <<
"ERROR: File " << currentFile <<
" is not a image file recognized by vigra." << std::endl;
1214 std::cerr <<
"ERROR: File " << currentFile <<
" does not exists." << std::endl;
1238 if (
Parameters.multiLayer && extension !=
"tif" && extension !=
"tiff")
1240 std::cerr <<
"ERROR: Multi layer output expects a tiff file as output." << std::endl
1241 <<
" Other image formates are not compatible with this option." << std::endl;
1244 bool success =
false;
1245 std::vector<InputImage*> images;
1246 for (
size_t i = 0; i < files.size(); ++i)
1249 if (images.back()->getROI().area() == 0)
1251 std::cerr <<
"ERROR: Image " << images.back()->getFilename() <<
" has no valid data." << std::endl;
1256 if (!images[0]->isColor() && !images[0]->isGrayscale())
1258 std::cerr <<
"ERROR: Only RGB and grayscale images are supported." << std::endl
1259 <<
" Image \"" << images[0]->getFilename() <<
"\" has " << images[0]->numPixelSamples() <<
" channels per pixel." << std::endl;
1263 if (images[0]->numExtraBands() > 1)
1265 std::cerr <<
"ERROR: Images with several alpha channels are not supported." << std::endl
1266 <<
" Image \"" << images[0]->getFilename() <<
"\" has " << images[0]->numExtraBands() <<
" extra channels." << std::endl;
1270 const std::string pixeltype(images[0]->getPixelType());
1272 for (
size_t i = 1; i < files.size(); ++i)
1274 if (!images[i]->isColor() && !images[i]->isGrayscale())
1276 std::cerr <<
"ERROR: Only RGB and grayscale images are supported." << std::endl
1277 <<
" Image \"" << images[i]->getFilename() <<
"\" has " << images[i]->numPixelSamples() <<
" channels per pixel." << std::endl;
1281 if (images[i]->numExtraBands() > 1)
1283 std::cerr <<
"ERROR: Images with several alpha channels are not supported." << std::endl
1284 <<
" Image \"" << images[i]->getFilename() <<
"\" has " << images[i]->numExtraBands() <<
" extra channels." << std::endl;
1288 if (images[0]->isColor() != images[i]->isColor())
1290 std::cerr <<
"ERROR: You can't merge color and grayscale images." << std::endl;
1294 if (images[0]->numPixelSamples() != images[i]->numPixelSamples())
1296 std::cerr <<
"ERROR: You can't merge image with different number of channels." << std::endl
1297 <<
" Image \"" << images[0]->getFilename() <<
"\" has " << images[0]->numBands() <<
" channels," << std::endl
1298 <<
" but image \"" << images[i]->getFilename() <<
"\" has " << images[i]->numBands() <<
" channels." << std::endl;
1302 if (pixeltype!=images[i]->getPixelType())
1304 std::cerr <<
"ERROR: You can't merge images with different pixel types." << std::endl
1305 <<
" Image \"" << images[0]->getFilename() <<
"\" has pixel type " << images[0]->getPixelType() <<
"," << std::endl
1306 <<
" but image \"" << images[i]->getFilename() <<
"\" has pixel type " << images[i]->getPixelType() <<
"." << std::endl;
1312 if (images[0]->isColor())
1314 if (pixeltype ==
"UINT8")
1316 success = main_stacker<vigra::RGBValue<vigra::UInt8>>(images);
1318 else if (pixeltype ==
"UINT16")
1320 success = main_stacker<vigra::RGBValue<vigra::UInt16>>(images);
1322 else if (pixeltype ==
"UINT32")
1324 success = main_stacker<vigra::RGBValue<vigra::UInt32>>(images);
1326 else if (pixeltype ==
"FLOAT")
1328 success = main_stacker<vigra::RGBValue<float>>(images);
1330 else if (pixeltype ==
"DOUBLE")
1332 success = main_stacker<vigra::RGBValue<double>>(images);
1336 std::cerr <<
" ERROR: unsupported pixel type: " << pixeltype << std::endl;
1342 if (pixeltype ==
"UINT8")
1344 success = main_stacker<vigra::UInt8>(images);
1346 else if (pixeltype ==
"UINT16")
1348 success = main_stacker<vigra::UInt16>(images);
1350 else if (pixeltype ==
"UINT32")
1352 success = main_stacker<vigra::UInt32>(images);
1354 else if (pixeltype ==
"FLOAT")
1356 success = main_stacker<float>(images);
1358 else if (pixeltype ==
"DOUBLE")
1360 success = main_stacker<double>(images);
1364 std::cerr <<
" ERROR: unsupported pixel type: " << pixeltype << std::endl;
virtual void getResult(ValueType &val)
std::vector< double > m_sortValues
bool FileExists(const std::string &filename)
checks if file exists
const std::string getName() const
std::string outputFilename
virtual void getResultAndSigma(ValueType &val, typename vigra::NumericTraits< ValueType >::RealPromote &sigma)
void CleanUp(std::vector< InputImage * > &images)
PixelType second_argument_type
virtual void getResult(ValueType &val) override
bool StackImages(std::vector< InputImage * > &images, Functor &stacker)
loads images line by line and merge into final image, save the result
const std::string getName() const
vigra::UInt8 third_argument_type
Some functions to create tiff images with masks.
vigra::UInt8 operator()(const vigra::TinyVector< realPixelType, 2 > &limits, const PixelType &gray, const vigra::UInt8 &mask, vigra::VigraTrueType) const
vigra::TinyVector< realPixelType, 2 > first_argument_type
static struct GeneralParameters Parameters
void operator()(const ValueType &val, vigra::VigraFalseType)
void EnforceExtension(std::string &filename, const std::string &defaultExtension)
check if filename contains extension, if not add default extension
virtual void operator()(const ValueType &val)
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.
bool CheckInput(const std::vector< InputImage * > &images, vigra::Rect2D &outputROI, vigra::Size2D &canvasSize)
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
std::string toupper(const std::string &s)
virtual void getResult(ValueType &val)
vigra::UInt8 operator()(const vigra::TinyVector< realPixelType, 2 > &limits, const PixelType &color, const vigra::UInt8 &mask, vigra::VigraFalseType) const
void operator()(const ValueType &val, vigra::VigraTrueType)
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)
bool IsFileTypeSupported(const std::string &filename)
return true, if file type by extension is supported by vigra
std::string getExtension(const std::string &basename2)
Get extension of a filename.
vigra::FRGBImage ImageType
void operator()(const ValueType &val)
void operator()(const ValueType &val, vigra::VigraFalseType)
vigra::NumericTraits< PixelType >::RealPromote realPixelType
void createAlphaTiffImage(ImageIterator upperleft, ImageIterator lowerright, ImageAccessor a, AlphaIterator alphaUpperleft, AlphaAccessor alphaA, vigra::TiffImage *tiff)
std::string stripExtension(const std::string &basename2)
remove extension of a filename
void operator()(const ValueType &val, vigra::VigraTrueType)
void getMeanSigma(const std::vector< ValueType > &values, ValueType &val, typename vigra::NumericTraits< ValueType >::RealPromote &sigma)
bool stringToInt(const std::string &s, int &val)
convert string to integer value, returns true, if sucessful
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
virtual void getResultAndSigma(ValueType &val, typename vigra::NumericTraits< ValueType >::RealPromote &sigma) override
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation.
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 createTiffDirectory(vigra::TiffImage *tiff, const std::string &pagename, const std::string &documentname, const std::string comp, uint16_t page, uint16_t nImg, vigra::Diff2D offset, vigra::Size2D fullSize, const vigra::ImageExportInfo::ICCProfile &icc)
write a new Tiff directory, for a new layer
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...
bool main_stacker(std::vector< InputImage * > &images)
bool SaveImage(ImageType &image, MaskType &mask, vigra::ImageExportInfo &exportImageInfo, std::string filetype, std::string pixelType)
save image, when possible with alpha channel, take care of formats which does not support alpha chann...
virtual void operator()(const ValueType &val)
void operator()(const ValueType &val, vigra::VigraFalseType)
void getMean(const std::vector< ValueType > &values, ValueType &val)
virtual void getResultAndSigma(ValueType &val, typename vigra::NumericTraits< ValueType >::RealPromote &sigma)
std::string GetHuginVersion()
return a string with version numbers
std::vector< ValueType > m_values
bool StackImagesAndMask(std::vector< InputImage * > &images, Functor &stacker)
std::vector< ValueType > m_values
const std::string getName() const
void operator()(const ValueType &val, vigra::VigraTrueType)
void getResult(ValueType &val)
bool SaveFinalImage(ImageType &image, MaskType &mask, const std::string &inputPixelType, vigra::ImageExportInfo &output)
save final image, take care of some supported pixel types and convert when necessary to smaller pixel...
virtual void getResult(ValueType &val)
std::string tolower(const std::string &s)
convert a string to lowercase
virtual void operator()(const ValueType &val)
vigra::UInt8 operator()(const vigra::TinyVector< realPixelType, 2 > &limits, const PixelType &pixel, const vigra::UInt8 &mask) const
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
void SetCompression(vigra::ImageExportInfo &output, const std::string &compression)
set compression for jpeg or tiff
int main(int argc, char *argv[])