图像旋转变换

Author:Maddock

Date:2015-01-01

转载请注明出处:http://www.cnblogs.com/adong7639/p/4197341.html

图像旋转是图像变换中的一种常见的操作,本文将从数学原理上来给出图像旋转的程序代码实现。

图像旋转是将图像围绕某点为中心,顺时针或者逆时针旋转一定的角度,构成一幅新的图像。按照不同的点旋转最后生成的图像大小和形状是一致的,唯一的差别在于空间坐标系的位置不同,本文假定按照图像的中心旋转。这里有一篇博客将图像旋转的公式介绍的非常详细http://hi.baidu.com/wangguang246/item/972a6508d16226dfdce5b040。本文直接给出图像旋转的基本公式如下:

其中(X0, Y0)为原始坐标系的坐标,(x, y) 为旋转后的像素点的坐标,θ表示旋转角度,顺时针旋转为正,逆时针旋转为负。

旋转变换的矩阵:

这种旋转公式是一个线性变换,通过图像的四个顶点坐标进行旋转变换后,出现新的四个顶点坐标,图像的其他像素点坐标经过同样的变换都会落入到四个顶点构成的平行四边形内部。如图所示,P1~P4为图像的四个顶点坐标,绿色方框表示原始图像区域, 为新的坐标, 蓝色区域为旋转后的图像区域。

原始图像的宽度和高度分别为W和H,通过就可以确定旋转后的图像宽度W‘和高度H‘。

上面的步骤确定了新的像素点的坐标的位置,接下来就是计算新的像素点的像素值,这里采取后向映射的方法,原理如下:

  • 首先可以根据原始变换矩阵H求出逆矩阵HINV,逆矩阵表示目标图像的坐标系映射到原始图像坐标系的对应关系。

    根据博客http://hi.baidu.com/wangguang246/item/972a6508d16226dfdce5b040中给出的图像坐标系到数学坐标系转换方法得出最终的HINV矩阵如下:

  • 根据依次遍历目标图像的每个点,根据HINV矩阵可以将目标图像的任意像素点位置

    Pdst映射到源图像中,显然按照公式计算出来的像素点位置坐标为小数,可能会落到非整数像素坐标点的位置,这是可以利用PSRC周围的几个像素点P1~P4的像素值来插值

通过P1 和P2可以计算出Z1的像素值,P3和P4可以计算出Z2的像素值,之后通过Z1和Z2可以计算出PSRC的像素值。

P1(X1,Y1), P2(X2,Y2) , P3(X3,Y3), P4(X4,Y4), Z1(XZ1,YZ1) , Z1(XZ2,YZ2)

PSRC(DX, DY)

X1 = (int)DX;

Y1 = (int)DY;

X2 = X1 + 1;

Y2 = Y1;

X3 = X1 + 1;

Y3 = Y3 + 1;

X4 = X1;

Y4 = Y4 + 1;

设定P( )表示某一像素点的像素值大小

P(Z1) = P(P1) * K1 + (1- K1) *P(P2); K1 = DX – (int)DX;

P(Z2) = P(P3) * K1 + (1- K1) *P(P4); K1 = DX – (int)DX;

P(PSRC) = P(Z1) * K2 + (1- K2) *P(Z2); K2 = DY – (int)DY;

完整的代码如下:

#include<cv.h>
#include<highgui.h>
#include <cmath>
#include <stdlib.h>
#include <iostream>
using namespace std;
const double PI = 3.141592653;   

const char *strimg = "woman.jpg";

