opencv学习:通过图像透视进行发票识别完整代码流程

server/2024/10/16 0:19:25/

概念:

        使用OpenCV库实现图像的透视变换处理,以矫正图像中的透视失真。通过本实验,学习者将掌握图像处理的基本操作,包括图像的读取、显示、大小调整、灰度转换、二值化、轮廓检测、轮廓近似以及透视变换。

步骤:

1. 导入库

导入必要的Python库,包括OpenCV和NumPy。

import numpy as np
import cv2

2. 定义函数

定义几个函数来处理图像的不同步骤。

cv_show(name, img)
  • 显示图像的函数,接受窗口名称和图像作为参数。
    def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)
order_points(pts)
  • 对四个点进行排序,确保它们按照左上、右上、右下、左下的顺序。
    def order_points(pts):rect = np.zeros((4,2),dtype='float32')   # 创建一个4x2的数组,指定了数组中元素的数据类型为32位浮点数# 按顺序找到对应坐标0123分别是左上、右上、右下、左下s = pts.sum(axis=1)   # 对pts矩阵的每一行进行求和操作rect[0] = pts[np.argmin(s)]#左上角的点rect[2] = pts[np.argmax(s)]#右下角的点diff = np.diff(pts,axis=1)   # 对pts矩阵的每一行进行差值rect[1] = pts[np.argmin(diff)]#右上角的点rect[3] = pts[np.argmax(diff)]#左下角的点return rect
four_point_transform(image, pts)
  • 根据四个点进行图像的透视变换。
    def four_point_transform(image,pts):# 获取输入坐标点rect = order_points(pts)(tl,tr,br,bl) = rect#tl 是左上角点,tr 是右上角点,br 是右下角点,bl 是左下角点。# 计算两个可能的宽度,取这两个宽度的最大值作为新图像的宽度。widthA = 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')# 图像透视变换 cv2.getPerspectiveTransform(src,dst[,solveMethod])→ MP获得转换之间的关系# cy2.warpPerspective(src, Mp, dsizel, dstl, flagsl, borderModel, borderValue]]1])- dst# #参数说明:# src:变换前图像四边形顶点坐标/第2个是原图# MP:透视变换矩阵,3行3列# dsize:输出图像的大小,二元元组(width,heiqht)M = cv2.getPerspectiveTransform(rect,dst)#计算透视变换矩阵 M,它描述了如何将原始图像中的点映射到目标坐标。warped = cv2.warpPerspective(image,M,(maxWidth,maxHeight))#透视变换# 返回变换后的结果return warped
resize(image, width=None, height=None, inter=cv2.INTER_AREA)
  • 调整图像大小的函数,接受图像、宽度、高度和插值方法作为参数。
    #用于调整图像的大小。
    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))#根据计算出的尺寸 dim 调整图像大小。resized=cv2.resize(image,dim,interpolation=inter)     # 默认为cV2.INTER_AREA,即面积插值,适用于缩放图像。return resized

3. 读取和显示原始图像

读取名为fapiao.jpg的发票图像,并显示。

# 读取输入
image = cv2.imread('fapiao.jpg')
cv_show('image',image)

4. 图像缩小处理

将图像缩小到一定高度(例如500像素),并显示缩小后的图像,以便于处理。

# 图片过大,进行缩小处理
ratio = image.shape[0] / 500.0  # 计算缩小比率
orig = image.copy()
image = resize(orig, height=500)
cv_show('1',image)

5. 轮廓检测

将图像转换为灰度图,进行二值化处理,并检测图像轮廓。

# 轮廓检测
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)[1]
#绘制轮廓
image_contours = cv2.drawContours(image.copy(),cnts,-1,(0,0,255),1)
cv_show('image_contours',image_contours)

6. 获取最大轮廓

找到面积最大的轮廓,并进行轮廓近似。

print('step 2 :获取最大轮廓')
#获取最大轮廓
screenCnt = sorted(cnts,key = cv2.contourArea,reverse=True)[0]   # 获取面积最大的轮廓
#计算轮廓周长
peri = cv2.arcLength(screenCnt,True)   # 计算轮廓周长
#轮廓近似
screenCnt = cv2.approxPolyDP(screenCnt,0.02*peri,True)  # 轮廓近似
#绘制近似轮廓
image_contour = cv2.drawContours(image.copy(),[screenCnt],-1,(0,255,0),2)cv2.imshow('image_contour',image_contour)
cv2.waitKey(0)

7. 透视变换

使用近似后的轮廓点进行透视变换,矫正发票图像的透视失真。

# 透视变换
warped = four_point_transform(orig,screenCnt.reshape(4,2)*ratio)

8. 显示和保存结果

显示透视变换后的图像,并将其保存为新文件。

cv2.imwrite('invoice_new.jpg',warped)
cv2.namedWindow('xx',cv2.WINDOW_NORMAL)
cv2.imshow('xx',warped)
cv2.waitKey(0)

9.运用形态学变换图像

形态学闭运算使图像更加清晰

