# 如何使用OpenCV进行发票的透视变换和二值化处理
如何使用OpenCV进行发票的透视变换和二值化处理
引言
在自动化处理发票和其他文档时,图像预处理是一个关键步骤,它可以帮助提高OCR(光学字符识别)的准确性。透视变换用于校正图像中的透视失真,而二值化处理则可以简化图像,使其更适合OCR处理。本文将介绍如何使用OpenCV库进行这些操作。
环境准备
确保您的环境中安装了OpenCV库。如果尚未安装,可以通过以下命令安装:
pip install opencv-python
代码实现
以下是完整的代码实现,包括图像读取、透视变换、二值化处理和显示结果。
import numpy as np
import cv2def cv_show(name, img):"""简单的图像显示函数,用于显示图像窗口,参数name为窗口名称,img为要显示的图像"""cv2.imshow(name, img)cv2.waitKey(0)def order_points(pts):"""对四个点进行排序,以便于进行透视变换参数pts为四个检测到的点的坐标返回值rect为排序后的点的坐标"""rect = np.zeros((4, 2), dtype="float32")s = pts.sum(axis=1) # 对pts矩阵的每一行进行求和操作(x+y)rect[0] = pts[np.argmin(s)] # 选择坐标和最小的点为左上角rect[2] = pts[np.argmax(s)] # 选择坐标和最大的点为右下角diff = np.diff(pts, axis=1) # 对pts矩阵的每一行进行求差操作(y-x)rect[1] = pts[np.argmin(diff)] # 选择差异最小的点为右上角rect[3] = pts[np.argmax(diff)] # 选择差异最大的点为左下角return rectdef four_point_transform(image, pts):"""根据四个点进行透视变换参数image为原始图像,pts为四个检测到的点的坐标返回值warped为变换后的图像"""rect = order_points(pts)(tl, tr, br, bl) = rectwidthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))maxWidth = max(int(widthA), int(widthB))heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 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 warpeddef resize(image, width=None, height=None, inter=cv2.INTER_AREA):"""调整图像大小参数image为原始图像,width和height为调整后的宽度和高度,inter为插值方法返回值resized为调整大小后的图像"""dim = None(h, w) = image.shape[:2]if width is None and height is None:return imageif 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# 读取输入图像
image = cv2.imread('fapiao.jpg')
cv_show('image', image)# 图片过大,进行缩小处理
ratio = image.shape[0] / 500.0 # 计算缩小比率
orig = image.copy()
image = resize(orig, height=500) # 缩小图像
cv_show('1', image)print('STEP 1: 轮廓检测')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转换为灰度图
edged = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 二值化
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[-2]
image_contours = cv2.drawContours(image.copy(), cnts, -1, (0, 0, 255), 1)
cv_show("image_contours", image_contours)print("STEP 2:获取最大轮廓")
screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0] # 获取面积最大的轮廓
peri = cv2.arcLength(screenCnt, True) # 计算轮廓周长
screenCnt = cv2.approxPolyDP(screenCnt, 0.05 * peri, True) # 轮廓近似
print(screenCnt.shape)
image_contours = cv2.drawContours(image.copy(), [screenCnt], -1, (0, 255, 0), 2)
cv_show("image_contours", image_contours)
cv2.waitKey(0)# 透视变换
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
cv2.imwrite('invoice_new.jpg', warped)
cv2.namedWindow('xx', cv2.WINDOW_NORMAL)
cv2.imshow("xx", warped)
cv2.waitKey(0)# 二值处理
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
ref = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('ref', ref)kernel = np.ones((2, 2), np.uint8) # 设置kernel大小
ref_new = cv2.morphologyEx(ref, cv2.MORPH_CLOSE, kernel) # 闭运算
ref_new = resize(ref_new.copy(), width=500)
cv_show('ref_new', ref_new)
rotated_image = cv2.rotate(ref_new, cv2.ROTATE_90_COUNTERCLOCKWISE)
cv2.imshow("result", rotated_image)
cv2.waitKey(0)
运行结果
步骤解析
- 图像读取和缩小处理:首先读取图像,并根据需要进行缩小处理。
- 轮廓检测:将图像转换为灰度图,然后进行二值化处理,最后检测轮廓。
- 获取最大轮廓:从检测到的轮廓中找到面积最大的轮廓,并进行多边形近似。
- 透视变换:对原始图像进行透视变换,以消除透视失真。
- 二值化处理:对变换后的图像进行二值化处理,并进行形态学操作以去除噪声。
- 旋转处理:根据需要对图像进行旋转处理。
结论
通过这篇文章,您学会了如何使用OpenCV进行发票的透视变换和二值化处理。这些步骤对于自动化处理发票和其他文档非常重要,可以显著提高OCR的准确性。希望这篇文章对您有所帮助!如果您有任何问题或建议,请在评论区留言。