news 2026/4/18 8:08:27

【OpenCV】Python图像处理之仿射变换

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【OpenCV】Python图像处理之仿射变换

仿射变换(Affine Transformation)是一种保持图像平行性共线性的几何变换,核心是通过线性变换(缩放、旋转、剪切)与平移变换的组合,改变图像的位置、姿态和尺寸,但不改变图形的平行关系(如平行线变换后仍平行)。OpenCV 中通过cv2.warpAffine()函数实现仿射变换,需先构造仿射变换矩阵,广泛用于图像校正、姿态调整、视角变换等场景。

一、核心原理

1. 仿射变换的数学表达

对于图像中任意像素点(x, y),仿射变换后映射到新坐标(x', y'),其数学公式为:

用矩阵形式表示为:

其中:

  • 2×3 矩阵[[a,b,c],[d,e,f]]仿射变换矩阵(OpenCV 中需用numpy.ndarray表示, dtype 为np.float32);
  • 前 2×2 子矩阵[[a,b],[d,e]]负责线性变换(缩放、旋转、剪切);
  • 最后一列[c,f]负责平移变换(x 方向平移c,y 方向平移f)。

2. 仿射变换的三大基础操作

仿射变换可分解为三种基础变换的组合,也可直接通过这三种变换构造矩阵:

基础变换作用变换矩阵特点
平移(Translation)图像沿 x/y 轴移动前 2×2 为单位矩阵[[1,0],[0,1]],平移量[c,f]
旋转(Rotation)图像绕原点 / 特定点旋转前 2×2 为旋转矩阵[[cosθ, -sinθ],[sinθ, cosθ]],可结合平移实现绕任意点旋转
缩放(Scaling)图像沿 x/y 轴缩放前 2×2 为对角矩阵[[sx,0],[0,sy]]sx/sy为宽 / 高缩放比例)

3. 仿射变换矩阵的构造方式

OpenCV 提供两种核心构造方法,无需手动计算矩阵:

  1. 通过三点映射构造:已知原图中 3 个非共线点及其变换后的对应点,用cv2.getAffineTransform(src_pts, dst_pts)自动计算变换矩阵(最常用);
  2. 手动构造:直接根据平移、旋转、缩放的数学公式创建 2×3 矩阵(适合简单变换)。

二、核心函数详解

1.cv2.getAffineTransform():通过三点映射生成变换矩阵

函数原型
cv2.getAffineTransform(src_pts, dst_pts)
参数说明
参数含义要求
src_pts原图中 3 个非共线点的坐标格式为np.float32([[x1,y1], [x2,y2], [x3,y3]])
dst_pts变换后对应 3 个点的坐标格式与src_pts一致,数量必须为 3
返回值

2×3 仿射变换矩阵(np.float32类型)。

2.cv2.warpAffine():应用仿射变换

函数原型
cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None)
参数说明
参数含义注意事项
src输入图像单通道 / 多通道均可(灰度图 / 彩色图)
M仿射变换矩阵必须是 2×3 的np.float32矩阵
dsize输出图像尺寸格式为(width, height)(与 OpenCV 图像shape相反)
flags插值算法(可选)默认cv2.INTER_LINEAR,缩小用INTER_AREA,高质量放大用INTER_CUBIC
borderMode边界填充模式(可选)默认cv2.BORDER_CONSTANT(常数填充),也可设为BORDER_REPLICATE(复制边界)
borderValue边界填充值(可选)borderMode=BORDER_CONSTANT有效,默认黑色(0),彩色图用(b,g,r)格式
返回值

变换后的输出图像(numpy.ndarray类型)。

三、完整实现代码(多种场景)

1. 基础场景:通过三点映射实现任意仿射变换

已知原图 3 个点和目标点,自动计算矩阵实现变换(如校正倾斜图像):

import cv2 import numpy as np import matplotlib.pyplot as plt # 1. 读取图像 img = cv2.imread("lena.jpg") if img is None: print("无法读取图像,请检查路径!") exit() h, w = img.shape[:2] img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转为RGB用于matplotlib显示 # 2. 定义原图3个点和变换后对应3个点(非共线) # 原图中选择3个特征点(如左上角、右上角、左下角) src_pts = np.float32([[50, 50], [200, 50], [50, 200]]) # 变换后目标点(示例:向右倾斜、向下平移) dst_pts = np.float32([[50, 50], [250, 80], [30, 220]]) # 3. 计算仿射变换矩阵 M = cv2.getAffineTransform(src_pts, dst_pts) # 4. 应用仿射变换(输出尺寸与原图一致) img_affine = cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_LINEAR, borderValue=(255,255,255)) img_affine_rgb = cv2.cvtColor(img_affine, cv2.COLOR_BGR2RGB) # 5. 绘制特征点(可视化对应关系) for (x, y) in src_pts.astype(int): cv2.circle(img_rgb, (x, y), 5, (255, 0, 0), -1) # 原图点:蓝色 for (x, y) in dst_pts.astype(int): cv2.circle(img_affine_rgb, (x, y), 5, (0, 255, 0), -1) # 目标点:绿色 # 6. 显示结果 plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.imshow(img_rgb) plt.title("Original Image (Blue Points)") plt.axis("off") plt.subplot(1, 2, 2) plt.imshow(img_affine_rgb) plt.title("Affine Transformation (Green Points)") plt.axis("off") plt.tight_layout() plt.show()

2. 常用场景:手动构造矩阵实现平移、旋转、缩放

(1)平移变换(沿 x 轴右移 100 像素,y 轴下移 50 像素)
import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread("lena.jpg") h, w = img.shape[:2] img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 构造平移矩阵:[[1,0,c],[0,1,f]],c=x平移量,f=y平移量 tx, ty = 100, 50 # x右移100,y下移50 M_translate = np.float32([[1, 0, tx], [0, 1, ty]]) # 应用变换(输出尺寸可适当放大,避免图像被截断) img_translate = cv2.warpAffine(img, M_translate, (w + tx, h + ty), borderValue=(255,255,255)) img_translate_rgb = cv2.cvtColor(img_translate, cv2.COLOR_BGR2RGB) # 显示 plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.imshow(img_rgb) plt.title(f"Original ({h}×{w})") plt.axis("off") plt.subplot(1, 2, 2) plt.imshow(img_translate_rgb) plt.title(f"Translated (x+100, y+50) ({img_translate.shape[0]}×{img_translate.shape[1]})") plt.axis("off") plt.show()
2)旋转变换(绕图像中心旋转 45°,缩放比例 0.8)

旋转矩阵需结合平移(先将旋转中心移至原点,旋转后再移回原位置),公式如下:

其中:θ为旋转角度(弧度),sx/sy为缩放比例,(cx, cy)为旋转中心。

import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread("lena.jpg") h, w = img.shape[:2] img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 旋转参数 angle = 45 # 旋转角度(度) scale = 0.8 # 旋转时的缩放比例 cx, cy = w // 2, h // 2 # 旋转中心(图像中心) # 计算旋转矩阵(OpenCV内置函数,无需手动计算) M_rotate = cv2.getRotationMatrix2D((cx, cy), angle, scale) # 应用旋转(输出尺寸可按旋转后的边界调整,避免截断) img_rotate = cv2.warpAffine(img, M_rotate, (w, h), flags=cv2.INTER_CUBIC, borderValue=(255,255,255)) img_rotate_rgb = cv2.cvtColor(img_rotate, cv2.COLOR_BGR2RGB) # 显示 plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.imshow(img_rgb) plt.title(f"Original ({h}×{w})") plt.axis("off") plt.subplot(1, 2, 2) plt.imshow(img_rotate_rgb) plt.title(f"Rotated {angle}° (scale={scale})") plt.axis("off") plt.show()
(3)缩放变换(宽度缩放 1.5 倍,高度缩放 0.8 倍)
import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread("lena.jpg") h, w = img.shape[:2] img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 构造缩放矩阵:[[sx,0,0],[0,sy,0]],sx=宽度缩放比,sy=高度缩放比 sx, sy = 1.5, 0.8 M_scale = np.float32([[sx, 0, 0], [0, sy, 0]]) # 应用缩放(输出尺寸=原图尺寸×缩放比) new_w, new_h = int(w * sx), int(h * sy) img_scale = cv2.warpAffine(img, M_scale, (new_w, new_h), flags=cv2.INTER_CUBIC) img_scale_rgb = cv2.cvtColor(img_scale, cv2.COLOR_BGR2RGB) # 显示 plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.imshow(img_rgb) plt.title(f"Original ({h}×{w})") plt.axis("off") plt.subplot(1, 2, 2) plt.imshow(img_scale_rgb) plt.title(f"Scaled (sx={sx}, sy={sy}) ({new_h}×{new_w})") plt.axis("off") plt.show()

3. 实用场景:图像校正(倾斜文档校正)

通过选择文档的四个角点(先取 3 个计算仿射矩阵),校正倾斜的文档图像:

import cv2 import numpy as np import matplotlib.pyplot as plt def correct_skew_image(img, src_pts, target_size): """ 校正倾斜图像(仿射变换) :param img: 输入倾斜图像 :param src_pts: 原图中文档的3个角点(np.float32) :param target_size: 校正后目标尺寸 (width, height) :return: 校正后的图像 """ # 定义校正后目标点(文档的三个角点:左上角、右上角、左下角) dst_pts = np.float32([[0, 0], [target_size[0]-1, 0], [0, target_size[1]-1]]) # 计算仿射矩阵 M = cv2.getAffineTransform(src_pts, dst_pts) # 应用变换 corrected_img = cv2.warpAffine(img, M, target_size, flags=cv2.INTER_CUBIC, borderValue=(255,255,255)) return corrected_img # 1. 读取倾斜文档图像 img_skew = cv2.imread("skew_document.jpg") if img_skew is None: print("无法读取倾斜图像,请检查路径!") exit() h, w = img_skew.shape[:2] img_skew_rgb = cv2.cvtColor(img_skew, cv2.COLOR_BGR2RGB) # 2. 手动选择原图中3个角点(可通过图像查看工具获取坐标) src_pts = np.float32([[60, 80], [420, 70], [50, 500]]) # 示例坐标,需根据实际图像调整 # 3. 校正图像(目标尺寸:宽400,高550) target_size = (400, 550) img_corrected = correct_skew_image(img_skew, src_pts, target_size) img_corrected_rgb = cv2.cvtColor(img_corrected, cv2.COLOR_BGR2RGB) # 4. 绘制角点可视化 for (x, y) in src_pts.astype(int): cv2.circle(img_skew_rgb, (x, y), 6, (0, 255, 0), -1) # 5. 显示结果 plt.figure(figsize=(15, 8)) plt.subplot(1, 2, 1) plt.imshow(img_skew_rgb) plt.title("Skewed Image (Green Corners)") plt.axis("off") plt.subplot(1, 2, 2) plt.imshow(img_corrected_rgb) plt.title(f"Corrected Image ({target_size[1]}×{target_size[0]})") plt.axis("off") plt.tight_layout() plt.show()

四、关键说明与应用场景

1. 仿射变换的核心特点

  • 保持平行性:原图中平行线,变换后仍为平行线;
  • 保持共线性:原图中共线点,变换后仍共线;
  • 灵活性:可组合平移、旋转、缩放、剪切等多种变换;
  • 仅需 3 个点:通过 3 个非共线点的映射关系即可唯一确定变换矩阵。

2. 典型应用场景

  • 图像校正:倾斜文档、车牌、身份证等图像的水平 / 垂直校正;
  • 姿态调整:调整图像的旋转角度、位置,适配特定显示区域;
  • 视角变换:模拟不同视角下的图像(如将倾斜的物体转为正面视角);
  • 数据增强:深度学习中通过仿射变换(旋转、平移、缩放)扩充样本集,提升模型泛化能力。

3. 与透视变换的区别

仿射变换 vs 透视变换(Perspective Transformation):

特性仿射变换透视变换
变换矩阵2×3 矩阵3×3 矩阵
核心特点保持平行性不保持平行性(可将平行线变为相交线)
点映射需求3 个非共线点4 个非共线点
适用场景简单姿态调整、校正复杂视角变换(如拍摄的文档转为正射投影)

五、注意事项

  1. 坐标格式src_ptsdst_pts必须是np.float32类型,否则会报错;
  2. 输出尺寸dsize格式为(width, height),需与图像shapeheight, width)区分,避免尺寸错乱;
  3. 边界填充:变换后图像可能超出原尺寸,需通过borderModeborderValue设置边界填充(如白色填充避免黑边);
  4. 插值算法选择
    • 缩小图像:用cv2.INTER_AREA(避免锯齿);
    • 放大图像 / 保持细节:用cv2.INTER_CUBICcv2.INTER_LINEAR
  5. 旋转中心:绕非原点旋转时,需先平移到原点、旋转、再平移回原位置,推荐用cv2.getRotationMatrix2D()自动计算矩阵,避免手动计算错误。

通过cv2.getAffineTransform()构造矩阵、cv2.warpAffine()应用变换,可轻松实现各类仿射变换需求,掌握三点映射和矩阵构造逻辑是核心。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 14:12:55

EmotiVoice能否生成新闻播报风格语音?正式情绪调校

EmotiVoice能否生成新闻播报风格语音?正式情绪调校 在主流媒体平台日益依赖自动化内容生产、24小时滚动播报成为常态的今天,一个现实问题摆在面前:我们是否可以用AI“复制”一位资深新闻主播的声音,并让其以庄重、清晰、权威的语气…

作者头像 李华
网站建设 2026/4/16 23:18:35

房产中介系统哪一款性价比高

在房产中介行业数字化转型的浪潮中,选择一款适配自身业务的管理系统成为提升效率、降低成本的关键。目前市场上的房产中介系统种类繁多,功能各异,价格跨度较大,让不少中介从业者在选择时陷入纠结。性价比作为核心考量因素&#xf…

作者头像 李华
网站建设 2026/4/17 22:37:47

网信发布2025年“人工智能+政务”规范应用案例拟入选名单公示

为深入贯彻党的二十大及二十届历次全会精神,全面落实党中央、国务院关于发展人工智能的决策部署,推动人工智能大模型在政务领域安全、稳妥、有序应用,在中央网信办信息化发展局指导下,中国网络社会组织联合会组织开展了2025年“人…

作者头像 李华
网站建设 2026/4/15 22:05:57

集体好奇心与企业敏捷管理的协同效应

集体好奇心与企业敏捷管理的协同效应关键词:集体好奇心、敏捷管理、组织学习、创新文化、团队协作、知识共享、适应性领导力摘要:本文探讨了集体好奇心与敏捷管理之间的协同效应,揭示了如何通过培养组织成员的集体好奇心来增强企业的敏捷响应…

作者头像 李华
网站建设 2026/4/17 13:22:19

28、Mac OS X 服务器配置与数据库搭建全攻略

Mac OS X 服务器配置与数据库搭建全攻略 手动配置 ipfw 防火墙 ipfw 防火墙是基于规则的过滤系统,默认规则允许所有来源的流量进入计算机,规则优先级为 65535(最低优先级): 65535 allow ip from any to any若要自定义此规则,可使用以下命令: $ ipfw add 65535 all…

作者头像 李华
网站建设 2026/3/25 3:28:46

Oracle 19c RAC报错ORA-17503,ORA-27300,ORA-27301,ORA-27302

发现alert日志频繁报错ORA-17503: ksfdopn:2 Failed to open file DATA/ORCL/PASSWORD/pwdmesprod.256.1168973143 ORA-27300: OS system dependent operation:open failed with status: 13 ORA-27301: OS failure message: Permission denied ORA-27302: failure occurred at:…

作者头像 李华