int main()
{
    IplImage * image;
    image = cvLoadImage(strimg,0);
    cvNamedWindow("image",CV_WINDOW_AUTOSIZE);
    cvShowImage("image",image);  

    /**************************************************************************************/
    //旋转图像 这里以逆时针为正  插值选用双线性插值 围绕左上角点进行旋转  双线性插值
    IplImage* rotateimg;
    double  angle = 15;
    double Hangle = angle*PI/180;
    int Width,Height;
    //double r,s;
    double  r,s;  

    unsigned char * ptr,*dst;  

    int temp[4];
    double z1,z2;
    //原点会发生移动
    double  fx,fy;  

    double Hcos = cos(Hangle);
    double Hsin = sin(Hangle);  

    //x y 存放原图中四个点的位置,以中心为原点 左上角开始 顺时针数
    int x[4];
    int y[4];
    int x1[4];
    int y1[4];
    x[0] = -(image->width-1)/2;
    x[1] = -x[0];
    x[2] = -x[0];
    x[3] = x[0];
    y[0] = -(image->height -1)/2;
    y[1] = y[0];
    y[2] = -y[0];
    y[3] = -y[0];
    int i =0 , j =0;
    //x1 y1 分别存放新图中图像的四个角点的位置 以中心为原点 左上角点开始 顺时针数
    for (i = 0; i < 4 ; i++)
    {
        x1[i] = (int)(x[i]*Hcos - y[i]*Hsin + 0.5);
        y1[i] = (int)(x[i]*Hsin + y[i]*Hcos + 0.5);
        printf("x:   %d ",x[i] );
        printf("y:   %d ",y[i]);
        printf("x1:   %d ",x1[i] );
        printf("y1:   %d \n",y1[i]);  

    }
    //确定新图像的长宽
    if (abs(y1[2] - y1[0]) > abs(y1[3] - y1[1]))
    {
        Height = abs(y1[2] - y1[0]);
        Width  = abs(x1[3] - x1[1]);
    }
    else{
        Height = abs(y1[3] - y1[1]);
        Width =  abs( x1[2] - x1[0]);
    }
    rotateimg = cvCreateImage(cvSize(Width,Height),image->depth,1);
    //两个偏移常量
    fx = -1*(Width -1)* Hcos*0.5 -(Height -1)*Hsin*0.5 + (image->width-1)/2;
    fy =  (Width -1)*Hsin*0.5 -(Height -1)*Hcos*0.5 + (image->height -1)/2;

    for (i = 0 ; i< Height ; i++)
    {
        for (j =0 ; j< Width; j++)
        {
            dst = (unsigned char *)(rotateimg->imageData + i*rotateimg->widthStep + j);
            s =   i*Hsin  + j*Hcos + fx;
            r =   i*Hcos  - j * Hsin + fy;  

            if (r < 1.0 || s < 1.0 || r >= image->height || s >= image->width)
            {
                *dst = 0;
            }
            else{
                r = r - 1;
                s = s - 1;
                ptr = (unsigned char *)(image->imageData + image->widthStep*(int)r + (int)s );
                temp[0] = *ptr;
                temp[1] = *(ptr+1);
                ptr = (unsigned char*)(image->imageData + image->widthStep *(int)(r+1) + int (s));
                temp[2] = *ptr;
                temp[3] = *(ptr+1);  

                z1 = (temp[1] - temp[0])*(s - int(s)) + temp[0];
                z2 = (temp[3] -temp[2])*(s- int(s)) + temp[2];
                *dst = (int)(z1 + (z2 -z1)*(r- (int)r));
            }  

        }
    }
    cvNamedWindow("rotate_image",1);
    cvShowImage("rotate_image",rotateimg);
    cvSaveImage("rotate.jpg",rotateimg);
    cvWaitKey(0);
    /**************************************************************************************/
    return 0;
}

效果如下:

参考:

http://blog.csdn.net/renshengrumenglibing/article/details/7176790

http://hi.baidu.com/wangguang246/item/972a6508d16226dfdce5b040

http://www.cnblogs.com/tingshuo/archive/2011/05/15/2047016.html

http://blog.csdn.net/housisong/article/details/1586717

时间: 2024-12-29 14:40:34

图像旋转变换的相关文章

图像几何变换:旋转,缩放,斜切

几何变换 几何变换可以看成图像中物体(或像素)空间位置改变,或者说是像素的移动. 几何运算需要空间变换和灰度级差值两个步骤的算法,像素通过变换映射到新的坐标位置,新的位置可能是在几个像素之间,即不一定为整数坐标.这时就需要灰度级差值将映射的新坐标匹配到输出像素之间.最简单的插值方法是最近邻插值,就是令输出像素的灰度值等于映射最近的位置像素,该方法可能会产生锯齿.这种方法也叫零阶插值,相应比较复杂的还有一阶和高阶插值. 插值算法感觉只要了解就可以了,图像处理中比较需要理解的还是空间变换. 空间变换

[opencv] 图像几何变换:旋转,缩放,斜切

几何变换 几何变换可以看成图像中物体(或像素)空间位置改变,或者说是像素的移动. 几何运算需要空间变换和灰度级差值两个步骤的算法,像素通过变换映射到新的坐标位置,新的位置可能是在几个像素之间,即不一定为整数坐标.这时就需要灰度级差值将映射的新坐标匹配到输出像素之间.最简单的插值方法是最近邻插值,就是令输出像素的灰度值等于映射最近的位置像素,该方法可能会产生锯齿.这种方法也叫零阶插值,相应比较复杂的还有一阶和高阶插值. 插值算法感觉只要了解就可以了,图像处理中比较需要理解的还是空间变换. 空间变换

