参考课程:Opencv计算机视觉实战(Python版)

基本材料准备

  1. 一张仅含数字的图像作为模板。
  2. 一张银行卡的图像作为检测样本。

代码编写或者阅读的习惯

  1. 常打断点
  2. 勤展示数组的shape等,以及数组的图像。

思路介绍

模板图像的处理

  1. 模板图像是一张背景色为255的白色且字体为黑色0 但是仍旧是三层通道的BGR彩色图像

  2. 由于图像识别等科学操作,使用彩色图没有一个比较好的效果,而二维的灰度图效果却很不错,因此在读入三维的彩色图像之后,需要转化为灰度图。

  3. 因为做轮廓检测之间需要二值图像,因此需要将灰度图再转化为二值图像
    这里的二值图像转换过程强调一点:二值图像不仅仅只有0和255两种值的情况。原因在于二值图像的实现是借助threshhold方法实现的,而这个方法需要自行指定阈值。所以最后的二值图像是只有0和255还是只有0和阈值等情况
    取决于你的method参数。

  4. 得到二值图像就可以调用findContours方法寻找轮廓,且给返回一个Contours对象。此时注意,findContours方法的参数的格式必须是:二值图像深度复制的副本、mode轮廓检测模式一般选择RETR_EXTERNAL,而method表示轮廓逼近方法:一般选择CHAIN_APPROX_SIMPLE(只保留各个轮廓的部分顶点或者转折点,足够用来描绘出轮廓!)

  5. 为了展示轮廓检测的效果,可以将contours对象作为参数,传入drawContours方法中。

  6. 我们希望在用模板识别信用卡数字时,能够按照0-9的顺序排列,所以需要对Countours对象中的10个轮廓list对象,进行排序。这里是自行写了一个方法。

  7. 排序的思想是:通过boundingRect方法获取到包含了每个轮廓的矩形的左上坐标,因为模板图像本身是按照从小到大的顺序排列,因此,通过比较个轮廓矩形的左上坐标的横坐标即可得到个轮廓的排序的列表refCnts。

  8. 通过定义一个digits字典来通过对refCnts列表的for循环来将数字0123456789与refCnts中的边框在ref图像中的像素点区域(相当于截取了该数字在模板上对应的数字模板)一一对应。

被识别图像的处理

  1. 因为被识别图像的内容比较丰富,此时如果机械地重复模板图像的处理流程(转化为灰度图、二值图像、轮廓检测)则会产生大量的问题。因此结合这个被识别的图像的具体情况,我们也可以针对性的提出一些附加的预处理操作和形态学处理操作。

  2. 形态学的处理操作其实是基于灰度图的因此事先需要先进行这方面的操作。

  3. 形态学的顶帽操作(原始输入–开运算的结果(先腐蚀再膨胀,以突出主体区域)以突出细节区域),另做顶帽操作的卷积核的大小设定,是考虑到自己想要识别的区域的长宽,比如“5412”这四个字的整体区域,因此选择了一个9*3的卷积核。
    其中,膨胀操作会使得像素点值大的得到膨胀,侵蚀像素值小的区域(比如:白色侵蚀黑色)
    腐蚀操作会使得像素点值小的颜色侵蚀像素点值大的区域(比如黑色侵蚀白色),此时也可以看出所谓侵蚀还是膨胀操作是以"像素点值大的区域"为中心进行称谓命名的。(像素值大的区域膨胀、像素值大的区域被侵蚀

#读取输入图像,预处理
image = cv2.imread("./images/credit_card_03.png")
cv_show('image',image)
image = myutils.resize(image, width=300)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)
## 查看腐蚀的结果
erosion_1 = cv2.erode(gray,rectKernel,iterations = 1)
cv_show('erosion_1', erosion_1)
## 查看膨胀的结果
dilate_1 = cv2.dilate(gray,rectKernel,iterations = 1)
cv_show('dilate_1', dilate_1)
## 查看开运算的结果
opening = cv2.morphologyEx(gray, cv2.MORPH_OPEN, rectKernel)
cv_show('opening', opening)
#礼帽操作,突出更明亮的区域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv_show('tophat',tophat)

