小波变换

小波变换是近年来在图象处理中受到十分重视的新技术,面向图象压缩、特征检测以及纹理分析的许多新方法,如多分辨率分析、时频域分析、金字塔算法等,都最终归于小波变换(wavelet transforms)的范畴中。

小波变换与傅立叶变换,个人觉得这之间有着千丝万缕的联系。可惜毕竟不是学数学的,功力不够

下面主要贴算法和相应代码,个人觉得http://http://shijuanfeng.blogbus.com/logs/221385402.html

用OpenCV & C++代码写的非常漂亮,建议大家可以去踩踩

本人专业不是搬砖,不是码农,班门弄斧,还希望大家批评指正。


本代码依赖于openCV开源库提供的相应函数,采用的是Mallat算法,其中Mallat只是小波变换中减少计算机运算量的一种算法,相当于傅里叶变换中快速傅里叶变换(FFT)的算法。

小波变换算法如下:

1.利用opencv中imread函数读取图像,存储到Mat类提供的矩阵中

2.将矩阵中的行数据或者列数据写到vector<>向量模板

3.使用Mallat类提供的方法完成小波变换,具体如下:

①,其中先逐行变换,得到高频与低频成分的二分之一下采样的向量,存储到Mat类的矩阵中,此时得到两个矩阵,一个存储低频信息(L),一个存储高频信息(H)

②对已采集到高频分量和低频分量再进行逐列列变换,得到高频与低频成分的二分之一下采样的向量,存储到Mat类的矩阵中,此时得到四个矩阵,信息代号分别为(LL)、(LH)、(HL)、(HH)

4,重复3步骤,得到不同级数的小波变换,注意每次的输入信号为(LL)信息矩阵,得到四中频率信息的矩阵。


小波逆变换小波变换的逆运算,不需要多解释了

关于Mallat类的创建:

粗略围观下小波变换,对于离散信号需要边界延拓,因此需要存储边界延拓的类型的私有数据和相应的公有方法;小波变换还需要知道小波基函数,常用的有那么几种,因此需要知道小波基函数的类型和对应的数据,因此得有相应的私有数据和私有方法(小波基函数的数据只和小波基函数类型有关而与信号的输入无关,私有方法即可。而边界延拓的实现需要使用信号输入,故采用公有方法

此外整个类必须实现能小波变换和小波变换的功能的公有方法


从弱类型数据的Matlab的编写转用C++强类型数据的编写,尤其要注意对数据类型和分配内存的考虑,下面不多说,贴主要代码(写的很渣,希望大家拍砖)

    string path= "D://testPic/CCD.jpg";
	Mat img=imread(path,1);//读取图像文件
	Mat gray;
	if(!img.data)
	    return -1;
	cvtColor(img,gray,CV_BGR2GRAY);//转为单通道灰度图形
	Size size;
	size.height=5;
	size.width=5;
	GaussianBlur(gray,gray,size,1.5,1.5);//高斯滤波
        //由于所做项目只需要低频成分,对高频部分数据没有处理
	Mat factorMat;
	gray.convertTo(factorMat,CV_32FC1);//注意数据类型转换(由unsignedchar转化成float数据)
	//Mat* detailMat;//高频成分处代码注释掉了

	for(int layer=0;layer<level;layer++)
	{
	    Mat approxMatRow;
	    Mat detailMatRow;
	    Mat approxMatCol;
	    Mat detailMatCol;	 
		//行变换小波分解
	    for(int i=0;i<factorMat.rows;i++)
	    {
	       vector<_TP> signalOut;
	       vector<_TP> signalExOut;
	       row2vector(factorMat,i,signalOut);//Mat行数据转到vector向量模板
	       Mallat<_TP> mallatSignal("db1","symmetricEx");//类进行初始化,由于代码未完善,边界延拓类型没有存储到该类中
	       mallatSignal.getSigEx("symmetricEx",signalOut,signalExOut);//信号延拓
	       vector<_TP> approx,detail;
	       mallatSignal.dwt(signalExOut,approx,detail);//小波整变换
	       approxMatRow.create(factorMat.rows,approx.size(),CV_32FC1);//将逐行进行的小波变换后的到的数据存储到Mat矩阵中,此处是预分配矩阵的数据大小类型
	       vector2row(approx,i,approxMatRow);
	    }
		factorMat.release();
		factorMat=approxMatRow;
		//列变换小波分解
		for(int i=0;i<factorMat.cols;i++)
	    {
		vector<_TP> signalOut;
		vector<_TP> signalExOut;
	        col2vector(factorMat,i,signalOut);
	        Mallat<_TP> mallatSignal("db1","symmetricEx");
	        mallatSignal.getSigEx("symmetricEx",signalOut,signalExOut);
		vector<_TP> approx,detail;
		mallatSignal.dwt(signalExOut,approx,detail);
		approxMatCol.create(approx.size(),factorMat.cols,CV_32FC1);
		vector2col(approx,i,approxMatCol);
	    }
		factorMat.release();
		factorMat=approxMatCol;
}
for(int layer=0;layer<level;layer++)
	{
//列变换小波重构
	for(int i=0;i<factorMat.cols;i++)
	    {
		vector<_TP> signalOut;
		vector<_TP> signalExOut;
	        col2vector(factorMat,i,signalOut);
	        Mallat<_TP> mallatSignal("db1","symmetricEx");	   
		mallatSignal.idwt(signalOut,signalExOut);
		approxMatCol.create(signalExOut.size(),factorMat.cols,CV_32FC1);
		vector2col(signalExOut,i,approxMatCol);
	    }
		  
		factorMat.release();
		factorMat=approxMatCol;
		//行变换小波分解
	    for(int i=0;i<factorMat.rows;i++)
	    {
		vector<_TP> signalOut;
		vector<_TP> signalExOut;
	        row2vector(factorMat,i,signalOut);
	        Mallat<_TP> mallatSignal("db1","symmetricEx");
	  	mallatSignal.idwt(signalOut,signalExOut);
		approxMatRow.create(factorMat.rows,signalExOut.size(),CV_32FC1);
		vector2row(signalExOut,i,approxMatRow);
	    }
		factorMat.release();
		factorMat=approxMatRow;	
	}


Mallat类的创建:主要代码

头文件

#include <iostream>


using namespace std;
namespace wavelet
{
template <typename _TP>
class Mallat
{
public:
Mallat(const string &waveletName,const string &signalExTp);
~Mallat();


void getSigEx(const string &signalExTp,vector<_TP> &signalInput,vector<_TP> &signalExOut);
void dwt(vector<_TP> &signalInput,vector<_TP> &approxCoefs,vector<_TP> &detailCoefs);
void idwt(vector<_TP> &approxCoefs,vector<_TP> &signalOutput);

private:
string wavelet;
//string extensionType;信号延拓类型被注释掉了,回头补上
vector<_TP> ld,hd,
            lr,hr;
void getFilter(const string &waveletName);
};

}
#endif
实现文件 主要代码(主要原理参照 http://http://blog.csdn.net/v_hyx/article/details/8557071)


Mallat<_TP>::Mallat(const string &waveletName,const string &signalExTp)
{
	if (waveletName !="db1" && waveletName !="db2" && waveletName !="db3" && waveletName !="db4")
	{
		cerr << "No such wavelet type!" <<endl;
		cvWaitKey(0); 
                exit(1);
	}
	getFilter(waveletName);

    if (signalExTp != "symmetricEx" && signalExTp != "cycleEx")
    {
    	       cerr << "No such extension type!" << endl;
	       cvWaitKey(0); 
               exit(1);
    }
}

template<typename _TP>
Mallat<_TP>::~Mallat()
{

}

template<typename _TP>
inline void Mallat<_TP>::getFilter(const string &waveletName)
{
	if("db1"==waveletName)
	   db1Coefs(ld,hd,lr,hr);
	if("db2"==waveletName)
	   db2Coefs(ld,hd,lr,hr);
	if("db3"==waveletName)
	   db3Coefs(ld,hd,lr,hr);
	if("db4"==waveletName)
	   db4Coefs(ld,hd,lr,hr);
}

template<typename _TP>
void Mallat<_TP>::getSigEx(const string &signalExTp,vector<_TP> &signalInput,vector<_TP> &signalExOut)
{
	vector<_TP> wavelet(ld);
	signalExtension(signalExTp,wavelet,signalInput,signalExOut);
}

template<typename _TP>
void Mallat<_TP>:: dwt(vector<_TP> &signalInput,vector<_TP> &approxCoefs,vector<_TP> &detailCoefs)
{
	int filterLen=ld.size();
	int sigLen=signalInput.size();
	if (filterLen>sigLen)
	{
		cerr<<"the length of  decret signal iputted must be  greater than that of the filters!"<<endl;
		cvWaitKey(0); 
		exit(1);
	}
	/*if (NULL==signalInput || NULL== approixCoefs || NULL==detailCoefs)
	{
		cerr<<"the pointer of related parameters inputted is NULL" <<endl;
		exit(1);
	}*/

	int decLen=(sigLen-filterLen)/2;
	approxCoefs.resize(decLen);
	detailCoefs.resize(decLen);
	for (int i = 0; i < decLen; i++)
	{
		approxCoefs.at(i)=0;
		detailCoefs.at(i)=0;
		for (int j = 0; j < filterLen; j++)
		{
			int pos=2*i-j+(filterLen-1);
			approxCoefs.at(i) += signalInput.at(pos)*ld.at(j);
			detailCoefs.at(i) += signalInput.at(pos)*hd.at(j);
		}
	}
}

template<typename _TP>
void Mallat<_TP> :: idwt(vector<_TP> &approxCoefs,vector<_TP> &signalOutput)//vector<_TP> &detailCoefs,
	
{
	/*if (NULL==approixCoefs || NULL==detailCoefs || NULL==signalOutput)
	{
		cerr<<"the pointer of related parameters inputted is NULL" <<endl;
		exit(1);
	}*/
	int filterLen=ld.size();
	int coefsLen=approxCoefs.size();
	int recLen=2*coefsLen-filterLen;
	signalOutput.resize(recLen);
	for (int i = 0; i < recLen; ++i)
	{
		signalOutput.at(i)=0;
		for (int j = 0; j < coefsLen; j++)
		{
			int pos=i-2*j+filterLen-1;
			if (pos>=0 && pos<filterLen)
			{
				signalOutput.at(i)=lr.at(pos)*approxCoefs.at(j);//+hr.at(j)*detailCoefs.at(pos);
			}
		}
	}

}

其余相关重要代码

信号延拓

template <typename _TP>
void signalExtension(const string &signalExTp,vector<_TP> &wavelet,vector<_TP> &signalExIn,vector<_TP> &signalExOut)

{
	/*if(NULL==wavelet || NULL==signalExIn ||NULL=signalExOut)
	{
		cerr<<"the pointer of related parameters inputted is NULL" <<endl;
		exit(1);
	}*/

    int signalInLen=signalExIn.size();
    int extendLen=wavelet.size();
	if ("symmetricEx"==signalExTp)
	{
		if (signalInLen%2)
		{
			signalExOut.resize(signalInLen+2*extendLen+1);
			for (int i = 0; i < signalInLen; i++)
			{
				signalExOut.at(extendLen+i)=signalExIn.at(i);
			}
			for (int i = 0; i <extendLen; i++)
			{
				signalExOut.at(i)=signalExOut.at(2*extendLen-i-1);
				signalExOut.at(signalInLen+extendLen+i)=signalExOut.at(extendLen+signalInLen-i-1);
			}
			signalExOut.at(signalInLen+2*extendLen)=signalExOut.at(signalInLen-1);
		}
		else
		{
			signalExOut.resize(signalInLen+2*extendLen);
			for (int i = 0; i < signalInLen; i++)
			{
				signalExOut.at(extendLen+i)=signalExIn.at(i);
			}
			for (int i = 0; i <extendLen; i++)
			{
				signalExOut.at(i)=signalExOut.at(2*extendLen-i-1);
				signalExOut.at(signalInLen+extendLen+i)=signalExOut.at(extendLen+signalInLen-i-1);
			}
		}
	}
	else if ("cycleEx"==signalExTp)
	{
		signalExOut.resize(extendLen+signalInLen);
		for (int i = 0; i < extendLen; i++)
		{
			signalExOut.at(i)=signalExIn.at(signalInLen-extendLen+i);
		}
		for (int i = 0; i < signalInLen; i++)
		{
			signalExOut.at(extendLen+i)=signalExIn.at(i);
		}
	}
}

矩阵行数据、列数据转vector向量


template<typename _TP>
void row2vector(const Mat &src,int rowN,vector<_TP> &signalOut)
{
    int width=src.cols;
signalOut.resize(width);
    for(int i=0;i<width;i++)
    {
        signalOut.at(i)=src.at<_TP>(rowN,i);
    }
}
template<typename _TP>
void col2vector(const Mat &src,int colN,vector<_TP> &signalOut)
{
    int height=src.rows;
signalOut.resize(height);
    for(int i=0;i<height;i++)
    {
        signalOut.at(i)=src.at<_TP>(i,colN);
    }
}

vector向量转mat

template <typename _TP> void vector2row(vector<_TP> & rowVector,int rowN,Mat & factorMat)
{
	for(int i=0;i<rowVector.size();i++)
	{
		factorMat.at<_TP>(rowN,i)=rowVector.at(i);
	}
}
template <typename _TP> void vector2col(vector<_TP> & colVector,int colN,Mat & factorMat)
{
	for(int i=0;i<colVector.size();i++)
	{
		factorMat.at<_TP>(i,colN)=colVector.at(i);
	}
}

代码写得很渣 再次强调


欢迎学习交流

你可能感兴趣的:(小波变换)