• 数字图像处理领域算法之图像旋转


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

    算法描述:图像旋转算法原理,可参见:http://hi.baidu.com/wangguang246/blog/item/124b9219981f530d35fa41ca.html

           程序实现:

    //角度到弧度转化的宏
    #define RADIAN(angle) ((angle)*PI/180.0)
    函数名称:RotateDIB()
    参数:
    LPSTR lpDIB  - 指向源DIB的指针
    int iRotateAngle - 旋转的角度(0-360度)
    返回值:HGLOBAL            - 旋转成功返回新DIB句柄,否则返回NULL。
    说明:该函数用来以图像中心为中心旋转DIB图像,返回新生成DIB的句柄。调用该函数会自动

    扩大图像以显示所有的象素。函数中采用最邻近插值算法进行插值。
    HGLOBAL WINAPI RotateDIB(LPSTR lpDIB, int iRotateAngle)

     // 源图像的宽度和高度
     LONG lWidth;
     LONG lHeight; 
     // 旋转后图像的宽度和高度
     LONG lNewWidth;
     LONG lNewHeight; 
     // 图像每行的字节数
     LONG lLineBytes; 
     // 旋转后图像的宽度(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;
     
     // 旋转角度(弧度)
     float fRotateAngle; 
     // 旋转角度的正弦和余弦
     float fSina, fCosa; 
     // 源图四个角的坐标(以图像中心为坐标系原点)
     float fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;
     // 旋转后四个角的坐标(以图像中心为坐标系原点)
     float fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;
     // 两个中间常量
     float f1,f2;
     // 找到源DIB图像象素起始位置
     lpDIBBits = ::FindDIBBits(lpDIB); 
     // 获取图像的"宽度"(4的倍数)
     lWidth = ::DIBWidth(lpDIB);
     // 计算图像每行的字节数
     lLineBytes = WIDTHBYTES(lWidth * 8);
     // 获取图像的高度
     lHeight = ::DIBHeight(lpDIB);

     // 将旋转角度从度转换到弧度
     fRotateAngle = (float) RADIAN(iRotateAngle);
     // 计算旋转角度的正弦
     fSina = (float) sin((double)fRotateAngle);
     // 计算旋转角度的余弦
     fCosa = (float) cos((double)fRotateAngle);
     
     // 计算原图的四个角的坐标(以图像中心为坐标系原点)
     fSrcX1 = (float) (- (lWidth  - 1) / 2);
     fSrcY1 = (float) (  (lHeight - 1) / 2);
     fSrcX2 = (float) (  (lWidth  - 1) / 2);
     fSrcY2 = (float) (  (lHeight - 1) / 2);
     fSrcX3 = (float) (- (lWidth  - 1) / 2);
     fSrcY3 = (float) (- (lHeight - 1) / 2);
     fSrcX4 = (float) (  (lWidth  - 1) / 2);
     fSrcY4 = (float) (- (lHeight - 1) / 2);
     
     // 计算新图四个角的坐标(以图像中心为坐标系原点)
     fDstX1 =  fCosa * fSrcX1 + fSina * fSrcY1;
     fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1;
     fDstX2 =  fCosa * fSrcX2 + fSina * fSrcY2;
     fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2;
     fDstX3 =  fCosa * fSrcX3 + fSina * fSrcY3;
     fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3;
     fDstX4 =  fCosa * fSrcX4 + fSina * fSrcY4;
     fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4;
     
     // 计算旋转后的图像实际宽度
     lNewWidth  = (LONG) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) )

    + 0.5); 
     // 计算新图像每行的字节数
     lNewLineBytes = WIDTHBYTES(lNewWidth * 8);
     // 计算旋转后的图像高度
     lNewHeight = (LONG) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) ) 

    + 0.5);
     
     // 两个常数,这样不用以后每次都计算了
     f1 = (float) (-0.5 * (lNewWidth - 1) * fCosa - 0.5 * (lNewHeight - 1) *

    fSina
      + 0.5 * (lWidth  - 1));
     f2 = (float) ( 0.5 * (lNewWidth - 1) * fSina - 0.5 * (lNewHeight - 1) *

    fCosa
      + 0.5 * (lHeight - 1));
     
     // 分配内存,以保存新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) (-((float) j) * fSina + ((float) i) * fCosa +

    f2 + 0.5);
       j0 = (LONG) ( ((float) j) * fCosa + ((float) i) * fSina +

    f1 + 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;
     }
     
     // 旋转角度
     int iRotateAngle;
     iRotateAngle=15;
     
     // 创建新DIB
     HDIB hNewDIB = NULL;
     
     // 更改光标形状
     BeginWaitCursor();
     
     // 调用RotateDIB()函数旋转DIB
     hNewDIB = (HDIB) RotateDIB(lpDIB, iRotateAngle);
     
     // 判断旋转是否成功
     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;
     }
     
     // 旋转角度
     int iRotateAngle;
     iRotateAngle=-15;
     
     // 创建新DIB
     HDIB hNewDIB = NULL;
     
     // 更改光标形状
     BeginWaitCursor();
     
     // 调用RotateDIB()函数旋转DIB
     hNewDIB = (HDIB) RotateDIB(lpDIB, iRotateAngle);
     
     // 判断旋转是否成功
     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();
    }

        变化效果:

  • 相关阅读:
    第123天:移动web开发中的常见问题
    第122天:移动端开发常见事件和流式布局
    第121天:移动端开发基本知识
    第120天:移动端-Bootstrap基本使用方法
    第119天:移动端:CSS像素、屏幕像素和视口的关系
    加入收藏 设为首页代码收藏本页的代码和收藏本站的代码设为首页代码
    JQuery和UpdatePannel的问题
    JS中apply与call的用法
    Sumlime text3 安装包、汉化包、注册码
    使用WITH AS提高性能简化嵌套SQL
  • 原文地址:https://www.cnblogs.com/LCGIS/p/3129415.html
Copyright © 2020-2023  润新知