关于图像旋转以及旋转后对应像素的位置

参考链接:http://www.echojb.com/image/2016/11/14/258268.html

一、首先来说一下关于像素旋转一定角度后的对应位置:

(1)旋转中心为左上角原点

旋转有一个绕什么转的问题。我们先来看最简单的,绕第一个像素转,则旋转的情况会像这样:

令旋转前有

旋转a角度后有

以矩阵形式表示为

(2)旋转中心为图像中心

当图片较大时,计算会很慢。主要是判断和计算太多了这里只讨论图像处理,程序的优化暂时放一边运行结果如下:

我们能看到,旋转后的图像有很多“蜂窝煤”。主要是点转换后要取整。导致原图中有些点映射到同一个点,而生成的图中有些点在原图中没有点映射到它。所以出现了很多“蜂窝煤”。果然理论还只是理论啊 下面我们来看看更通常一点的做法:以图像的中心为圆心进行旋转。这里涉及到一个坐标系的转换问题。看下图:

在矩阵中我们的坐标系通常是AB和AC方向的,而传统的笛卡尔直角坐标系是DE和DF方向的。令图像表示为M×N的矩阵,对于点A而言,两坐标系中的坐标分别是(0,0)和(-N/2,M/2)矩阵中点(x‘,y‘)转换为笛卡尔坐标系(x,y)的转换关系为:

逆变换为

于是我们得到图像以中心旋转的思路

  • 将矩阵坐标上点(原谅我这样称呼它)转换为笛卡尔坐标系
  • 将该点旋转a度。旋转公式前面已经给出了
  • 将旋转后的点再转换为矩阵坐标

于是得到最后结果

python中numpy有矩阵运算能力,但这里我们直接进行数值计算就可以了。用方程表示如下:

二、关于图像旋转:

M = cv2.getRotationMatrix2D(crop_center, (a * (-1)), 1.0)  #顺时针旋转
tar_img = cv2.warpAffine(crop_img, M, (crop_width, crop_height))  #旋转后的图片

如上,首先使用getRotationMatrix2D获取旋转矩阵,然后再使用warpAffine利用这个矩阵进行旋转;

总结:计算像素旋转的核心算法其实就是像平面坐标系和笛卡尔坐标系之间的转换,因为直接旋转像平面坐标系不太好计算旋转之后的像素的位置,但是基于笛卡尔坐标系下计算像素旋转后的位置却很容易,因此这里引入了笛卡尔坐标系作为一个辅助坐标系,这种思想很重要的!比如在摄影测量学中,为了建立像平面上的点和对应的大地坐标下的点的对应关系,引入了像空坐标系,像辅坐标系,这样一来通过像平面坐标系-》像空坐标系-》像辅坐标系-》大地坐标系,就建立了对应关系。所以通过构建辅助坐标系在计算空间关系时特别有用!!!

注意:像素旋转中使用到的公式针对的是逆时针旋转,而图像旋转中使用到的是顺时针旋转!!!所以在同时使用的时候要特别注意这一点(可能要乘一个-1)!

 

放上一段我自己写的代码,用到了这两个旋转:

def rotation(src_img_size , crop_img , src_box_info , src_pts , angle):  #返回旋转后的pts坐标和boc框
    src_height = int(src_img_size[0])  #原始大图片的尺寸
    src_width = int(src_img_size[1])
    crop_height = crop_img.shape[0]  #截取的图片尺寸
    crop_width = crop_img.shape[1]
    tar_pts = np.zeros((4 , 2) , dtype = int)
    tar_box_info = np.zeros((2 , 2) , dtype = int)  #存储缩放后的box框
    a = random.randint(0 , angle)
    angle_pi = a * math.pi / 180.0
    #crop_img进行旋转============================================================================
    crop_center = (crop_width / 2 , crop_height / 2)  #旋转中心设为图片中心
    M = cv2.getRotationMatrix2D(crop_center, (a * (-1)), 1.0)  #顺时针旋转
    tar_img = cv2.warpAffine(crop_img, M, (crop_width, crop_height))  #旋转后的图片
    #============================================================================================
    for i in range(len(src_pts) / 2):
        tar_pts[i][0] = int(int(src_pts[2 * i]) * math.cos(angle_pi) - int(src_pts[2 * i + 1]) * math.sin(angle_pi) - 0.5 * src_width * math.cos(angle_pi) + 0.5 * src_height * math.sin(angle_pi) + 0.5 * src_width)
        tar_pts[i][1] = int(int(src_pts[2 * i]) * math.sin(angle_pi) + int(src_pts[2 * i + 1]) * math.cos(angle_pi) - 0.5 * src_width * math.sin(angle_pi) - 0.5 * src_height * math.cos(angle_pi) + 0.5 * src_height)
    for i in range(len(src_box_info) / 2):
        tar_box_info[i][0] = int(int(src_box_info[2 * i]) * math.cos(angle_pi) - int(src_box_info[2 * i + 1]) * math.sin(angle_pi) - 0.5 * src_width * math.cos(angle_pi) + 0.5 * src_height * math.sin(angle_pi) + 0.5 * src_width)
        tar_box_info[i][1] = int(int(src_box_info[2 * i]) * math.sin(angle_pi) + int(src_box_info[2 * i + 1]) * math.cos(angle_pi) - 0.5 * src_width * math.sin(angle_pi) - 0.5 * src_height * math.cos(angle_pi) + 0.5 * src_height)
    return tar_img , tar_box_info , tar_pts

