zoukankan      html  css  js  c++  java
  • 转:基于opencv的小波变换

    转自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);
  • 相关阅读:
    oracle(八)块清除
    oracle(七)索引
    oracle(六) physical read and logical read
    oracle动态视图(一)stat
    oracle(五)tkprof 使用 transient kernal profile 侧面 轮廓
    dbms_stats.gather_table_stats详解
    oracle(四) 常用语句
    oracle(三) SQL语句
    [Swift]LeetCode269. 外星人词典 $ Alien Dictionary
    [Mac]如何让两个窗口各占半个屏幕
  • 原文地址:https://www.cnblogs.com/yingying0907/p/2130968.html
Copyright © 2011-2022 走看看