opencv-图像透视转换

代码实现了一个典型的文档/物体轮廓检测与透视矫正流程:先找到图像中最大的四边形轮廓,然后通过透视变换把它"拉正",最后做二值化、去噪和旋转,方便后续识别或处理。

代码示例:


1. 辅助函数

1.1 cv_show(name, img)

def cv_show(name, img):

cv2.imshow(name, img)

cv2.waitKey(0)

  • 作用:封装 OpenCV 的显示函数,方便调试。

  • 知识点:cv2.imshow 显示窗口,cv2.waitKey(0) 等待任意按键后关闭/继续。

1.2 order_points(pts)

def order_points(pts):

rect = np.zeros((4,2), dtype="float32")

s = pts.sum(axis=1)

rect0 = ptsnp.argmin(s) # 左上

rect2 = ptsnp.argmax(s) # 右下

diff = np.diff(pts, axis=1)

rect1 = ptsnp.argmin(diff) # 右上

rect3 = ptsnp.argmax(diff) # 左下

return rect

  • 作用:将无序的 4 个角点按 左上、右上、右下、左下 的顺序排列。

  • 知识点:

    • 对于左上和右下:sum = x + y,左上角点 x+y 最小,右下角点 x+y 最大。

    • 对于右上和左下:diff = y - x(因为 np.diff 对每行做后一列减前一列),右上角点 y - x 最小(x 大 y 小),左下角点 y - x 最大(x 小 y 大)。

1.3 four_point_transform(image, pts)

def four_point_transform(image, pts):

rect = order_points(pts)

(tl, tr, br, bl) = rect

计算宽度

widthA = np.sqrt(((br0-bl0)**2)+((br1-bl1)**2))

widthB = np.sqrt(((tr0-tl0)**2)+((tr1-tl1)**2))

maxWidth = max(int(widthA), int(widthB))

计算高度

heightA = np.sqrt(((tr0-br0)**2)+((tr1-br1)**2))

heightB = np.sqrt(((tl0-bl0)**2)+((tl1-bl1)**2))

maxHeight = max(int(heightA), int(heightB))

目标点

dst = np.array(\[0,0,maxWidth-1,0,maxWidth-1,maxHeight-1,0,maxHeight-1], dtype="float32")

M = cv2.getPerspectiveTransform(rect, dst)

warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

return warped

  • 作用:根据 4 个源角点计算透视变换矩阵,将原图中的四边形区域矫正为矩形。

  • 知识点:

    • 欧氏距离计算两点距离,分别求上下边、左右边长度,取最大值作为目标矩形的宽和高。

    • cv2.getPerspectiveTransform(src, dst):根据 4 对点计算 3×3 透视变换矩阵。

    • cv2.warpPerspective(image, M, dsize):应用透视变换,输出尺寸为 (maxWidth, maxHeight)

    • 透视变换可以校正拍摄角度造成的变形,是文档扫描的核心步骤。

1.4 resize(image, width=None, height=None, inter=cv2.INTER_AREA)

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):

(h, w) = image.shape:2

if width is None and height is None:

return image

if width is None:

r = height / float(h)

dim = (int(w * r), height)

else:

r = width / float(w)

dim = (width, int(h * r))

resized = cv2.resize(image, dim, interpolation=inter)

return resized

  • 作用:等比缩放图像,指定宽度或高度之一即可。

  • 知识点:

    • cv2.resize 可以调整图像尺寸。

    • 插值方法 cv2.INTER_AREA 适合缩小图像,能更好地保留细节并减少锯齿。


2. 主流程

2.1 读取并缩放图像

image = cv2.imread('4.jpg')

ratio = image.shape0 / 500.0

orig = image.copy()

image = resize(orig, height=500)

  • 作用:读取原图,记录缩放比例 ratio,将图像等比缩放至高度 500 像素,便于后续处理(加快速度、减少噪声)。

  • 知识点:image.shape[0] 是高度,image.shape[1] 是宽度。

2.2 灰度化 + Otsu 二值化

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

edged = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)1

  • 作用:转为灰度图,然后用 Otsu 自动阈值得到二值图(前景为白色,背景为黑色)。

  • 知识点:

    • cv2.cvtColor:颜色空间转换,COLOR_BGR2GRAY 表示 BGR 转灰度。

    • cv2.threshold:固定/自动阈值二值化。这里 THRESH_OTSU 自动计算最优阈值,使前景和背景的类间方差最大。

    • 注意:变量名 edged 虽然叫 "edged",但这里其实不是边缘检测(如 Canny),而是二值图。后面 findContours 就是在这个二值图上找轮廓。

2.3 轮廓检测与绘制

cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)-2

image_contours = cv2.drawContours(image.copy(), cnts, -1, (0,255,0), 1)

  • 作用:在二值图中找出所有外部轮廓,并画在原图上显示。

  • 知识点:

    • cv2.findContours

      • 第一个参数是二值图像(非零像素被视为前景)。

      • RETR_EXTERNAL:只提取最外层轮廓,忽略内部孔洞。

      • CHAIN_APPROX_SIMPLE:压缩水平、垂直、对角线段,只保留端点,减少存储量。

    • 不同 OpenCV 版本返回值的数量不同,OpenCV 3/4 返回 (image, contours, hierarchy),所以用 [-2]contours

    • cv2.drawContours:可以绘制多条轮廓,-1 表示绘制所有轮廓。

2.4 获取最大轮廓并进行多边形近似

screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)0

