zoukankan      html  css  js  c++  java
  • 图像旋转变换

      参考原文http://vipbase.net/ipbook/chap02.htm   

       这里主要讨论以图象的中心为圆心旋转。旋转之后若要保持目标区域大小不变,则整幅图像变大;若要保持整幅图像的大小不变,则旋转出去的部分需要裁剪掉。

     

     

             旋转前的图

        旋转后的图

     

    旋转后保持原图大小,转出的部分被裁掉

        以顺时针旋转为例来堆到旋转变换公式。如下图所示。

     

    旋转前:

    x0=rcosby0=rsinb

    旋转a角度后:

    x1=rcos(b-a)=rcosbcosa+rsinbsina=x0cosa+y0sina

    y1=rsin(b-a)=rsinbcosa-rcosbsina=-x0sina+y0cosa

    矩阵形式为

    逆变换为

     

        上面的公式是以图像的左下角为原点旋转的。现我们要以图像的中心为原点旋转。因此需要先将坐标平移到图像中心,如下所示

    设图象的宽为w,高为h,容易得到:

    逆变换为

         现在可以分三步来完成旋转变换:

         1. 将坐标系x'o'y'平移到xoy ;  2. 在xoy坐标系下作旋转变换;  3.变换后将坐标系平移回原来位置。

         用矩阵表示就是        

       其中R表示旋转变换矩阵。当旋转不改变图像大小时,T 与 T' 互为逆矩阵;当旋转后图像变大时,T 与 T'不是逆矩阵关系,因为图像变大了,第一次平移和第二次平移坐标系的距离不一样。因此当图像变大时,公式应该如下:

        由于算法实现过程中我们需要的是逆变换的公式,因此我们只写出逆变换的表达式,如下:

           其中wn ,hn 表示新图像的宽和高,wo, ho 表示原图像的宽和高。

         这样,对于新图中的每一点,我们就可以根据上面逆变换公式求出对应原图中的点,得到它的灰度。如果超出原图范围,则设置为背景色。要注意的是,由于有浮点运算,计算出来点的坐标可能不是整数,采用取整处理,即找最接近的点,这样会带来一些误差(图象可能会出现锯齿)。更精确的方法是采用插值,这里暂不讨论。

        C++代码如下:

    /*
    * rotate.cpp
    * 图像旋转变换(顺时针)
    * Created on: 2011-10-10
    * Author: LiChanghai
    */
    // 以图像中心为坐标原点,旋转后不改变图像大小
    // 函数返回值为指针,指向新申请的内存区域
    // 因为新图像大小改变了,需要返回新图像的尺寸
    // 因此形参的高度和宽度都采用指针变量
    #include<string.h>
    #include<stdlib.h>
    #include<cmath>
    #define pi 3.1415926535
    unsigned char * rotate(unsigned char *pImage, int *width, int *height, int biBitCount, float angle)
    {
    //定义以图像中心为原点的坐标系下原图像和新图像的四个角点坐标
    float src_x1, src_y1, src_x2, src_y2, src_x3, src_y3, src_x4, src_y4;
    float dst_x1, dst_y1, dst_x2, dst_y2, dst_x3, dst_y3, dst_x4, dst_y4;

    //定义新图像的高度和宽度
    int wnew, hnew;

    //定义计算过程中需要的相关变量
    float sina, cosa, temp1, temp2, alpha;

    //角度转化为弧度
    alpha=pi*angle/180;

    cosa = float(cos(double(alpha)));
    sina = float(sin(double(alpha)));

    //原图像的四个角点的坐标
    src_x1 = float(-0.5*(*width)); src_y1 = float(0.5*(*height));
    src_x2 = float(0.5*(*width)); src_y2 = src_y1;
    src_x3 = src_x1; src_y3 = float(-0.5*(*height));
    src_x4 = src_x2; src_y4 = src_y3;

    //计算新图像的四个角点坐标
    dst_x1 = cosa*src_x1+sina*src_y1;
    dst_y1 = -sina*src_x1+cosa*src_y1;

    dst_x2 = cosa*src_x2+sina*src_y2;
    dst_y2 = -sina*src_x2+cosa*src_y2;

    dst_x3 = cosa*src_x3+sina*src_y3;
    dst_y3 = -sina*src_x3+cosa*src_y3;

    dst_x4 = cosa*src_x4+sina*src_y4;
    dst_y4 = -sina*src_x4+cosa*src_y4;

    //计算新图像的高度和宽度
    float t1 = fabs(dst_x4-dst_x1), t2 = fabs(dst_x3-dst_x2);
    wnew = int(t1>t2 ? t1:t2);
    t1 = fabs(dst_y4-dst_y1), t2 = fabs(dst_y3-dst_y2);
    hnew = int(t1>t2 ? t1:t2);

    // 计算旋转变换中的两个中间变量,便于以后计算
    temp1=float( -0.5*wnew*cosa+0.5*hnew*sina+0.5*(*width));
    temp2=float(-0.5*wnew*sina-0.5*hnew*cosa+0.5*(*height));
    //计算原图像和新图像每行像素所占的字节数(必须是4的倍数)
    int lineByte = ((*width) * biBitCount/8+3)/4*4;
    int lineByte2=(wnew * biBitCount/8+3)/4*4;

    //申请新的位图数据存储空间
    unsigned char *pImage2;
    pImage2=new unsigned char[lineByte2*hnew];

    //将新图像设置为背景色
    memset(pImage2, 0, lineByte2*hnew);

    //遍历新图像的每一个像素进行判断
    int x, y, x0, y0; // x0, y0为原图像中对应坐标
    for(y=0; y<hnew; y++)
    for(x=0; x<wnew; x++)
    {
    x0= int(x*cosa-y*sina+temp1);
    y0= int(x*sina+y*cosa+temp2);
    //如果在原图像范围内则复制像素值
    if( (x0>=0) && (x0<(*width)) && (y0>=0) && (y0<(*height)))
    {
    *(pImage2+lineByte2*y+x) = *(pImage+lineByte*y0+x0);
    }
    }

    //修改原图像的高度和宽度
    *width = wnew;
    *height = hnew;
    delete [ ] pImage; //释放原内存空间
    return pImage2;
    }

        该程序在Eclipse上调试通过,结果正确。






  • 相关阅读:
    [Nginx] 解决跨域been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    [GO项目]开源免费在线客服系统-真正免费开源-GOFLY0.3.2发布-极简强大Go语言开发网页客服
    [PHP] php使用curl_multi_exec并行同时执行http请求
    [PHP] PHP redis滑动窗口频率限制
    [PHP] xml转为数组函数
    [javascript] 全国省市县JSON/XML数据(包含台湾和海外国家一级)
    [MySQL] 注意MySQL5.1不支持utf8mb4 Error 1115: Unknown character set: 'utf8mb4'
    [Go] linux下安装go1.16
    [GO项目]开源免费在线客服系统-真正免费开源-GOFLY0.2.9发布-极简强大Go语言开发网页客服
    [PHP]PHP不支持方法重载和只支持方法覆盖
  • 原文地址:https://www.cnblogs.com/haigege/p/2205718.html
Copyright © 2011-2022 走看看