当前位置: 首页 > ds >正文

# 如何使用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)

运行结果

在这里插入图片描述
在这里插入图片描述

步骤解析

  1. 图像读取和缩小处理:首先读取图像,并根据需要进行缩小处理。
  2. 轮廓检测:将图像转换为灰度图,然后进行二值化处理,最后检测轮廓。
  3. 获取最大轮廓:从检测到的轮廓中找到面积最大的轮廓,并进行多边形近似。
  4. 透视变换:对原始图像进行透视变换,以消除透视失真。
  5. 二值化处理:对变换后的图像进行二值化处理,并进行形态学操作以去除噪声。
  6. 旋转处理:根据需要对图像进行旋转处理。

结论

通过这篇文章,您学会了如何使用OpenCV进行发票的透视变换和二值化处理。这些步骤对于自动化处理发票和其他文档非常重要,可以显著提高OCR的准确性。希望这篇文章对您有所帮助!如果您有任何问题或建议,请在评论区留言。

http://www.xdnf.cn/news/4765.html

相关文章:

  • EasyRTC嵌入式音视频通话SDK驱动智能硬件音视频应用新发展
  • 集成变压器的网口的PCB设计
  • 【MySQL】存储引擎 - MEMORY详解
  • 【JS逆向基础】前端基础-HTML与CSS
  • 初学者的AI智能体课程:构建AI智能体的十堂课
  • SpringBoot 讯飞星火AI WebFlux流式接口返回 异步返回 对接AI大模型 人工智能接口返回
  • oracle 对一个字段的数据做排序 :值的依次排序为.“思考”->“asd”->“三点“
  • MySQL 8.0 OCP 英文题库解析(一)
  • Web开发-JavaEE应用SpringBoot栈ActuatorSwaggerHeapDump提取自动化
  • 【Bluedroid】 HID 设备应用注册与主机服务禁用流程源码解析
  • SpringBoot项目接入DeepSeek
  • 「Mac畅玩AIGC与多模态24」开发篇20 - 多语言输出工作流示例
  • 17.Java 注解与实例
  • C++回顾 Day4
  • 【Bootstrap V4系列】学习入门教程之 组件-轮播(Carousel)高级用法
  • 基于供热企业业务梳理的智能化赋能方案
  • 易境通散货拼柜系统:如何让拼箱货代协作效率翻倍?
  • 编程日志4.28
  • python23-函数返回值和参数处理,变量作用域
  • 记录学习的第三十五天
  • 2025-05-08-如何在一次 cmd 会话中批量设置多个 API key?
  • 英文论文查重笔记
  • 用3D slicer 去掉影像中的干扰体素而还原干净影像(脱敏切脸处理同)
  • 按拼音首字母进行排序组成新的数组(vue)
  • 强人工智能是否会诞生于现在的AI之中
  • 第二章 MySql
  • lc3341. 到达最后一个房间的最少时间 Ⅰ 算法解析
  • Red Hat linux环境openssh升级到openssh-10.0p1
  • FileInputStream
  • 日语学习-日语知识点小记-构建基础-JLPT-N4阶段(15):何と どういう