推荐阅读

几何变换

OpenCV 几何变换介绍

几何变换是图像处理中改变图像空间关系的关键操作,常用于图像校正、视角变换、缩放等场景。OpenCV 提供的主要几何变换包括:

  1. 缩放 (Resize)

    • 改变图像尺寸
    • 插值方法:INTER_NEAREST(最近邻)、INTER_LINEAR(双线性)、INTER_CUBIC(双三次)等
  2. 平移 (Translation)

    • 沿X/Y轴移动图像
    • 使用仿射变换矩阵实现
  3. 旋转 (Rotation)

    • 绕指定中心点旋转图像
    • 可同时控制缩放比例
  4. 仿射变换 (Affine Transformation)

    • 保持平行性的变换(平移+旋转+缩放+错切)
    • 需3对非共线点定义变换
  5. 透视变换 (Perspective Transformation)

    • 实现视角转换(如鸟瞰图)
    • 需4对点定义变换矩阵

代码实现(Python)

import cv2
import numpy as np

# 读取图像
img = cv2.imread('image.jpg')
height, width = img.shape[:2]

# 1. 缩放 (缩小50%)
resized = cv2.resize(img, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_LINEAR)

# 2. 平移 (向右100px,向下50px)
M_trans = np.float32([[1, 0, 100], [0, 1, 50]])
translated = cv2.warpAffine(img, M_trans, (width, height))

