《Opencv》图像的透视变换--处理发票

embedded/2025/1/25 3:44:23/

目录

1. 引言

2. 准备工作

3. 图像预处理

4. 轮廓检测

5. 获取最大轮廓

6. 透视变换

7. 二值化处理

8. 结果展示

9、完整代码

 10、结果展示

(1)、原图

(2)、处理后的图

11. 结论


计算机视觉领域,透视变换是一种常用的技术,用于将图像从一个视角转换到另一个视角。透视变换在图像处理中有着广泛的应用,例如在文档扫描、车牌识别、以及本文将要介绍的发票处理中。本文将详细介绍如何使用Python和OpenCV库对发票图像进行透视变换,并对其进行后续处理。

1. 引言

在实际应用中,我们经常会遇到需要从图像中提取特定区域的需求。例如,在处理发票时,我们可能需要将发票从背景中提取出来,并将其转换为一个标准的矩形图像,以便后续的OCR(光学字符识别)处理。透视变换正是实现这一目标的关键技术。

2. 准备工作

在开始之前,我们需要安装并导入必要的Python库:

import numpy as np
import cv2

3. 图像预处理

首先,我们需要加载并预处理图像。为了便于处理,我们将图像的高度调整为500像素,并保持其宽高比不变。

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):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 resizedimg = cv2.imread('./images/fapiao.jpg')
ratio = img.shape[0] / 500.0
orig = img.copy()
img = resize(orig, height=500)

4. 轮廓检测

接下来,我们需要检测图像中的轮廓。首先将图像转换为灰度图,然后使用二值化处理来突出边缘。

gray = cv2.cvtColor(img, 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]
img_contours = cv2.drawContours(img.copy(), cnts, -1, (0, 0, 255), 1)

5. 获取最大轮廓

我们假设发票是图像中最大的轮廓,因此我们可以通过计算轮廓的面积来找到最大的轮廓。

screenCnt = sorted(cnts, key=cv2.contourArea, reverse=True)[0]
peri = cv2.arcLength(screenCnt, True)
screenCnt = cv2.approxPolyDP(screenCnt, 0.02 * peri, True)

6. 透视变换

找到发票的轮廓后,我们需要对其进行透视变换,将其转换为一个标准的矩形图像。

def four_point_transform(image, pts):rect = order_points(pts)(tl, tr, br, bl) = rectwidthA = distance(br, bl)widthB = distance(tr, tl)maxWidth = max(int(widthA), int(widthB))hightA = distance(tl, bl)hightB = distance(tr, br)maxHeight = max(int(hightA), int(hightB))dst = np.array([[0, 0], [maxWidth, 0], [maxWidth, maxHeight], [0, maxHeight]], dtype="float32")M = cv2.getPerspectiveTransform(rect, dst)warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))return warpedwarped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
warped = cv2.rotate(warped, cv2.ROTATE_90_COUNTERCLOCKWISE)

7. 二值化处理

为了便于后续的OCR处理,我们需要对透视变换后的图像进行二值化处理。

warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
warped_th = cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
kernel = np.ones((2, 2), np.uint8)
warped_th = cv2.erode(warped_th, kernel, iterations=2)
warped_th = cv2.dilate(warped_th, kernel, iterations=1)
warped_th = resize(warped_th, height=800)

8. 结果展示

最后,我们将处理后的图像显示出来,并保存结果。

cv2.namedWindow('xx', cv2.WINDOW_NORMAL)
cv2.imshow("xx", warped)
cv2.waitKey(0)b = np.zeros((800, 544), 'uint8')
r = np.zeros((800, 544), 'uint8')
warped_th[warped_th == 0] = 100
AA = cv2.merge((b, warped_th, r))
cv_show('AA', AA)

9、完整代码

