天天看點

使用liner、feather、multiband對已經拼接的資料進行融合(下)

了解mulitband。所謂的mulitband,其實就是一種多尺度的樣條融合,其實作的主要方法就是laplace金字塔。高斯金字塔是向下采樣,而laplace金字塔式向上采樣(也就是恢複),采用的都是內插補點的方法。如何能夠在金字塔各個層次上面進行圖像的融合,結果證明是相當不錯的。網絡上面流傳的一個類解釋了這個問題,并且能夠拿來用:

#

include

"stdafx.h"

#

include

<iostream>

#

include

<vector>

#

include

<opencv2/core/core.hpp>

#

include

<opencv2/imgproc/imgproc.hpp>

#

include

<opencv2/highgui/highgui.hpp>

#

include

<opencv2/features2d/features2d.hpp>

#

include

<opencv2/calib3d/calib3d.hpp>

using

namespace

cv;

#

ifdef

_DEBUG

#

define

new

DEBUG_NEW

#

endif

#

define

DllExport _declspec (dllexport)

/*

1.設計一個mask(一半全1,一半全0),并計算level層的gaussion_mask[i];

2.計算兩幅圖像每一層的Laplacian[i],并與gaussion_mask[i]相乘,合成一幅result_lapacian[i];

3.對兩幅圖像不斷求prydown,并把最高層儲存在gaussion[i],與gaussion_mask[i]相乘,合成一幅result_gaussion;

4,對result_gaussion不斷求pryup,每一層都與result_lapacian[i]合成,最後得到原-圖像大小的融合圖像。

*/

class

LaplacianBlending { 

private

                Mat_<Vec3f> top; 

                Mat_<Vec3f> down; 

                Mat_<

float

> blendMask; 

                vector<Mat_<Vec3f> > topLapPyr,downLapPyr,resultLapPyr; //Laplacian Pyramids  

                Mat topHighestLevel, downHighestLevel, resultHighestLevel; 

                vector<Mat_<Vec3f> > maskGaussianPyramid; //masks are 3-channels for easier multiplication with RGB  

int

levels; 

                 //建立金字塔

void

buildPyramids() { 

                                buildLaplacianPyramid(top,topLapPyr,topHighestLevel);  

                                buildLaplacianPyramid(down,downLapPyr,downHighestLevel); 

                                buildGaussianPyramid(); 

                } 

                 //建立gauss金字塔

void

buildGaussianPyramid() {//金字塔内容Y為a每一層的掩模  

                                assert(topLapPyr.size()>0); 

                                maskGaussianPyramid.clear(); 

                                Mat currentImg; 

                                 //blendMask就是掩碼

                                cvtColor(blendMask, currentImg, CV_GRAY2BGR); //store color img of blend mask into maskGaussianPyramid  

                                maskGaussianPyramid.push_back(currentImg); //0-level  

                                currentImg = blendMask; 

for

(

int

l=1; l<levels+1; l++) { 

                                                Mat _down; 

if

(topLapPyr.size() > l) 

                                                                pyrDown(currentImg, _down, topLapPyr[l].size()); 

else

                                                                pyrDown(currentImg, _down, topHighestLevel.size()); //lowest level  

                                                Mat down; 

                                                cvtColor(_down, down, CV_GRAY2BGR); 

                                                maskGaussianPyramid.push_back(down); //add color blend mask into mask Pyramid  

                                                currentImg = _down; 

                                } 

                } 

                 //建立laplacian金字塔

void

buildLaplacianPyramid(

const

Mat& img, vector<Mat_<Vec3f> >& lapPyr, Mat& HighestLevel) { 

                                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;  //存儲的就是殘D差

                                                lapPyr.push_back(lap); 

                                                currentImg = down; 

                                } 

                                currentImg.copyTo(HighestLevel); 

                } 

                Mat_<Vec3f> reconstructImgFromLapPyramid() { 

                                 //将左右laplacian圖像拼成的resultLapPyr金字塔中每一層  

                                 //從上到下插值放大并相加,即得blend圖像結果  

                                Mat currentImg = resultHighestLevel; 

for

(

int

l=levels-1; l>=0; l--) { 

                                                Mat up; 

                                                pyrUp(currentImg, up, resultLapPyr[l].size()); 

                                                currentImg = up + resultLapPyr[l]; 

                                } 

return

currentImg; 

                } 

