zoukankan      html  css  js  c++  java
  • 数字图像处理领域算法之图像缩放

    摘自:http://blog.csdn.net/v_july_v/article/details/6227072

     算法描述:

        I、最邻近插值(近邻取样法):
      最临近插值的的思想很简单,对于通过反向变换得到的的一个浮点坐标,对其进行简单的取整,得到一个整数型坐标,这个整数型坐标对应的像素值就是目的像素的像素值,也就是说,取浮点坐标最邻近的左上角点(对于DIB是右上角,因为它的扫描行是逆序存储的)对应的像素值。可见,最邻近插值简单且直观,但得到的图像质量不高。
     
        II、双线性内插值:
      对于一个目的像素,设置坐标通过反向变换得到的浮点坐标为(i+u,j+v),其中i、j均为非负整数,u、v为[0,1)区间的浮点数,则这个像素得值 f(i+u,j+v) 可由原图像中坐标为 (i,j)、(i+1,j)、(i,j+1)、(i+1,j+1)所对应的周围四个像素的值决定,即:
        f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)

    其中f(i,j)表示源图像(i,j)处的的像素值,以此类推
      这就是双线性内插值法。双线性内插值法计算量大,但缩放后图像质量高,不会出现像素值不连续的的情况。由于双线性插值具有低通滤波器的性质,使高频分量受损,所以可能会使图像轮廓在一定程度上变得模糊。

      III、三次卷积法能够克服以上两种算法的不足,计算精度高,但计算量大,他考虑一个浮点坐标(i+u,j+v)周围的16个邻点,目的像素值f(i+u,j+v)可由如下插值公式得到:
        f(i+u,j+v) = [A] * [B] * [C]

    [A]=[ S(u + 1)  S(u + 0)  S(u - 1)  S(u - 2) ]

      ┏ f(i-1, j-1)  f(i-1, j+0)  f(i-1, j+1)  f(i-1, j+2) ┓
    [B]=┃ f(i+0, j-1)  f(i+0, j+0)  f(i+0, j+1)  f(i+0, j+2) ┃
      ┃ f(i+1, j-1)  f(i+1, j+0)  f(i+1, j+1)  f(i+1, j+2) ┃
      ┗ f(i+2, j-1)  f(i+2, j+0)  f(i+2, j+1)  f(i+2, j+2) ┛

      ┏ S(v + 1) ┓
    [C]=┃ S(v + 0) ┃
      ┃ S(v - 1) ┃
      ┗ S(v - 2) ┛

       ┏ 1-2*Abs(x)^2+Abs(x)^3           , 0<=Abs(x)<1
    S(x)={ 4-8*Abs(x)+5*Abs(x)^2-Abs(x)^3  , 1<=Abs(x)<2
       ┗ 0                               , Abs(x)>=2
    S(x)是对 Sin(x*Pi)/x 的逼近(Pi是圆周率——π)

        总结:最邻近插值(近邻取样法)、双线性内插值、三次卷积法 等插值算法对于旋转变换、错切变换、一般线性变换 和 非线性变换 都适用。

        程序实现:

    //该函数用来缩放DIB图像,返回新生成DIB的句柄。
    HGLOBAL WINAPI ZoomDIB(LPSTR lpDIB, float fXZoomRatio, float fYZoomRatio)

     // 源图像的宽度和高度
     LONG lWidth;
     LONG lHeight;
     // 缩放后图像的宽度和高度
     LONG lNewWidth;
     LONG lNewHeight;
     
     // 缩放后图像的宽度(lNewWidth',必须是4的倍数)
     LONG lNewLineBytes;
     // 指向源图像的指针
     LPSTR lpDIBBits;
     // 指向源象素的指针
     LPSTR lpSrc;
     // 缩放后新DIB句柄
     HDIB hDIB;
     // 指向缩放图像对应象素的指针
     LPSTR lpDst;
     // 指向缩放图像的指针
     LPSTR lpNewDIB;
     LPSTR lpNewDIBBits;
     // 指向BITMAPINFO结构的指针(Win3.0)
     LPBITMAPINFOHEADER lpbmi; 
     // 指向BITMAPCOREINFO结构的指针
     LPBITMAPCOREHEADER lpbmc;
     
     // 循环变量(象素在新DIB中的坐标)
     LONG i;
     LONG j;
     
     // 象素在源DIB中的坐标
     LONG i0;
     LONG j0;
     
     // 图像每行的字节数
     LONG lLineBytes;
     
     // 找到源DIB图像象素起始位置
     lpDIBBits = ::FindDIBBits(lpDIB);
     
     // 获取图像的宽度
     lWidth = ::DIBWidth(lpDIB);
     // 计算图像每行的字节数
     lLineBytes = WIDTHBYTES(lWidth * 8); 
     // 获取图像的高度
     lHeight = ::DIBHeight(lpDIB);

     // 计算缩放后的图像实际宽度
     // 此处直接加0.5是由于强制类型转换时不四舍五入,而是直接截去小数部分
     lNewWidth = (LONG) (::DIBWidth(lpDIB) * fXZoomRatio + 0.5);
     
     // 计算新图像每行的字节数
     lNewLineBytes = WIDTHBYTES(lNewWidth * 8);
     
     // 计算缩放后的图像高度
     lNewHeight = (LONG) (lHeight * fYZoomRatio + 0.5);
     
     // 分配内存,以保存新DIB
     hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)

    lpDIB + ::PaletteSize(lpDIB));
     
     // 判断是否内存分配失败
     if (hDIB == NULL)
     {
      // 分配内存失败
      return NULL;
     }
     
     // 锁定内存
     lpNewDIB =  (char * )::GlobalLock((HGLOBAL) hDIB);
     
     // 复制DIB信息头和调色板
     memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
     
     // 找到新DIB象素起始位置
     lpNewDIBBits = ::FindDIBBits(lpNewDIB);
     
     // 获取指针
     lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
     lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;
     
     // 更新DIB中图像的高度和宽度
     if (IS_WIN30_DIB(lpNewDIB))
     {
      // 对于Windows 3.0 DIB
      lpbmi->biWidth = lNewWidth;
      lpbmi->biHeight = lNewHeight;
     }
     else
     {
      // 对于其它格式的DIB
      lpbmc->bcWidth = (unsigned short) lNewWidth;
      lpbmc->bcHeight = (unsigned short) lNewHeight;
     }
     
     // 针对图像每行进行操作
     for(i = 0; i < lNewHeight; i++)
     {
      // 针对图像每列进行操作
      for(j = 0; j < lNewWidth; j++)
      {
       
       // 指向新DIB第i行,第j个象素的指针
       // 注意此处宽度和高度是新DIB的宽度和高度
       lpDst = (char *)lpNewDIBBits + lNewLineBytes * (lNewHeight

    - 1 - i) + j;
       
       // 计算该象素在源DIB中的坐标
       i0 = (LONG) (i / fYZoomRatio + 0.5);
       j0 = (LONG) (j / fXZoomRatio + 0.5);
       
       // 判断是否在源图范围内
       if( (j0 >= 0) && (j0 < lWidth) && (i0 >= 0) && (i0 <

    lHeight))
       {
        
        // 指向源DIB第i0行,第j0个象素的指针
        lpSrc = (char *)lpDIBBits + lLineBytes * (lHeight

    - 1 - i0) + j0;
        
        // 复制象素
        *lpDst = *lpSrc;
       }
       else
       {
        // 对于源图中没有的象素,直接赋值为255
        * ((unsigned char*)lpDst) = 255;
       }  
      }
     } 
     // 返回
     return hDIB;
    }

    //缩小图像
    void CMyDIPView::OnMenuitem32778()
    {
     // 图像缩放
     // 获取文档
     CMyDIPDoc* pDoc = GetDocument();
     // 指向DIB的指针
     LPSTR lpDIB;
     
     // 锁定DIB
     lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());
     
     // 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的缩放,其它的可以类

    推)
     if (::DIBNumColors(lpDIB) != 256)
     {
      // 提示用户
      MessageBox("目前只支持256色位图的缩放!", "系统提示" ,

    MB_ICONINFORMATION | MB_OK);

      // 解除锁定
      ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
      
      // 返回
      return;
     }
     
     // 缩放比率
     float fXZoomRatio;
     float fYZoomRatio;

     //缩放量
     fXZoomRatio = 0.8;  //缩小的比率
     fYZoomRatio = 0.8;

     
     // 创建新DIB
     HDIB hNewDIB = NULL; 
     // 更改光标形状
     BeginWaitCursor();
     
     // 调用ZoomDIB()函数转置DIB
     hNewDIB = (HDIB) ZoomDIB(lpDIB, fXZoomRatio, fYZoomRatio);
     
     // 判断缩放是否成功
     if (hNewDIB != NULL)
     {
      
      // 替换DIB,同时释放旧DIB对象
      pDoc->ReplaceHDIB(hNewDIB);

      // 更新DIB大小和调色板
      pDoc->InitDIBData();
      
      // 设置脏标记
      pDoc->SetModifiedFlag(TRUE);
      
      // 重新设置滚动视图大小
      SetScrollSizes(MM_TEXT, pDoc->GetDocSize());

      // 更新视图
      pDoc->UpdateAllViews(NULL);
     }
     else
     {
      // 提示用户
      MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION |

    MB_OK);
     }
     
     // 解除锁定
     ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());

     // 恢复光标
     EndWaitCursor();
     
    }

    //放大图像
    void CMyDIPView::OnMenuitem32779()
    {
     // 图像缩放
     // 获取文档
     CMyDIPDoc* pDoc = GetDocument();
     // 指向DIB的指针
     LPSTR lpDIB; 
     // 锁定DIB
     lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());
     
     // 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的缩放,其它的可以类

    推)
     if (::DIBNumColors(lpDIB) != 256)
     {
      // 提示用户
      MessageBox("目前只支持256色位图的缩放!", "系统提示" ,

    MB_ICONINFORMATION | MB_OK);

      // 解除锁定
      ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
      
      // 返回
      return;
     }
     
     // 缩放比率
     float fXZoomRatio;
     float fYZoomRatio;

     //缩放量
     fXZoomRatio = 1.25;  //放大的比率
     fYZoomRatio = 1.25;

     
     // 创建新DIB
     HDIB hNewDIB = NULL;
     
     // 更改光标形状
     BeginWaitCursor();
     
     // 调用ZoomDIB()函数转置DIB
     hNewDIB = (HDIB) ZoomDIB(lpDIB, fXZoomRatio, fYZoomRatio);
     
     // 判断缩放是否成功
     if (hNewDIB != NULL)
     {
      
      // 替换DIB,同时释放旧DIB对象
      pDoc->ReplaceHDIB(hNewDIB);

      // 更新DIB大小和调色板
      pDoc->InitDIBData();
      
      // 设置脏标记
      pDoc->SetModifiedFlag(TRUE);
      
      // 重新设置滚动视图大小
      SetScrollSizes(MM_TEXT, pDoc->GetDocSize());

      // 更新视图
      pDoc->UpdateAllViews(NULL);
     }
     else
     {
      // 提示用户
      MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION |

    MB_OK);
     }
     
     // 解除锁定
     ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());

     // 恢复光标
     EndWaitCursor();
    }

     

    变换效果(找到参照物判断):

  • 相关阅读:
    idea 界面乱码问题 file was loaded in the wrong enconding:"utf-8"
    svn 下载,安装,创建库,设置用户和用户组,赋权限
    eclipse文件中的乱码问题
    Eclipse安装Spring插件springsource-tool-suite
    vue.js2.0:搭建开发环境及构建项目
    排序List集合中的元素
    Java GC机制和对象Finalize方法的一点总结
    xfire发布的Webservice中Spring注入为空的解决方案
    Http报文格式学习及Get和Post主要区别总结
    [转] tomcat组成及工作原理
  • 原文地址:https://www.cnblogs.com/LCGIS/p/3129410.html
Copyright © 2011-2022 走看看