peri = cv2.arcLength(screenCnt, True)

screenCnt = cv2.approxPolyDP(screenCnt, 0.05*peri, True)

  • 作用:选择面积最大的轮廓(假设它是目标文档),计算其周长,然后用 Douglas-Peucker 算法近似为多边形(通常得到四边形)。

  • 知识点:

    • cv2.contourArea:计算轮廓面积。

    • cv2.arcLength:计算轮廓周长,True 表示闭合曲线。

    • cv2.approxPolyDP:多边形近似,epsilon=0.05*peri 是近似精度,值越大形状越简单。

    • 这里假设最大轮廓就是目标文档,如果图像中有其他更大的轮廓(如背景边框),会出错。

2.5 透视变换矫正

warped = four_point_transform(orig, screenCnt.reshape(4,2)*ratio)

  • 作用:将轮廓的 4 个角点乘以 ratio 还原到原始图像尺寸,然后对原图进行透视矫正。

  • 知识点:

    • 因为之前的轮廓是在缩放后的图像上检测的,坐标需要乘 ratio 才能对应到原图。

    • screenCnt 形状通常是 (N,1,2)reshape(4,2) 变成 (4,2) 方便处理。

2.6 再次二值化与缩放

warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)

ref = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)1

ref = resize(ref, width=900)

  • 作用:将矫正后的彩色图转为灰度图,再次 Otsu 二值化,使文字/内容更清晰,然后等比缩放至宽度 900。

  • 知识点:二次二值化可以进一步分离前景和背景,便于后续处理。

2.7 形态学腐蚀

kernel = np.ones((2,2), np.uint8)

ref_new = cv2.erode(ref, kernel, iterations=1)

  • 作用:用 2×2 的矩形结构元素对二值图进行一次腐蚀操作。

  • 知识点:

    • cv2.erode:腐蚀操作,可以去除小的白色噪点、断开细微连接。

    • kernel 是结构元素,决定腐蚀的邻域形状和大小。

    • iterations=1 表示腐蚀一次。

2.8 旋转图像

rotated_image = cv2.rotate(ref_new, cv2.ROTATE_90_COUNTERCLOCKWISE)

cv_show('rotated_image', rotated_image)

  • 作用:将图像逆时针旋转 90 度并显示。

  • 知识点:cv2.rotate 是固定角度旋转,比仿射变换更简单。常用参数:

    • ROTATE_90_CLOCKWISE:顺时针 90°

    • ROTATE_90_COUNTERCLOCKWISE:逆时针 90°

    • ROTATE_180:旋转 180°


3. 主要知识点总结

操作 知识点 OpenCV 函数
缩放 等比缩放、插值方法 cv2.resize
灰度化 BGR → Gray cv2.cvtColor
二值化 Otsu 自动阈值 cv2.threshold + THRESH_OTSU
轮廓检测 只找外部轮廓、压缩存储 cv2.findContours
轮廓属性 面积、周长 cv2.contourAreacv2.arcLength
轮廓近似 Douglas-Peucker 算法 cv2.approxPolyDP
透视变换 四点矫正、视角校正 cv2.getPerspectiveTransformcv2.warpPerspective
形态学操作 腐蚀去噪 cv2.erode
旋转 固定角度旋转 cv2.rotate

4. 注意事项

  1. cv2.findContours 版本差异 :OpenCV 3/4 返回 3 个值,用 [-2] 取轮廓;OpenCV 2 返回 2 个值,需调整。

  2. 最大轮廓假设:代码默认最大轮廓是目标文档,如果图像中有更大的干扰轮廓,结果会错误。

  3. 多边形近似点数approxPolyDP 可能得到多于或少于 4 个点,若点数不是 4,four_point_transform 会报错。实际应用中应检查 len(screenCnt) == 4

  4. Otsu 的适用性:Otsu 适合直方图双峰明显的图像,如果光照不均或前景背景差异小,二值化效果会差。

  5. 腐蚀结构元素:结构元素太小(2×2)去噪能力有限,太大又会损伤文字笔画,需根据图像调整。

  6. 缩放比例还原 :注意 ratio 的计算基于高度缩放,若之后也做了宽度缩放则可能不适用,但这里缩放函数保证等比,所以没问题。

相关推荐
aneasystone本尊1 小时前
学习大模型推理的分词:从文本到 Token
人工智能
牧羊人.3331 小时前
计算机视觉基础 第 11 章| 特征检测与特征匹配
图像处理·人工智能·opencv·计算机视觉
艾莉丝努力练剑1 小时前
【AI大模型接入SDK】项目的数据结构设计
数据结构·人工智能·大模型·sdk·文件系统·岗位
白猫不黑1 小时前
AI Agent自动化渗透测试实战:从原理到红队实践
运维·人工智能·web安全·网络安全·信息安全·渗透测试·自动化
sel_91 小时前
【Pytorch】PyTorch 深度学习框架详解:从安装到实战
人工智能·pytorch·深度学习·算法·语言模型
veminhe1 小时前
使用neo4j构建知识图谱
人工智能·知识图谱·neo4j
Java后端的Ai之路1 小时前
01、Python - 设计模式介绍
java·人工智能·python·设计模式·通用
wujian83111 小时前
【腾讯元宝手机版生成的表格怎么复制下来】?试试 [ AI 导出鸭 ] 的“格式网关”
人工智能·ai·chatgpt·智能手机·ai导出鸭
zzzll11111 小时前
大模型技术原理与应用实践
java·数据库·人工智能