灰度图:

腐蚀操作之后:像素点值大的被腐蚀

膨胀操作:

开运算操作:

顶帽操作:

综合来看:
4. 通过sobel算子对输入图像进行处理,得到输入图像的边缘特征(注意,边缘特征杂而乱,不等于轮廓特征的规整。)
而边缘特征进行检测时的流程时,对X方向或者Y方向或者XY方向以此进行Soble计算、绝对值操作、归一化、uint8类型转变。(这里选择的时对X方向进行运算。)

5. 想要实现一种行为:将数字构成的四个组块提取出来,为此用到闭操作(先膨胀后腐蚀)使得数字连在一起。


6. 灰度图的形态学处理完成后,还需要做二值化处理。这里的threashhold方法要采取系统自动指定阈值的方式来进行二值化操作处理。

7. 为了使得分组的图像中的空洞位置同样被白色填充,我们可以再进行一步闭操作。这样做的好处提升外轮廓定位的准确率

8. 调用findContours方法以及显示所有的轮廓。

9. 因为找到的所有轮廓中包含大量不规则且不是我们想要的边框区域,所以进行过滤操作,而过滤操作的实现思路是,人为地指定四组数字所有的区域的范围的坐标,使得Contours对象中的各个轮廓的坐标不处于这个范围之内的轮廓被排除掉。处理后,依旧进行排序操作。(此时的排序操作,不需要根据边框的左上点的横坐标来排序)。
10.为了使得每一组边框中的图像一一与0-9的数字进行模板匹配,需要再将每一组轮廓中的四个数字再次细分为四个数字,而这一步就类似于模板图像提取每个数据模板的过程(灰度图的基础上二值化处理、轮廓检测、排序、根据每一个轮廓截取二值图像中的相应轮廓的位置)。


10. 截至到目前,我们已经获得模板图像中截取出来的10个数字模板。同时也从银行卡中截取到的16个数字且这26个图像的大小经过resize都搞成了一样的shape。此时就可以做模板匹配了。思想即是,对于每一个要验证的数字,使用10个数字模板一一遍历匹配,并计算ROI得分,选择最大值的数字。
11. 当上一步操作结束,即可将加过呈现在原来的图片上。

代码实现

  1. 主程序
# 导入工具包
from imutils import contours
import numpy as np
import argparse
import cv2
import myutils# 设置参数
# ap = argparse.ArgumentParser()
# ap.add_argument("-i", "--image", required=True,
#   help="path to input image")
# ap.add_argument("-t", "--template", required=True,
#   help="path to template OCR-A image")
# args = vars(ap.parse_args())# 指定信用卡类型
FIRST_NUMBER = {"3": "American Express","4": "Visa","5": "MasterCard","6": "Discover Card"
}
# 绘图展示
def cv_show(name,img):cv2.imshow(name, img)cv2.waitKey(0)cv2.destroyAllWindows()
# 读取一个模板图像
# img = cv2.imread(args["template"])
img = cv2.imread("ocr_a_reference.png")
cv_show('img',img)
# 灰度图
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)
# 二值图像
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('ref',ref)# 计算轮廓
#cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标
#返回的list中每个元素都是图像中的一个轮廓ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show('img',img)
print (np.array(refCnts).shape)
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] #排序,从左到右,从上到下
digits = {}# 遍历每一个轮廓
for (i, c) in enumerate(refCnts):# 计算外接矩形并且resize成合适大小(x, y, w, h) = cv2.boundingRect(c)roi = ref[y:y + h, x:x + w]roi = cv2.resize(roi, (57, 88))# 每一个数字对应每一个模板digits[i] = roi# 初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))# ==============================================================================================================================
#读取输入图像,预处理
image = cv2.imread("./images/credit_card_03.png")
cv_show('image',image)
image = myutils.resize(image, width=300)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)#礼帽操作,突出更明亮的区域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
cv_show('tophat',tophat)
#
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, #ksize=-1相当于用3*3的ksize=-1)gradX = np.absolute(gradX)
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))
gradX = gradX.astype("uint8")print (np.array(gradX).shape)
cv_show('gradX',gradX)#通过闭操作(先膨胀,再腐蚀)将数字连在一起
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
cv_show('gradX',gradX)
#THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(gradX, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('thresh',thresh)#再来一个闭操作thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) #再来一个闭操作
cv_show('thresh',thresh)# 计算轮廓thresh_, threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cnts = threshCnts
cur_img = image.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3)
cv_show('img',cur_img)
locs = []# 遍历轮廓
for (i, c) in enumerate(cnts):# 计算矩形(x, y, w, h) = cv2.boundingRect(c)ar = w / float(h)# 选择合适的区域,根据实际任务来,这里的基本都是四个数字一组if ar > 2.5 and ar < 4.0:if (w > 40 and w < 55) and (h > 10 and h < 20):#符合的留下来locs.append((x, y, w, h))# 将符合的轮廓从左到右排序
locs = sorted(locs, key=lambda x:x[0])
output = []# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):# initialize the list of group digitsgroupOutput = []# 根据坐标提取每一个组group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]cv_show('group',group)# 预处理group = cv2.threshold(group, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]cv_show('group',group)# 计算每一组的轮廓group_,digitCnts,hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)digitCnts = contours.sort_contours(digitCnts,method="left-to-right")[0]# 计算每一组中的每一个数值for c in digitCnts:# 找到当前数值的轮廓,resize成合适的的大小(x, y, w, h) = cv2.boundingRect(c)roi = group[y:y + h, x:x + w]roi = cv2.resize(roi, (57, 88))cv_show('roi',roi)# 计算匹配得分scores = []# 在模板中计算每一个得分for (digit, digitROI) in digits.items():# 模板匹配result = cv2.matchTemplate(roi, digitROI,cv2.TM_CCOEFF)(_, score, _, _) = cv2.minMaxLoc(result)scores.append(score)# 得到最合适的数字groupOutput.append(str(np.argmax(scores)))# 画出来cv2.rectangle(image, (gX - 5, gY - 5),(gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)cv2.putText(image, "".join(groupOutput), (gX, gY - 15),cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)# 得到结果output.extend(groupOutput)# 打印结果
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)
  1. 其中 myutils.py
import cv2def sort_contours(cnts, method="left-to-right"):reverse = Falsei = 0if method == "right-to-left" or method == "bottom-to-top":reverse = Trueif method == "top-to-bottom" or method == "bottom-to-top":i = 1boundingBoxes = [cv2.boundingRect(c) for c in cnts] #用一个最小的矩形,把找到的形状包起来x,y,h,w(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),key=lambda b: b[1][i], reverse=reverse))return cnts, boundingBoxes
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 resized

====================== T H E E N D ===========================

信用卡数字识别OpenCV实现(含代码)【DataWhale项目】相关推荐

  1. 信用卡数字识别—opencv

    信用卡数字识别:就是识别信用卡的卡号,然后将卡号打印出来! 然后对应的数字模板如下图所示: 接下来我们就一步步的分析程序吧 1.导入相关的包 # 导入工具包 from imutils import c ...

  2. 基于Pytorch的MNIST手写数字识别实现(含代码+讲解)

    说明:本人也是一个萌新,也在学习中,有代码里也有不完善的地方.如果有错误/讲解不清的地方请多多指出 本文代码链接: GitHub - Michael-OvO/mnist: mnist_trained_ ...

  3. (八)OpenCV入门,代码练习,详细注释【信用卡数字识别】【240行】【原创】

    文章目录 信用卡图片 数字模板图片 一.数字模板图片处理步骤 1,读取模板图片 2,灰度处理图片 3,二值化处理图片 4,检测数字轮廓图片 二.识别信用卡图片处理步骤 1,图片信用卡 2,图片灰度处理 ...

  4. OpenCV实践小项目(一): 信用卡数字识别

    1. 写在前面 今天整理一个OpenCV实践的小项目, 前几天整理了一篇OpenCV处理图像的知识笔记,后面,就通过一些小项目把这些知识运用到实践中去,一个是加深理解,另一个是融会贯通,连成整体,因为 ...

  5. Opencv项目实战-信用卡数字识别

    Opencv项目实战:信用卡数字识别 导入库,定义展示函数 import cv2 import numpy as np from imutils import contours import myut ...

  6. 【项目实战】基于python+pycharm+OpenCV的信用卡数字识别

    一.pycharm实现参数配置 直接运行程序会报错: usage: ocr_template_match.py [-h] -i IMAGE -t TEMPLATE ocr_template_match ...

  7. python信用卡客户_Python开发之基于模板匹配的信用卡数字识别功能

    环境介绍 python 3.6 + OpenCV 3.4.1.15 原理介绍 首先,提取出模板中每一个数字的轮廓,再对信用卡图像进行处理,提取其中的数字部分,将该部分数字与模板进行匹配,即可得到结果. ...

  8. 使用python和pyqt5轻松上手人脸识别系统(含代码)

    使用python和pyqt5轻松上手人脸识别系统(含代码) 一. 环境配置 1.1 python环境配置 1.1.1 安装 anaconda 1.1.2 安装pycharm 1.1.3 配置pip源 ...

  9. opencv-实战-信用卡数字识别

    信用卡-数字识别 功能说明 简要步骤 先得到轮廓的外接矩形 然后对模板和图像进行轮廓检测得到外轮廓 例如先对4进行外接轮廓检测后再一一和模板里面的一一匹配 处理 先读入图像转入灰度图 对两个图像先re ...

最新文章

  1. 台湾国立大学郭彦甫Matlab教程笔记(9) basic plotting
  2. java bmp转jpg,在java中将bmp转换为jpg
  3. 图像视频压缩:深度学习,有一套
  4. 程序员薪资怎么论高级还是初级_Java程序员的薪水取决于年龄还是技术?
  5. 基于粒子群优化算法的移动机器人全局路径规划-附代码
  6. NumPy库---介绍
  7. discuz开发经验discuz x3 怎么在帖子列表显示论坛板块图标
  8. 看!Mac上好用的流程图软件就是它
  9. CrossApp 0.4.2 发布,隆重推出 WebView
  10. rpm -ivh *rpm 是什么意思
  11. 淘宝数据库,主键如何设计以及自增ID的问题
  12. lnmp安装tpshop
  13. 2019年上半年云桌面排名前五企业
  14. PPPOE开机自动拨号
  15. 【Koltin Flow(二)】Flow操作符之末端操作符
  16. 东半球最好的TV桌面开源项目
  17. 两小时学会MySQL查询语句(上篇)
  18. java 开源 视频会议_Openmeetings 开源视频会议系统介绍与部署
  19. [Vulnhub]Momentum2
  20. 小程序地图定位授权取消后再次授权

热门文章

  1. 试用金山的猎豹浏览器
  2. URP中如何用多个相机?
  3. 【物联网初探】- 03 - ESP32 结合 TFT_eSPI 库标定 TFT 触摸屏 (Arduino IDE)
  4. 机器学习 Machine Learning 深度学习 Deep Learning 资料
  5. mindspore-gpu模型运行,警告数据集为动态shape
  6. 在线中文命名实体识别 ( NER ) 的工具
  7. 简简单单,带你撸个人脸识别登录
  8. python簇状柱形图_《R数据可视化手册》一3.2 绘制簇状条形图
  9. 自动化点焊流水线(鑫金雨)非标自动化解决方案
  10. matlab function_MATLAB处理INCA采集数据(mdf,dat等)一