這篇文章呢,主要是看了上篇金字塔在圖像分割的應用之後,知道了金字塔的主要應用還在於圖像融合,所以就又看了相關的內容,
用金字塔進行圖像融合的主要步驟如下:
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哦,向偶像學習。
結果如圖: