【图像处理】-- 仿射变换原理透析(附代码)

发布于:2025-07-16 ⋅ 阅读:(12) ⋅ 点赞:(0)

目录

背景

普通坐标表示法

平移变换

        比例变换

        旋转变换

齐次坐标表示法

        平移变换

比例变换

        旋转变换

代码


背景

        仿射变换(Affine Transformation)是几何学中一种重要的线性变换,广泛应用于图像处理、计算机视觉和图形学等领域。它包括平移、旋转、缩放、剪切等操作,能够保持图像的“仿射性”,即保持点的共线性和平行线不变。仿射变换可以通过矩阵运算来表示,通常使用一个 2×3 的变换矩阵来实现对二维图像的处理。与线性变换不同的是,仿射变换允许在变换过程中加入平移操作,使其更具灵活性和实用性。在实际应用中,仿射变换常用于图像的几何校正、目标对齐、图像配准等任务,是图像处理中不可或缺的基础工具之一。

普通坐标表示法

使用 n 维坐标来表示 n维图形,对于 2 维图像,用 [  x , y  ] 行向量或列向量表示

基本的变换包括 3 类:平移变换、比例变换、旋转变换

平移变换

即图像的平移,只需在向量上加上一个增量向量即可:

\begin{bmatrix} x{}^{'}\\ y{}^{'} \end{bmatrix} = \begin{bmatrix} x+a\\ y+b \end{bmatrix} = \begin{bmatrix} x\\ y \end{bmatrix}+ \begin{bmatrix} a\\ b \end{bmatrix}

比例变换

即图像的拉伸、收缩,比例变换是让 x、y 坐标乘一个数,进行缩放,需乘一个二维矩阵:

\begin{bmatrix} x^{'}\\ y^{'} \end{bmatrix} = \begin{bmatrix}a\cdot x\\ b\cdot y\end{bmatrix}= \begin{bmatrix} a &0 \\ 0 &b \end{bmatrix}\cdot \begin{bmatrix} x\\ y \end{bmatrix}

旋转变换

即图像的旋转,其中,\theta 是图形以坐标为旋转中心旋转的角度:

\begin{bmatrix} x^{'}\\ y^{'} \end{bmatrix} = \begin{bmatrix} x\cos \theta -y\sin \theta \\ x\sin \theta +y\cos \theta \end{bmatrix} = \begin{bmatrix} \cos\theta &-\sin\theta \\ \sin\theta& \cos\theta \end{bmatrix}\cdot \begin{bmatrix} x\\ y \end{bmatrix}

上面的变换矩阵都是基于列向量的,要是想基于行向量,仅需将变换矩阵转置一下即可

除了上面的一些基本变换,还可以将这三个基本变换进行组合,形成对称、错切等变换。

齐次坐标表示法

        普通坐标表示法有一个很大的问题,进行多个基本变换的混合时,平移变换是加一个向量、旋转和比例变换是乘一个矩阵,无法统一表示,这时就需要用齐次坐标表示法:

        齐次坐标表示法是一种数学工具,用于在 n 维空间中描述点和向量,通过增加一个额外的维度来简化几何变换的计算。对于二维空间中的点 (x, y),其齐次坐标形式为 (xh, yh, h),其中 h 是非零的比例因子,通常取为 1,以便于计算。这种表示法允许所有仿射变换(包括平移、旋转、缩放)以矩阵乘法的形式统一表达,极大地方便了计算机图形学和图像处理中的应用。例如,在二维空间中使用 3×3 矩阵可以简洁地实现这些变换,而在三维空间中则使用 4×4 矩阵。这种方法不仅简化了变换过程,也便于进行透视变换等复杂操作。

基于齐次坐标的三个基本变换公式为:

平移变换

\begin{bmatrix} x{}^{'}\\ y{}^{'}\\1 \end{bmatrix} = \begin{bmatrix} x+a\\ y+b \\ 1+0\end{bmatrix} =\begin{bmatrix} 1 &0 &a \\ 0& 1 & b\\ 0& 0 &1 \end{bmatrix}\cdot \begin{bmatrix} x\\ y\\1 \end{bmatrix}

比例变换

\begin{bmatrix} x^{'}\\ y^{'}\\ 1 \end{bmatrix} = \begin{bmatrix}a\cdot x\\ b\cdot y\\ 1\cdot1\end{bmatrix}= \begin{bmatrix} a& 0 & 0\\ 0& b& 0\\ 0& 0 &1 \end{bmatrix} \cdot \begin{bmatrix} x\\ y\\ 1 \end{bmatrix}