原文地址:https://www.cnblogs.com/zf-blog/p/8947800.html

时间: 2024-10-13 22:38:21

关于图像旋转以及旋转后对应像素的位置的相关文章

Opencv图像识别从零到精通(7)----图像平移、旋转、镜像

根据vc6.0c++的学习经验,如果可以很好的自己编程,让图像进行平移旋转这些操作,那么就好像能够清楚的看见图像的内部结构当然这里你怎么访问像素,这个可以自己选一种适合的,最多的是ptr指针,at也是挺多的.看着很简单的变换,可以对图像处理上手的更快,当然对于旋转可能就稍微i难了一点,不过opencv提供了resize(0,remap()等这样的函数,可以方便的让我们进行学习-特别是旋转的时候,有很多的变换,你可以任意旋转一个角度,也可能一直旋转,当然还可以保持图像大小不变的旋转和大小变换的旋转

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

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

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

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

将一个4X4的数组进行逆时针旋转90度后输出,要求原数组数据随机输入

//将一个4X4的数组进行逆时针旋转90度后输出,要求原数组数据随机输入 #include<stdio.h> int main() { int a[4][4],b[4][4],i,j;//a存放原是数组数据,b存放旋转后的数组数据 printf("please input 16 number:"); for(i=0;i<4;i++) for(j=0;j<4;j++) { scanf("%d",&a[i][j]); b[3-j][i]=

IT企业面试题(java描述)-字符串旋转(旋转字母或者单词)

这一章节我们来讨论一下IT企业面试题:字符串旋转(旋转字母或者单词). 题目: 将字符串"abcdef"旋转成"defabc" 或者 将字符串"i am a student."旋转成"student. a am i" 而且在上面的题目里面还会加上不能够使用库函数的限制,我们下面将讨论解题的思路以及具体的代码. 1.思路 (1)暴力解法 就是一个字符一个字符的往后扔 (2)分部法 将不旋转部分和旋转部分分开来处理,先各自反转,再

Android 使用动画效果后的控件位置处理 类似系统通知栏下拉动画

Android的动画的使用,请参考.Android的动画,在设计方面,我有点不太理解,觉得这样搞很怪,因为在控件动画后,即使设置了停留在动画结束时的位置,我们也确实看到了控件停在那个位置,但其实该控件的真实位置还是在原来动画前的那里.举个例子,如果有个Button,你给它设置了动画,让它移动到其他位置,当移动完成后,你会发现,点击Button没有任何效果,而在Button原来的位置,就是动画前的位置点击,明明没有任何控件,却看到了点击Button的效果.不知道Google为什么要这样设计.解决思

Matlab 图像平移、旋转、缩放、镜像

今天学习了用Matlab实现对图像的基本操作.在Matlab中,图像是按照二维矩阵的形式表示的.所以对图像的操作就是对矩阵的操作. 对图像进行缩放.平移.旋转,都可以转化为矩阵的运算. 关于变换矩阵的构造,请参考: < [gym 101047C Robotics Competition] 矩阵快速幂求解点旋转平移N次之后的位置> 参考原图:  1. 图像平移 init = imread('Fig3.tif'); % 读取图像 [R, C] = size(init); % 获取图像大小 res

碰撞检测 (矩形、圆形、点、旋转、矩形框、像素)

一.矩形碰撞 1. 使用rectangle的intersects判断碰撞 let rectA:egret.Rectangle = this.red.getBounds(); let rectB:egret.Rectangle = this.blue.getBounds(); //获得的rect不包含x,y位置 console.log(rectA); //x=0,y=0,width=200,height=200 console.log(rectB); //x=0,y=0,width=200,hei

php图像旋转,图片旋转(逆时针90或者顺时针90)

//src 图片完整路径 //$direction 1顺时针90 2 逆时针90 function imgturn($src,$direction=1) { $ext = pathinfo($src)['extension']; switch ($ext) { case 'gif': $img = imagecreatefromgif($src); break; case 'jpg': case 'jpeg': $img = imagecreatefromjpeg($src); break; c