在此記錄一下
興幸在網上看到關於小波變換的代碼,但是在逆變換的時候結果跟matlab的有很大差別,因此對照一下matlab的具體代碼,對已有的代碼進行一點改動。
說明:
1.配置好opencv,就可以運行(附Demo)
2.小波包的選擇,代碼中只包括了haar,db1,sym2,如需要更多種類的小波包,可以在matlab裏查看wfilters函數,對應寫進代碼中。
代碼如下:
1. WaveTransform.h文件
#include<opencv.hpp>
#include <imgproc/imgproc.hpp>
using namespace cv;
class WaveTransform
{
public:
WaveTransform(void);
~WaveTransform(void);
Mat WDT(const Mat &_src,const string _wname,const int _level);//小波分解
Mat IWDT(const Mat &_src,const string _wname,const int _level);//小波重構
void wavelet_D( const string _wname, Mat &_lowFilter, Mat &_highFilter );//分解包
void wavelet_R( const string _wname, Mat &_lowFilter, Mat &_highFilter );//重構包
Mat waveletDecompose( const Mat &_src, const Mat &_lowFilter, const Mat &_highFilter );
Mat waveletReconstruct(const Mat &_src, const Mat &_lowFilter, const Mat &_highFilter);
};
2. .WaveTransform.cpp文件
#include "WaveTransform.h"
WaveTransform::WaveTransform(void)
{
}
WaveTransform::~WaveTransform(void)
{
}
Mat WaveTransform::WDT(const Mat &_src,const string _wname,const int _level)
{
//int reValue=THID_ERR_NONE;
Mat_<float> src=Mat_<float>(_src);
Mat dst=Mat::zeros(src.rows,src.cols,src.type());
int row=src.rows;
int col=src.cols;
//高通低通濾波器
Mat lowFilter;
Mat highFilter;
wavelet_D(_wname,lowFilter,highFilter);
//小波變換
int t=1;
while (t<=_level)
{
//先進行 行小波變換
//#pragma omp parallel for
for (int i=0;i<row;i++)
{
//取出src中要處理的數據的一行
Mat oneRow=Mat::zeros(1,col,src.type());
for (int j=0;j<col;j++)
{
oneRow.at<float>(0,j)=src.at<float>(i,j);
}
oneRow=waveletDecompose(oneRow,lowFilter,highFilter);
for (int j=0;j<col;j++)
{
dst.at<float>(i,j)=oneRow.at<float>(0,j);
}
}
#if 0
// normalize(dst,dst,0,255,NORM_MINMAX);
IplImage dstImg1=IplImage(dst);
cvSaveImage("dst1.jpg",&dstImg1);
#endif
//小波列變換
//#pragma omp parallel for
for (int j=0;j<col;j++)
{
Mat oneCol=Mat::zeros(row,1,src.type());
for (int i=0;i<row;i++)
{
oneCol.at<float>(i,0)=dst.at<float>(i,j);//dst,not src
}
oneCol=(waveletDecompose(oneCol.t(),lowFilter,highFilter)).t();
for (int i=0;i<row;i++)
{
dst.at<float>(i,j)=oneCol.at<float>(i,0);
}
}
#if 0
// normalize(dst,dst,0,255,NORM_MINMAX);
IplImage dstImg2=IplImage(dst);
cvSaveImage("dst2.jpg",&dstImg2);
#endif
/*
char s[10];
itoa(t,s,10);
imshow(s,Mat_<uchar>(dst));
waitKey(1);
*/
//歸化各子圖範圍0~255
/*
int r_len=row/2,c_len=col/2;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
Point p1=Point(i*c_len,j*r_len);
Point p2=Point((i+1)*c_len,(j+1)*r_len);
Mat ROI=dst(Rect(p1,p2));
//ROI=cv::abs(ROI);
normalize(ROI,ROI,0,255,CV_MINMAX);
//imshow("a",Mat_<uchar>(ROI));
//waitKey(0);
}
}
*/
//
//更新
row/=2;
col/=2;
t++;
src=dst;
}
return dst;
}
Mat WaveTransform::IWDT(const Mat &_src,const string _wname,const int _level)
{
//int reValue=THID_ERR_NONE;
Mat src=Mat_<float>(_src);
Mat dst;//=Mat::zeros(src.rows,src.cols,src.type());
src.copyTo(dst);
int N=src.rows;
int D= src.cols;
//高低通濾波器
Mat lowFilter;
Mat highFilter;
wavelet_R(_wname,lowFilter,highFilter);
//小波變換
int t=1;
int row=N/std::pow(2.,_level-1);
int col=D/std::pow(2.,_level-1);
while(row<=N && col<=D)
//while(t<=_level)
{
//列逆變換
for(int j=0;j<col;j++)
{
Mat oneCol=Mat::zeros(row,1,src.type());
for(int i=0;i<row;i++)
{
oneCol.at<float>(i,0)=src.at<float>(i,j);
}
oneCol=(waveletReconstruct(oneCol.t(),lowFilter,highFilter)).t();
for(int i=0;i<row;i++)
{
dst.at<float>(i,j)=oneCol.at<float>(i,0);
}
}
#if 0
IplImage dstImg2=IplImage(dst);
cvSaveImage("dst.jpg",&dstImg2);
#endif
//行逆變換
for(int i=0;i<row;i++)
{
Mat oneRow=Mat::zeros(1,col,src.type());
for(int j=0;j<col;j++)
{
oneRow.at<float>(0,j)=dst.at<float>(i,j);
}
oneRow=waveletReconstruct(oneRow,lowFilter,highFilter);
for(int j=0;j<col;j++)
{
dst.at<float>(i,j)=oneRow.at<float>(0,j);
}
}
#if 0
IplImage dstImg1=IplImage(dst);
cvSaveImage("dst.jpg",&dstImg1);
#endif
char s[10];
itoa(t,s,10);
//Rect rrr=Rect(Point(col-1,row-1),Point(src.cols-1,src.rows-1));
//Rect rrr=Rect(Point(0,0),Point(col-1,row-1));
/*
Mat showImg;//=//dst;//(rrr);
dst.copyTo(showImg);
Mat showImg1;
showImg.copyTo(showImg1);
normalize(showImg1,showImg1,0,255,CV_MINMAX);
imshow(s,Mat_<uchar>(showImg1));
waitKey(1);
*/
row*=2;
col*=2;
t++;
src=dst;
}
return dst;
}
void WaveTransform::wavelet_D( const string _wname, Mat &_lowFilter, Mat &_highFilter )
{
if (_wname=="haar"||_wname=="db1")
{
int N=2;
_lowFilter=Mat::zeros(1,N,CV_32F);
_highFilter=Mat::zeros(1,N,CV_32F);
_lowFilter.at<float>(0,0)=1/sqrtf(N);
_lowFilter.at<float>(0,1)=1/sqrtf(N);
_highFilter.at<float>(0,0)=-1/sqrtf(N);
_highFilter.at<float>(0,1)=1/sqrtf(N);
}
else if (_wname=="sym2")
{
int N=4;
float h[]={-0.4830, 0.8365, -0.2241, -0.1294};
float l[]={-0.1294, 0.2241, 0.8365, 0.4830};
_lowFilter=Mat::zeros(1,N,CV_32F);
_highFilter=Mat::zeros(1,N,CV_32F);
for (int i=0;i<N;i++)
{
_lowFilter.at<float>(0,i)=l[i];
_highFilter.at<float>(0,i)=h[i];
}
}
}
void WaveTransform::wavelet_R( const string _wname, Mat &_lowFilter, Mat &_highFilter )
{
if (_wname=="haar"||_wname=="db1")
{
int N=2;
_lowFilter=Mat::zeros(1,N,CV_32F);
_highFilter=Mat::zeros(1,N,CV_32F);
_lowFilter.at<float>(0,0)=1/sqrtf(N);
_lowFilter.at<float>(0,1)=1/sqrtf(N);
_highFilter.at<float>(0,0)=1/sqrtf(N);
_highFilter.at<float>(0,1)=-1/sqrtf(N);
}
else if (_wname=="sym2")
{
int N=4;
float h[]={-0.1294,-0.2241,0.8365,-0.4830};
float l[]={0.4830, 0.8365, 0.2241, -0.1294};
_lowFilter=Mat::zeros(1,N,CV_32F);
_highFilter=Mat::zeros(1,N,CV_32F);
for (int i=0;i<N;i++)
{
_lowFilter.at<float>(0,i)=l[i];
_highFilter.at<float>(0,i)=h[i];
}
}
}
Mat WaveTransform::waveletDecompose( const Mat &_src, const Mat &_lowFilter, const Mat &_highFilter )
{
assert(_src.rows==1 && _lowFilter.rows==1 && _highFilter.rows ==1);
assert(_src.cols>=_lowFilter.cols && _src.cols>=_highFilter.cols );
Mat &src=Mat_<float>(_src);
int D=src.cols;
Mat &lowFilter=Mat_<float>(_lowFilter);
Mat &highFilter=Mat_<float>(_highFilter);
//頻域濾波或時域卷積;ifft( fft(x) * fft(filter)) = cov(x,filter)
Mat dst1=Mat::zeros(1,D,src.type());
Mat dst2=Mat::zeros(1,D,src.type());
filter2D(src,dst1,-1,lowFilter);
filter2D(src,dst2,-1,highFilter);
//下采樣
//數據拼接
for (int i=0,j=1;i<D/2;i++,j+=2)
{
src.at<float>(0,i)=dst1.at<float>(0,j);//lowFilter
src.at<float>(0,i+D/2)=dst2.at<float>(0,j);//highFilter
}
return src;
}
Mat WaveTransform::waveletReconstruct(const Mat &_src, const Mat &_lowFilter, const Mat &_highFilter)
{
assert(_src.rows == 1 && _lowFilter.rows == 1 && _highFilter.rows == 1);
assert(_src.cols >= _lowFilter.cols && _src.cols >= _highFilter.cols);
Mat &src = Mat_<float>(_src);
int D = src.cols;
Mat &lowFilter = Mat_<float>(_lowFilter);
Mat &highFilter = Mat_<float>(_highFilter);
/// 插值;
Mat Up1 = Mat::zeros(1, D, src.type());
Mat Up2 = Mat::zeros(1, D, src.type());
//Mat roi1(src, Rect(0, 0, D / 2, 1));
//Mat roi2(src, Rect(D / 2, 0, D / 2, 1));
/// 插值爲0
for ( int i=0, cnt=0; i<D/2; i++,cnt+=2 )
{
Up1.at<float>( 0, cnt ) = src.at<float>( 0, i ); ///< 前一半
Up2.at<float>( 0, cnt ) = src.at<float>( 0, i+D/2 ); ///< 後一半
}
//std::cout<<Up1<<std::endl;
/// 線性插值
//resize(roi1, Up1, Up1.size(), 0, 0, INTER_CUBIC);
//resize(roi2, Up2, Up2.size(), 0, 0, INTER_CUBIC);
/// 前一半低通,後一半高通
Mat dst1 = Mat::zeros(1, D, src.type());
Mat dst2 = Mat::zeros(1, D, src.type());
filter2D(Up1, dst1, -1, lowFilter);
filter2D(Up2, dst2, -1, highFilter);
/// 結果相加
dst1 = dst1 + dst2;
return dst1;
}
3. Demo
#include "WaveTransform.h"
#include<iostream>
#include<opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
char*filename="1.jpg";
Mat src=imread(filename);
int level=3;//分解階次
double dishu=2;
int result=(int)pow(dishu,level);
WaveTransform m_waveTransform;
//double a=clock();
//resize(src,src,Size((512/result)*result,(512/result)*result));
Mat img;
cvtColor(src,img,CV_RGB2GRAY);
normalize(img,img,0,255,CV_MINMAX);
imshow("img",img);
Mat float_src;
img.convertTo(float_src,CV_32F);
Mat imgWave=m_waveTransform.WDT(float_src,"sym2",level); //haar,sym2
imgWave.convertTo(float_src,CV_32F);
Mat imgIWave=m_waveTransform.IWDT(float_src,"sym2",level);
imshow("imgWave",Mat_<uchar>(imgWave));
normalize(imgIWave,imgIWave,0,255,CV_MINMAX);
imshow("IWDT",Mat_<uchar>(imgIWave));
waitKey(0)
return 0;
}
4. 效果圖
原圖:
小波分解圖:(爲了顯示效果,對每個子圖灰度值進行了normalization,WDT程序中註釋掉部分)
小波重構圖:
完!