1 Mallat算法

离散序列的Mallat算法分解公式如下:

其中,H(n)、G(n)分别表示所选取的小波函数对应的低通和高通滤波器的抽头系数序列。

从Mallat算法的分解原理可知,分解后的序列就是原序列与滤波器序列的卷积再进行隔点抽取而来。

离散序列的Mallat算法重构公式如下:

其中,h(n)、g(n)分别表示所选取的小波函数对应的低通和高通滤波器的抽头系数序列。

2 小波变换实现过程(C/C++)

2.1       小波变换结果序列长度

小波的Mallat算法分解后的序列长度由原序列长SoureLen和滤波器长FilterLen决定。从Mallat算法的分解原理可知,分解后的序列就是原序列与滤波器序列的卷积再进行隔点抽取而来。即分解抽取的结果长度为(SoureLen+FilterLen-1)/2。

2.2       获取滤波器组

对于一些通用的小波函数,简单起见,可以通过Matlab的wfilters(‘wavename’)获取4个滤波器;特殊的小波函数需要自行构造获得。

下面以db1小波函数(Haar小波)为例,其变换与重构滤波器组的结果如下:

  1. //matlab输入获取命令
  2. >> [Lo_D,Hi_D,Lo_R,Hi_R] = wfilters('db1')
  3. //获取的结果
  4. Lo_D =
  5. 0.7071    0.7071
  6. Hi_D =
  7. -0.7071    0.7071
  8. Lo_R =
  9. 0.7071    0.7071
  10. Hi_R =
  11. 0.7071   -0.7071
//matlab输入获取命令
>> [Lo_D,Hi_D,Lo_R,Hi_R] = wfilters('db1') //获取的结果
Lo_D =
0.7071 0.7071
Hi_D =
-0.7071 0.7071
Lo_R =
0.7071 0.7071
Hi_R =
0.7071 -0.7071
2.3       信号边界延拓

在Mallat算法中,假定输入序列是无限长的,而实际应用中输入的信号是有限的采样序列,这就会出现信号边界处理问题。对于边界信号的延拓一般有3种方法,即零延拓、对称延拓和周期延拓。

3种延拓方法比较情况如下:

对于正交小波变换来说,前两种延拓方法实现起来比较简单,但重建时会产生边界效应,而且分解的层数越多,产生的边界效应越显著。零延拓方法给人一种跳跃的感觉。至于对称性延拓,由于正交小波滤波器一般都是非对称性的(Haar小波基虽然是正交的,但它是非连续的),重建图象给人一种错位的感觉。相比较而言,只有最后一种延拓方式可以得到比较精确的重建结果,它不仅能保证分解与重建正确计算,而且恢复的质量也好。不过,周期性延拓方法虽然是常用的三种方法中比较好的方法,但会导致信号边缘的非连续性,从而会使得较高频率(子带)层的小波系数很大,即使信号本身相当平滑。从信号压缩的角度看,大的系数是希望避免的。信号的对称延拓可避免边缘的非连续性问题。然而,对称延拓只能和对称的小波滤波器一起适用。如果降低正交性要求,选择双正交小波变换,对称性延拓不失为一种好的方法。周期延拓可适用于任何小波变换,但可能导致输入序列边缘的不连续,使得高频系数较大。而对称延拓则避免了输入序列边界的不连续,是当前广泛采用的一种延拓方法。

下式中给出了最常用的对称延拓表达式。

当原序列长sLEN为偶数时延拓后的序列长为sLEN+2*(filterLEN),而原序列长为奇数时则需要在右端再延拓一个元素。注:在Matlab中默认使用了对称延拓。

2.4       小波分解

在db1小波函数下,离散序列的Mallat算法分解公式展开如下:

其它的db小波,不再详述。小波分解C++源码如下。

  1. /**
  2. * @brief 小波变换之分解
  3. * @param sourceData 源数据
  4. * @param dataLen 源数据长度
  5. * @param db 过滤器类型
  6. * @param cA 分解后的近似部分序列-低频部分
  7. * @param cD 分解后的细节部分序列-高频部分
  8. * @return
  9. *         正常则返回分解后序列的数据长度,错误则返回-1
  10. */
  11. int Wavelet::Dwt(double *sourceData, int dataLen, Filter db, double *cA, double *cD)
  12. {
  13. if(dataLen < 2)
  14. return -1;
  15. if((NULL == sourceData)||(NULL == cA)||(NULL == cD))
  16. return -1;
  17. m_db = db;
  18. int filterLen = m_db.length;
  19. int n,k,p;
  20. int decLen = (dataLen+filterLen-1)/2;
  21. double tmp=0;
  22. cout<<"decLen="<<decLen<<endl;
  23. for(n=0; n<decLen; n++)
  24. {
  25. cA[n] = 0;
  26. cD[n] = 0;
  27. for(k=0; k<filterLen; k++)
  28. {
  29. p = 2*n-k;  // 感谢网友onetrain指正,此处由p = 2*n-k+1改为p = 2*n-k,解决小波重构后边界异常问题--2013.3.29 by hmm
  30. // 信号边沿对称延拓
  31. if((p<0)&&(p>=-filterLen+1))
  32. tmp = sourceData[-p-1];
  33. else if((p>dataLen-1)&&(p<=dataLen+filterLen-2))
  34. tmp = sourceData[2*dataLen-p-1];
  35. else if((p>=0)&&(p<dataLen-1))
  36. tmp = sourceData[p];
  37. else
  38. tmp = 0;
  39. // 分解后的近似部分序列-低频部分
  40. cA[n] += m_db.lowFilterDec[k]*tmp;
  41. // 分解后的细节部分序列-高频部分
  42. cD[n] += m_db.highFilterDec[k]*tmp;
  43. }
  44. }
  45. return decLen;
  46. }
/**
* @brief 小波变换之分解
* @param sourceData 源数据
* @param dataLen 源数据长度
* @param db 过滤器类型
* @param cA 分解后的近似部分序列-低频部分
* @param cD 分解后的细节部分序列-高频部分
* @return
* 正常则返回分解后序列的数据长度,错误则返回-1
*/
int Wavelet::Dwt(double *sourceData, int dataLen, Filter db, double *cA, double *cD)
{
if(dataLen < 2)
return -1;
if((NULL == sourceData)||(NULL == cA)||(NULL == cD))
return -1; m_db = db;
int filterLen = m_db.length;
int n,k,p;
int decLen = (dataLen+filterLen-1)/2;
double tmp=0;
cout<<"decLen="<<decLen<<endl; for(n=0; n<decLen; n++)
{
cA[n] = 0;
cD[n] = 0;
for(k=0; k<filterLen; k++)
{
p = 2*n-k; // 感谢网友onetrain指正,此处由p = 2*n-k+1改为p = 2*n-k,解决小波重构后边界异常问题--2013.3.29 by hmm // 信号边沿对称延拓
if((p<0)&&(p>=-filterLen+1))
tmp = sourceData[-p-1];
else if((p>dataLen-1)&&(p<=dataLen+filterLen-2))
tmp = sourceData[2*dataLen-p-1];
else if((p>=0)&&(p<dataLen-1))
tmp = sourceData[p];
else
tmp = 0; // 分解后的近似部分序列-低频部分
cA[n] += m_db.lowFilterDec[k]*tmp; // 分解后的细节部分序列-高频部分
cD[n] += m_db.highFilterDec[k]*tmp;
} } return decLen;
}
2.5      小波重构
  1. /**
  2. * @brief 小波变换之重构
  3. * @param cA 分解后的近似部分序列-低频部分
  4. * @param cD 分解后的细节部分序列-高频部分
  5. * @param cALength 输入数据长度
  6. * @param db 过滤器类型
  7. * @param recData 重构后输出的数据
  8. */
  9. void  Wavelet::Idwt(double *cA, double *cD,  int cALength, Filter db, double *recData)
  10. {
  11. if((NULL == cA)||(NULL == cD)||(NULL == recData))
  12. return;
  13. m_db = db;
  14. int filterLen = m_db.length;
  15. int n,k,p;
  16. int recLen = 2*cALength-filterLen+1;
  17. cout<<"recLen="<<recLen<<endl;
  18. for(n=0; n<recLen; n++)
  19. {
  20. recData[n] = 0;
  21. for(k=0; k<cALength; k++)
  22. {
  23. p = n-2*k+filterLen-1;
  24. // 信号重构
  25. if((p>=0)&&(p<filterLen))
  26. {
  27. recData[n] += m_db.lowFilterRec[p]*cA[k] + m_db.highFilterRec[p]*cD[k];
  28. //cout<<"recData["<<n<<"]="<<recData[n]<<endl;
  29. }
  30. }
  31. }
  32. }
