一、图像平移
"平移操作是通过一个平移矩阵来实现的。这个矩阵是一个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_NEAREST 、INTER_CUBIC 。 |
borderMode |
边界模式 | 可选参数,处理边界像素的方式(如 cv2.BORDER_CONSTANT 、BORDER_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 |
使用规则:
尺寸优先级 :
dsize
参数优先于fx/fy
互斥规则:
当指定
dsize
时,fx
和fy
被忽略当
dsize=(0,0)
时,通过fx
和fy
计算尺寸
插值方法选择建议:
场景 推荐方法 特点 图像缩小 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()