几何变换详解:平移、缩放、旋转

声明:此文章主要参考两位大佬的博客,参考文章在文末。


本文介绍图像三种主要的几何变换:平移、缩放、旋转。

平移变换

将三维空间中的一个点 [ x , y , z , 1 ] [x, y, z, 1] [x,y,z,1] 移动到另外一个点 [ x ′ , y ′ , z ′ , 1 ] [x', y', z', 1] [x,y,z,1] ,三个坐标轴的移动分量分别为 d x = T x , d y = T y , d z = T z dx=Tx, dy=Ty, dz=Tz dx=Tx,dy=Ty,dz=Tz , 即
x ′ = x + T x x' = x + Tx x=x+Tx
y ′ = y + T y y' = y + Ty y=y+Ty
z ′ = z + T z z' = z + Tz z=z+Tz
平移变换的矩阵如下:
[ x ′ , y ′ , z ′ , 1 ] = [ x , y , z , 1 ] ∗ A [x^{'},y^{'},z^{'},1]=[x,y,z,1]*A [x,y,z,1]=[x,y,z,1]A
A = ( 1 0 0 0 0 1 0 0 0 0 1 0 T x T y T z 0 ) A = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0\\ T_x & T_y & T_z & 0\\ \end{pmatrix} A=100Tx010Ty001Tz0000

缩放变换

将模型放大或者缩小,本质也是对模型上每个顶点进行放大和缩小(顶点坐标值变大或变小),假设变换前的点是 [ x , y , z , 1 ] [x, y, z, 1] [x,y,z,1],变换后的点是 [ x ′ , y ′ , z ′ , 1 ] [x', y', z', 1] [x,y,z,1],那么
x ′ = x ∗ S x x' = x * S_x x=xSx
y ′ = y ∗ S y y' = y * S_y y=ySy
z ′ = z ∗ S z z' = z * S_z z=zSz
缩放变换的矩阵如下:
[ x ′ , y ′ , z ′ , 1 ] = [ x , y , z , 1 ] ∗ B [x^{'},y^{'},z^{'},1]=[x,y,z,1]*B [x,y,z,1]=[x,y,z,1]B
B = ( S x 0 0 0 0 S x 0 0 0 0 S x 0 0 0 0 1 ) B = \begin{pmatrix} S_x & 0 & 0 & 0 \\ 0 & S_x & 0 & 0 \\ 0 & 0 & S_x & 0\\ 0 & 0 & 0 & 1 \\ \end{pmatrix} B=Sx0000Sx0000Sx00001

旋转变换

绕X轴旋转

在这里插入图片描述
旋转的正方向为顺时针方向。

绕X轴旋转变换的矩阵如下:
[ x ′ , y ′ , z ′ , 1 ] = [ x , y , z , 1 ] ∗ C 1 [x^{'},y^{'},z^{'},1]=[x,y,z,1]*C_1 [x,y,z,1]=[x,y,z,1]C1
C 1 = ( 1 0 0 0 0 cos ⁡ θ sin ⁡ θ 0 0 − sin ⁡ θ cos ⁡ θ 0 0 0 0 1 ) C_1 = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos\theta & \sin\theta & 0 \\ 0 & -\sin\theta & \cos\theta & 0\\ 0 & 0 & 0 & 1 \\ \end{pmatrix} C1=10000cosθsinθ00sinθcosθ00001

绕Y轴旋转

在这里插入图片描述

绕Y轴旋转变换的矩阵如下:
[ x ′ , y ′ , z ′ , 1 ] = [ x , y , z , 1 ] ∗ C 2 [x^{'},y^{'},z^{'},1]=[x,y,z,1]*C_2 [x,y,z,1]=[x,y,z,1]C2

C 2 = ( cos ⁡ θ 0 − sin ⁡ θ 0 0 1 0 0 sin ⁡ θ 0 cos ⁡ θ 0 0 0 0 1 ) C_2 = \begin{pmatrix} \cos\theta & 0 & -\sin\theta & 0 \\ 0 & 1 & 0 & 0 \\ \sin\theta & 0 & \cos\theta & 0\\ 0 & 0 & 0 & 1 \\ \end{pmatrix} C2=cosθ0sinθ00100sinθ0cosθ00001

绕Z轴旋转

在这里插入图片描述
绕Z轴旋转变换的矩阵如下:
[ x ′ , y ′ , z ′ , 1 ] = [ x , y , z , 1 ] ∗ C 3 [x^{'},y^{'},z^{'},1]=[x,y,z,1]*C_3 [x,y,z,1]=[x,y,z,1]C3

C 3 = ( cos ⁡ θ sin ⁡ θ 0 0 − sin ⁡ θ cos ⁡ θ 0 0 0 0 1 0 0 0 0 1 ) C_3 = \begin{pmatrix} \cos\theta & \sin\theta & 0 & 0 \\ -\sin\theta & \cos\theta & 0 & 0 \\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & 1 \\ \end{pmatrix} C3=cosθsinθ00sinθcosθ0000100001

绕坐标轴旋转的矩阵推导

上面三种绕坐标轴旋转的情况属于特殊的二维旋转,比如绕Z轴旋转,相当于在与 X O Y XOY XOY平面上绕原点做二维旋转。

假设点 P ( x , y ) P(x, y) P(x,y)是平面直角坐标系内一点,其到原点的距离为 r r r,其与 X X X轴的夹角为 A A A,现将点 P P P绕原点旋转 θ θ θ度,得到点 P ′ ( x ′ , y ′ ) P'(x', y') P(x,y) P ′ P' P X X X轴的夹角为 B B B,则 A = B − θ A = B - θ A=Bθ。(注意,在二维坐标中,逆时针旋转时角度为正,顺时针旋转时角度为负,下图中由 P P P旋转到 P ′ P' P,角度为 θ θ θ,若是由 P ′ P' P转到 P P P,则角度为 − θ -θ θ)。

在这里插入图片描述
在这里插入图片描述得到下面的转换方程:
在这里插入图片描述
写成矩阵的形式:
在这里插入图片描述
求得旋转矩阵:
在这里插入图片描述
由于这里使用齐次坐标,所以还需加上一维,最终变成如下形式:
绕Z轴旋转变换矩阵

在这里插入图片描述
对于绕X轴旋转的情况,我们只需将式一中的x用y替换,y用z替换,z用x替换即可:
在这里插入图片描述
绕X轴旋转变换矩阵
在这里插入图片描述
绕Y轴旋转变换矩阵
在这里插入图片描述

逆矩阵

平移变换矩阵的逆矩阵与原来的平移量相同,但是方向相反:
在这里插入图片描述
旋转变换矩阵的逆矩阵与原来的旋转轴相同但是角度相反:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200423170641358.pn

g?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwMzE3MjA0,size_16,color_FFFFFF,t_70)
缩放变换的逆矩阵正好和原来的效果相反,如果原来是放大,则逆矩阵是缩小,如果原来是缩小,则逆矩阵是放大:

在这里插入图片描述

代码实战

1.平移

图像平移:设(x0, y0)是缩放后的坐标,(x, y)是缩放前的坐标,dx、dy为偏移量,则公式如下:
在这里插入图片描述
图像平移首先定义平移矩阵M,再调用warpAffine()函数实现平移,核心函数如下:
M = np.float32([[1, 0, x], [0, 1, y]])
shifted = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))

(注:M作为仿射变换矩阵,一般反映平移或旋转的关系,为InputArray类型的2×3的变换矩阵)
cv2.imread()和cv2.cvtColor() 的使用
cv2.warpAffine 参数详解

import cv2
import numpy as np

# 读取图片
img = cv2.imread('my goddess zhang.jpg')
image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 图像平移 下、上、右、左平移
M = np.float32([[1, 0, 0], [0, 1, 100]])
img1 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))

M = np.float32([[1, 0, 0], [0, 1, -100]])
img2 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))

M = np.float32([[1, 0, 100], [0, 1, 0]])
img3 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))

M = np.float32([[1, 0, -100], [0, 1, 0]])
img4 = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))

# 显示图形
cv2.imshow('original', image)
cv2.imshow('down', img1)
cv2.imshow('up', img2)
cv2.imshow('right', img3)
cv2.imshow('left', img4)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果如下:
在这里插入图片描述

2.缩放

图像缩放主要调用resize()函数实现:
result = cv2.resize(src, dsize[, result[. fx[, fy[, interpolation]]]])
其中src表示原始图像,dsize表示缩放大小,fx和fy也可以表示缩放大小倍数,他们两个(dsize或fx\fy)设置一个即可实现图像缩放。
如:
方法1. result = cv2.resize(src, (160,160))
方法2. result = cv2.resize(src, None, fx=0.5, fy=0.5)
图像缩放:设 ( x 0 , y 0 ) (x0, y0) x0,y0是缩放后的坐标, ( x , y ) (x, y) x,y是缩放前的坐标, s x sx sx s y sy sy为缩放因子,则公式如下:
在这里插入图片描述
方法一:

import cv2

# 读取图片
src = cv2.imread('my goddess zhang.jpg')

# 图像缩放
result = cv2.resize(src, (200, 300))
print(result.shape)

# 显示图像
cv2.imshow("src", src)
cv2.imshow("result", result)

# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

方法二:

import cv2
import numpy as np

# 读取图片
src = cv2.imread('my goddess zhang.jpg')
rows, cols = src.shape[:2]
print(rows, cols)

# 图像缩放 dsize(列,行)
result = cv2.resize(src, (int(cols * 0.6), int(rows * 1.2)))

# 显示图像
cv2.imshow("src", src)
cv2.imshow("result", result)

# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

import cv2

# 读取图片
src = cv2.imread('my goddess zhang.jpg')
rows, cols = src.shape[:2]
print(rows, cols)

# 图像缩放
result = cv2.resize(src, None, fx=1.5, fy=1.5)

# 显示图像
cv2.imshow("src", src)
cv2.imshow("result", result)

# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

3.旋转

图像旋转主要调用getRotationMatrix2D()函数和warpAffine()函数实现,绕图像的中心旋转,具体如下:

M = cv2.getRotationMatrix2D((cols/2, rows/2), 30, 1)
参数分别为:旋转中心、旋转度数、scale
rotated = cv2.warpAffine(src, M, (cols, rows))
参数分别为:原始图像、旋转参数、原始图像宽高

图像旋转:设(x0, y0)是旋转后的坐标,(x, y)是旋转前的坐标,(m,n)是旋转中心,a是旋转的角度,(left,top)是旋转后图像的左上角坐标,则公式如下:
在这里插入图片描述

import cv2

# 读取图片
src = cv2.imread('my goddess zhang.jpg')

# 原图的高、宽 以及通道数
rows, cols, channel = src.shape

# 绕图像的中心旋转
# 参数:旋转中心 旋转度数 scale
M1 = cv2.getRotationMatrix2D((cols / 2, rows / 2), 30, 1)
M2 = cv2.getRotationMatrix2D((cols / 2, rows / 2), -60, 1)
# 参数:原始图像 旋转参数 元素图像宽高
rotated1 = cv2.warpAffine(src, M1, (cols, rows))
rotated2 = cv2.warpAffine(src, M2, (cols, rows))

# 显示图像
cv2.imshow("src", src)
# cv2.imshow("rotated", rotated1)
cv2.imshow("rotated", rotated2)

# 等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
在这里插入图片描述

参考文章

https://blog.csdn.net/zhengxiuchen86/article/details/81951608
https://blog.csdn.net/Eastmount/article/details/82454335?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值