前言:信用卡卡号识别技术的发展有利于提高银行系统的业务水平和办事效率。相信此次通过学习使用OpenCV中的图像处理方法来实现信用卡卡号识别的项目,能让大家清楚地了解图像处理技术的一般方法与步骤以及如何使用OpenCV库。

1、设计思路

不同银行发行的信用卡,其卡号中的数字外观形状是有点区别的,由于小编是通过模板匹配的方法完成信用卡卡号识别的,既然是模板匹配,则必须有一套与信用卡中外形一模一样的数字模板,通过比对信用卡中的数字和模板中数字的差别来确定识别结果,模板图像和信用卡图像分布如图1和图2所示。

图1

图2

在进行模板匹配之前,必须通过图像处理方法,比如形态学等,先从信用卡图像中找到本次项目的感兴趣域——即卡号所在区域,并且将该区域分割出来,然后提取出该区域中的数字分别与模板中的10个数字进行比对,认为数字与模板中匹配得分最高的数字相同。

2、代码实现

项目实现包括main.py和myutils.py两部分代码,要想观察实验结果运行main.py就行,myutils.py中主要包含轮廓排序方法和resize方法,main.py中会调用myutils.py模块中的函数。

main.py文件中的代码如下:

# 导入工具包
from imutils import contours
import numpy as np
import cv2
import myutils# 指定信用卡类型
FIRST_NUMBER = {"3": "American Express","4": "Visa","5": "MasterCard","6": "Discover Card"
}# 绘图函数def cv_show(name, img1):cv2.imshow(name, img1)cv2.waitKey(0)cv2.destroyAllWindows()# 读取模板
img = cv2.imread("template.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)# 计算轮廓
refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
#print(np.size(refCnts))返回值refcnts返回的是10组轮廓及其每个轮廓所有组成点的坐标
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):(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('object.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)
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 = 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)# 计算轮廓
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):groupOutput = []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)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:(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_SCRIPT_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)

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](cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes), key=lambda b: b[1][i], reverse=reverse))return cnts, boundingBoxesdef 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

代码中出现的template.png就是图1,object.png就是图2。信用卡卡号识别项目的最终识别结果如图3和图4所示。

图3

图4

【项目实战二】基于模板匹配和形态学操作的信用卡卡号识别(OpenCV+Python)相关推荐

  1. 招商银行信用卡卡号识别项目(第一篇),Python OpenCV 图像处理取经之旅第 53 篇

    Python OpenCV 365 天学习计划,与橡皮擦一起进入图像领域吧.本篇博客是这个系列的第 53 篇. 该系列文章导航参考:https://blog.csdn.net/hihell/categ ...

  2. 【图像识别】基于模板匹配实现蓝色、绿色、黄色车牌识别附matlab代码

    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信.

  3. (项目实战)基于QT嵌入式ARM数据采集卡上位机(二)——页面布局

    (项目实战)基于QT嵌入式ARM数据采集卡上位机(二)--页面布局 上一篇文章<基于 QT 嵌入式ARM数据采集卡上位机(一)> 下一篇文章<(项目实战)基于QT嵌入式ARM数据采集 ...

  4. Taro多端开发实现原理与项目实战(二)

    Taro多端开发实现原理与项目实战(二) 多端电商平台项目概述及开发准备 学习了前面的基础知识和进阶后是否跃跃欲试?我们准备了一个电商平台的项目来和大家一起实践使用 Taro 开发电商平台. 项目概述 ...

  5. 基于模板匹配和遗传算法的人眼定位

    基于模板匹配和遗传算法的人眼定位 余甜甜,唐普英(电子科技大学光电信息学院,四川成都6l0054) 摘要:文中提出了一种利用模板匹配与遗传算法相结合的人眼定位算法.根据人脸几何特征将人脸分为几个特征区 ...

  6. 项目实战4: 基于 SpringBoot 的超市账单管理系统

    文章目录 一.项目介绍 二.数据库设计 三.概要设计 确立对象,划分模块 四.详细设计 4.1 Shiro 授权与鉴权流程梳理 4.1.1 了解 Shiro 4.1.2 Shiro 数据库设计 4.1 ...

  7. Android项目实战系列—基于博学谷(七)课程模块(上)

    由于这个模块内容较多,分为上.中.下 三篇博客分别来讲述,请耐心阅读. 课程模块分为四个部分 课程列表 课程详情 视频播放 播放记录 课程模块(上)主要讲述课程列表部分 一.水平滑动广告栏界面 1.创 ...

  8. android中私有方法 继承,Android项目实战系列—基于博学谷(五)个人资料

    由于这个模块内容较多,篇幅较长,请耐心阅读. 个人资料模块分为两个部分 [x] [个人资料]() [x] [资料修改]() 一.个人资料 1.个人资料界面 (1).创建个人资料界面 在com.buxu ...

  9. android注册文件打开,Android项目实战系列—基于博学谷(三)注册与登录模块

    由于这个模块内容较多,篇幅较长,请耐心阅读. 注册与登录模块分为三个部分 [x] [欢迎界面]() [x] [注册界面]() [x] [登录界面]() 一.欢迎界面 1.创建工程,命名为BoXueGu ...

最新文章

  1. 发展大数据还有三道坎要迈
  2. 会说话,减少奋斗30年
  3. QT的QTransform类的使用
  4. angular4获得焦点事件_Angular 4 文本框自动获取焦点二
  5. php ci model条件查询,php – CodeIgniter中的多条件WHERE子句
  6. JQuery实现的Table表头固定展示效果
  7. javax.mail.MessagingException: 501 Syntax: HELO hostname Linux端异常解决
  8. 单片机交通灯实训c语言编程,单片机交通灯程序(C语言).docx
  9. win7如何设置通电自动开机_win7系统设置自动开机
  10. NYOJ 33 蛇形填数
  11. 五子棋游戏AI智能算法设计
  12. 单片机片内存储器烧写
  13. Java入门第112课——使用Iterator的hasNext方法、next方法遍历集合
  14. 格式化什么意思?格式化了数据还能恢复吗?
  15. DWZ (JUI) 教程 修正 Tab 选项卡多次加载
  16. C. Anu Has a Function
  17. 1700. 无法吃午餐的学生数量(难度:简单)
  18. Glance支持镜像的格式
  19. C# 连接basler相机
  20. python自动备份交换机配置脚本_python代码自动备份交换机配置

热门文章

  1. 我们为什么选择NEXTCHIP?为什么要选择ISP?为什么要选择AHD?为什么选择北京冠宇铭通?
  2. 程序员的吵架,跟女朋友能讲理吗?
  3. 汉庭酒店专属歌曲发布,由左小祖咒和罗永浩创作
  4. 程序员后来都干啥去了
  5. php验证电子邮件,如何在PHP中验证电子邮件地址
  6. android使图片变为圆形
  7. Unity 多人签名
  8. Problem F: Matrix Problem (III) : Array Practice Time Limit: 1 Sec Memory Limit: 4 MB Submit: 8787
  9. 低成本DC/DC转换器34063的应用(图)
  10. 京东云申元庆:用创新技术改变中国,顺道改变世界