|
传送带上的工件是斜的、快递单被拍成梯形、仪表盘在广角镜下桶形畸变——直接送进 OCR 或模板匹配,识别率会掉一大截。读完本文掌握 resize、仿射变换、旋转与透视矫正的用法。 --- 一、为什么需要几何变换 摄像头很难正对目标。PCB 在传送带上可能倾斜 15 度,文档扫描时被拍成梯形,广角镜头下桶形畸变让直线变弯。如果直接把这些图送进检测算法,坐标系是歪的,ROI 区域对不上,后面所有测量都会带偏。几何变换的目标就是把图像恢复到标准视角,让后续算法在统一的坐标系里工作。 几何变换解决的是图像坐标系不统一的问题,是检测和识别的前置步骤。 --- 二、几何变换的本质 所有几何变换都是像素重采样:原图每个像素坐标 (x, y) 经过变换矩阵映射到新位置 (x', y'),再用插值补齐缺失像素。 缩放:改变输出尺寸,配合插值控制平滑度。放大用 INTER_CUBIC,缩小用 INTER_AREA 仿射变换:保持直线平行性,能做平移、旋转、缩放、剪切,用 2×3 矩阵描述 透视变换:能处理梯形、斜拍等不平行情况,用 4 组对应点求解 3×3 单应矩阵 缩放和仿射用 2×3 矩阵,透视用 3×3 矩阵,两者本质都是坐标映射加插值。 --- 三、核心接口 接口名称 | 核心功能 | 关键参数 | 工业推荐取值 | | cv2.resize | 缩放图像 | dsize , interpolation | 放大用 INTER_CUBIC,缩小用 INTER_AREA | | cv2.warpAffine | 仿射变换 | M , dsize | 2×3 矩阵,dsize 等于输出尺寸 | | cv2.getRotationMatrix2D | 生成旋转矩阵 | center , angle, scale | 中心取图像中点,scale=0.8~1.0 | | cv2.getPerspectiveTransform | 求透视矩阵 | 4 组对应点 | 源点按顺序对应目标点 | | cv2.warpPerspective | 透视变换 | M , dsize | 输出尺寸等于目标矩形宽高 |
cv2.resize 缩放图像,dsize 是 (宽, 高) 不是 (高, 宽)。cv2.getRotationMatrix2D 生成旋转矩阵,angle 为正表示逆时针。cv2.getPerspectiveTransform 从 4 组源点和目标点计算 3×3 透视矩阵,工业上最常用的是在图像上标出目标区域的四个角点然后拉成矩形。 import cv2import numpy as npimport osdef main(): out_dir = "output/opencv_series" os.makedirs(out_dir, exist_ok=True) # 构造一张 400x400 的梯形图:模拟斜拍文档 img = np.ones((400, 400, 3), dtype=np.uint8) * 255 pts = np.array([[80, 60], [320, 50], [340, 350], [60, 340]], np.int32) cv2.fillPoly(img, [pts], (200, 200, 200)) cv2.polylines(img, [pts], True, (0, 0, 0), 2) cv2.imwrite(os.path.join(out_dir, "trapezoid_src.png"), img) # 缩放 resized = cv2.resize(img, (200, 200), interpolation=cv2.INTER_AREA) # 旋转 15 度 h, w = img.shape[:2] M_rot = cv2.getRotationMatrix2D((w // 2, h // 2), 15, 0.9) rotated = cv2.warpAffine(img, M_rot, (w, h), borderMode=cv2.BORDER_CONSTANT, borderValue=(255, 255, 255)) # 透视矫正:把梯形区域拉成 300x300 矩形 src_pts = np.float32([[80, 60], [320, 50], [340, 350], [60, 340]]) dst_pts = np.float32([[0, 0], [300, 0], [300, 300], [0, 300]]) M_persp = cv2.getPerspectiveTransform(src_pts, dst_pts) corrected = cv2.warpPerspective(img, M_persp, (300, 300)) cv2.imwrite(os.path.join(out_dir, "resized.png"), resized) cv2.imwrite(os.path.join(out_dir, "rotated.png"), rotated) cv2.imwrite(os.path.join(out_dir, "corrected.png"), corrected) print("几何变换完成,结果保存在", out_dir)if __name__ == "__main__": main()resize/warpAffine 处理平移旋转缩放,warpPerspective 处理梯形畸变。 --- 四、效果验证与场景选型 运行后得到三张结果图:resized.png 尺寸 200×200;rotated.png 逆时针旋转 15 度加白边填充;corrected.png 把梯形恢复为 300×300 矩形。 选型建议: 只统一分辨率 → resize,注意缩小用 INTER_AREA 只旋转平移 → warpAffine + getRotationMatrix2D 斜拍梯形畸变 → 必须用 warpPerspective 有桶形畸变 → 先 cv2.undistort 做相机标定校正,再做透视矫正 Jetson 嵌入式 → 用 cv2.cuda.warpPerspective 加速,参数与 CPU 版一致 按畸变类型选变换方法,旋转矫正优先于透视矫正。 --- 五、常见问题 坑 | 现象 | 解法 | resize 尺寸写反 | 输出图被压扁 | dsize 是 (宽, 高) | 旋转后黑边过多 | 四角大面积黑色 | 调小 scale 或扩大输出尺寸 | 透视矩阵顺序错 | 矫正后严重扭曲 | 保证 src_pts 与 dst_pts 一一对应 | 插值选错 | 缩小图出现摩尔纹 | 缩小用 INTER_AREA | 角点坐标精度不够 | 结果有锯齿 | 用 np.float32 传入角点 |
透视变换的 4 组角点顺序是头号踩坑点,错一个结果就全歪。 --- 六、总结 几何变换是工业视觉对齐的核心手段。按畸变类型分层处理:先标定去畸变,再透视矫正,最后旋转缩放对齐到标准模板。在产线上,通常把角点检测、矩阵计算、warp 三步封装成一个函数,输入原始图和模板尺寸,直接输出矫正后的 ROI。 分层处理是工业几何变换的最佳实践——先标定,再透视,最后仿射。 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |