图像融合之拉普拉斯融合(laplacian blending)

一、拉普拉斯融合基本步骤

   1. 两幅图像L,R,以及二值掩模mask,给定金字塔层数level。

  2. 分别根据L,R构建其对应的拉普拉斯残差金字塔(层数为level),并保留高斯金字塔下采样最顶端的图像(尺寸最小的图像,第level+1层):

    拉普拉斯残差金字塔构建方法如下,以L图为例:

    (1) 对L进行高斯下采样得到downL,OpenCV中pyrDown()函数可以实现此功能。然后再对downL进行高斯上采样得到upL,OpenCV中pyrUp()函数可以实现此功能。

    (2) 计算原图L与upL之间的残差,得到一幅残差图lapL0。作为残差金字塔最低端的图像。

    (3) 对downL继续进行(1) (2)操作,不断计算残差图lapL1, lap2, lap3.....lapN。这样得到一系列残差图,即为拉普拉斯残差金字塔。

    (4)拉普拉斯 残差金字塔中一共有level幅图像。而我们需要保留第level+1层的高斯下采样图topL,以便后面使用。

  3. 二值掩模mask下采样构建高斯金字塔,同样利用pyrDown()实现,共有level+1层。

  4. 利用mask金字塔每一层的mask图,将L图和R图的拉普拉斯残差金字塔对应层的图像合并为一幅图像。这样得到合并后的拉普拉斯残差金字塔。同时利用最顶端的mask将步骤2中保留的topL和topR合并为topLR。

  5. 以topLR为金字塔最顶端的图像,利用pyrUp()函数对topLR进行高斯上采样,得到upTopLR,并将upTopLR与步骤4中合并后的残差金字塔对应层的图像相加,重建出该层的图像。

  6. 重复步骤5,直至重建出第0层,也就是金字塔最低端的图像,即blendImg。输出。

  拉普拉斯金字塔的OpenCV实现代码如下:

  1 #include <opencv2/opencv.hpp>
  2 #include <iostream>
  3 #include <string>
  4 
  5 using namespace std;
  6 using namespace cv;
  7 
  8 /************************************************************************/
  9 /* 说明:
 10 *金字塔从下到上依次为 [0,1,...,level-1] 层
 11 *blendMask 为图像的掩模
 12 *maskGaussianPyramid为金字塔每一层的掩模
 13 *resultLapPyr 存放每层金字塔中直接用左右两图Laplacian变换拼成的图像
 14 */
 15 /************************************************************************/
 16 
 17 
 18 class LaplacianBlending {
 19 private:
 20     Mat left;
 21     Mat right;
 22     Mat blendMask;
 23 
 24     //Laplacian Pyramids
 25     vector<Mat> leftLapPyr, rightLapPyr, resultLapPyr;
 26     Mat leftHighestLevel, rightHighestLevel, resultHighestLevel;
 27     //mask为三通道方便矩阵相乘
 28     vector<Mat> maskGaussianPyramid; 
 29 
 30     int levels;
 31 
 32     void buildPyramids() 
 33     {
 34         buildLaplacianPyramid(left, leftLapPyr, leftHighestLevel);
 35         buildLaplacianPyramid(right, rightLapPyr, rightHighestLevel);
 36         buildGaussianPyramid();
 37     }
 38 
 39     void buildGaussianPyramid() 
 40     {
 41         //金字塔内容为每一层的掩模
 42         assert(leftLapPyr.size()>0);
 43 
 44         maskGaussianPyramid.clear();
 45         Mat currentImg;
 46         cvtColor(blendMask, currentImg, CV_GRAY2BGR);
 47         //保存mask金字塔的每一层图像
 48         maskGaussianPyramid.push_back(currentImg); //0-level
 49 
 50         currentImg = blendMask;
 51         for (int l = 1; l<levels + 1; l++) {
 52             Mat _down;
 53             if (leftLapPyr.size() > l)
 54                 pyrDown(currentImg, _down, leftLapPyr[l].size());
 55             else
 56                 pyrDown(currentImg, _down, leftHighestLevel.size()); //lowest level
 57 
 58             Mat down;
 59             cvtColor(_down, down, CV_GRAY2BGR);
 60             //add color blend mask into mask Pyramid
 61             maskGaussianPyramid.push_back(down);
 62             currentImg = _down;
 63         }
 64     }
 65 
 66     void buildLaplacianPyramid(const Mat& img, vector<Mat>& lapPyr, Mat& HighestLevel)
 67     {
 68         lapPyr.clear();
 69         Mat currentImg = img;
 70         for (int l = 0; l<levels; l++) {
 71             Mat down, up;
 72             pyrDown(currentImg, down);
 73             pyrUp(down, up, currentImg.size());
 74             Mat lap = currentImg - up;
 75             lapPyr.push_back(lap);
 76             currentImg = down;
 77         }
 78         currentImg.copyTo(HighestLevel);
 79     }
 80 
 81     Mat reconstructImgFromLapPyramid() 
 82     {
 83         //将左右laplacian图像拼成的resultLapPyr金字塔中每一层
 84         //从上到下插值放大并与残差相加,即得blend图像结果
 85         Mat currentImg = resultHighestLevel;
 86         for (int l = levels - 1; l >= 0; l--)
 87         {
 88             Mat up;
 89             pyrUp(currentImg, up, resultLapPyr[l].size());
 90             currentImg = up + resultLapPyr[l];
 91         }
 92         return currentImg;
 93     }
 94 
 95     void blendLapPyrs() 
 96     {
 97         //获得每层金字塔中直接用左右两图Laplacian变换拼成的图像resultLapPyr
 98         resultHighestLevel = leftHighestLevel.mul(maskGaussianPyramid.back()) +
 99             rightHighestLevel.mul(Scalar(1.0, 1.0, 1.0) - maskGaussianPyramid.back());
100         for (int l = 0; l<levels; l++) 
101         {
102             Mat A = leftLapPyr[l].mul(maskGaussianPyramid[l]);
103             Mat antiMask = Scalar(1.0, 1.0, 1.0) - maskGaussianPyramid[l];
104             Mat B = rightLapPyr[l].mul(antiMask);
105             Mat blendedLevel = A + B;
106 
107             resultLapPyr.push_back(blendedLevel);
108         }
109     }
110 
111 public:
112     LaplacianBlending(const Mat& _left, const Mat& _right, const Mat& _blendMask, int _levels) ://construct function, used in LaplacianBlending lb(l,r,m,4);
113         left(_left), right(_right), blendMask(_blendMask), levels(_levels)
114     {
115         assert(_left.size() == _right.size());
116         assert(_left.size() == _blendMask.size());
117         //创建拉普拉斯金字塔和高斯金字塔
118         buildPyramids();
119         //每层金字塔图像合并为一个
120         blendLapPyrs();
121     };
122 
123     Mat blend() 
124     {
125         //重建拉普拉斯金字塔
126         return reconstructImgFromLapPyramid();
127     }
128 };
129 
130 Mat LaplacianBlend(const Mat &left, const Mat &right, const Mat &mask) 
131 {
132     LaplacianBlending laplaceBlend(left, right, mask, 10);
133     return laplaceBlend.blend();
134 }
135 
136 int main() {
137     Mat img8UL = imread("data/apple.jpg");
138     Mat img8UR = imread("data/orange.jpg");
139 
140     int imgH = img8UL.rows;
141     int imgW = img8UL.cols;
142 
143     imshow("left", img8UL);
144     imshow("right", img8UR);
145 
146     Mat img32fL, img32fR; 
147     img8UL.convertTo(img32fL, CV_32F);
148     img8UR.convertTo(img32fR, CV_32F);
149 
150     //创建mask
151     Mat mask = Mat::zeros(imgH, imgW, CV_32FC1);
152     mask(Range::all(), Range(0, mask.cols * 0.5)) = 1.0;
153 
154     Mat blendImg = LaplacianBlend(img32fL, img32fR, mask);
155 
156     blendImg.convertTo(blendImg, CV_8UC3);
157     imshow("blended", blendImg);
158 
159     waitKey(0);
160     return 0;
161 }
View Code

 融合结果如下图:

  

金字塔层数level=5

金字塔层数level=10

猜你喜欢

转载自www.cnblogs.com/riddick/p/8922381.html