opencv 小波變換與逆變換C++

在此記錄一下

興幸在網上看到關於小波變換的代碼,但是在逆變換的時候結果跟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程序中註釋掉部分)

小波重構圖:

 

完!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章