基于opencv的小波变换

提供函数DWT()和IDWT(),前者完成任意层次的小波变换,后者完成任意层次的小波逆变换。输入图像要求必须是单通道浮点图像,对图像大小也有要求(1层变换:w,h必须是2的倍数;2层变换:w,h必须是4的倍数;3层变换:w,h必须是8的倍数......),变换后的结果直接保存在输入图像中。
1、函数参数简单,图像指针pImage和变换层数nLayer。
2、一个函数直接完成多层次二维小波变换,尽量减少下标运算,避免不必要的函数调用,以提高执行效率。
3、变换过程中,使用了一个指针数组pData用于保存每行数据的起始位置,pRow和pColumn用于保存一行和一列临时数据,用于奇偶分离或合并,内存消耗较少。

代码:全选
// 二维离散小波变换(单通道浮点图像)
void DWT(IplImage *pImage, int nLayer)
{
   // 执行条件
   if (pImage)
   {
      if (pImage->nChannels == 1 &&
         pImage->depth == IPL_DEPTH_32F &&
         ((pImage->width >> nLayer) << nLayer) == pImage->width &&
         ((pImage->height >> nLayer) << nLayer) == pImage->height)
      {
         int     i, x, y, n;
         float   fValue   = 0;
         float   fRadius  = sqrt(2.0f);
         int     nWidth   = pImage->width;
         int     nHeight  = pImage->height;
         int     nHalfW   = nWidth / 2;
         int     nHalfH   = nHeight / 2;
         float **pData    = new float*[pImage->height];
         float  *pRow     = new float[pImage->width];
         float  *pColumn  = new float[pImage->height];
         for (i = 0; i < pImage->height; i++)
         {
            pData[i] = (float*) (pImage->imageData + pImage->widthStep * i);
         }
         // 多层小波变换
         for (n = 0; n < nLayer; n++, nWidth /= 2, nHeight /= 2, nHalfW /= 2, nHalfH /= 2)
         {
            // 水平变换
            for (y = 0; y < nHeight; y++)
            {
               // 奇偶分离
               memcpy(pRow, pData[y], sizeof(float) * nWidth);
               for (i = 0; i < nHalfW; i++)
               {
                  x = i * 2;
                  pData[y][i] = pRow[x];
                  pData[y][nHalfW + i] = pRow[x + 1];
               }
               // 提升小波变换
               for (i = 0; i < nHalfW - 1; i++)
               {
                  fValue = (pData[y][i] + pData[y][i + 1]) / 2;
                  pData[y][nHalfW + i] -= fValue;
               }
               fValue = (pData[y][nHalfW - 1] + pData[y][nHalfW - 2]) / 2;
               pData[y][nWidth - 1] -= fValue;
               fValue = (pData[y][nHalfW] + pData[y][nHalfW + 1]) / 4;
               pData[y][0] += fValue;
               for (i = 1; i < nHalfW; i++)
               {
                  fValue = (pData[y][nHalfW + i] + pData[y][nHalfW + i - 1]) / 4;
                  pData[y][i] += fValue;
               }
               // 频带系数
               for (i = 0; i < nHalfW; i++)
               {
                  pData[y][i] *= fRadius;
                  pData[y][nHalfW + i] /= fRadius;
               }
            }
            // 垂直变换
            for (x = 0; x < nWidth; x++)
            {
               // 奇偶分离
               for (i = 0; i < nHalfH; i++)
               {
                  y = i * 2;
                  pColumn[i] = pData[y][x];
                  pColumn[nHalfH + i] = pData[y + 1][x];
               }
               for (i = 0; i < nHeight; i++)
               {
                  pData[i][x] = pColumn[i];
               }
               // 提升小波变换
               for (i = 0; i < nHalfH - 1; i++)
               {
                  fValue = (pData[i][x] + pData[i + 1][x]) / 2;
                  pData[nHalfH + i][x] -= fValue;
               }
               fValue = (pData[nHalfH - 1][x] + pData[nHalfH - 2][x]) / 2;
               pData[nHeight - 1][x] -= fValue;
               fValue = (pData[nHalfH][x] + pData[nHalfH + 1][x]) / 4;
               pData[0][x] += fValue;
               for (i = 1; i < nHalfH; i++)
               {
                  fValue = (pData[nHalfH + i][x] + pData[nHalfH + i - 1][x]) / 4;
                  pData[i][x] += fValue;
               }
               // 频带系数
               for (i = 0; i < nHalfH; i++)
               {
                  pData[i][x] *= fRadius;
                  pData[nHalfH + i][x] /= fRadius;
               }
            }
         }
         delete[] pData;
         delete[] pRow;
         delete[] pColumn;
      }
   }
}

// 二维离散小波恢复(单通道浮点图像)
void IDWT(IplImage *pImage, int nLayer)
{
   // 执行条件
   if (pImage)
   {
      if (pImage->nChannels == 1 &&
         pImage->depth == IPL_DEPTH_32F &&
         ((pImage->width >> nLayer) << nLayer) == pImage->width &&
         ((pImage->height >> nLayer) << nLayer) == pImage->height)
      {
         int     i, x, y, n;
         float   fValue   = 0;
         float   fRadius  = sqrt(2.0f);
         int     nWidth   = pImage->width >> (nLayer - 1);
         int     nHeight  = pImage->height >> (nLayer - 1);
         int     nHalfW   = nWidth / 2;
         int     nHalfH   = nHeight / 2;
         float **pData    = new float*[pImage->height];
         float  *pRow     = new float[pImage->width];
         float  *pColumn  = new float[pImage->height];
         for (i = 0; i < pImage->height; i++)
         {
            pData[i] = (float*) (pImage->imageData + pImage->widthStep * i);
         }
         // 多层小波恢复
         for (n = 0; n < nLayer; n++, nWidth *= 2, nHeight *= 2, nHalfW *= 2, nHalfH *= 2)
         {
            // 垂直恢复
            for (x = 0; x < nWidth; x++)
            {
               // 频带系数
               for (i = 0; i < nHalfH; i++)
               {
                  pData[i][x] /= fRadius;
                  pData[nHalfH + i][x] *= fRadius;
               }
               // 提升小波恢复
               fValue = (pData[nHalfH][x] + pData[nHalfH + 1][x]) / 4;
               pData[0][x] -= fValue;
               for (i = 1; i < nHalfH; i++)
               {
                  fValue = (pData[nHalfH + i][x] + pData[nHalfH + i - 1][x]) / 4;
                  pData[i][x] -= fValue;
               }
               for (i = 0; i < nHalfH - 1; i++)
               {
                  fValue = (pData[i][x] + pData[i + 1][x]) / 2;
                  pData[nHalfH + i][x] += fValue;
               }
               fValue = (pData[nHalfH - 1][x] + pData[nHalfH - 2][x]) / 2;
               pData[nHeight - 1][x] += fValue;
               // 奇偶合并
               for (i = 0; i < nHalfH; i++)
               {
                  y = i * 2;
                  pColumn[y] = pData[i][x];
                  pColumn[y + 1] = pData[nHalfH + i][x];
               }
               for (i = 0; i < nHeight; i++)
               {
                  pData[i][x] = pColumn[i];
               }
            }
            // 水平恢复
            for (y = 0; y < nHeight; y++)
            {
               // 频带系数
               for (i = 0; i < nHalfW; i++)
               {
                  pData[y][i] /= fRadius;
                  pData[y][nHalfW + i] *= fRadius;
               }
               // 提升小波恢复
               fValue = (pData[y][nHalfW] + pData[y][nHalfW + 1]) / 4;
               pData[y][0] -= fValue;
               for (i = 1; i < nHalfW; i++)
               {
                  fValue = (pData[y][nHalfW + i] + pData[y][nHalfW + i - 1]) / 4;
                  pData[y][i] -= fValue;
               }
               for (i = 0; i < nHalfW - 1; i++)
               {
                  fValue = (pData[y][i] + pData[y][i + 1]) / 2;
                  pData[y][nHalfW + i] += fValue;
               }
               fValue = (pData[y][nHalfW - 1] + pData[y][nHalfW - 2]) / 2;
               pData[y][nWidth - 1] += fValue;
               // 奇偶合并
               for (i = 0; i < nHalfW; i++)
               {
                  x = i * 2;
                  pRow[x] = pData[y][i];
                  pRow[x + 1] = pData[y][nHalfW + i];
               }
               memcpy(pData[y], pRow, sizeof(float) * nWidth);
            }
         }
         delete[] pData;
         delete[] pRow;
         delete[] pColumn;
      }
   }
}

上述代码只能对单通道进行变换,并且对图像位深和大小也有要求,还是不太好用。没关系,就这两个函数,可以对任意大小的彩色图像进行任意层次的小波变换,给段代码:

代码:全选
// 小波变换层数
int nLayer = 2;
// 输入彩色图像
IplImage *pSrc = cvLoadImage("Lena.jpg", CV_LOAD_IMAGE_COLOR);
// 计算小波图象大小
CvSize size = cvGetSize(pSrc);
if ((pSrc->width >> nLayer) << nLayer != pSrc->width)
{
   size.width = ((pSrc->width >> nLayer) + 1) << nLayer;
}
if ((pSrc->height >> nLayer) << nLayer != pSrc->height)
{
   size.height = ((pSrc->height >> nLayer) + 1) << nLayer;
}
// 创建小波图象
IplImage *pWavelet = cvCreateImage(size, IPL_DEPTH_32F, pSrc->nChannels);
if (pWavelet)
{
   // 小波图象赋值
   cvSetImageROI(pWavelet, cvRect(0, 0, pSrc->width, pSrc->height));
   cvConvertScale(pSrc, pWavelet, 1, -128);
   cvResetImageROI(pWavelet);
   // 彩色图像小波变换
   IplImage *pImage = cvCreateImage(cvGetSize(pWavelet), IPL_DEPTH_32F, 1);
   if (pImage)
   {
      for (int i = 1; i <= pWavelet->nChannels; i++)
      {
         cvSetImageCOI(pWavelet, i);
         cvCopy(pWavelet, pImage, NULL);
         // 二维离散小波变换
         DWT(pImage, nLayer);
         // 二维离散小波恢复
         // IDWT(pImage, nLayer);
         cvCopy(pImage, pWavelet, NULL);
      }
      cvSetImageCOI(pWavelet, 0);
      cvReleaseImage(&pImage);
   }
   // 小波变换图象
   cvSetImageROI(pWavelet, cvRect(0, 0, pSrc->width, pSrc->height));
   cvConvertScale(pWavelet, pSrc, 1, 128);
   cvResetImageROI(pWavelet); // 本行代码有点多余,但有利用养成良好的编程习惯
   cvReleaseImage(&pWavelet);
}
// 显示图像pSrc
// ...
cvReleaseImage(&pSrc);

基于opencv的小波变换的更多相关文章

  1. 基于opencv的小波变换代码和图像结果

    #include "stdafx.h" #include "WaveTransform.h" #include <math.h> #include ...

  2. [转载]卡尔曼滤波器及其基于opencv的实现

    卡尔曼滤波器及其基于opencv的实现 源地址:http://hi.baidu.com/superkiki1989/item/029f65013a128cd91ff0461b 这个是维基百科中的链接, ...

  3. 基于Opencv和Mfc的图像处理增强库GOCVHelper(索引)

    GOCVHelper(GreenOpen Computer Version Helper )是我在这几年编写图像处理程序的过程中积累下来的函数库.主要是对Opencv的适当扩展和在实现Mfc程序时候的 ...

  4. 基于OpenCv的人脸检测、识别系统学习制作笔记之一

    基于OpenCv从视频文件到摄像头的人脸检测 在OpenCv中读取视频文件和读取摄像头的的视频流然后在放在一个窗口中显示结果其实是类似的一个实现过程. 先创建一个指向CvCapture结构的指针 Cv ...

  5. 基于opencv网络摄像头在ubuntu下的视频获取

     基于opencv网络摄像头在ubuntu下的视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译运行步骤 安装编译opencv-2.3  参 ...

  6. 基于opencv在摄像头ubuntu根据视频获取

     基于opencv在摄像头ubuntu根据视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译执行步骤 安装编译opencv-2.3  參考h ...

  7. OpenCV2学习笔记(十四):基于OpenCV卡通图片处理

    得知OpenCV有一段时间.除了研究的各种算法的内容.除了从备用,据导游书籍和资料,尝试结合链接的图像处理算法和日常生活,第一桌面上(随着摄像头)完成了一系列的视频流处理功能.开发平台Qt5.3.2+ ...

  8. Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

    Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图 分类: OpenCV图像处理2013-02-21 21:35 6459人阅读 评论(8) 收藏 举报   原文链接  ht ...

  9. 每日一练之自适应中值滤波器(基于OpenCV实现)

    本文主要介绍了自适应的中值滤波器,并基于OpenCV实现了该滤波器,并且将自适应的中值滤波器和常规的中值滤波器对不同概率的椒盐噪声的过滤效果进行了对比.最后,对中值滤波器的优缺点了进行了总结. 空间滤 ...

随机推荐

  1. Linux--------------安装tomcat8

    系统:     CentOS 7.2x64最小化安装 IP:      192.168.0.171 二.安装JDK环境 JDK(Java Development Kit) 是 Java 语言的软件开发 ...

  2. Android(java)学习笔记159:Dalivk虚拟机的初始化过程

    1.初始化下面系统函数(调用dvmStartup函数初始化所有相关的函数) 开始学习虚拟机的初始化过程,先从dvmStartup函数开始,这个函数实现所有开始虚拟机的准备工作: dvmAllocTra ...

  3. 获取本地IP和端口号的指令

    ipconfig就可以获取ip 获取端口号的指令: 开始--运行--cmd--输入netstat an(中间有一空格)

  4. iOS之AVPlayer的简单应用

    1.引入系统框架 2.创建视频的url 3.创建播放项目 4.初始化播放器 5.设置播放页面 //引入系统文件 #import <AVFoundation/AVFoundation.h> ...

  5. 正则表达式 和 junit测试

    需要知道一些常规的正则表达式语句,然后可以仿照规则写出一下正则表达式语句.然后是关于junit测试. 知道了一个之前看过的文档,然后有功夫就看一下那个文档就可以,或者后面找时间搜索一下. 正则表达式是 ...

  6. 请列出你在从事IT生涯中,最难以忘怀的一次误操作

    IT系统最怕什么,我觉得就两点: 1.不可靠的软硬件. 2.误操作. 第一点就不用解释了,第二点是该文的内容,主要摘选自ITPUB的精华贴——[精华] 请列出你在从事DBA生涯中,最难以忘怀的一次误操 ...

  7. rndc: connect failed: 127.0.0.1#953: connection refused

    [root@localhost sbin]# ./named -v bind 9.5.1-p3-v3.0.9 问题现象: [root@localhost sbin]# ./rndc flush -p ...

  8. day-5

    /* 还有几半天了 上午考试暴力暴力暴力... 亏我还写了对拍 没有卵用 T2 差点事 T3不难却没咋么认真想 这tm就很尴尬了23333 下午整理题 一下午.... 晚上打月赛 + 单调队列 继续说 ...

  9. PHP中的ob_start() 的使用

    1.在PHP编程中, 我们经常会遇到一些直接产生输出的函数, 如passthru(),readfile(), var_dump() 等. 但有时我们想把这些函数的输出导入到文件中,或者先经过处理再输出 ...

  10. 创建自定义 HTTP 模块

    本主题中描述的自定义 HTTP 模块阐释了 HTTP 模块的基本功能.在响应下面两个事件时调用该模块:BeginRequest 事件和 EndRequest 事件.这使该模块可以在处理页请求之前和之后 ...