1 仿射变换与透视变换
1.1 仿射变换
之前在图像旋转实验中已经接触过仿射变换,仿射变换是一个二维坐标系到另一个二维坐标系的过程,在仿射变换中符合直线的平直性和平行性。
1.2 透视变换
透视变换是把一个图像投影到一个新的视平面的过程。在现实世界中,观察到的物体在人类视觉中都会受到透视效果的影响:近大远小。
1.3 透视变换矩阵
与仿射变换相同,透视变换也有对应的透视变换矩阵,在这个过程原始图像src中的点(x,y)通过透视变换被转换到到dst图像中的新坐标点(x',y')
代码运行步骤:
图片输入→坐标选取→获取透视变换矩阵→透视变换→插值方法→边缘填充→图片输出
原始图片:4.jpg
import cv2 # 导入OpenCV库,用于计算机视觉任务
import numpy as np # 导入NumPy库,用于数值计算和数组操作
import matplotlib.pyplot as plt
if __name__ == '__main__':
# 1. 图片输入
path = '4.jpg' # 定义图片路径
image_np = cv2.imread(path) # 读取图片,返回NumPy数组格式的图像数据
# 2. 坐标选取
# 左上、右上、左下、右下
points = [[171, 5], [271, 105], [27, 150], [127, 248]]
# 转换为np数组
pts1 = np.float32(points) # src的四个角点:将点列表转换为NumPy数组,数据类型为32位浮点数
print(pts1) # 打印点坐标
print(type(pts1)) # 打印数据类型
# 画红框,标记ROI区域
image_line = image_np.copy() # 创建原图的副本,避免修改原图
# 画四条线,标记出要校正的区域
cv2.line(
image_line, # 在哪个图像上画线
points[0], # 起点
points[1], # 终点
(0, 0, 255), # 颜色(B,G,R格式),这里是红色
2, # 线条粗细
cv2.LINE_AA # 抗锯齿线型,使线条更平滑
)
# 重复画线操作,连接其他点形成四边形
cv2.line(image_line, points[1], points[3], (0, 0, 255), 2, cv2.LINE_AA)
cv2.line(image_line, points[2], points[3], (0, 0, 255), 2, cv2.LINE_AA)
cv2.line(image_line, points[0], points[2], (0, 0, 255), 2, cv2.LINE_AA)
# 3. 获取透视变换矩阵
# 获得原图分辨率,这个原图分辨率是后面定义矫正后的图片分辨率大小。
# img_shape = image_np.shape # 获取图像形状(高度, 宽度, 通道数)
# print("原图分辨率:", img_shape)
img_shape = (260, 170, 3) # 可自行定义图像形状(高度, 宽度, 通道数)
# 定义目标点:左上、右上、左下、右下 - 对应整个图像的四个角
points = [[0, 0], [img_shape[1], 0], [0, img_shape[0]], [img_shape[1], img_shape[0]]]
print(points) # 打印目标点坐标
# 转换为np数组
pts2 = np.float32(points) # dst的四个角点:将目标点转换为NumPy数组
# 生成透视变换矩阵
M = cv2.getPerspectiveTransform(
pts1, # src的四个角点: 源图像的四个角点(要校正的区域)
pts2 # dst的四个角点: 源图像的四个角点(要校正的区域)
)
print(M) # 打印透视变换矩阵
# 4. 透视变换 + 5. 插值方法 + 6. 边缘填充
correct_image = cv2.warpPerspective(
image_np, # 原图
M, # 透视变换矩阵
(img_shape[1], img_shape[0]), # dst分辨率:输出图像尺寸(宽度, 高度)
cv2.INTER_LINEAR, # 插值方法:双线性插值,平衡速度和质量
cv2.BORDER_WRAP # 边缘填充:边缘像素环绕
)
# 使用matplotlib手动去看要截取的x,y的数组参数
q = plt.imread(path)
plt.imshow(q)
plt.axis('off') # 取消坐标轴显示
plt.show()
# 7. 图片输出
cv2.imshow('image_line', image_line) # 显示带有标记线的图像
cv2.imshow('correct_image', correct_image) # 显示校正后的图像
cv2.waitKey(0) # 等待键盘输入,0表示无限等待
cv2.imwrite('jz.png', correct_image)
运行结果: