Python----OpenCV(几何变换--图像平移、图像旋转、放射变换、图像缩放、透视变换)

一、图像平移

"平移操作是通过一个平移矩阵来实现的。这个矩阵是一个2x3的矩阵,表示图像坐标的变 换。

其中,Tx 和 Ty 分别表示图像在 x 轴和 y 轴方向上平移的距离。

举个例子:

如果我们想将图像平移 100 个像素到右,50 个像素到下,Tx 就是 100,Ty 就是 50。

python 复制代码
warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
参数名 类型 说明
src 输入图像 需要进行仿射变换的原始图像,通常为NumPy数组(如灰度或BGR格式)。
M 2x3变换矩阵 用于指定旋转、平移、缩放等仿射变换的矩阵(浮点型)。
dsize 元组 (宽, 高) 输出图像的尺寸,格式为 (width, height)
dst 输出图像 可选参数,存储变换后的图像,类型和大小与 src 相同。
flags 插值方法 可选参数,默认 cv2.INTER_LINEAR,其他选项如 INTER_NEARESTINTER_CUBIC
borderMode 边界模式 可选参数,处理边界像素的方式(如 cv2.BORDER_CONSTANTBORDER_REPLICATE)。
borderValue 标量值 可选参数,当 borderMode=cv2.BORDER_CONSTANT 时使用的填充值(默认为0)。
python 复制代码
# 导入OpenCV和NumPy库
import cv2
import numpy as np

# 读取图像文件,路径为'./images/nezha.png'
img = cv2.imread('./images/nezha.png')

# 获取图像的高度(h)和宽度(w),img.shape返回的是(高度, 宽度, 通道数)
h, w = img.shape[:2]

# 定义2x3的仿射变换矩阵M,这里是一个平移变换:
# [[1, 0, tx], [0, 1, ty]],其中tx=100(水平向右平移100像素),ty=50(垂直向下平移50像素)
M = np.float32([[1, 0, 100], [0, 1, 50]])

# 应用仿射变换,参数说明:
# img: 输入图像
# M: 变换矩阵
# (w, h): 输出图像的尺寸(保持和原图相同大小)
res = cv2.warpAffine(img, M, (w, h))

# 显示原始图像,窗口名称为'img'
cv2.imshow('img', img)

# 显示变换后的图像,窗口名称为'res'
cv2.imshow('res', res)

# 等待用户按键,0表示无限等待
cv2.waitKey(0)

# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()

二、图像旋转

2.1、出现裁剪的旋

图像的旋转变换时图像的位置变换,旋转后图像的大小一般会改变。

python 复制代码
getRotationMatrix2D(center, angle, scale) →  retval

| 参数名 | 说明 |
| center | 表示旋转的中心点 |
| angle | 表示旋转的角度(正数逆时针) |

scale 表示图像缩放因子

旋转矩阵


重点:

scale 是缩放比例(比如 1.0 表示不缩放)

t_x 和 t_y 是平移的偏移量,OpenCV 会根据你设定的旋转中心,自动帮你算好。

python 复制代码
# 导入OpenCV和NumPy库
import cv2
import numpy as np

# 读取图像文件,路径为'./images/nezha.png'
img = cv2.imread('./images/nezha.png')

# 获取图像的高度(h)和宽度(w),img.shape返回的是(高度, 宽度, 通道数)
h, w = img.shape[:2]

# 创建旋转矩阵M:
# 参数说明:
# (w//2, h//2) - 旋转中心点(图像中心)
# 45 - 旋转角度(逆时针45度)
# 1 - 缩放比例(1表示保持原大小)
M = cv2.getRotationMatrix2D((w//2, h//2), 45, 1)

# 应用仿射变换进行图像旋转:
# img: 输入图像
# M: 旋转矩阵
# (w, h): 输出图像的尺寸(保持和原图相同大小)
res = cv2.warpAffine(img, M, (w, h))

# 显示原始图像,窗口名称为'img'
cv2.imshow('img', img)

# 显示旋转后的图像,窗口名称为'res'
cv2.imshow('res', res)

# 等待用户按键,0表示无限等待
cv2.waitKey(0)

# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()

2.2、不出现裁剪的旋转

python 复制代码
# 导入OpenCV和NumPy库
import cv2
import numpy as np

# 读取图像文件
img = cv2.imread('./images/nezha.png')

# 获取原始图像的高度和宽度
h, w = img.shape[:2]

# 创建旋转矩阵:
# 参数说明:
# (w//2, h//2) - 以图像中心为旋转中心
# 45 - 旋转角度(逆时针45度)
# 1 - 缩放比例(1表示保持原大小)
M = cv2.getRotationMatrix2D((w//2, h//2), 45, 1)

# 计算旋转矩阵中的cos和sin绝对值
cos = np.abs(M[0, 0])  # 旋转矩阵中的cosθ分量
sin = np.abs(M[0, 1])  # 旋转矩阵中的sinθ分量

# 计算旋转后图像的新尺寸(避免裁剪)
# 新宽度 = 原高度*sinθ + 原宽度*cosθ
nW = int((h * sin) + (w * cos))  
# 新高度 = 原高度*cosθ + 原宽度*sinθ
nH = int((h * cos) + (w * sin))  

# 调整旋转矩阵的平移分量,使旋转后的图像居中显示
# 水平方向偏移:新宽度/2 - 原宽度/2
M[0, 2] += (nW / 2) - (w / 2)
# 垂直方向偏移:新高度/2 - 原高度/2
M[1, 2] += (nH / 2) - (h / 2)

# 应用仿射变换,使用调整后的参数:
# img - 输入图像
# M - 调整后的旋转矩阵
# (nW, nH) - 新的图像尺寸(确保完整显示旋转后的图像)
res = cv2.warpAffine(img, M, (nW, nH))

# 显示原始图像
cv2.imshow('img', img)
# 显示旋转后的图像
cv2.imshow('res', res)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

三、放射变换

放射变换是一种二维坐标空间中的线性变换+平移,它可以实现图像的:平移(Translation) 缩放(Scaling) 旋转(Rotation) 翻转(Reflection) 错切(Shear)

应用场景

图像校准

图像配准(如航拍图拼接)

仿射数据增强(如训练图像预处理)

python 复制代码
warpAffine(src,M,dsize[,dest[,flags[,boederModel[,borderValue]]]])→dest
参数名 类型 说明 默认值
src numpy.ndarray 输入图像矩阵(BGR或灰度图) 无(必须参数)
dst numpy.ndarray 输出图像矩阵,尺寸由dsize指定,类型与src一致 None(自动创建)
M np.float32 (2×3) 仿射变换矩阵 格式:[[a11, a12, b1], [a21, a22, b2]] 无(必须参数)
dsize tuple (width,height) 输出图像尺寸(注意:宽度在前!) 无(必须参数)
flags int 插值方法: INTER_NEAREST(最近邻) INTER_LINEAR(双线性,默认) INTER_CUBIC(三次样条) INTER_LINEAR
borderMode int 边缘填充方式: BORDER_CONSTANT(常量填充,默认) BORDER_REPLICATE(复制边缘) BORDER_REFLECT(镜像) BORDER_CONSTANT
borderValue scalar/tuple borderMode=CONSTANT时的填充值: - 灰度图:单值(如0) - BGR图:三元组(如(0,255,0) 0(黑色)
python 复制代码
# 导入OpenCV和NumPy库
import cv2
import numpy as np

# 读取图片
img = cv2.imread('./images/nezha.png')

# 获取图片的宽高和通道数
# rows: 图像高度(行数)
# cols: 图像宽度(列数) 
# channels: 图像通道数(如3表示BGR彩色图)
rows, cols, channels = img.shape

# 定义原图上三个点的坐标(左上、右上、左下)
# 这些点将用于定义变换前的三角形区域
p1 = np.float32([
    [0, 0],          # 左上角
    [cols-1, 0],     # 右上角
    [0, rows-1]      # 左下角
])

# 定义变换后三个点的目标坐标
# 这里将左下角点移动到右下角位置,实现类似"推斜"效果
p2 = np.float32([
    [0, 0],          # 左上角(保持不变)
    [cols-1, 0],     # 右上角(保持不变)
    [cols-1, rows-1] # 原左下角移动到右下角
])

# 计算仿射变换矩阵
# 根据三组对应点计算2x3变换矩阵
M = cv2.getAffineTransform(p1, p2)

# 应用仿射变换
# img: 输入图像
# M: 变换矩阵
# (cols, rows): 输出图像尺寸(保持原图大小)
dst = cv2.warpAffine(img, M, (cols, rows))

# 显示原始图像
cv2.imshow("img", img)
# 显示变换后的图像
cv2.imshow("dst", dst)
# 等待按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()

四、图像缩放

图像比例缩放是指将给定的图像在x轴方向按比例缩放x倍,在y轴方向按比例缩放y倍,从 而获得一幅新图像。

python 复制代码
resize(src,dsize[,dst[fx[,interpolation]]]]→dst
参数名 类型 说明 注意事项
src numpy.ndarray 输入图像矩阵(BGR或灰度图) 必须参数
dsize tuple (width, height) 目标图像尺寸 与(fx,fy)不能同时为零
fx float x轴方向缩放因子 当dsize=(0,0)时生效
fy float y轴方向缩放因子 当dsize=(0,0)时生效
interpolation int 插值方法: - INTER_NEAREST(最近邻) - INTER_LINEAR(双线性,默认) - INTER_CUBIC(三次样条) - INTER_AREA(区域重采样) 缩小推荐INTER_AREA 放大推荐INTER_LINEAR

使用规则:

  1. 尺寸优先级dsize 参数优先于 fx/fy

  2. 互斥规则

    • 当指定 dsize 时,fxfy 被忽略

    • dsize=(0,0) 时,通过 fxfy 计算尺寸

插值方法选择建议:

场景 推荐方法 特点
图像缩小 INTER_AREA 避免摩尔纹
常规放大 INTER_LINEAR 平衡速度质量
高质量放大 INTER_CUBIC 速度慢但更平滑
边缘保留 INTER_LANCZOS4 8x8像素邻域

插值(Interpolation)

最近邻插值(Nearest Neighbor Interpolation)

立方插值(Cubic Interpolation)

Lanczos 插值(Lanczos Interpolation)
实际应用场景

图像预处理:将所有输入图像统一为相同尺寸

目标检测:在不同尺度上检测目标(图像金字塔)

图像增强:放大图像以便观察细节

图像压缩:缩小图像以节省存储空间

python 复制代码
# 导入OpenCV和NumPy库
import cv2
import numpy as np

# 读取图片
img = cv2.imread('./images/nezha.png')

# 方式1:直接指定目标尺寸进行缩放
# 将图像调整为800×600像素大小
# 使用双线性插值(INTER_LINEAR)保证缩放质量
resized_image_800_600 = cv2.resize(
    img,                   # 原始图像
    (800, 600),            # 目标尺寸(宽度,高度)
    interpolation=cv2.INTER_LINEAR  # 插值方法
)

# 方式2:使用缩放因子进行等比缩放
# 将图像宽高都缩小为原来的一半
# None表示不直接指定尺寸,通过fx/fy计算
resized_image_05_05 = cv2.resize(
    img,                   # 原始图像
    None,                  # 不直接指定尺寸
    fx=0.5,                # 宽度缩放因子(0.5倍)
    fy=0.5,                # 高度缩放因子(0.5倍)
    interpolation=cv2.INTER_LINEAR  # 插值方法
)

# 显示原始图像
cv2.imshow("img", img)
# 显示800×600缩放结果
cv2.imshow("resized_image_800_600", resized_image_800_600)
# 显示0.5倍缩放结果
cv2.imshow("resized_image_05_05", resized_image_05_05)

# 等待按键操作(0表示无限等待)
cv2.waitKey(0)
# 销毁所有OpenCV窗口
cv2.destroyAllWindows()

五、透视变换

透视变换是一种图像处理技术,用于将二维平面上的图像或物体映射到三维空间中。它通 过改变图像的视角和投影来创建一个具有透视效果的图像。

透视变换是一种射影变换(Projective Transformation),它会保持直线的性质,即变换 前的直线在变换后依然是直线。透视变换的核心原理是找到两个图像平面上4个点之间的映 射关系。

cv2.getPerspectiveTransform() 函数用于计算一个透视变换矩阵。透视变换是图像处理中的一种几何 变换,能够将图像中的一个矩形区域转换为另一个矩形区域,通常用于图像的校正、透视投 影等应用。

参数名 类型 说明 注意事项
srcPoints np.float32 (4,2) 源图像中四边形的4个顶点坐标,顺序必须为: 左上 → 右上 → 右下 → 左下 必须严格按顺序排列,否则会导致扭曲错误
dstPoints np.float32 (4,2) 目标图像中对应的4个顶点坐标,顺序与 srcPoints 一致 若希望输出为矩形,目标点应定义为矩形坐标

**cv2.warpPerspective()**将透视变换矩阵应用到源图像,生成透视变换后的图像。

参数名 类型 说明 默认值/注意事项
src numpy.ndarray 输入图像(BGR或灰度图) 必须为OpenCV图像格式(如 cv2.imread() 读取)
M np.float32 (3,3) 透视变换矩阵(来自 cv2.getPerspectiveTransform() 必须是3×3矩阵
dsize tuple (width, height) 输出图像尺寸 若小于输入尺寸,会裁剪图像
flags int 插值方法: INTER_LINEAR(默认) INTER_NEAREST INTER_CUBIC 放大图像推荐 INTER_CUBIC
borderMode int 边界填充方式: BORDER_CONSTANT(默认) BORDER_REPLICATE 填充黑色区域时可指定 borderValue
borderValue scalar/tuple 边界填充值(如 (0, 255, 0) 表示绿色) 默认 0(黑色)

基本步骤

选择源点和目标点: 透视变换的关键是源图像中的四个点和目标图像中的四个点。你需要选择四个对应点(源图像和目标图像的四个 点),这些点通常是矩形的四个角。

计算透视变换矩阵: 使用 cv2.getPerspectiveTransform() 函数来计算变换矩阵,输入源图像四个点和目标图像四个点。

应用透视变换: 使用 cv2.warpPerspective() 函数将透视变换矩阵应用到源图像。
透视变换的应用场景

文档校正:对手机拍摄的书页、名片、票据等图像进行校正,使其恢复为标准矩形,便于后续 OCR(光学字符识别)处理。

车道检测:在自动驾驶系统中,将摄像头拍摄的道路图像透视变换为鸟瞰图,有助于车道线检测和车辆定位。

增强现实(AR):通过透视变换将虚拟图像投影到真实物体表面,实现虚实结合的效果。

图像拼接:在全景图制作过程中,对多个重叠图像进行透视变换,便于图像之间的无缝拼接。

python 复制代码
# 导入必要的库
import cv2
import numpy as np

# 读取图像文件
image = cv2.imread('./images/piao.png')

# 全局变量,用于存储鼠标点击的坐标点
points = []

# 鼠标回调函数
def mouse_callback(event, x, y, flags, param):
    global points
    # 检测鼠标左键点击事件
    if event == cv2.EVENT_LBUTTONDOWN:
        # 将坐标点添加到列表中
        points.append((x, y))
        # 在图像上绘制绿色实心圆标记点击位置(半径5像素)
        cv2.circle(image, (x, y), 5, (0, 255, 0), -1)
        # 更新显示图像
        cv2.imshow("Original", image)

        # 当收集到4个点后
        if len(points) == 4:
            # 将点转换为numpy数组(float32类型)
            pts1 = np.float32(points)
            print(pts1)  # 打印坐标点
            cv2.destroyAllWindows()  # 关闭所有窗口

# 显示原始图像
cv2.imshow("Original", image)   

# 设置鼠标回调函数,关联到"Original"窗口
cv2.setMouseCallback("Original", mouse_callback)

# 等待用户操作(0表示无限等待)
cv2.waitKey(0)

# 将收集到的点转换为numpy数组(float32类型)
pts1 = np.float32([list(i) for i in points])

# 定义目标点坐标(300x300的正方形)
pts2 = np.float32([[0, 0], [300, 0], [300, 300], [0, 300]])

# 计算透视变换矩阵(3x3矩阵)
M = cv2.getPerspectiveTransform(pts1, pts2)

# 应用透视变换,输出300x300的图像
dst = cv2.warpPerspective(image, M, (300, 300))

# 获取变换后图像的尺寸
rows, cols = dst.shape[:2]

# 创建旋转矩阵(以图像中心旋转90度)
M2 = cv2.getRotationMatrix2D((cols/2, rows/2), 90, 1)

# 应用旋转变换
res = cv2.warpAffine(dst, M2, (cols, rows))

# 显示最终结果
cv2.imshow("res", res)
cv2.waitKey(0)
cv2.destroyAllWindows()

相关推荐
zadyd1 小时前
vLLM Linux 双卡部署大模型服务器指南
linux·人工智能·python·机器学习·vllm
j_xxx404_1 小时前
Linux命名管道:跨进程通信实战指南|附源码
linux·运维·服务器·人工智能·ai
叼烟扛炮1 小时前
C++ 知识点08 类与对象
开发语言·c++·算法·类和对象
紫小米7 小时前
后端日志管理
python·fastapi
你不是我我7 小时前
【Java 开发日记】HTTP3 性能更好,为什么内网微服务依然多用 HTTP2?HTTP2 内网优势是什么?
java·开发语言·微服务
agicall.com7 小时前
座机通话双方语音分离技术解决方案详解
人工智能·语音识别·信创电话助手·座机语音转文字·固话座机录音转文字
AI机器学习算法7 小时前
《动手学深度学习PyTorch版》笔记
人工智能·学习·机器学习
Goboy8 小时前
「我的第一次移动端 AI 办公」TRAE SOLO 三端联动, 通勤路上就把活干了,这设计,老罗看了都想当场退役
人工智能·ai编程·trae
qq_452396238 小时前
第二十篇:《UI自动化测试的未来:AI驱动的智能测试与低代码平台》
人工智能·低代码·ui
tjl521314_218 小时前
04C++ 名称空间(Namespace)
开发语言·c++