/**
* @brief 小波变换之重构
* @param cA 分解后的近似部分序列-低频部分
* @param cD 分解后的细节部分序列-高频部分
* @param cALength 输入数据长度
* @param db 过滤器类型
* @param recData 重构后输出的数据
*/
void Wavelet::Idwt(double *cA, double *cD, int cALength, Filter db, double *recData)
{
if((NULL == cA)||(NULL == cD)||(NULL == recData))
return; m_db = db;
int filterLen = m_db.length; int n,k,p;
int recLen = 2*cALength-filterLen+1;
cout<<"recLen="<<recLen<<endl; for(n=0; n<recLen; n++)
{
recData[n] = 0;
for(k=0; k<cALength; k++)
{
p = n-2*k+filterLen-1; // 信号重构
if((p>=0)&&(p<filterLen))
{
recData[n] += m_db.lowFilterRec[p]*cA[k] + m_db.highFilterRec[p]*cD[k];
//cout<<"recData["<<n<<"]="<<recData[n]<<endl;
} }
}
}
2.6      c++实现结果

3 小波变换实现(MATLAB)

使用matlab小波工具箱实现db4的情况如下。

1、MatlabDB4.m文件内容。

  1. %加载txt数据示例
  2. s=importdata('data2.txt'); %load data2.txt;
  3. subplot(521);plot(s); %画出原始信号的波形图
  4. title('原始信号');
  5. [cA,cD]=dwt(s,'db4'); %采用db4小波并对信号进行一维离散小波分解。
  6. y=idwt(cA,cD,'db4'); %一维离散小波反变换
  7. subplot(522);
  8. plot(cA); %画出波形图
  9. title('MATLAB低频部分dwt-cA');
  10. subplot(523);
  11. plot(cD); %画出波形图
  12. title('MATLAB高频部分dwt-cD');
  13. subplot(524);
  14. plot(y); %画出波形图
  15. title('MATLAB重构idwt');
%加载txt数据示例
s=importdata('data2.txt'); %load data2.txt;
subplot(521);plot(s); %画出原始信号的波形图
title('原始信号'); [cA,cD]=dwt(s,'db4'); %采用db4小波并对信号进行一维离散小波分解。
y=idwt(cA,cD,'db4'); %一维离散小波反变换
subplot(522);
plot(cA); %画出波形图
title('MATLAB低频部分dwt-cA'); subplot(523);
plot(cD); %画出波形图
title('MATLAB高频部分dwt-cD'); subplot(524);
plot(y); %画出波形图
title('MATLAB重构idwt');

2、波形图如下。

4 小结

在此,采用C++实现了dbN系列小波的单层一维离散小波变换,通过对比db4小波变换发现(笔者也同样对比验证了db1-db3),C++实现效果和Matlab效果完全一样。通过这一过程,可以很好地帮助理解小波变换的Mallat算法原理,并将C++代码快速应用到工程实践,同时对MATLAB小波工具箱的实现细节也有更深入的理解。相关文献表明,C++代码实现的DWT算法比Matlab小波工具箱dwt方法效率更高。

注:对小波变换见识还不深,有问题者,欢迎提出讨论交流,对源码细节感兴趣的tx,可以到如下链接下载。

小波学习之一(单层一维离散小波变换DWT的Mallat算法C++和MATLAB实现) ---转载的更多相关文章

  1. 小波学习之二(单层一维离散小波变换DWT的Mallat算法C++实现优化)--转载

    小波学习之二(单层一维离散小波变换DWT的Mallat算法C++实现优化)   在上回<小波学习之一>中,已经详细介绍了Mallat算法C++实现,效果还可以,但也存在一些问题,比如,代码 ...

  2. [Python ]小波变化库——Pywalvets 学习笔记

    [Python ]小波变化库——Pywalvets 学习笔记 2017年03月20日 14:04:35 SNII_629 阅读数:24776 标签: python库pywavelets小波变换 更多 ...

  3. 小波变化库——Pywalvets学习笔记

    笔记 术语(中英对照): 尺度函数:scaling function(又称父函数 father wavelet) 小波函数:wavelet function(又称母函数 mother wavelet) ...

  4. 基于python的小波阈值去噪算法

    https://blog.csdn.net/alwaystry/article/details/52756051 发表于 2018-01-10 16:32:17 嵌入式设计应用 +关注 小波图像去噪原 ...

  5. 小波说雨燕 第三季 构建 swift UI 之 UI组件集-视图集(六)Picker View视图 学习笔记

    想对PickerView进行操作,只能在代码中操作. 下面 ,再添加三个label组件,然后将所有组件配置到代码中(看代码),然后要实现对PickerView的操作,就要实现它的DataSource协 ...

  6. 多尺度二维离散小波重构waverec2

    clc,clear all,close all; load woman; [c,s]=wavedec2(X,2,'haar');%进行2尺度二维离散小波分解.分解小波函数haar %多尺度二维离散小波 ...

  7. 单尺度二维离散小波重构(逆变换)idwt2

    clc,clear all,close all; load woman; %单尺度二维离散小波分解.分解小波函数haar [cA,cH,cV,cD]=dwt2(X,'haar'); %单尺度二维离散小 ...

  8. 多尺度二维离散小波分解wavedec2

    对X进行N尺度小波分解 [C,S]=wavedec2(X,N,'wname'); clc,clear all,close all; load woman; [c,s]=wavedec2(X,2,'db ...

  9. 单尺度二维离散小波分解dwt2

    clc,clear all,close all; load woman; [cA,cH,cV,cD]=dwt2(X,'haar');%单尺度二维离散小波分解.分解小波函数haar figure,ims ...

随机推荐

  1. Spring Batch 介绍

    在企业应用的关键环境中,通常有需要很多应用来来处理大量的应用.这商业操作包括了自动化,并且负责的处理程序来对大量数据进行高效的处理,通常这些程序不需要人工进行干预.这些事件包括有基于时间周期产生的操作 ...

  2. Red and Black HDU - 1312

    There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A ...

  3. 【洛谷p1932】A+B A-B A*B A/B A%B Problem

    (emmmm) 这道题成功让我见识到了Dev撤回的高端大气上档(dàng)次. A+B A-B A*B A/B A%B Problem[传送门](真是个优秀的高精) 算法:::::::(模板题弄这么费 ...

  4. python-django缓存

    三 Django的缓存机制 1.1 缓存介绍 1.缓存的简介 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的 ...

  5. Lunx下 怎样启动和关闭oracle数据库

    1.因为oracle运行在Linux系统下,首先,要连接Linux系统 2.切换到oracle安装用户下. 我的是 ora12. 3.运行oracle的环境变量, 以便输入相关命令. 4.进入orac ...

  6. Mybatis中,当插入数据后,返回最新主键id的几种方法,及具体用法

    insert元素 属性详解 其属性如下: parameterType ,入参的全限定类名或类型别名 keyColumn ,设置数据表自动生成的主键名.对特定数据库(如PostgreSQL),若自动生成 ...

  7. Android应用启动时Activity被创建两次

    项目需要使用到播放器,用开源的ijkplayer播放器改装. 但是在调试过程中Activity的OnCreate()被调用两次,调试时直接连接手机调试,有时候又不一定是两次. 后来偶尔看到一句话 “当 ...

  8. nodejs sequelize 对应数据库操作符的定义

    const Op = Sequelize.Op [Op.and]: {a: } // 且 (a = 5) [Op.or]: [{a: }, {a: }] // (a = 5 或 a = 6) [Op. ...

  9. Kali安装教程(VMWare)

    1.下载镜像及相关 1.1下载镜像文件 下载链接:https://www.kali.org/downloads/ 选择自己需要的版本下载,根据经验先下载种子文件(torrent)再用迅雷下载网速是最有 ...

  10. 利用模板导出文件(二)之jacob利用word模板导出word文件(Java2word)

    https://blog.csdn.net/Fishroad/article/details/47951061?locationNum=2&fps=1 先下载jacob.jar包.解压后将ja ...