OpenCV发票图像处理:轮廓检测、透视变换与图像预处理

在实际的计算机视觉项目中,拍摄得到的发票图片通常存在尺寸过大、角度倾斜、背景复杂等问题。如果直接进行文字识别,容易影响识别效果。因此,在进行OCR等操作之前,通常需要先对图片进行预处理。这段代码以发票图片为例,主要使用了图像缩放、灰度化、二值化、轮廓检测、透视变换、腐蚀和旋转等操作,最终得到一张更加规整的发票图片。

一、辅助函数与图像缩放

代码首先定义了cv_show()函数,用于快速显示图片:

python 复制代码
def cv_show(name, img):
    """
    快速显示图像的函数
    Args:
        name: 窗口名称
        img: 要显示的图像
    """
    cv2.imshow(name, img)  # 显示图像
    cv2.waitKey(0)         # 等待键盘输入,0表示无限等待

其中cv2.imshow()负责显示图像,cv2.waitKey(0)表示等待键盘输入。将这两句封装起来后,后面只需要调用cv_show()即可。

order_points()函数用于对4个坐标点进行排序,将它们按照左上、右上、右下、左下的顺序排列。这里使用了NumPy中的sum()diff()

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)

假设4个点的坐标为(x,y),那么通过计算x+y可以找到左上和右下两个点,通过计算y-x可以找到右上和左下两个点。这样就可以统一4个角点的顺序,为后面的透视变换做准备。

four_point_transform()函数主要负责透视变换。首先计算发票上下边和左右边的长度,然后确定变换后的宽度和高度,最后通过:

M = cv2.getPerspectiveTransform(rect,dst)

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

完成透视变换。透视变换可以理解为把一张倾斜拍摄的发票"拉正",让发票恢复成接近正面拍摄的效果。

另外,代码中的resize()函数用于调整图片尺寸,同时尽量保持原始宽高比例。例如:

image = resize(orig,height=500)

表示将图片高度调整为500,宽度根据原来的比例自动计算。对于尺寸较大的图片,先进行缩小可以减少后续轮廓检测的计算量。

二、轮廓检测与发票轮廓获取

读取图片之后,代码首先记录缩放比例:

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

ratio = image.shape0/500.0

orig = image.copy()

image = resize(orig,height=500)

这里的ratio非常重要。因为后面的轮廓检测是在缩小后的图片上进行的,而最终透视变换需要使用原始图片,所以需要通过ratio把缩小图片中的坐标恢复到原图。

接下来进行灰度化:

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

彩色图像包含B、G、R三个通道,而轮廓检测通常不需要颜色信息,因此先转换成灰度图,可以降低数据量,同时方便后续处理。

然后使用OTSU方法进行二值化:

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

二值化的作用是将图像转换成主要由黑色和白色组成的图像。THRESH_OTSU可以自动寻找一个合适的阈值,因此不需要手动指定具体的阈值。

得到二值图后,通过findContours()寻找轮廓:

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

轮廓可以理解为图像中物体的边界。发票通常是图片中面积比较大的矩形区域,因此可以先找到所有轮廓,再按照面积进行排序:

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

cv2.contourArea()用于计算轮廓面积,reverse=True表示按照从大到小排序,最终取面积最大的轮廓。

得到最大轮廓之后,计算轮廓周长:

peri = cv2.arcLength(screenCnt,True)

然后使用:

复制代码
screenCnt = cv2.approxPolyDP(screenCnt,0.05 * peri,True)

进行多边形近似。原始轮廓可能包含很多点,而发票本身通常接近一个四边形,因此可以通过多边形近似减少轮廓点。如果最终得到4个点,那么这4个点基本上就是发票的四个角。

三、透视变换

得到发票四个角点后,就可以进行透视变换:

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

这里的reshape(4,2)表示将轮廓重新整理成4组二维坐标。由于之前的轮廓是在缩小后的图片上获取的,所以需要乘以ratio,将坐标转换回原始图片中的位置。

透视变换主要解决的是拍摄角度导致的图像变形问题

例如实际拍摄的发票可能是:

复制代码

经过透视变换后,可以变成:

复制代码

这样可以让后续的文字识别更加方便。

变换后的图片通过:

cv2.imwrite('invoice_new.jpg',warped)

保存下来。cv2.imwrite()的作用就是将图像写入指定文件,第一个参数是保存的文件名,第二个参数是需要保存的图像。

四、二值化、腐蚀与旋转

透视变换完成后,得到的是一张比较规整的发票图片。接下来再次进行灰度化:

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

然后进行OTSU二值化:

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

经过二值化后,文字和背景之间的区别更加明显,有利于后面的文字处理。

然后将图片宽度调整到900:

ref = resize(ref,width=900)

接着创建一个2×2的卷积核:

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

并进行腐蚀操作:

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

腐蚀是OpenCV形态学处理中的一种操作,可以让图像中的白色区域缩小。它常用于去除一些细小的白色噪声,也可以调整文字和线条的形态。在不同的图像中,腐蚀效果会受到卷积核大小和迭代次数的影响。

最后将图片逆时针旋转90度:

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

这样可以根据实际发票的方向调整最终图片的显示方向。

五、整个程序的处理流程

把整段代码串起来,可以得到一个比较完整的发票图像预处理流程:

读取发票图片

缩小图片

灰度化

OTSU二值化

查找所有轮廓

获取最大轮廓

多边形近似

获取发票四个角点

透视变换

得到拉正后的发票

灰度化

二值化

调整图片大小

腐蚀

旋转

得到最终结果

其中比较重要的函数有:

cv2.cvtColor() → 颜色空间转换

cv2.threshold() → 图像二值化

cv2.findContours() → 查找轮廓

cv2.contourArea() → 计算轮廓面积

cv2.arcLength() → 计算轮廓周长

cv2.approxPolyDP() → 多边形近似

cv2.getPerspectiveTransform() → 获取透视变换矩阵

cv2.warpPerspective() → 执行透视变换

cv2.erode() → 腐蚀

cv2.rotate() → 图像旋转

cv2.imwrite() → 保存图片

六、总结

这段代码实际上完成了一套比较典型的票据图像预处理流程。首先通过缩放降低图片尺寸,然后利用灰度化和二值化突出图像中的轮廓,通过轮廓面积找到发票区域,再利用多边形近似获取发票的四个角点。得到角点后,通过透视变换将倾斜的发票拉正,最后再进行二值化、腐蚀和旋转,为后续的OCR文字识别提供更加规整的图片。

相关推荐
clorinda1 小时前
OpenCV图像增强基础——图像金字塔、直方图与特征提取
人工智能·opencv·计算机视觉
这张生成的图像能检测吗2 小时前
(论文速读)MANTIS:时间序列分类的轻量级基础模型
人工智能·时序模型·分类模型
u0103055272 小时前
AI Agent加速安卓应用快速落地
人工智能·新浪微博
angered2 小时前
「AI 应用 / AI Agent」行业日报 · 2026-08-21
人工智能
李昊哲小课2 小时前
大模型应用开发课程 —— 项目 09~12 完整教程
大数据·人工智能·大模型
xierui1231232 小时前
AI Agent 隐私架构:本地化重点为什么是登录态与执行权限
java·人工智能·网络安全·架构
u0103055272 小时前
昇腾AI赋能安卓智能助手
人工智能·笔记
回眸&啤酒鸭2 小时前
【回眸】Grok 4.6 核心能力落地与实战应用指南
大数据·人工智能
冬奇Lab2 小时前
Code Agent 解剖(07):外部工具怎么接进来?MCP 集成是怎么做的?
人工智能