这篇文章呢,主要是看了上篇金字塔在图像分割的应用之后,知道了金字塔的主要应用还在于图像融合,所以就又看了相关的内容,
用金字塔进行图像融合的主要步骤如下:
1,有两张原图像,还有一张模板图(用来确定用左边图像的哪部分,右边图像的哪部分来组合成最终的结果);
Mat_<Vec3f> left,right;
Mat_<float> mask;
2,有了原图之后就要进行分割求金字塔图像了
vector<Mat_<Vec3f>> leftpyr,rightpyr,maskpyr;
不过leftpyr和right保存的是拉普拉斯金字塔,mask保存的是高斯金字塔,我们知道图下采样之后是DOG,图减去DOG上采样之后是LOG,所以如果对最顶层的图不断上采样并加上LOG,最终会得到原图下采样的结果。
对左右原图进行拉普拉斯金字塔就是为了能够获得每层的细节信息,并且使用mask高斯金字塔每层对应的模板 进行融合,这就相当于得到了一系列的LOG,那对这些LOG不断的上采样就得到了最后的逼近真实的融合图。
另外一个原因就是在采样的过程中有模糊处理,所以融合的边缘不会是突兀的,而是很自然的呈现。
3, 分别得到了两图的LOG之后,就要通过maskpyr得到融合之后的LOG了。
vector<Mat_<Vec3f>> resultpyr;
4,然后就是不断的上采样这个pyr,得到最后的结果图。
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
class pyr_blend{
private:
Mat_<Vec3f> left,right;
Mat_<float> mask;
int level;
vector<Mat_<Vec3f>> leftpyr,rightpyr,maskpyr;
vector<Mat_<Vec3f>> resultpyr;
public:
void calclogpyr(const Mat& img,vector<Mat_<Vec3f>> &logpyr){
logpyr.clear();
Mat currentimg = img;
Mat down,up,logimg;
for(int k=0;k<level;k++){
pyrDown(currentimg,down);
pyrUp(down,up,currentimg.size());
logimg = currentimg - up;
logpyr.push_back(logimg);
currentimg = down;
}
logpyr.push_back(currentimg);
}
void calcdogpyr(){
assert(leftpyr.size()>0);
maskpyr.clear();
Mat mask_3;
cvtColor(mask,mask_3,CV_GRAY2BGR);
maskpyr.push_back(mask_3);
Mat currentimg = mask;
for (int k=1;k<level+1;k++){
Mat down;
pyrDown(currentimg,down,leftpyr[k].size());
cvtColor(down,mask_3,CV_GRAY2BGR);
maskpyr.push_back(mask_3);
currentimg = down;
}
}
void calcpyr(){
calclogpyr(left,leftpyr);
calclogpyr(right,rightpyr);
calcdogpyr();
}
void calcblend(){
Mat ll ,rr;
Mat_<Vec3f> blend;
for (int k=0;k<level;k++){
ll = leftpyr[k].mul(maskpyr[k]);
rr = rightpyr[k].mul(Scalar(1.0,1.0,1.0) - maskpyr[k]);
blend = ll + rr;
resultpyr.push_back(blend);
}
Mat resulthighest = leftpyr.back().mul(maskpyr.back()) + rightpyr.back().mul(Scalar(1.0,1.0,1.0) - maskpyr.back());
resultpyr.push_back(resulthighest);
}
pyr_blend(const Mat_<Vec3f>& _left,const Mat_<Vec3f>& _right,const Mat_<float>& _mask,const int _level):left(_left),right(_right),mask(_mask),level(_level){
assert(_left.size == _right.size);
assert(_left.size == _mask.size);
calcpyr();
calcblend();
}
Mat_<Vec3f> calcresult(){
Mat current,up;
current = resultpyr.back();
for (int k=level-1;k>=0;k--){
pyrUp(current,up,resultpyr[k].size());
current = up + resultpyr[k];
}
return current;
}
};
int main(){
Mat l8u = imread("apple.jpg");
Mat r8u = imread("orange.jpg");
Mat_<Vec3f> l,r;
l8u.convertTo(l,CV_32F,1.0/255.0);
r8u.convertTo(r,CV_32F,1.0/255.0);
Mat_<float> mask(l.rows,l.cols,0.0);
mask(Range::all(),Range(0,mask.cols/2))=1.0;
pyr_blend pyr_blend_two(l,r,mask,4);
Mat_<Vec3f> result = pyr_blend_two.calcresult();
imshow("l",l);
imshow("r",r);
imshow("result",result);
waitKey(0);
return 0;
}
这里跟美女学霸学了几个很好的细节http://blog.csdn.net/abcjennifer/article/details/7628655
1,一个就是对mask的处理,因为我们知道通常的mask都是二值图像,所以这里把mask转换成跟原图一样的类型,是为了能够在计算左右两图的权重的时候直接使用而计算简便,
2,就是C++再一次的佩服啊,果然很好很强大啊。O(∩_∩)O哈哈~,fighting哦,向偶像学习。
结果如图: