28#ifndef POISSON_BLEND_H
29#define POISSON_BLEND_H
32#include <vigra/stdimage.hxx>
33#include <vigra/convolution.hxx>
34#include <vigra/stdconvolution.hxx>
35#include <vigra/basicgeometry.hxx>
49template <
class Image,
class Mask>
50inline typename vigra::NumericTraits<typename Image::PixelType>::RealPromote
ProcessNeighborPixels(
const int x,
const int y,
const int dx,
const int dy,
const Image& image,
const Mask& mask)
52 const typename Mask::PixelType
m1 = mask[y + dy][x + dx];
53 const typename Mask::PixelType
m2 = mask[y - dy][x - dx];
56 return image[y + dy][x + dx] + image[y - dy][x - dx];
62 return 2 * image[y + dy][x + dx];
66 return 2 * image[y - dy][x - dx];
70template <
class Image,
class Mask,
class SeamMask>
71inline typename vigra::NumericTraits<typename Image::PixelType>::RealPromote
ProcessBorderPixel(
const int x,
const int y,
const int dx,
const int dy,
const Image& image,
const Mask& mask,
const SeamMask&
seam)
73 const typename SeamMask::PixelType
seam1 =
seam[y + dy][x + dx];
74 const typename SeamMask::PixelType
seam2 =
seam[y - dy][x - dx];
75 const typename Mask::PixelType
mask1 = mask[y + dy][x + dx];
76 const typename Mask::PixelType
mask2 = mask[y - dy][x - dx];
81 return image[y + dy][x + dx] + image[y - dy][x - dx];
85 return 2 *image[y + dy][x + dx];
89 return 2 * image[y - dy][x - dx];
96 return 2 * image[y + dy][x + dx];
100 return vigra::NumericTraits<typename vigra::NumericTraits<typename Image::PixelType>::RealPromote>::zero();
107 return 2 * image[y - dy][x - dx];
111 return vigra::NumericTraits<typename vigra::NumericTraits<typename Image::PixelType>::RealPromote>::zero();
114 return vigra::NumericTraits<typename vigra::NumericTraits<typename Image::PixelType>::RealPromote>::zero();
117template <
class Image,
class SeamMask>
118inline typename Image::PixelType
GetBorderGradient(
const int x,
const int y,
const int dx,
const int dy,
const SeamMask&
seams,
const Image& image1,
const vigra::Point2D& offset)
120 if (
seams[y + dy][x + dx] == 1)
122 return image1[offset.y + y + dy][offset.x + x + dx];
124 return vigra::NumericTraits<typename Image::PixelType>::zero();
127template <
class Image,
class SeamMask>
128inline typename vigra::NumericTraits<typename Image::PixelType>::RealPromote
GetBorderValues(
const int x,
const int y,
int dx,
int dy,
const Image& image,
const SeamMask&
seams)
130 const typename SeamMask::PixelType
s1 =
seams[y + dy][x + dx];
131 const typename SeamMask::PixelType
s2 =
seams[y - dy][x - dx];
132 if (
s1 > 1 &&
s2 > 1)
134 return image[y + dy][x + dx] + image[y - dy][x - dx];
138 return (2 - std::min<int>(
s2, 2))*image[y + dy][x + dx] + (2 - std::min<int>(
s1, 2))*image[y - dy][x - dx];
142template <
class Image>
147 filter2D.initExplicitly(vigra::Diff2D(-1, -1), vigra::Diff2D(1, 1)) = 0.25, 0.5, 0.25, 0.5, 1, 0.5, 0.25, 0.5, 0.25;
149 vigra::convolveImage(vigra::srcImageRange(in), vigra::destImage(
smoothImage), vigra::kernel2d(
filter2D));
151 vigra::resizeImageLinearInterpolation(vigra::srcImageRange(
smoothImage), vigra::destImageRange(
out));
159 const int v =
static_cast<int>(
vf);
168 if (
v == 85 ||
v == 89 ||
v == 93 ||
v == 97)
186template <
class Image1,
class Image2>
189 vigra_precondition(image1.size() == image2.size(),
"ConvolveImage: Image size does not match");
190 vigra_precondition(image1.width() >= 2 && image1.height() >= 2,
"ConvolveImage: Image too small");
191 const int width = image1.width();
192 const int height = image1.height();
195 for (
int x = 1; x < width - 1; ++x)
199 image2[0][width - 1] =
factor1*image1[0][width - 1] +
factor2*image1[0][width - 2] +
factor2*image1[1][width - 1];
200#pragma omp parallel for
201 for (
int y = 1; y < height - 1; ++y)
205 for (
size_t x = 1; x < width - 1; ++x)
210 image2[y][width - 1] =
factor1*image1[y][width - 1] +
factor2*image1[y - 1][width - 1]
211 +
factor2*image1[y][width - 2] +
factor2*image1[y + 1][width - 1];
214 image2[height - 1][0] =
factor1*image1[height - 1][0] +
factor2*image1[height - 1][1] +
factor2*image1[height - 2][0];
215 for (
size_t x = 1; x < width - 1; ++x)
217 image2[height - 1][x] =
factor1*image1[height - 1][x] +
factor2*image1[height - 1][x - 1] +
factor2*image1[height - 1][x + 1] +
factor2*image1[height - 2][x];
219 image2[height - 1][width - 1] =
factor1*image1[height - 1][width - 1] +
factor2*image1[height - 1][width - 2] +
factor2*image1[height - 2][width - 1];
234template <
class Image>
243template <
class ComponentType>
246template <
class ComponentType>
247double GetRealValue(
const vigra::RGBValue<ComponentType>& val) {
return val.magnitude(); }
249template <
class Image,
class SeamMask>
253 const int width = target.width();
254 const int height = target.height();
269 target[0][0] +=
delta;
275 target[0][0] +=
delta;
278 for (
int x = 1; x < width - 1; ++x)
284 target[0][x] +=
delta;
287 if (
seams[0][width - 1] > 1)
293 target[0][width - 1] +=
delta;
299 target[0][width - 1] +=
delta;
302#pragma omp parallel for reduction(+: error) schedule(dynamic, 100)
303 for (
int y = 1; y < height - 1; ++y)
310 + target[y][1] + target[y][width - 1]) / 4.0f - target[y][0]);
312 target[y][0] +=
delta;
318 target[y][0] +=
delta;
321 for (
int x = 1; x < width - 1; ++x)
329 const TargetPixelType sum =
detail::GetBorderValues(x, y, 1, 0, target,
seams) +
detail::GetBorderValues(x, y, 0, 1, target,
seams);
332 target[y][x] +=
delta;
336 const TargetPixelType sum = target[y + 1][x] + target[y][x + 1] + target[y - 1][x] + target[y][x - 1];
339 target[y][x] +=
delta;
343 if (
seams[y][width - 1] > 1)
349 target[y][width - 1] +=
delta;
355 target[y][width - 1] +=
delta;
360 if (
seams[height - 1][0] > 1)
364 const TargetPixelType delta =
omega * ((
gradient[height - 1][0] + 2 * target[height - 2][0] + target[height - 1][1] + target[height - 1][width - 1]) / 4.0f - target[height - 1][0]);
366 target[height - 1][0] +=
delta;
372 target[height - 1][0] +=
delta;
375 for (
int x = 1; x < width - 1; ++x)
377 if (
seams[height - 1][x] > 1)
381 target[height - 1][x] +=
delta;
384 if (
seams[height - 1][width - 1] > 1)
388 const TargetPixelType delta =
omega * ((
gradient[height - 1][width - 1] + 2 * target[height - 2][width - 1] + target[height - 1][width - 2] + target[height - 1][0]) / 4.0f - target[height - 1][width - 1]);
390 target[height - 1][width - 1] +=
delta;
394 const TargetPixelType delta =
omega * ((
gradient[height - 1][width - 1] + 2 * target[height - 2][width - 1] + 2 * target[height - 1][width - 2]) / 4.0f - target[height - 1][width - 1]);
396 target[height - 1][width - 1] +=
delta;
408template <
class Image,
class SeamMask>
412 const int width = target.width();
413 const int height = target.height();
419 const ImagePixelType sum = 2 * target[1][0] + target[0][1] + target[0][width - 1];
420 error[0][0] = (4 * target[0][0] - sum -
gradient[0][0]);
425 error[0][0] = (4 * target[0][0] - sum -
gradient[0][0]);
428 for (
int x = 1; x < width - 1; ++x)
433 error[0][x] = (4 * target[0][x] - sum -
gradient[0][x]);
436 if (
seam[0][width - 1] > 1)
440 const ImagePixelType sum = 2 * target[1][width - 1] + target[0][width - 2] + target[0][0];
441 error[0][width - 1] = (4 * target[0][width - 1] - sum -
gradient[0][width - 1]);
445 const ImagePixelType sum = 2 * target[1][width - 1] + 2 * target[0][width - 2];
446 error[0][width - 1] = (4 * target[0][width - 1] - sum -
gradient[0][width - 1]);
449#pragma omp parallel for schedule(dynamic, 100)
450 for (
int y = 1; y < height - 1; ++y)
457 error[y][0] = (4 * target[y][0] - sum -
gradient[y][0]);
462 error[y][0] = (4 * target[y][0] - sum -
gradient[y][0]);
465 for (
int x = 1; x < width - 1; ++x)
473 const ImagePixelType sum =
detail::GetBorderValues(x, y, 1, 0, target,
seam) +
detail::GetBorderValues(x, y, 0, 1, target,
seam);
474 error[y][x] = (4 * target[y][x] - sum -
gradient[y][x]);
478 const ImagePixelType sum = target[y + 1][x] + target[y][x + 1] + target[y - 1][x] + target[y][x - 1];
479 error[y][x] = (4 * target[y][x] - sum -
gradient[y][x]);
483 if (
seam[y][width - 1] > 1)
488 error[y][width - 1] = (4 * target[y][width - 1] - sum -
gradient[y][width - 1]);
493 error[y][width - 1] = (4 * target[y][width - 1] - sum -
gradient[y][width - 1]);
498 if (
seam[height - 1][0] > 1)
502 const ImagePixelType sum = 2 * target[height - 2][0] + target[height - 1][width - 1] + target[height - 1][1];
503 error[height - 1][0] = (4 * target[height - 1][0] - sum -
gradient[height - 1][0]);
507 const ImagePixelType sum = 2 * target[height - 2][0] + 2 * target[height - 1][1];
508 error[height - 1][0] = (4 * target[height - 1][0] - sum -
gradient[height - 1][0]);
511 for (
int x = 1; x < width - 1; ++x)
513 if (
seam[height - 1][x]>1)
516 error[height - 1][x] = (4 * target[height - 1][x] - sum -
gradient[height - 1][x]);
519 if (
seam[height - 1][width - 1] > 1)
523 const ImagePixelType sum = 2 * target[height - 2][width - 1] + target[height - 1][width - 2] + target[height - 1][0];
524 error[height - 1][width - 1] = (4 * target[height - 1][width - 1] - sum -
gradient[height - 1][width - 1]);
528 const ImagePixelType sum = 2 * target[height - 2][width - 1] + 2 * target[height - 1][width - 2];
529 error[height - 1][width - 1] = (4 * target[height - 1][width - 1] - sum -
gradient[height - 1][width - 1]);
536template <
class PixelType>
542 template <
class ITERATOR>
546 return vigra::NumericTraits<PixelType>::max();
550 return vigra::NumericTraits<PixelType>::zero();
554 template <
class ITERATOR,
class DIFFERENCE>
559 return vigra::NumericTraits<PixelType>::max();
563 return vigra::NumericTraits<PixelType>::zero();
569template <
class PixelType>
575 template <
class ITERATOR>
579 return vigra::NumericTraits<PixelType>::max();
583 return vigra::NumericTraits<PixelType>::zero();
587 template <
class ITERATOR,
class DIFFERENCE>
592 return vigra::NumericTraits<PixelType>::max();
596 return vigra::NumericTraits<PixelType>::zero();
602template <
class Image,
class Pyram
idImage>
609 for (
size_t i = 1;
i <=
seams.highestLevel(); ++
i)
612 vigra::resizeImageNoInterpolation(vigra::srcImageRange(
scaledImage), vigra::destImageRange(
smaller));
618template<
class Image,
class Mask,
class SeamMask,
class GradientType>
622 const int width = image2.width();
623 const int height = image2.height();
629 GradientPixelType value = 4 * image2[0][0] - image2[0][1] - 2 * image2[1][0] - image2[0][width - 1];
638 GradientPixelType value = 4 * image2[0][0] - 2 * image2[0][1] - 2 * image2[1][0];
645 for (
int x = 1; x < width - 1; ++x)
656 if (
seam[0][width - 1] == 2)
660 GradientPixelType value = 4 * image2[0][width - 1] - image2[0][width - 2] - 2 * image2[1][width - 1] - image2[0][0];
668 GradientPixelType value = 4 * image2[0][width - 1] - 2 * image2[0][width - 2] - 2 * image2[1][width - 1];
674#pragma omp parallel for
675 for (
int y = 1; y < height - 1; ++y)
697 for (
int x = 1; x < width - 1; ++x)
699 const typename SeamMask::PixelType
seamVal =
seam[y][x];
722 if (
seam[y][width - 1] == 2)
744 if (
seam[height - 1][0] == 2)
748 GradientPixelType value = 4 * image2[height - 1][0] - image2[height - 1][1] - 2 * image2[height - 2][0] - image2[height - 1][width - 1];
756 GradientPixelType value = 4 * image2[height - 1][0] - 2 * image2[height - 1][1] - 2 * image2[height - 2][0];
762 for (
size_t x = 1; x < width - 1; ++x)
764 if (
seam[height - 1][x] == 2)
773 if (
seam[height - 1][width - 1] == 2)
777 GradientPixelType value = 4 * image2[height - 1][width - 1] - image2[height - 1][width - 2] - 2 * image2[height - 2][width - 1] - image2[height - 1][0];
781 gradient[height - 1][width - 1] = value;
785 GradientPixelType value = 4 * image2[height - 1][width - 1] - 2 * image2[height - 1][width - 2] - 2 * image2[height - 2][width - 1];
788 gradient[height - 1][width - 1] = value;
793template <
class Image,
class SeamMask>
796 const int width =
out.width();
797 const int height =
out.height();
803 Image
err(width, height);
804 Image
err2((width + 1) / 2, (height + 1) / 2);
817 std::cout <<
"ERROR: No suitable mask, this should not happen." << std::endl
822 const float omega = 1.6f;
832 vigra::destImage(
out),
833 vigra::functor::Arg1() - vigra::functor::Arg2());
PixelType operator()(ITERATOR const &i, DIFFERENCE d) const
MaskGreaterAccessor(PixelType val)
PixelType operator()(ITERATOR const &i) const
PixelType operator()(ITERATOR const &i) const
PixelType operator()(ITERATOR const &i, DIFFERENCE d) const
MaskSmallerAccessor(PixelType val)
void combineTwoImagesIf(SrcImageIterator1 src1_upperleft, SrcImageIterator1 src1_lowerright, SrcAccessor1 src1_acc, SrcImageIterator2 src2_upperleft, SrcAccessor2 src2_acc, MaskImageIterator mask_upperleft, MaskAccessor mask_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc, const Functor &func)
void transformImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc, const Functor &func)
vigra::NumericTraits< typenameImage::PixelType >::RealPromote GetBorderValues(const int x, const int y, int dx, int dy, const Image &image, const SeamMask &seams)
vigra::Int8Image FindEdgesForPoisson(const Image &input)
mark edges in input image for poisson blending * input: expected an image with following meanings lab...
double GetRealValue(const ComponentType &val)
vigra::NumericTraits< typenameImage::PixelType >::RealPromote ProcessNeighborPixels(const int x, const int y, const int dx, const int dy, const Image &image, const Mask &mask)
void SimpleConvolveImage4(const Image1 &image1, Image2 &image2, const double factor1, const double factor2)
void CalcResidualError(Image &error, const Image &target, const Image &gradient, const SeamMask &seam, const bool doWrap)
void SOR(Image &target, const Image &gradient, const SeamMask &seams, const float omega, const float errorThreshold, const int maxIter, const bool doWrap)
void RestrictErrorToNextLevel(const Image &in, Image &out)
vigra::NumericTraits< typenameImage::PixelType >::RealPromote ProcessBorderPixel(const int x, const int y, const int dx, const int dy, const Image &image, const Mask &mask, const SeamMask &seam)
Image::PixelType GetBorderGradient(const int x, const int y, const int dx, const int dy, const SeamMask &seams, const Image &image1, const vigra::Point2D &offset)
void Multigrid(Image &out, const Image &gradient, const vigra::ImagePyramid< SeamMask > &seamMaskPyramid, int minLen, const float errorThreshold, const int maxIter, const bool doWrap)
void BuildSeamPyramid(const Image &input, vigra::ImagePyramid< PyramidImage > &seams, const int minLength)
void BuildGradientMap(const Image &image1, const Image &image2, const Mask &mask2, const SeamMask &seam, GradientType &gradient, const vigra::Point2D &offset, const bool doWrap)
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
vigra::RGBValue< T, RIDX, GIDX, BIDX > log(vigra::RGBValue< T, RIDX, GIDX, BIDX > const &v)
component-wise logarithm
vigra::triple< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImageRange(ROIImage< Image, Alpha > &img)
vigra::Int8 operator()(float const &vf) const
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.