OpenCV OCR实战:卡号识别
本文主要介绍通过OpenCV- python实现简单的银行卡卡号识别的思路和具体实现过程。
目录
知识准备
项目概述
实现过程
代码讲解
1.自定义函数
2.模版读入与预处理
3.银行卡读入与形态学操作
4. 卡号筛选与ROI切割
5.模版匹配,得出结果
结语
知识准备
该过程需要用到以下知识:
1.OpenCV图像基础操作,如读取,灰度转换,改变大小等
2.阈值操作,如二值化
3.轮廓检测以及boundingBox构建
4.卷积核构建
5.Sobel算子求梯度,梯度融合
6.形态学操作,如tophat,close操作
7.machTemplate模版匹配
8.用pyplot查看图片,便于debug
项目概述
本项目旨在综合运用OpenCV的各种方法实现对银行卡卡号的自动识别。
主要原理基于模版匹配,故需要提供与银行卡数字字体相同的数字模版作为参照。
实现过程
1.读入模版图片,识别边框,取出各个数字作为参考项。
2.读入银行卡图片,进行形态学操作,识别边框,筛选数字区域。
3.将银行卡的卡号数字割出来,与模版比较,选出相似度最高的答案。
代码讲解
1.自定义函数
import cv2
import matplotlib.pyplot as pltdef read(img, thresh=127, inv=False):origin = cv2.imread(img)gray = cv2.imread(img, 0)binary = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY_INV if inv else cv2.THRESH_BINARY)[1]return origin, gray, binarydef unify_size(img_list):outputlist = []xsize, ysize = img_list[0].shapefor img in img_list:outputlist.append(cv2.resize(img, (ysize, xsize)))return outputlist
在本项目中,笔者自定义了两个函数。read()实现了传入一个图片文件名,返回其原图,灰度图以及二值化处理后的结果。unify_size()实现了传入一个由图片构成的列表,对列表中所有元素按照列表第一个图片的大小进行大小统一。
2.模版读入与预处理
template_bgr, template_gray, template_bin = read('template.png', inv=True)
contours, hier = cv2.findContours(template_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
rectangles = []
for cnt in contours:x, y, w, h = cv2.boundingRect(cnt)rectangles.append([x, y, w, h])
rectangles.sort(key=lambda rect: rect[0])
num_template = []
for [x, y, w, h] in rectangles:num_template.append(template_bin[y:y + h, x:x + w])
num_template = unify_size(num_template)
在本段代码中,首先调用自定义的read()方法返回了模版的bgr格式,灰度和二值化(反向)后的结果。然后调用findContours方法识别了模版图片中的所有外边界,储存在contours列表中。在循环中遍历所有外边框,将每个边框的x,y,w,h存储在rectangles列表中,并对其按照从左到右排序,使得下标和数字一一对应。最后截取每个ROI,储存在num_template列表中,并进行大小的统一。
3.银行卡读入与形态学操作
# 读入
idcard_bgr, idcard_gray, idcard_bin = read('1.png', 127)
# 构建三个将来会用到的卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 5))
rectKernel2 = cv2.getStructuringElement(cv2.MORPH_RECT, (18, 7))
basicKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# 改变大小
idcard_bgr, idcard_gray, idcard_bin = cv2.resize(idcard_bgr, (583, 368)), cv2.resize(idcard_gray,(583, 368)), cv2.resize(idcard_bin,(583, 368))
# 顶帽操作
idcard_gray_tophat = cv2.morphologyEx(idcard_gray, cv2.MORPH_TOPHAT, rectKernel)
plt.imshow(idcard_gray_tophat)
plt.show()
# 梯度计算
gradX = cv2.convertScaleAbs(cv2.Sobel(idcard_gray_tophat, cv2.CV_64F, 1, 0, ksize=3))
gradY = cv2.convertScaleAbs(cv2.Sobel(idcard_gray_tophat, cv2.CV_64F, 0, 1, ksize=3))
grad = cv2.addWeighted(gradX, 0.5, gradY, 0.5, 0)
plt.imshow(grad)
plt.show()
# 闭操作
grad_close = cv2.morphologyEx(grad, cv2.MORPH_CLOSE, rectKernel)
plt.imshow(grad_close)
plt.show()
# 自适应阈值二值化
close_autobin = cv2.threshold(grad_close, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
plt.imshow(close_autobin)
plt.show()
# 闭操作
close2 = cv2.morphologyEx(close_autobin, cv2.MORPH_CLOSE, rectKernel2)
plt.imshow(close2)
plt.show()
这段代码对读入的银行卡图片进行了多次形态学操作,其输出如下:
tophat
tophat操作将图片中的反差较大的信息提取了出来。
grad
梯度操作在tophat的基础上描出了梯度变化较大的部分。
第一次闭操作
闭操作将梯度轮廓进行了粘连。
二值化
第二次闭操作
进一步粘连二值化后的结果,使四个号码成块出现。
需要注意的是,实现上述效果的具体途径不是唯一的,各种操作综合运用是关键所在。在上面给出的例子中,经过反复调整,笔者发现,卷积核大小的设置是至关重要的,卷积核过小的话,进行闭操作无法将数字连在一起,分离的数字不利于下一步的筛选;而卷积核设置过大的话,数字可能会和其他色块粘连在一起,无法通过下一步的像素宽高比和色块大小进行筛选出来,导致特征丢失。
4. 卡号筛选与ROI切割
# 找边界
contours, hier = cv2.findContours(close2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
boundingBoxes = []
# 按照宽高比和像素范围筛选数字组
for cnt in contours:x, y, w, h = cv2.boundingRect(cnt)ar = w / float(h)if 2.6 < ar < 3.8 and 70 < w < 115 and 15 < h < 45:boundingBoxes.append([x, y, w, h])
boundingBoxes.sort(key=lambda box: box[0])
group = []
# ROI
for [x, y, w, h] in boundingBoxes:group.append(idcard_gray[y - 5:y + h + 5, x - 5:x + w + 5])plt.imshow(idcard_gray[y - 5:y + h + 5, x - 5:x + w + 5])plt.show()
group_binary = []
# 对数字组进行形态学操作
for nominee in group:nominee_bin = cv2.threshold(nominee, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]nominee_close = cv2.morphologyEx(nominee_bin, cv2.MORPH_CLOSE, basicKernel)group_binary.append(nominee_close)plt.imshow(cv2.threshold(nominee, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1])plt.show()
num_nominee = []
# 对数字组找边界
for nominee in group_binary:contours, hier = cv2.findContours(nominee, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)rectangles = []for cnt in contours:x, y, w, h = cv2.boundingRect(cnt)rectangles.append([x, y, w, h])rectangles.sort(key=lambda rect: rect[0])# ROI切割出单个数字for [x, y, w, h] in rectangles:if w > 8 and h > 20:num_nominee.append(nominee[y:y + h, x:x + w])plt.imshow(nominee[y:y + h, x:x + w])plt.show()
输出如下:
数字组ROI
形态学操作后
单个数字ROI
本节代码中要注意几点:
1.按照二次闭操作后的结果找到原图的边界后,需要对边界进行筛选,这里按照边界外接矩形的宽高比和像素大小进行筛选,这里的范围自行确定,只要避免错选和漏选。
2.第一次ROI切割要保留几个像素的切割余量。
3.对数字组ROI二值化后又进行闭操作是为了防止单个数字的笔画没有连起来。
4.对单个数字的筛选同1。
5.要注意对轮廓外矩形排序后提取ROI。
5.模版匹配,得出结果
num_nominee = unify_size(num_nominee)
num_standard = []
(x, y) = num_nominee[0].shape
for i in range(len(num_template)):num_standard.append(cv2.resize(num_template[i], (y, x)))
ans = []
for nominee in num_nominee:score = []for standard in num_standard:res = cv2.matchTemplate(nominee, standard, cv2.TM_SQDIFF_NORMED)min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)score.append(min_val)ans.append(score.index(min(score)))
print(ans)
首先对模版数字和待匹配数字大小统一化。
外循环遍历待匹配数字,内循环将其与10个模版匹配并打分,这里笔者采用了TM_SQDIFF_NORMED模式,分数越低,相似度越高。然后获取最低分对应的数组下标作为结果输出。
结语
实现这样一个OCR的效果并不难,主要是对OpenCV基础函数的综合运用。本文提到的方法还有大量的改进空间,还存在很大的局限性。
OpenCV OCR实战:卡号识别相关推荐
- OpenCv NDK 银行卡/身份证号识别(3) 银行卡/身份证图像处理和卡号区域剪切
通过前两篇我们已经对Opencv有所了解了,接下来就要真正的来处理我们的图像,然后把卡号给提取出来.首先我们先简单分析以下银行卡然后把处理流程列出来: 由上图我们很容易知道既然我们要找到卡号,银行卡的 ...
- Opencv项目实战-信用卡数字识别
Opencv项目实战:信用卡数字识别 导入库,定义展示函数 import cv2 import numpy as np from imutils import contours import myut ...
- mysql通过卡号识别银行_Java 根据银行卡号获取银行名称以及图标
转 https://blog.csdn.net/N_007/article/details/78835526 一.支付宝接口获取名称 根据 卡号 获取 银行信息 接口 https://ccdcapi. ...
- Java使用OpenCV和Tesseract-OCR实现银行卡图片处理与卡号识别
直接上代码,代码每一步都是解释与插图,一步步实现,如果不清楚opencv的环境如何搭建,可上网查或者参见我的前几篇博客,不多说了, java代码如下: package com.zmx.opencvte ...
- OpenCV OCR实战 文档扫描与文字检测
本文讲述使用OpenCV- python以及easyocr库实现文档扫描与文字检测的思路和具体实现过程. 目录 知识准备 项目概述 实现过程 代码讲解 1.读入图片并进行预处理(灰度转换,高斯滤波) ...
- Opencv项目实战之信用卡识别
任务要求 学了这么久opencv,不做个实战项目怎么行(手动狗头)
- openCV+Python实战练习——银行卡号识别
目录 项目Introduce: 项目名称: 具体操作步骤以及代码: 实现结果展示: 代码整体展示: 项目Introduce: 项目名称: 通过导入模板数字,对银行卡面上的数字进行识别,提取出银行卡面上 ...
- 文本的检测、识别实战:使用 Tesseract 进行 OpenCV OCR 和文本识别
在本篇文章中,我们将使用 OpenCV.Python 和 Tesseract 执行 (1) 文本检测和 (2) 文本识别. 上篇文章,我向您展示了如何使用 OpenCV 的 EAST 深度学习模型执行 ...
- python opencv 文字识别_文本识别 使用 Tesseract 进行 OpenCV OCR 和 文本识别
文本识别 用 Tesseract 进行 OpenCV OCR 和 文本识 在本教程中,您将学习如何应用OpenCV OCR(光学字符识别).我们将使用OpenCV,Python和Tesseract 执 ...
最新文章
- IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期
- 详解django三种文件下载方式
- 简述力法计算弹性固定无铰拱的原理_《隧道结构体系设计》PPT课件.ppt
- 解决jsp两种提交方式乱码 的方法
- Disqus API 用法 How to get your Disqus API keys
- [BZOJ3676][Apio2014]回文串
- 史上最全的php面试题-带有答案,史上最全的PHP面试题-带有答案
- MSCRM4.0删除Money类型属性可能引起的问题
- opera官方教程 预订一
- nginx中upstream的max_conns属性使用
- sigmoid画图_博弈画图软件(Window版和MAC版)
- mac 思科 链路聚合_思科链路聚合协议实验.docx
- 联想硬盘保护系统 计算机名 后缀,联想硬盘保护7.07.6安装及计算机名相同的解决方法...
- C语言扑克牌洗牌发牌代码
- fit into用法
- Jsonviewer2 for Notepad++ 64 bit
- linux 获取文件父目录权限,Linux 文件权限中,操作一个文件需要父目录的那些权限?...
- Swift游戏实战-跑酷熊猫 07 平台的移动
- 数据驱动的瑞幸咖啡未来会能赚!
- 数据库原理——关系模式的范式的简明判断