import numpy as np
import cv2# 变换图片大小的函数
def resize(image, width=None, height=None, inter=cv2.INTER_AREA):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)#参数interpolation指定了在图像大小调整过程中如何处理像素插值的方法。cv2.INTER_AREA具体意味着使用面积插值方法。return resized
# 定义显示图片函数
def cv_show(name, image):cv2.imshow(name, image)cv2.waitKey(0)
# 计算欧氏距离
def distance(p1,p2):return np.sqrt(((p1[0] - p2[0]) ** 2) + ((p1[1] - p2[1]) ** 2))
# 确定原图四个顶点(排序)
def order_points(pts):rect = np.zeros((4,2),dtype="float32")s = pts.sum(axis=1)rect[0] = pts[np.argmin(s)]rect[2] = pts[np.argmax(s)]d = np.diff(pts,axis=1)rect[1] = pts[np.argmin(d)]rect[3] = pts[np.argmax(d)]return rectdef four_point_transform(image,pts):rect = order_points(pts)(tl,tr,br,bl) = rect# 计算w,hwidthA = distance(br,bl)widthB = distance(tr,tl)maxWidth = max(int(widthA),int(widthB))hightA = distance(tl,bl)hightB = distance(tr,br)maxHeight = max(int(hightA),int(hightB))dst = np.array([[0,0],[maxWidth,0],[maxWidth,maxHeight],[0,maxHeight]],dtype="float32")M = cv2.getPerspectiveTransform(rect,dst)warped = cv2.warpPerspective(image,M,(maxWidth,maxHeight))return warpedimg = cv2.imread('./images/fapiao.jpg')
cv_show('image',img)ratio = img.shape[0] / 500.0
orig = img.copy()
img = resize(orig,height=500)
cv_show('1',img)# 轮廓检测
gray = cv2.cvtColor(img,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]
img_contours = cv2.drawContours(img.copy(),cnts,-1,(0,0,255),1)
cv_show('img_contours',img_contours)# 获取最大轮廓
screenCnt = sorted(cnts,key=cv2.contourArea,reverse=True)[0]
# 周长
peri = cv2.arcLength(screenCnt,True)
# 轮廓近似
screenCnt = cv2.approxPolyDP(screenCnt,0.02*peri,True)
print(screenCnt.shape)
img_contour = cv2.drawContours(img.copy(),[screenCnt],-1,(0,255,0),2)
cv_show('img_contour',img_contour)# 透视变换
warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)
warped = cv2.rotate(warped,cv2.ROTATE_90_COUNTERCLOCKWISE)
# cv2.imwrite('image/invoice_new.jpg', warped)
cv2.namedWindow('xx',cv2.WINDOW_NORMAL)
cv2.imshow("xx", warped)
cv2.waitKey(0)# 二值化处理
warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
warped_th = cv2.threshold(warped,0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
kernel = np.ones((2,2),np.uint8)
# warped_th = cv2.morphologyEx(warped_th,cv2.MORPH_CLOSE,kernel)
warped_th = cv2.erode(warped_th,kernel,iterations=2)
warped_th = cv2.dilate(warped_th,kernel,iterations=1)warped_th = resize(warped_th,height=800)
cv_show('warped_th',warped_th)# 800*544
b = np.zeros((800,544),'uint8')
r = np.zeros((800,544),'uint8')
# b[b==0]=255
# r[r==0]=255
warped_th[warped_th==0] = 100
AA = cv2.merge((b,warped_th,r))
cv_show('AA',AA)

 10、结果展示

(1)、原图

(2)、处理后的图

 

11. 结论

通过本文的介绍,我们学习了如何使用Python和OpenCV对发票图像进行透视变换。透视变换不仅可以帮助我们提取图像中的特定区域,还可以为后续的图像处理任务(如OCR)提供标准化的输入。


http://www.ppmy.cn/embedded/156740.html

相关文章

c语言贪吃蛇(极简版,基本能玩)

c语言贪吃蛇 整体逻辑 界面绘制定义结构体以及结构体的初始化 2.1 一节变三节蛇的移动 3.1 监控键盘 3.2 蛇的移动食物 4.1 定义 4.2 初始化 4.3 食物的绘制食物的再生与身体增长、分数死亡与结束优化 7.1 getch()函数会返回两个数值,过滤第一个,留下第…

Vue3初学之Element Plus Dialog对话框,Message组件,MessageBox组件

Dialog的使用&#xff1a; 控制弹窗的显示和隐藏 <template><div><el-button click"dialogVisible true">打开弹窗</el-button><el-dialogv-model"dialogVisible"title"提示"width"30%":before-close&qu…

matlab绘图——彩色螺旋图

代码生成的图形是一个动态的彩色螺旋&#xff0c;展示了如何利用极坐标和颜色映射创建视觉吸引力强的图形。该图形可以用于数据可视化、艺术创作或数学演示&#xff0c;展示了 MATLAB 在图形处理方面的强大能力。通过调整 theta 和 r 的范围&#xff0c;可以创建出不同形状和复…

数据结构——实验八·学生管理系统

嗨~~欢迎来到Tubishu的博客&#x1f338;如果你也是一名在校大学生&#xff0c;正在寻找各种编程资源&#xff0c;那么你就来对地方啦&#x1f31f; Tubishu是一名计算机本科生&#xff0c;会不定期整理和分享学习中的优质资源&#xff0c;希望能为你的编程之路添砖加瓦⭐&…

RPC是什么?和HTTP区别?

RPC 是什么&#xff1f;HTTP 是什么&#xff1f; 作为一个程序员&#xff0c;假设我们需要从A电脑的进程发送一段数据到B电脑的进程&#xff0c;我们一般会在代码中使用 Socket 进行编程。 此时&#xff0c;可选性一般就是 TCP 和 UDP 二选一&#xff0c;由于 TCP 可靠、UDP 不…

GitCode 助力 AutoTable:共创 MyBatis 生态的自动表格管理新篇章

项目仓库https://gitcode.com/dromara/auto-table 解放双手&#xff0c;专注业务&#xff1a;MyBatis 生态的“自动表格”创新 AutoTable 是一款致力于为 MyBatis 生态赋予“自动表格”功能的创新插件。其核心理念是通过 Java 实体类自动生成和维护数据库的表结构&#xff0c…

汽车制造行业案例 | 发动机在制造品管理全解析(附解决方案模板)

目录 前言概述 业务背景 典型业务难题 智能制造解决思路 1.建立工序协同机制与动态调度系统 2.构建在制品全生命周期质量追溯平台 3.自定义搭建数字化智能生产计划 4.全方位设备预防性管理与应急管理 智能制造模板 前言概述 在制品管理是指对企业生产过程中处于加工、…

把网站程序数据上传到服务器的方法和注意事项

将网站程序数据上传到服务器是一个常见的网站开发和部署流程。主要涉及到FTP上传、FileZilla、rsync(在Linux下)、或其他相关的文件同步工具。以下是一般步骤和方法&#xff1a; 使用FTP&#xff1a; 1. 选择FTP客户端软件&#xff1a; - 常见的FTP客户端包括FileZilla(开源)、…