线性代数的运用之图像的旋转

您所在的位置:网站首页 坐标平移法则有哪些 线性代数的运用之图像的旋转

线性代数的运用之图像的旋转

2023-06-11 11:32| 来源: 网络整理| 查看: 265

提起线性代数,老师似乎只会告诉我们矩阵的应用范围很广,很重要。但是 一学期学下来,大家似乎也只会做题并不知道矩阵是如何运用的。一开始的我也是很疑惑,所学的知识似乎和实际的运用丝毫挂不上边。比如,以前听人说图像矩阵可以旋转。但是如何旋转,怎么旋转一直都不了解。虽然上网百度网上只是给出了图像旋转的公式,但却没有给出具体的解释。经过一番钻研还是了解了图像旋转的全过程,这里分享给大家,希望对大家有所帮助。

图像旋转的步骤

首先,大家要先了解图像旋转的步骤有哪些,只有知道自己每一步在做什么才不致于迷茫: 我们先读取一张图片,想象将图片放入一个坐标系中,图片的左上角与坐标原点重合,这时候的图片矩阵的索引与坐标系中的坐标(x,y)相吻合。再接着以图片对应的每一个(x,y)坐标进行一定角度的旋转得到(x1,y1),这时候的坐标x1,y1有的可能为负值,这样的负值在矩阵的索引中是不科学的。所以我们需要将负值变为正值,这相当于平移到正值的象限,平移后的坐标为(x2,y2)。最后将原图像矩阵根据索引(x,y)得到像素值,并将其赋值给相对应的矩阵索引(x2,y2)。这样就完成了。 图文并茂才能更好的理解,下面看图: 在这里插入图片描述

实现难点

下面我们就来说旋转矩阵是怎么来的以及它是什么样子的。 假设一个点为(x,y),旋转角度为 θ \theta θ。在直角坐标系中难以表示旋转,我们以极坐标系来表示: x 2 + y 2 = r 2 x = r cos ⁡ α y = r sin ⁡ α x^2+y^2 = r^2\qquad x = r\cos\alpha \qquad y = r\sin\alpha x2+y2=r2x=rcosαy=rsinα 则旋转后的坐标为: x = r cos ⁡ ( α − θ ) y = r sin ⁡ ( α − θ ) x = r\cos(\alpha-\theta) \qquad y = r\sin(\alpha-\theta) x=rcos(α−θ)y=rsin(α−θ) 化简后为: x 1 = x cos ⁡ θ + y sin ⁡ θ y 1 = y cos ⁡ θ − x sin ⁡ θ x1 = x\cos\theta+y\sin\theta \qquad y1 = y\cos\theta-x\sin\theta x1=xcosθ+ysinθy1=ycosθ−xsinθ 根据化简后的公式可得出矩阵计算公式: [ x y ] ∗ [ cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ] = [ x 1 y 1 ] \begin{bmatrix}x & y\\ \end{bmatrix}*\begin{bmatrix}\cos\theta&-\sin\theta\\ \sin\theta&\cos\theta\\ \end{bmatrix}=\begin{bmatrix}x1 & y1\\ \end{bmatrix} [x​y​]∗[cosθsinθ​−sinθcosθ​]=[x1​y1​] 上面的旋转公式只是理论上的,但在实际运用的时候还需要对其进行进一步的改造。一般的旋转都是默认进行图像中心位置的旋转,这样我们需要先将图像中心移动到原点,在旋转,最后将其移动到原位置。(这里的w,h代表了图像的长和宽) [ x y 1 ] ∗ [ 1 0 0 0 1 0 − w / 2 − h / 2 1 ] ∗ [ cos ⁡ θ − sin ⁡ θ 0 sin ⁡ θ cos ⁡ θ 0 0 0 1 ] ∗ [ 1 0 0 0 1 0 w / 2 h / 2 1 ] = [ x 1 y 1 1 ] \begin{bmatrix}x & y&1\\ \end{bmatrix}*\begin{bmatrix}1&0&0\\0&1&0\\-w/2&-h/2&1\\ \end{bmatrix}*\begin{bmatrix}\cos\theta&-\sin\theta&0\\ \sin\theta&\cos\theta&0\\0&0&1\\ \end{bmatrix}*\begin{bmatrix}1&0&0\\0&1&0\\w/2&h/2&1\\ \end{bmatrix}=\begin{bmatrix}x1 & y1&1\\ \end{bmatrix} [x​y​1​]∗ ​10−w/2​01−h/2​001​ ​∗ ​cosθsinθ0​−sinθcosθ0​001​ ​∗ ​10w/2​01h/2​001​ ​=[x1​y1​1​] 再对其进行化简得 [ x y 1 ] ∗ [ cos ⁡ θ − sin ⁡ θ 0 sin ⁡ θ cos ⁡ θ 0 w / 2 − w / 2 ∗ cos ⁡ − h / 2 ∗ sin ⁡ w / 2 ∗ sin ⁡ − h / 2 ∗ cos ⁡ + h / 2 1 ] = [ x 1 y 1 1 ] \begin{bmatrix}x & y&1\\ \end{bmatrix}*\begin{bmatrix}\cos\theta&-\sin\theta&0\\ \sin\theta&\cos\theta&0\\w/2-w/2*\cos-h/2*\sin&w/2*\sin-h/2*\cos+h/2&1\\ \end{bmatrix}=\begin{bmatrix}x1 & y1&1\\ \end{bmatrix} [x​y​1​]∗ ​cosθsinθw/2−w/2∗cos−h/2∗sin​−sinθcosθw/2∗sin−h/2∗cos+h/2​001​ ​=[x1​y1​1​] 这个就是最终我们在编程是要使用的公式 到这为止我们的核心工作就完成了,下面就可以用代码来实现了。