void

blendLapPyrs() { 

                                 //獲得每層金字塔中直接用左右兩圖Laplacian變換拼成的圖像

                                 //一半的一半就是在這個地方計算的。 是基于掩模的方式進行的.

                                resultHighestLevel = topHighestLevel.mul(maskGaussianPyramid.back()) + 

                                                downHighestLevel.mul(Scalar(1.0,1.0,1.0) - maskGaussianPyramid.back()); 

for

(

int

l=0; l<levels; l++) { 

                                                Mat A = topLapPyr[l].mul(maskGaussianPyramid[l]); 

                                                Mat antiMask = Scalar(1.0,1.0,1.0) - maskGaussianPyramid[l]; 

                                                Mat B = downLapPyr[l].mul(antiMask); 

                                                Mat_<Vec3f> blendedLevel = A + B; 

                                                resultLapPyr.push_back(blendedLevel); 

                                } 

                } 

public

                LaplacianBlending(

const

Mat_<Vec3f>& _top,

const

Mat_<Vec3f>& _down,

const

Mat_<

float

>& _blendMask,

int

_levels)://預設數y據Y,使1用 LaplacianBlending lb(l,r,m,4);  

                  top(_top),down(_down),blendMask(_blendMask),levels(_levels) 

                  { 

                                  assert(_top.size() == _down.size()); 

                                  assert(_top.size() == _blendMask.size()); 

                                  buildPyramids();  //建立laplacian金字塔和gauss金字塔

                                  blendLapPyrs();   //将左右金字塔融合成為a一個圖檔  

                  }; 

                  Mat_<Vec3f> blend() { 

return

reconstructImgFromLapPyramid();//reconstruct Image from Laplacian Pyramid  

                  } 

}; 

Mat_<Vec3f> LaplacianBlend(

const

Mat_<Vec3f>& t,

const

Mat_<Vec3f>& d,

const

Mat_<

float

>& m) { 

                LaplacianBlending lb(t,d,m,4); 

return

lb.blend(); 

DllExport

double

aValue =1.5;

DllExport

int

dlladd()

{

return

5;

}

DllExport

int

dlladd(

int

a,

int

b)

{

return

a+b;

}

DllExport cv::Mat imagetest()

{

                cv::Mat image1= cv::imread( "C:\\apple.png",1);

                cv::Mat image2= cv::imread( "C:\\orange.png",1);

                Mat_<Vec3f> t; image1.convertTo(t,CV_32F,1.0/255.0); //Vec3f表示有三個通道,即 [row][column][depth]  

                Mat_<Vec3f> d; image2.convertTo(d,CV_32F,1.0/255.0); 

                Mat_<

float

> m(t.rows,d.cols,0.0);                 //将m全部賦3值為a0  

                 //m(Range::all(),Range(0,m.cols/2)) = 1.0;    //原來初始的掩碼是在這裡

                m(Range(0,m.rows/2),Range::all())=1.0;

                Mat_<Vec3f> blend = LaplacianBlend(t,d, m); 

                imshow( "blended",blend); 

return

blend;

}

需要注意的是, m(Range(0,m.rows/2),Range::all())=1.0表明了原始圖像的掩碼,這個掩碼就是那個分界的地方。

比如比如:

使用liner、feather、multiband對已經拼接的資料進行融合(下)

;

使用liner、feather、multiband對已經拼接的資料進行融合(下)

永達實際的項目上面,應該是這樣。

在使用這種方法進行大規模拼接的時候,主要是兩個問題

一個是效果,在上面的那個橘子蘋果的例子中,隻有前景的顔色有變化,實際上其它幾個地方色彩亮度變化不是很大。但是對于實際情況下的拼接來說,亮度有變化,比較難以處理。

使用liner、feather、multiband對已經拼接的資料進行融合(下)

二是效率。laplacian需要大量的過程,造成結果記憶體的需求很大,一時半會很難優化好。multband看來隻能夠在符合要求的簡單拼接中去實作使用。

來自為知筆記(Wiz)

目前方向:圖像拼接融合、圖像識别

聯系方式:[email protected]

繼續閱讀