基于opencv的小波变换

基于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);
时间: 2024-10-14 09:09:09

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

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

1 #include "stdafx.h" 2 #include "WaveTransform.h" 3 #include <math.h> 4 #include <imgproc/imgproc.hpp> 5 Mat WaveTransform::WDT(const Mat &_src,const string _wname,const int _level) 6 { 7 Mat src=Mat_<float>(_src

基于OpenCV的图片卡通化处理

学习OpenCV已有一段时间,除了研究各种算法的内容,在空闲之余,根据书本及资料的引导,尝试结合图像处理算法和日常生活联系起来,首先在台式机上(带摄像头)完成一系列视频流处理功能,开发平台为Qt5.3.2+OpenCV2.4.9. 本次试验实现的功能主要有: 调用摄像头捕获视频流: 将帧图像转换为素描效果图片: 将帧图像卡通化处理: 简单地生成"怪物"形象: 人脸肤色变换. 本节所有的算法均由类cartoon中的函数cartoonTransform()来实现: // Frame:输入每

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

GOCVHelper(GreenOpen Computer Version Helper )是我在这几年编写图像处理程序的过程中积累下来的函数库.主要是对Opencv的适当扩展和在实现Mfc程序时候的功能增强. 这里将算法库开放源代码,并且编写一系列blog对函数实现进行说明.目的是在于“取之于互联网,用之于互联网”.并且也希望该库能够继续发展下去. 由于算法库基于Opencv和Mfc进行编写,所以要求阅读使用者具备一定基础. 最终提交的是GOCVHelper.h 和GOCVHelper版本号.

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

 基于opencv网络摄像头在ubuntu下的视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译运行步骤 安装编译opencv-2.3  参考http://blog.csdn.net/xiabodan/article/details/23547847 3  测试代码 编译 g++ cameraCaptrue.cpp -o test `pkg-config --libs --cflags opencv` cameraCaptrue.cpp

Csharp调用基于Opencv编写的类库文件

现在将Csharp调用基于Opencv编写的类库文件(Dll)的方法定下来,我取名叫做GreenOpenCsharpWarper,简称GOCW. 一.CLR编写的DLL部分 1.按照正常方法引入Opencv; 2.提供接口函数,进行图像处理(这里只是实现了cvtColor,实际过程中可以用自己编写的复杂函数) String^  Class1::Method(cli::array<unsigned char>^ pCBuf1){     pin_ptr<System::Byte> p

基于 OpenCV 的人脸识别

基于 OpenCV 的人脸识别 一点背景知识 OpenCV 是一个开源的计算机视觉和机器学习库.它包含成千上万优化过的算法,为各种计算机视觉应用提供了一个通用工具包.根据这个项目的关于页面,OpenCV 已被广泛运用在各种项目上,从谷歌街景的图片拼接,到交互艺术展览的技术实现中,都有 OpenCV 的身影. OpenCV 起始于 1999 年 Intel 的一个内部研究项目.从那时起,它的开发就一直很活跃.进化到现在,它已支持如 OpenCL 和 OpenGL 的多种现代技术,也支持如 iOS

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

本文主要介绍了自适应的中值滤波器,并基于OpenCV实现了该滤波器,并且将自适应的中值滤波器和常规的中值滤波器对不同概率的椒盐噪声的过滤效果进行了对比.最后,对中值滤波器的优缺点了进行了总结. 空间滤波器 一个空间滤波器包括两个部分: 一个邻域,滤波器进行操作的像素集合,通常是一个矩形区域 对邻域中像素进行的操作 一个滤波器就是在选定的邻域像素上执行预先定义好的操作产生新的像素,并用新的像素替换掉原来像素形成新的图像. 通常,也可以将滤波器称之为核(kernel),模板(template)或者窗

基于opencv和mfc的摄像头采集代码(GOMFCTemplate2)

基于opencv和mfc的摄像头采集框架(GOMFCTemplate2) 编写带界面的图像处理程序,选择opencv+mfc是一种很好的选择:在读取摄像头数据方面,网上的方法很多,其中shiqiyu的camerads的方法是较好的. 基于现有资料,通过在实际项目中的积累,我总结出来一套结合opencv和mfc的摄像头采集框架.具有以下特点: 1.基于directshow,兼容性好,速度快.到目前为止,无论是工业相机还是普通相机,没发现不兼容的: 2.摄像头部分通过线程读取,保证界面的运行流畅:

基于opencv的人脸检测的web应用

参考资料 https://github.com/bsdnoobz/web-based-face-detect http://opencv-code.com/projects/web-based-interface-for-face-detection-with-opencv/ http://www.cnblogs.com/findingsea/archive/2012/03/31/2427833.html 流程如下图 背景知识 php调用exe的返回 <html> <body> &