旋转变换

\begin{bmatrix} x^{'}\\ y^{'}\\1 \end{bmatrix} = \begin{bmatrix} x\cos \theta -y\sin \theta \\ x\sin \theta +y\cos \theta\\0+1 \end{bmatrix} = \begin{bmatrix} \cos \theta &-\sin \theta & 0\\ \sin \theta & \cos \theta & 0\\ 0 &0 &1 \end{bmatrix} \cdot \begin{bmatrix} x\\ y \\1\end{bmatrix}

有了齐次坐标,对于一些混合变换,变换矩阵的维数是一样的,仅需要对各个变换矩阵相乘即可得到最终变换矩阵。

例如对任意一点(非原点)做比例变换,则需将该点先平移到原点,相对原地做比例变换后,再平移回去。

变换矩阵:

T^{'}\cdot S^{'}\cdot T^{} =

\begin{bmatrix} 1 & 0&-a \\ 0&1 &-b \\ 0& 0&1 \end{bmatrix}\cdot \begin{bmatrix} \lambda & 0&0 \\ 0&\beta &0 \\ 0& 0 &1 \end{bmatrix}\cdot \begin{bmatrix} 1 & 0&a \\ 0&1 &b \\ 0& 0&1 \end{bmatrix}= \begin{bmatrix} \lambda & 0&a\lambda-a \\ 0&\beta &b\beta -b \\ 0& 0&1 \end{bmatrix}

仅需将最后的变换矩阵带入即可:

\begin{bmatrix} x^{'}\\ y^{'}\\1 \end{bmatrix} = \begin{bmatrix} \lambda & 0&a\lambda-a \\ 0&\beta &b\beta -b \\ 0& 0&1 \end{bmatrix} \cdot \begin{bmatrix} x\\ y \\1\end{bmatrix}

上面的变换矩阵都是基于列向量的,要是想基于行向量,仅需将变换矩阵转置一下即可

代码

        这些运算设计矩阵运算,虽然直接编写代码会比较复杂,但 opencv 库已经为我们封装好了相关函数,直接调用就好。

也希望大家在编程过程中使用相关库时,最好理解其意,而不是直接 AI ,当 CV 工程师(Ctrl+C、Ctrl+V),就算 AI 的代码,也得理解其意,应当把 AI 当作学习的工具,而不是纯......,不然已经企业招人直接招 AI 了,还要你干嘛,而且学习原理过程中也能添加成就感、为代码生活增添一番风趣。

opencv 库下载:

pip install opencv-python

引入:

import cv2

应用:

import cv2
import numpy as np

# 读取图像
image = cv2.imread(r"D:\tcy_works\data\DJI\org_8b46fca2adb21a34_1751624788000.jpg")

# 获取图像尺寸
rows, cols, _ = image.shape

# 平移变换
def translate(image, tx, ty):
    # 定义平移矩阵
    matrix = np.float32([[1, 0, tx], [0, 1, ty]])
    translated = cv2.warpAffine(image, matrix, (cols, rows))
    return translated

# 旋转变换
def rotate(image, angle, center=None, scale=1.0):
    # angle 正逆负顺
    # scale 缩放因子,不进行缩放设置为1
    if center is None:
        center = (cols // 2, rows // 2)
    # 计算旋转矩阵
    matrix = cv2.getRotationMatrix2D(center, angle, scale)
    # 应用旋转矩阵
    rotated = cv2.warpAffine(image, matrix, (cols, rows))
    return rotated

# 拉伸变换(缩放变换)
def stretch(image, fx, fy):
    stretched = cv2.resize(image, None, fx=fx, fy=fy, interpolation=cv2.INTER_LINEAR)
    # INTER_LINEAR 双线性插值
    return stretched

# 应用变换
translated_image = translate(image, 50, 30)  # 向右平移50像素,向下平移30像素
rotated_image = rotate(image, 45)  # 绕中心点逆时针旋转45度
stretched_image = stretch(image, 1.5, 1.5)  # 在x轴和y轴方向上都放大1.5倍

# 显示结果
cv2.imshow('Translated Image', translated_image)
cv2.imshow('Rotated Image', rotated_image)
cv2.imshow('Stretched Image', stretched_image)

cv2.imwrite("Translated_Image.jpg", translated_image)
cv2.imwrite('Rotated_Image.jpg', rotated_image)
cv2.imwrite('Stretched_Image.jpg', stretched_image)

cv2.waitKey(0)
cv2.destroyAllWindows()

感谢您的观看!!!


网站公告

今日签到

点亮在社区的每一天
去签到