尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Opencv总结4——项目实战-信用卡数字识别

Opencv总结4——项目实战-信用卡数字识别
📅 发布时间:2026/6/27 14:58:35

先看效果:

代码资料看本人博客资源。

首先模板是

需要预测的图像是

任务是:使用模板匹配,一定要是数字特别接近的模板,然后匹配银行卡上面的数字。

1.1 模板处理

灰度处理——> 二值处理——> 轮廓处理

# 灰度图 ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值图像 ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]

RETR_EXTERNAL表示计算外轮廓,计算外接矩形

# 计算轮廓 #cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标 #返回的list中每个元素都是图像中的一个轮廓 ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) # -1 表示画出所有的轮廓 cv2.drawContours(img,refCnts,-1,(0,0,255),3) refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] #排序,从左到右,从上到下

上面调用了sort_contours方法,下面是计算并排序的方法,boundingBoxes 是一个元组,总共包含4个值x,y,h,w,直接按照横坐标x来判断数字在模板中的位置。

def sort_contours(cnts, method="left-to-right"): reverse = False i = 0 if method == "right-to-left" or method == "bottom-to-top": reverse = True if method == "top-to-bottom" or method == "bottom-to-top": i = 1 boundingBoxes = [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))

在得到10个轮廓之后,进行逐个遍历,c代表每一个轮廓

# 遍历每一个轮廓 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

1.2 对输入图像进行处理

总体流程:

对图片的处理——灰度处理——> 二值处理——>图像闭操作——>分组提取数字 ——> 切分成每个小的区域—— > 对于每个小区域都进行模板匹配。

信用卡的背景中有很多的干扰项,需要做一些额外的预处理操作

# 初始化卷积核 rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3)) sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
#读取输入图像,预处理 image = cv2.imread(args["image"]) 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)进行归一化处理,将其数值范围映射到 0-255 的图像像素范围,并转换为可显示的整数格式

gradX = np.absolute(gradX) # 对梯度数组gradX的每一个元素取绝对值。 (minVal, maxVal) = (np.min(gradX), np.max(gradX)) # 计算取绝对值后梯度数组的最小值(minVal)和最大值(maxVal) gradX = (255 * ((gradX - minVal) / (maxVal - minVal))) # 将梯度值从原来的任意范围(比如[5.2, 189.7])映射到0-255的范围 gradX = gradX.astype("uint8") # 将归一化后的浮点型数组转换为uint8类型(8 位无符号整数,取值范围 0-255)。 print (np.array(gradX).shape) # 打印处理后数组的形状(维度)。 cv_show('gradX',gradX)

接下来就是如何让上面的数字更像一个块,opencv中可以使用闭操作来完成

#通过闭操作(先膨胀,再腐蚀)将数字连在一起 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)

我们需要过滤掉数字以外的轮廓

# 遍历轮廓 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 digits 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) # 二值化了,更明亮,见下图 # 计算每一组的轮廓 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)))

然后程序就可以输出预测啦。

相关新闻

  • PyTorch-CUDA-v2.6镜像中定时备份Jupyter Notebook脚本的方法
  • 清华镜像源加速下载PyTorch-CUDA-v2.6,解决installing this may take a few minutes问题
  • 企业级社区医疗服务可视化系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】

最新新闻

  • Type-C一拖多快充线:智能功率分配与选购指南
  • 94个公共Tracker服务器:彻底终结BT下载卡在99%的终极解决方案
  • 生产环境下的Agent记忆机制设计:短期上下文与长期向量库的工程化取舍
  • 硬件预取器安全挑战与PhantomFetch防御技术解析
  • 基于4G和GPS的智慧养殖物联网终端设计与优化
  • 前端XSS攻击防御实战:从原理到2025年立体化安全方案

日新闻

  • 单节点跑业务稳如泰山 扩容高可用集群反而频繁卡死 复盘完整连接交互揪出深层根因
  • Boss直聘批量投递工具:5倍效率提升的求职价值重构指南
  • 3分钟解锁VLC点击暂停插件:让视频控制变得如此简单!

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号