三维图像技术与OpenGL基础理论

英文原文:3D Graphics with OpenGL Basic Theory 中文译文:三维图像技术与OpenGL基础理论 1. 计算机图像硬件 1.1 GPU(图像处理单元) 如今,计算机拥有用来专门做图像处理显示的GPU模块,拥有独立的图像处理储存(显存). 1.2 像素和画面 任何图像显示都是基于栅格的格式.一个栅格既是一张二维的像素直角坐标网.像素具有两个属性:颜色和位置.颜色通常使用RGB(红绿蓝)来表示,典型的有用8位或者24位二进制位(真彩色)表示一种颜色.位置则用坐标(x,

医学CT图像特征提取算法--肺结节CT图像特征提取算法

摘自本人毕业论文<肺结节CT影像特征提取算法研究> 医学图像特征提取可以认为是基于图像内容提取必要特征,医学图像中需要什么特征基于研究需要,提取合适的特征.相对来说,医学图像特征提取要求更加高,因为对医生的辅助诊断起着至关重要的作用,所以需要严谨可靠的特征.肺结节CT影像特征提取也是属于医学图像特征提取领域的一个部分,有着医学图像特征提取的基本要求.既有其他医学图像特征提取的方法,也有针对肺结节的特定特征提取方法.本小节主要对一些常用的肺结节CT影像医学图像特征提取方法进行介绍,主要可以分为灰

C#数字图像处理算法学习笔记(三)--图像几何变换

C#数字图像处理算法学习笔记(三)--图像几何变换 几何图像处理包括 图像的平移变换,镜像变换,旋转变换,伸缩变换,在这里仅以水平镜像为例,通过代码来理解其基本操作方式: 翻转前: 翻转后: //后台代码: public partial class Form1 : Form { private string _curFileName; private Bitmap _srcBitmap; private Bitmap _dstBitmap; public Form1() { Initialize

Android 中的图像特效(Matrix)

以前在线性代数中学习了矩阵,对矩阵的基本运算有一些了解,现在在Android中有一个Matrix类,它的中文意思就是矩阵.Matrix主要是用于图像的缩放.平移.旋转.扭曲等操作.图像处理,主要用到的是乘法. 下面是一个乘法的公式: 在Android里面,Matrix由9个float值构成,是一个3*3的矩阵.如下图 其含义如下: sinX和cosX,表示旋转角度的cos值和sin值(旋转角度是按顺时针方向计算的).translateX和translateY表示x和y的平移量.scale是缩放的

[翻译]鲁棒的尺度不变特征匹配在遥感图像配准中应用(Robust Scale-Invariant Feature Matching for Remote Sensing Image Registration)

李乔亮,汪国有,刘建国,会员,IEEE,和陈少波 2008年8月7日接收;2008年10月22日和2008年11月27日修改.2009年2月2日首版:当前版本出版于2009年4月17日.本项工作由中国国家基础研究项目60672060资助. 中国湖北省武汉市华中科技大学模式识别与人工智能国家重点实验室,邮编430074(邮箱:[email protected];   [email protected];  [email protected];  [email protected]) 数字对象识别编

图像局部显著性—点特征

基于古老的Marr视觉理论,视觉识别和场景重建的基础即第一阶段为局部显著性探测.探测到的主要特征为直觉上可刺激底层视觉的局部显著性--特征点.特征线.特征块. SalientDetection 已经好就没有复习过了,DNN在识别领域的超常表现在各个公司得到快速应用,在ML上耗了太多时间,求职时被CV的知识点虐死... 点探测总结(SIft.PCA-SIft.Surf.GLOH)         原文链接(SIFT):http://www.cnblogs.com/cfantaisie/archiv

图像的仿射变换与AffineTransform类

在图像匹配研究领域中,仿射变换图像是一个重要的研究对象,因此需要对仿射变换在图像中的操作有基本认识.学习了网上一些博客和教程,简单记录了一下: 图像的仿射变换主要包含以下一系列操作:翻转(Flip).旋转(Rotation).平移(Translation).缩放(Scale)和错切(Shear). AffineTransform类描述了一种二维仿射变换的功能,它是一种二维坐标到二维坐标之间的线性变换,保持二维图形的"平直性"(straightness)即变换后直线依然保持直线,圆弧还是