a=cv2.imread('invoice_new.jpg')
a=cv2.cvtColor(a,cv2.COLOR_BGR2GRAY)
a=cv2.threshold(a,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
a=cv2.resize(a,(800,600))
a=np.rot90(a,1)kernel = np.ones((1,1), np.uint8)c=cv2.morphologyEx(a,cv2.MORPH_CLOSE,kernel)cv2.imshow('a',c)
cv2.waitKey(0)

代码结果

完整代码

import numpy as np
import cv2
#透视变换
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)def order_points(pts):rect = np.zeros((4,2),dtype='float32')   # 创建一个4x2的数组,指定了数组中元素的数据类型为32位浮点数# 按顺序找到对应坐标0123分别是左上、右上、右下、左下s = pts.sum(axis=1)   # 对pts矩阵的每一行进行求和操作rect[0] = pts[np.argmin(s)]#左上角的点rect[2] = pts[np.argmax(s)]#右下角的点diff = np.diff(pts,axis=1)   # 对pts矩阵的每一行进行差值rect[1] = pts[np.argmin(diff)]#右上角的点rect[3] = pts[np.argmax(diff)]#左下角的点return rectdef four_point_transform(image,pts):# 获取输入坐标点rect = order_points(pts)(tl,tr,br,bl) = rect#tl 是左上角点,tr 是右上角点,br 是右下角点,bl 是左下角点。# 计算两个可能的宽度,取这两个宽度的最大值作为新图像的宽度。widthA = 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')# 图像透视变换 cv2.getPerspectiveTransform(src,dst[,solveMethod])→ MP获得转换之间的关系# cy2.warpPerspective(src, Mp, dsizel, dstl, flagsl, borderModel, borderValue]]1])- dst# #参数说明:# src:变换前图像四边形顶点坐标/第2个是原图# MP:透视变换矩阵,3行3列# dsize:输出图像的大小,二元元组(width,heiqht)M = cv2.getPerspectiveTransform(rect,dst)#计算透视变换矩阵 M,它描述了如何将原始图像中的点映射到目标坐标。warped = cv2.warpPerspective(image,M,(maxWidth,maxHeight))#透视变换# 返回变换后的结果return warped#用于调整图像的大小。
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))#根据计算出的尺寸 dim 调整图像大小。resized=cv2.resize(image,dim,interpolation=inter)     # 默认为cV2.INTER_AREA,即面积插值,适用于缩放图像。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)[1]
#绘制轮廓
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.02*peri,True)  # 轮廓近似
#绘制近似轮廓
image_contour = cv2.drawContours(image.copy(),[screenCnt],-1,(0,255,0),2)cv2.imshow('image_contour',image_contour)
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)a=cv2.imread('invoice_new.jpg')
a=cv2.cvtColor(a,cv2.COLOR_BGR2GRAY)
a=cv2.threshold(a,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
a=cv2.resize(a,(800,600))
a=np.rot90(a,1)kernel = np.ones((1,1), np.uint8)c=cv2.morphologyEx(a,cv2.MORPH_CLOSE,kernel)cv2.imshow('a',c)
cv2.waitKey(0)

http://www.ppmy.cn/server/123200.html

相关文章

pycharm2024版 搭配Anaconda创建pytorch项目

pycharm2024版 搭配Anaconda创建pytorch项目 ​ 刚接触anaconda和pytorch,b站看的教学视频中博主使用的是2019版的pycharm,所以在创建pytorch项目时有些懵,在多次摸索后大概明白了一些 上图中是2024版pycharm的新项目创建界面 Project venv…

众数问题,

在本实验中&#xff0c;需要编写一个程序来处理一组输入数据&#xff0c;找出其中的众数&#xff0c;即出现次数最多的数字。程序会读取文件中的数据进行处理&#xff0c;并将结果与标准答案进行比对&#xff0c;判断程序输出是否正确。 #include <bits/stdc.h> #define …

集成Elasticsearch到django restful

文章目录 集成ES到django restful服务端项目安装haystack基本使用安装配置索引模型ORM模型中新增discount_json字段方法全文索引字段模板 索引序列化器全文搜索的索引视图路由手动构建es索引 集成ES到django restful服务端项目 如果直接在Django项目直接编写代码作为ElasticSe…

宝塔部署vue项目出现的各种问题

使用宝塔面板&#xff0c;网站页面&#xff0c;构建php静态网页 问题一&#xff1a;图片等静态资源无法加载 找到真正请求的url&#xff0c; 然后在项目目录下面创建对应的目录&#xff0c;将资源放入 问题二&#xff1a;刷新出现404 在这里任意位置添加 ## 添加上这个配…

STMCubeMx——C8T6的串口调试、接收与发送

一、stmCubeMX串口通信的步骤 1、新建一个文件&#xff0c;选择自己的芯片 2、配置时钟 3、配置串口 串口的模式解析可以跳转到以下文章查看 stmCubemx——配置串口时的几种模式-CSDN博客在STM32CubeMX中配置串口&#xff08;USART或UART&#xff09;时&#xff0c;可以设置…

【机器学习】——决策树以及随机森林

文章目录 1. 决策树的基本概念与结构1.1 决策树的构建过程 2. 决策树的划分标准2.1 信息增益&#xff08;Information Gain&#xff09;2.2 信息增益比&#xff08;Information Gain Ratio&#xff09;2.3 基尼指数&#xff08;Gini Index&#xff09;2.4 均方误差&#xff08;…

mac-m1安装nvm,docker,miniconda

1.安装minicondaMAC OS(M1)安装配置miniconda_mac-mini m1 conda-CSDN博客 2.安装nvm&#xff08;用第二个方法&#xff09;Mac电脑安装nvm(node包版本管理工具)-CSDN博客 3.安装docker dmg下载链接docker-toolbox-mac-docker-for-mac安装包下载_开源镜像站-阿里云 教程MacOS系…

10个Android性能优化工具

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 在Android性能优化方面&#xff0c;以下是一些常见工具&#xff1a; Android Studio Profiler&#xff1a;这是一个集成在Android Studio中的性…