您的位置:首页 > 运维架构

基于opencv的小波变换

2014-10-29 22:11 260 查看
申明,本文非笔者原创,原文转载自:http://www.cnblogs.com/zhangzhi/archive/2009/09/19/1569888.html

提供函数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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: