-
Notifications
You must be signed in to change notification settings - Fork 4
/
LaplacianBlending.h
executable file
·107 lines (87 loc) · 3.2 KB
/
LaplacianBlending.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#ifndef LAPLACIANBLENDING_H
#define LAPLACIANBLENDING_H
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
using namespace cv;
class LaplacianBlending
{
public:
LaplacianBlending(const Mat_<Vec3f>& _left, const Mat_<Vec3f>& _right, const Mat_<float>& _blendMask, int _levels):
left(_left),right(_right),blendMask(_blendMask),levels(_levels)
{
assert(_left.size() == _right.size());
assert(_left.size() == _blendMask.size());
buildPyramids();
blendLapPyrs();
};
Mat_<Vec3f> blend() {
return reconstructImgFromLapPyramid();
}
private:
Mat_<Vec3f> left;
Mat_<Vec3f> right;
Mat_<float> blendMask;
vector<Mat_<Vec3f> > leftLapPyr,rightLapPyr,resultLapPyr;
Mat leftSmallestLevel, rightSmallestLevel, resultSmallestLevel; // top image
vector<Mat_<Vec3f> > maskGaussianPyramid; //masks are 3-channels for easier multiplication with RGB
int levels;
void buildPyramids() {
buildLaplacianPyramid(left,leftLapPyr,leftSmallestLevel);
buildLaplacianPyramid(right,rightLapPyr,rightSmallestLevel);
buildGaussianPyramid();
}
void buildGaussianPyramid() {
assert(leftLapPyr.size()>0);
maskGaussianPyramid.clear();
Mat currentImg;
cvtColor(blendMask, currentImg, CV_GRAY2BGR);
maskGaussianPyramid.push_back(currentImg); //highest level
currentImg = blendMask;
for (int l=1; l<levels+1; l++) {
Mat _down;
if (leftLapPyr.size() > l) {
pyrDown(currentImg, _down, leftLapPyr[l].size());
} else {
pyrDown(currentImg, _down, leftSmallestLevel.size()); //smallest level
}
Mat down;
cvtColor(_down, down, CV_GRAY2BGR);
maskGaussianPyramid.push_back(down);
currentImg = _down;
}
}
void buildLaplacianPyramid(const Mat& img, vector<Mat_<Vec3f> >& lapPyr, Mat& smallestLevel) {
lapPyr.clear();
Mat currentImg = img;
for (int l=0; l<levels; l++) {
Mat down,up;
pyrDown(currentImg, down);
pyrUp(down, up, currentImg.size());
Mat lap = currentImg - up;
lapPyr.push_back(lap);
currentImg = down;
}
currentImg.copyTo(smallestLevel);
}
Mat_<Vec3f> reconstructImgFromLapPyramid() {
Mat currentImg = resultSmallestLevel;
for (int l=levels-1; l>=0; l--) {
Mat up;
pyrUp(currentImg, up, resultLapPyr[l].size());
currentImg = up + resultLapPyr[l];
}
return currentImg;
}
void blendLapPyrs() {
resultSmallestLevel = leftSmallestLevel.mul(maskGaussianPyramid.back()) +
rightSmallestLevel.mul(Scalar(1.0,1.0,1.0) - maskGaussianPyramid.back());
for (int l=0; l<levels; l++) {
Mat A = leftLapPyr[l].mul(maskGaussianPyramid[l]);
Mat antiMask = Scalar(1.0,1.0,1.0) - maskGaussianPyramid[l];
Mat B = rightLapPyr[l].mul(antiMask);
Mat_<Vec3f> blendedLevel = A + B;
resultLapPyr.push_back(blendedLevel);
}
}
};
#endif // LAPLACIANBLENDING_H