小波变换是近年来在图象处理中受到十分重视的新技术,面向图象压缩、特征检测以及纹理分析的许多新方法,如多分辨率分析、时频域分析、金字塔算法等,都最终归于小波变换(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); } }
代码写得很渣 再次强调
欢迎学习交流