线性代数应用系列-1-图像旋转(1/N)-最基础直接的方式

最近考虑到个人发展的事情,打算巩固下图像处理相关方面的基础,于是开始重温一本关于线性代数及其应用的书《Linear Algebra with Applications, 9th edition》。

使用经典的Lena图(512x512尺寸),请自行搜索获取。
在这里插入图片描述

线性代数与点旋转

直接说结论,对于二维平面上的一个点来说,将其逆时针旋转 θ \theta θ 即表示其对应的旋转矩阵为
[ c o s ( θ ) − s i n ( θ ) s i n ( θ ) c o s ( θ ) ] \left[ \begin{matrix} cos(\theta) & -sin(\theta)\\ sin(\theta) & cos(\theta) \end{matrix} \right] [cos(θ)sin(θ)sin(θ)cos(θ)]
实际应用中,取得是其齐次坐标的形式,即
[ c o s ( θ ) − s i n ( θ ) 0 s i n ( θ ) c o s ( θ ) 0 0 0 1 ] \left[ \begin{matrix} cos(\theta) & -sin(\theta) & 0\\ sin(\theta) & cos(\theta) & 0\\ 0 & 0 & 1 \end{matrix} \right] cos(θ)sin(θ)0sin(θ)cos(θ)0001

以将点 [1,1], [2, 2] 分别逆时针旋转45°为例,
θ = 45 / 180 ∗ n p . p i \theta=45 / 180 * np.pi θ=45/180np.pi
旋转矩阵为
r o t a t i o n _ m a t r i x = [ 0.7071 − 0.7071 0 0.7071 0.7071 0 0 0 1 ] rotation\_matrix = \left[ \begin{matrix} 0.7071 & -0.7071 & 0\\ 0.7071 & 0.7071 & 0\\ 0 & 0 & 1 \end{matrix} \right] rotation_matrix=0.70710.707100.70710.70710001
进行矩阵乘法

rotated_points = rotation_matrix @ np.array([[1, 1, 1], [2, 2, 1]]).T

结果为
r o t a t i o n _ m a t r i x = [ 0. 0. 1.4142 2.8284 1 1 ] rotation\_matrix = \left[ \begin{matrix} 0. & 0.\\ 1.4142 & 2.8284\\ 1 & 1 \end{matrix} \right] rotation_matrix=0.1.414210.2.82841
即[1, 1]旋转后的坐标为[0., 1.4142],[2, 2]旋转后的坐标为[0, 2.8284]。

图像边界的确定

设图像宽高像素分别为wh,则旋转后的图像边界坐标点为

new_boundary = np.dot(rotation_matrix, np.array([[0, 0, 1], [0, w, 1], [h, w, 1], [h, 0, 1]]).T).T

计算得出结果为

array([[   0.        ,    0.        ,    1.        ],
        [-362.03867197,  362.03867197,    1.        ],
        [   0.        ,  724.07734394,    1.        ],
        [ 362.03867197,  362.03867197,    1.        ]]

下面开始计算图像的新边界。因为图像的横纵坐标只支持正整数,所以需要对图像整体做一个偏移

min_x, max_x = new_boundary[:, 0].min(), new_boundary[:, 0].max()
min_y, max_y = new_boundary[:, 1].min(), new_boundary[:, 1].max()
new_h = int(max_y - min_y) + 1  # 725
new_w = int(max_x - min_x) + 1  # 725

即对所有图像中的点,都需要减去下面这个偏移量,转化为正坐标

min_value = int(round(new_boundary[:, 0].min())), int(round(new_boundary[:, 1].min()))  # (-362, 0)

由上述计算可知,新图像是一个725x725的矩阵。

图像的旋转

本文使用最基础直接的方式对图像旋转,即用一个二重循环,对图像上的每一个点,经由矩阵乘法获取其新坐标,并将原图的像素值复制过去。

# 构建一个空数组,用于放置旋转后的图像
rotated_img = np.empty((new_h + 0, new_w + 0, 3), dtype='uint8')
# 迭代每一行
for i in range(h):
	# 迭代每一列
    for j in range(w):
    	# 计算新坐标:矩阵乘之后,减去偏移量
        new_coord = np.dot(rotation_matrix, [i, j, 1]).astype(np.int16)[:2] - min_value
        # 赋值
        # 这里注意要用`tuple(new_coord)`而不是数组或者列表,否则是对选定得两行赋值
        rotated_img[tuple(new_coord)] = img_arr[i, j]

得到的新图为
在这里插入图片描述

上图黑色条码的解释

上图存在很明显的黑色条码,这是由于原图与新图的像素坐标数量不是一一对应造成的。
原图坐标映射到新图上,有可能是同一点。
下一篇文章会解决这个问题。

参考

使用MarkDown画矩阵
markdown中公式编辑教程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值