# 3. 旋转 (中心点旋转45度,缩放0.8)
center = (width//2, height//2)
M_rot = cv2.getRotationMatrix2D(center, 45, 0.8)
rotated = cv2.warpAffine(img, M_rot, (width, height))

# 4. 仿射变换 (三角形顶点映射)
pts1 = np.float32([[50,50], [200,50], [50,200]])  # 原始点
pts2 = np.float32([[10,100], [200,50], [100,250]]) # 变换后点
M_affine = cv2.getAffineTransform(pts1, pts2)
affined = cv2.warpAffine(img, M_affine, (width, height))

# 5. 透视变换 (四边形到任意四边形)
src_pts = np.float32([[56,65], [368,52], [28,387], [389,390]])
dst_pts = np.float32([[0,0], [300,0], [0,300], [300,300]])
M_persp = cv2.getPerspectiveTransform(src_pts, dst_pts)
perspected = cv2.warpPerspective(img, M_persp, (300, 300))

# 显示结果
cv2.imshow("Original", img)
cv2.imshow("Resized", resized)
cv2.imshow("Translated", translated)
cv2.imshow("Rotated", rotated)
cv2.imshow("Affine", affined)
cv2.imshow("Perspective", perspected)
cv2.waitKey(0)
cv2.destroyAllWindows()

关键函数解析

函数作用核心参数说明
cv2.resize()图像缩放fx/fy: XY缩放因子
cv2.warpAffine()执行仿射变换M: 2x3变换矩阵
getRotationMatrix2D()生成旋转矩阵center, angle, scale
getAffineTransform()通过点对计算仿射矩阵3对对应点
getPerspectiveTransform()计算透视变换矩阵4对对应点
warpPerspective()执行透视变换M: 3x3变换矩阵

注意事项

  1. 插值方法选择:
    • 缩小图像优先用 INTER_AREA
    • 放大图像用 INTER_CUBIC(慢但质量好)或 INTER_LINEAR
  2. 变换矩阵类型:
    • 仿射变换:2×3 矩阵
    • 透视变换:3×3 矩阵
  3. 边界处理:
    • 使用 borderValue 参数设置填充颜色(如 borderValue=(255,0,0) 填充蓝色)

建议:处理几何变换时始终保留原始图像副本,避免多次变换导致图像质量下降。

仿射变换

仿射变换(Affine Transformation)概念详解

核心定义

仿射变换是一种二维平面到二维平面的线性变换,由以下两个核心操作组成:

  1. 线性变换(旋转、缩放、错切)
  2. 平移变换(位置偏移)

数学表达:
[x'] [a b] [x] [tx]
[y'] = [c d] [y] + [ty]
或使用齐次坐标(更简洁):
[x'] [a b tx] [x]
[y'] = [c d ty] [y]
[1 ] [0 0 1 ] [1]

六大核心特性
  1. 直线保持性:直线变换后仍是直线
  2. 平行性保持:平行线变换后仍保持平行
  3. 比例不变性:直线上点的相对位置比例不变
  4. 共线性保持:共线点变换后仍共线
  5. 凸性保持:凸图形变换后仍是凸图形
  6. 组合封闭性:多个仿射变换组合仍是仿射变换
变换自由度(6个参数)
参数数学符号控制效果
a缩放/旋转X方向缩放和旋转分量
b错切/旋转XY耦合变换分量
c错切/旋转YX耦合变换分量
d缩放/旋转Y方向缩放和旋转分量
tx平移X方向位移
ty平移Y方向位移
基础变换分解

任何仿射变换都可分解为:

仿射变换 = 旋转 × 缩放 × 错切 × 平移
与透视变换的关键区别
特性仿射变换透视变换
平行保持✓ 保持平行✗ 平行线可能相交
矩阵形式2×3 或 3×3(最后行001)3×3(自由参数)
点对需求3对非共线点4对点(任意四边形)
深度变化✗ 保持平面性✓ 产生近大远小效果
变换类型平面刚体变换+缩放/错切投影变换(3D->2D映射)
OpenCV实现关键
# 计算变换矩阵 (需3对对应点)
src_points = np.float32([[x1,y1], [x2,y2], [x3,y3]])
dst_points = np.float32([[x1',y1'], [x2',y2'], [x3',y3']])
M = cv2.getAffineTransform(src_points, dst_points)

# 应用变换
result = cv2.warpAffine(image, M, (width, height))
典型应用场景
  1. 图像几何校正(文档扫描、板件定位)
  2. 机械视觉中的物体位姿估计
  3. 倾斜文字/车牌校正
  4. 简单图像配准(不同角度拍摄的平面物体)
  5. 2D动画中的刚体运动模拟

重要原则:选择变换点时必须确保三点不共线,否则无法解出唯一变换矩阵。实际应用中常使用特征检测算法(如SIFT, ORB)自动匹配特征点。

透视变换

透视变换(Perspective Transformation)概念详解

核心定义

透视变换(又称投影变换)是一种非线性的二维空间变换,通过3×3变换矩阵实现从二维平面到二维平面的映射,其核心特点是:

  • 模拟真实世界中的透视效果
  • 能够产生近大远小的视觉现象
  • 直线保持性(直线变换后仍是曲线)

数学表达(齐次坐标):

[x']   [a b c] [x]
[y'] = [d e f] [y]
[w']   [g h 1] [1]

实际坐标:

x'' = x'/w' = (ax + by + c)/(gx + hy + 1)
y'' = y'/w' = (dx + ey + f)/(gx + hy + 1)
核心特性
  1. 直线保持性:直线变换后仍是直线(但平行性可能丢失)
  2. 深度模拟:能表现物体距离观察者的远近关系
  3. 可逆性:存在逆变换矩阵
  4. 非线性性:变换后的坐标与原始坐标呈分式线性关系
  5. 8自由度:变换矩阵有8个可调参数(最后元素固定为1)
与仿射变换的关键对比
特性透视变换仿射变换
矩阵形式3×3(任意值,最后元素为1)3×3(最后行固定为[0,0,1])
平行保持✗ 平行线可能相交于消失点✓ 保持平行关系
点对需求4对点3对非共线点
变换复杂度非线性变换线性变换
典型应用视角校正、虚拟视角生成平面物体旋转/缩放/平移
变换自由度(8个参数)
参数控制效果
a,eX/Y方向缩放和旋转分量
b,dXY/YX耦合变换分量
c,fX/Y方向平移
g,h透视分量(产生非线性效果)
OpenCV实现关键
# 计算变换矩阵 (需4对对应点)
src_pts = np.float32([[x1,y1], [x2,y2], [x3,y3], [x4,y4]])
dst_pts = np.float32([[x1',y1'], [x2',y2'], [x3',y3'], [x4',y4']])
M = cv2.getPerspectiveTransform(src_pts, dst_pts)

# 应用变换 (可控制输出尺寸)
result = cv2.warpPerspective(image, M, (new_width, new_height))
典型应用场景
  1. 文档/车牌矫正:将倾斜拍摄的平面物体转换为正视图

    # 示例:将梯形区域转换为矩形
    src = np.float32([[56,65],[368,52],[28,387],[389,390]])
    dst = np.float32([[0,0],[300,0],[0,300],[300,300]])
    
  2. 虚拟视角生成:改变观察视角(如鸟瞰图变换)

    # 生成鸟瞰图 (俯视视角)
    src = np.float32([[200,100],[400,100],[0,400],[600,400]])
    dst = np.float32([[0,0],[600,0],[0,800],[600,800]])
    
  3. 增强现实:将虚拟物体按透视关系嵌入真实场景

  4. 图像拼接:对齐不同视角拍摄的图像

特殊效果实现
  1. 消失点控制:通过调整变换矩阵的g,h参数控制透视强度

    # 增强透视效果(增大g,h值)
    M[2,0] = 0.001  # g参数
    M[2,1] = 0.002  # h参数
    
  2. 逆透视变换:将透视视图转换为正视图(常用于自动驾驶的车道线检测)

    M_inv = cv2.getPerspectiveTransform(dst_pts, src_pts)
    
注意事项
  1. 点选择原则:

    • 4个点中任意3点不能共线
    • 点对应关系必须准确(建议使用特征点匹配算法)
  2. 图像边界处理:

    # 设置填充色(默认黑色)
    warped = cv2.warpPerspective(img, M, (w,h), 
                               borderMode=cv2.BORDER_CONSTANT,
                               borderValue=(255,255,255))
    
  3. 性能优化:

    • 对大图像先缩小计算变换矩阵,再应用于原图
    • 对视频流可缓存变换矩阵(当视角固定时)

高级技巧:结合特征检测算法(如SIFT/SURF/ORB)自动获取匹配点对,实现智能透视变换,适用于扫描APP等自动校正场景。

直线保持性

直线保持性(Line Preservation Property)深度解析

核心定义

直线保持性是几何变换的核心性质,指变换前后直线仍保持为直线的特性。数学表述为:
若三点 ( P_1, P_2, P_3 ) 共线,则变换后的点 ( P_1’, P_2’, P_3’ ) 也必须共线。

关键特性图解
变换类型直线保持性典型表现
仿射变换✓ 严格保持平行线仍平行
透视变换✓ 保持平行线可能相交于消失点
非线性变换✗ 破坏直线可能变为曲线(如鱼眼矫正)
数学本质

对于线性变换(含仿射/透视):
[
\begin{cases}
x’ = \frac{a_{11}x + a_{12}y + a_{13}}{a_{31}x + a_{32}y + 1} \
y’ = \frac{a_{21}x + a_{22}y + a_{23}}{a_{31}x + a_{32}y + 1}
\end{cases}
]
当 ( a_{31} = a_{32} = 0 ) 时退化为仿射变换(保持平行性),否则为透视变换(保持直线但不保持平行)。

OpenCV验证实验
import cv2
import numpy as np

# 创建测试图像(带十字线)
img = np.zeros((400, 400, 3), dtype=np.uint8)
cv2.line(img, (100,100), (300,100), (0,0,255), 2)  # 水平红线
cv2.line(img, (100,200), (300,200), (0,255,0), 2)   # 水平绿线
cv2.line(img, (200,50), (200,350), (255,0,0), 2)    # 垂直蓝线

# 透视变换(产生消失点)
src_pts = np.float32([[100,100],[300,100],[100,300],[300,300]])
dst_pts = np.float32([[80,80],[320,80],[120,320],[280,320]])
M = cv2.getPerspectiveTransform(src_pts, dst_pts)
warped = cv2.warpPerspective(img, M, (400,400))

# 显示结果
cv2.imshow("Original", img)
cv2.imshow("Perspective", warped)
cv2.waitKey(0)

实验结果:

  1. 原始图像中的三条直线(红/绿/蓝)在透视变换后:
    • 仍保持笔直(验证直线保持性)
    • 水平线不再平行(红绿线向一点汇聚)
    • 垂直线产生倾斜(蓝线角度变化)
工程意义
  1. 文档处理:确保矫正后的文字行仍为直线
  2. CAD/CAM:保持设计图纸的几何精度
  3. 视觉测量:避免引入曲线畸变误差
  4. AR/VR:正确渲染虚拟物体的边缘
特殊场景分析

当直线保持性被破坏时(如鱼眼矫正):

# 鱼眼效果(非线性变换)
map_x = np.zeros(img.shape[:2], np.float32)
map_y = np.zeros(img.shape[:2], np.float32)
for i in range(img.shape[0]):
    for j in range(img.shape[1]):
        # 非线性映射公式
        map_x[i,j] = j + (j-200)*((i-200)/400)**2
        map_y[i,j] = i + (i-200)*((j-200)/400)**2
distorted = cv2.remap(img, map_x, map_y, cv2.INTER_LINEAR)

此时直线将变为曲线(如建筑摄影中的桶形畸变)

扩展知识
  1. 射影几何:研究直线保持变换的数学分支
  2. 齐次坐标:用三维向量表示二维点的数学工具
    [
    \begin{bmatrix} x’ \ y’ \ w’ \end{bmatrix} = M \cdot \begin{bmatrix} x \ y \ 1 \end{bmatrix}
    ]
  3. 变换层级:
    • 欧式变换(仅旋转+平移)
    • 相似变换(+均匀缩放)
    • 仿射变换(+非均匀缩放/错切)
    • 射影变换(+透视效果)

最佳实践建议:在需要测量真实长度的场景(如工业检测)优先选择仿射变换,在需要模拟人眼视觉的场景(如游戏开发)使用透视变换。

更多推荐