代码实现

在实现过程中会有一些关键点,我也都做了注释

import cv2 import numpy as np #创建用于图像坐标转换的矩阵 def create_rotation_matrix(angle,w,h): cos = np.cos(np.deg2rad(angle)) sin = np.sin(np.deg2rad(angle)) matrix = np.array([[cos,-sin,0],[sin,cos,0],[w-w*cos-h*sin,w*sin-h*cos+h,1]]) return matrix #图像旋转 def rotation_image(image,matrix,background = 0): #获取图像的大小 w,h,z = image.shape #创建旋转图像的矩阵的变量名 rotation_image = None #创建图像坐标矩阵,这里新创建的矩阵相当于图纸,而旋转后的坐标代表要在纸上画图的位置 coordinate = np.array([[i,j,1] for i in range(w) for j in range(h)],dtype = np.int16) #矩阵旋转 rotation_coordinate = np.dot(coordinate,matrix) #将矩阵由浮点型转换为整数型,矩阵的索引需要整数。 rotation_coordinate = rotation_coordinate.astype(np.int16) #将对应坐标像素赋值,此方法是将超出图像背景的部分进行了裁剪 if background == 0: #创建旋转图像的矩阵 rotation_image = np.zeros((w,h,z),dtype = np.uint8) #循环将相对应的像素进行赋值 for i in range(coordinate.shape[0]): x,y,_ = coordinate[i] rot_x,rot_y,_ = rotation_coordinate[i] if rot_x=w or rot_y=h: #对于超出旋转矩阵范围的坐标点,不做处理 pass else: rotation_image[rot_x,rot_y,:] = image[x,y,:] #非零代表不裁剪 else: #找出坐标矩阵中最小的x和y min_coor = np.min(rotation_coordinate,axis = 0) #让坐标矩阵的所有x和y减去对应的最小x和y,这是坐标位于第一象限(都为正直) rotation_coordinate = rotation_coordinate-min_coor #再找出坐标矩阵的最大的x和y,作为rotation_image矩阵的大小 max_coor = np.max(rotation_coordinate,axis = 0) rotation_image = np.zeros((max_coor[0]+1,max_coor[1]+1,z),dtype = np.uint8) #像素赋值 for i in range(coordinate.shape[0]): x,y,_ = coordinate[i] rot_x,rot_y,_ = rotation_coordinate[i] rotation_image[rot_x,rot_y,:] = image[x,y,:] return rotation_image if __name__ == '__main__': #读取图像 image = cv2.imread(r'C:\Users\Administrator\Desktop\1.png') #image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) w,h,_= image.shape #注意这里传入的旋转点w,h不能直接传入的是w,h = image.shape #传入的应该是0至(w-1)和0至(h-1) matrix = create_rotation_matrix(angle=-45,w =w/2,h = h/2) #background为0时代表的是旋转后的图像与原图像大小相同相当于裁剪了图像, #传入其他数值则为显示完整的旋转图像 rotation_image = rotation_image(image,matrix,background = 1) cv2.imshow('image',image) cv2.imshow('rotation_image',rotation_image) cv2.waitKey() cv2.destroyAllWindows()

效果截图: 在这里插入图片描述 左边是原图,右边是旋转之后的图像。

总结

相信大家看见了旋转之后的图像中存在小黑点,这是因为图像在旋转之后的坐标值一般都为小数,但我们将其直接转换为了整数,这会导致旋转后的位置没有像素点。可能也会是其他原因。 这种旋转方式是前向的像素传值,还有一种是后向的像素传值(按照旋转之后的坐标到原图像中寻找对应的像素值)加上一种像素的插值法就可以解决上面的问题了。 这篇文章主要是想讲一下矩阵的运用,对于解决上面的旋转之后的小黑点问题,等到下一篇文章再讲解吧。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3