基于机器视觉的银行卡识别系统 - opencv python 计算机竞赛

1 前言

🔥 优质竞赛项目系列,今天要分享的是

基于深度学习的银行卡识别算法设计

该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

2 算法设计流程

银行卡卡号识别技术原理是先对银行卡图像定位,保障获取图像绝对位置后,对图像进行字符分割,然后将分割完成的信息与模型进行比较,从而匹配出与其最相似的数字。主要流程图如图

在这里插入图片描述

1.银行卡号图像
由于银行卡卡号信息涉及个人隐私,作者很难在短时间内获取大量的银行卡进行测试和试验,本文即采用作者个人及模拟银行卡进行卡号识别测试。

2.图像预处理
图像预处理是在获取图像后必须优先进行的技术性处理工作,先对银行卡卡号图像进行色彩处理,具体做法与流程是先将图像灰度化,去掉图像识别上无用的信息,然后利用归一化只保留有效的卡号信息区域。

3.字符分割
字符分割是在对图像进行预处理后,在获取有效图像后对有效区域进行进一步细化处理,将图像分割为最小识别字符单元。

4.字符识别
字符识别是在对银行卡卡号进行字符分割后,利用图像识别技术来对字符进行分析和匹配,本文作者利用的模板匹配方法。

2.1 颜色空间转换

由于银行卡卡号识别与颜色无关,所以银行卡颜色是一个无用因素,我们在图像预处理环节要先将其过滤掉。另外,图像处理中还含有颜色信息,不仅会造成空间浪费,增加运算量,降低系统的整体效率,还会给以后的图像分析和处理带来干扰。因此,有必要利用灰度处理来滤除颜色信息。

灰度处理的实质是将颜色信息转化为亮度信息,即将原始的三维颜色信息还原为一维亮度信息。灰度化的思想是用灰度值g来表示原始彩色图像的R(绿色)、g(红色)和B(蓝色)分量的值,具体的流程设计如图

在这里插入图片描述

2.2 边缘切割

对于采集到的银行卡号图像,由于背景图案的多样性和卡号字体的不同,无法直接对卡号图像进行分割。分割前要准确定位卡号,才能得到有效区域。数字字符所在的区域有许多像素。根据该特征,通过设置阈值来确定原始图像中卡号图像的区域。银行卡图像的切边处理设计如图

在这里插入图片描述

2.3 模板匹配

模板匹配是一种将需要识别的字符与已有固定模板进行匹配的算法技术,该技术是将已经切割好的字符图像逐个与模板数字图像进行对比分析,其原理就是通过数字相似度来衡量两个字符元素,将目标字符元素逐个与模板数字图像进行匹配,找到最接近的数字元素即可。匹配计算量随特征级别的增加而减少。根据第一步得到的特征,选择第二种相关计算方法来解决图像匹配问题。银行卡模板匹配流程设计如图

在这里插入图片描述

2.4 卡号识别

银行卡卡号识别有其独有的特性,因为目前市面上大多数银行卡卡号是凹凸不平的数字形式,如果使用传统的计算机字符识别技术已显然不适用,本文针对银行卡此类特点,研究了解决此类问题的识别方案。从银行卡待识别的凸凹字符进行预处理,然后根据滑块算法逐个窗口对银行卡字符进行匹配识别,卡号识别一般从切割后的图像最左端开始,设定截图选定框大小为64*48像素,因为银行卡所需要识别的字符一般为45像素左右。故而以此方式循环对卡片上所有数字进行匹配、识别,如果最小值大于设置的阈值,我们将认为这里没有字符,这是一个空白区域,并且不输出字符。同时,窗口位置J向下滑动,输出f<19&&j;+20<图像总长度并判断,最后循环得到字符数f、j。

在这里插入图片描述

3 银行卡字符定位 - 算法实现

首先就是将整张银行卡号里面的银行卡号部分进行识别,且分出来,这一个环节学长用的技术就是faster-rcnn的方法

将目标识别部分的银行卡号部门且分出来,进行保存

主程序的代码如下(非完整代码):

#!/usr/bin/env pythonfrom __future__ import absolute_importfrom __future__ import divisionfrom __future__ import print_functionimport argparseimport osimport cv2import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom lib.config import config as cfgfrom lib.utils.nms_wrapper import nmsfrom lib.utils.test import im_detectfrom lib.nets.vgg16 import vgg16from lib.utils.timer import Timeros.environ["CUDA_VISIBLE_DEVICES"] = '0'   #指定第一块GPU可用config = tf.ConfigProto()config.gpu_options.per_process_gpu_memory_fraction = 0.8  # 程序最多只能占用指定gpu50%的显存config.gpu_options.allow_growth = True      #程序按需申请内存sess = tf.Session(config = config)CLASSES = ('__background__','lb')NETS = {'vgg16': ('vgg16_faster_rcnn_iter_70000.ckpt',), 'res101': ('res101_faster_rcnn_iter_110000.ckpt',)}DATASETS = {'pascal_voc': ('voc_2007_trainval',), 'pascal_voc_0712': ('voc_2007_trainval+voc_2012_trainval',)}def vis_detections(im, class_name, dets, thresh=0.5):"""Draw detected bounding boxes."""inds = np.where(dets[:, -1] >= thresh)[0]if len(inds) == 0:returnim = im[:, :, (2, 1, 0)]fig, ax = plt.subplots(figsize=(12, 12))ax.imshow(im, aspect='equal')sco=[]for i in inds:score = dets[i, -1]sco.append(score)maxscore=max(sco)# print(maxscore)成绩最大值for i in inds:# print(i)score = dets[i, -1]if score==maxscore:bbox = dets[i, :4]# print(bbox)#目标框的4个坐标img = cv2.imread("data/demo/"+filename)# img = cv2.imread('data/demo/000002.jpg')sp=img.shapewidth = sp[1]if bbox[0]>20 and bbox[2]+20<width:cropped = img[int(bbox[1]):int(bbox[3]), int(bbox[0]-20):int(bbox[2])+20] # 裁剪坐标为[y0:y1, x0:x1]if bbox[0]<20 and bbox[2]+20<width:cropped = img[int(bbox[1]):int(bbox[3]), int(bbox[0]):int(bbox[2])+20] # 裁剪坐标为[y0:y1, x0:x1]if bbox[0] > 20 and bbox[2] + 20 > width:cropped = img[int(bbox[1]):int(bbox[3]), int(bbox[0] - 20):int(bbox[2])]  # 裁剪坐标为[y0:y1, x0:x1]path = 'cut1/'# 重定义图片的大小res = cv2.resize(cropped, (1000, 100), interpolation=cv2.INTER_CUBIC)  # dsize=(2*width,2*height)cv2.imwrite(path+str(i)+filename, res)ax.add_patch(plt.Rectangle((bbox[0], bbox[1]),bbox[2] - bbox[0],bbox[3] - bbox[1], fill=False,edgecolor='red', linewidth=3.5))ax.text(bbox[0], bbox[1] - 2,'{:s} {:.3f}'.format(class_name, score),bbox=dict(facecolor='blue', alpha=0.5),fontsize=14, color='white')ax.set_title(('{} detections with ''p({} | box) >= {:.1f}').format(class_name, class_name,thresh),fontsize=14)plt.axis('off')plt.tight_layout()plt.draw()def demo(sess, net, image_name):"""Detect object classes in an image using pre-computed object proposals."""# Load the demo imageim_file = os.path.join(cfg.FLAGS2["data_dir"], 'demo', image_name)im = cv2.imread(im_file)# Detect all object classes and regress object boundstimer = Timer()timer.tic()scores, boxes = im_detect(sess, net, im)timer.toc()print('Detection took {:.3f}s for {:d} object proposals'.format(timer.total_time, boxes.shape[0]))# Visualize detections for each classCONF_THRESH = 0.1NMS_THRESH = 0.1for cls_ind, cls in enumerate(CLASSES[1:]):cls_ind += 1  # because we skipped backgroundcls_boxes = boxes[:, 4 * cls_ind:4 * (cls_ind + 1)]cls_scores = scores[:, cls_ind]# print(cls_scores)#一个300个数的数组#np.newaxis增加维度  np.hstack将数组拼接在一起dets = np.hstack((cls_boxes,cls_scores[:, np.newaxis])).astype(np.float32)keep = nms(dets, NMS_THRESH)dets = dets[keep, :]vis_detections(im, cls, dets, thresh=CONF_THRESH)def parse_args():"""Parse input arguments."""parser = argparse.ArgumentParser(description='Tensorflow Faster R-CNN demo')parser.add_argument('--net', dest='demo_net', help='Network to use [vgg16 res101]',choices=NETS.keys(), default='vgg16')parser.add_argument('--dataset', dest='dataset', help='Trained dataset [pascal_voc pascal_voc_0712]',choices=DATASETS.keys(), default='pascal_voc')args = parser.parse_args()return argsif __name__ == '__main__':args = parse_args()# model pathdemonet = args.demo_netdataset = args.dataset#tfmodel = os.path.join('output', demonet, DATASETS[dataset][0], 'default', NETS[demonet][0])tfmodel = r'./default/voc_2007_trainval/cut1/vgg16_faster_rcnn_iter_8000.ckpt'# 路径异常提醒if not os.path.isfile(tfmodel + '.meta'):print(tfmodel)raise IOError(('{:s} not found.\nDid you download the proper networks from ''our server and place them properly?').format(tfmodel + '.meta'))# set configtfconfig = tf.ConfigProto(allow_soft_placement=True)tfconfig.gpu_options.allow_growth = True# init sessionsess = tf.Session(config=tfconfig)# load networkif demonet == 'vgg16':net = vgg16(batch_size=1)# elif demonet == 'res101':# net = resnetv1(batch_size=1, num_layers=101)else:raise NotImplementedErrornet.create_architecture(sess, "TEST", 2,tag='default', anchor_scales=[8, 16, 32])saver = tf.train.Saver()saver.restore(sess, tfmodel)print('Loaded network {:s}'.format(tfmodel))# # 文件夹下所有图片进行识别# for filename in os.listdir(r'data/demo/'):#     im_names = [filename]#     for im_name in im_names:#         print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')#         print('Demo for data/demo/{}'.format(im_name))#         demo(sess, net, im_name)##     plt.show()# 单一图片进行识别filename = '0001.jpg'im_names = [filename]for im_name in im_names:print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')print('Demo for data/demo/{}'.format(im_name))demo(sess, net, im_name)plt.show()

效果如下:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4 字符分割

将切分出来的图片进行保存,然后就是将其进行切分:

主程序的代码和上面第一步的步骤原理是相同的,不同的就是训练集的不同设置

效果图如下:

在这里插入图片描述

5 银行卡数字识别

仅部分代码:

import osimport tensorflow as tffrom PIL import Imagefrom nets2 import nets_factoryimport numpy as npimport matplotlib.pyplot as plt# 不同字符数量CHAR_SET_LEN = 10# 图片高度IMAGE_HEIGHT = 60# 图片宽度IMAGE_WIDTH = 160# 批次BATCH_SIZE = 1# tfrecord文件存放路径TFRECORD_FILE = r"C:\workspace\Python\Bank_Card_OCR\demo\test_result\tfrecords/1.tfrecords"# placeholderx = tf.placeholder(tf.float32, [None, 224, 224])os.environ["CUDA_VISIBLE_DEVICES"] = '0'   #指定第一块GPU可用config = tf.ConfigProto()config.gpu_options.per_process_gpu_memory_fraction = 0.5  # 程序最多只能占用指定gpu50%的显存config.gpu_options.allow_growth = True      #程序按需申请内存sess = tf.Session(config = config)# 从tfrecord读出数据def read_and_decode(filename):# 根据文件名生成一个队列filename_queue = tf.train.string_input_producer([filename])reader = tf.TFRecordReader()# 返回文件名和文件_, serialized_example = reader.read(filename_queue)features = tf.parse_single_example(serialized_example,features={'image' : tf.FixedLenFeature([], tf.string),'label0': tf.FixedLenFeature([], tf.int64),})# 获取图片数据image = tf.decode_raw(features['image'], tf.uint8)# 没有经过预处理的灰度图image_raw = tf.reshape(image, [224, 224])# tf.train.shuffle_batch必须确定shapeimage = tf.reshape(image, [224, 224])# 图片预处理image = tf.cast(image, tf.float32) / 255.0image = tf.subtract(image, 0.5)image = tf.multiply(image, 2.0)# 获取labellabel0 = tf.cast(features['label0'], tf.int32)return image, image_raw, label0# 获取图片数据和标签image, image_raw, label0 = read_and_decode(TFRECORD_FILE)# 使用shuffle_batch可以随机打乱image_batch, image_raw_batch, label_batch0 = tf.train.shuffle_batch([image, image_raw, label0], batch_size=BATCH_SIZE,capacity=50000, min_after_dequeue=10000, num_threads=1)# 定义网络结构train_network_fn = nets_factory.get_network_fn('alexnet_v2',num_classes=CHAR_SET_LEN * 1,weight_decay=0.0005,is_training=False)with tf.Session() as sess:# inputs: a tensor of size [batch_size, height, width, channels]X = tf.reshape(x, [BATCH_SIZE, 224, 224, 1])# 数据输入网络得到输出值logits, end_points = train_network_fn(X)# 预测值logits0 = tf.slice(logits, [0, 0], [-1, 10])predict0 = tf.argmax(logits0, 1)# 初始化sess.run(tf.global_variables_initializer())# 载入训练好的模型saver = tf.train.Saver()saver.restore(sess, '../Cmodels/model/crack_captcha1.model-6000')# saver.restore(sess, '../1/crack_captcha1.model-2500')# 创建一个协调器,管理线程coord = tf.train.Coordinator()# 启动QueueRunner, 此时文件名队列已经进队threads = tf.train.start_queue_runners(sess=sess, coord=coord)for i in range(6):# 获取一个批次的数据和标签b_image, b_image_raw, b_label0 = sess.run([image_batch,image_raw_batch,label_batch0])# 显示图片img = Image.fromarray(b_image_raw[0], 'L')plt.imshow(img)plt.axis('off')plt.show()# 打印标签print('label:', b_label0)# 预测label0 = sess.run([predict0], feed_dict={x: b_image})# 打印预测值print('predict:', label0[0])# 通知其他线程关闭coord.request_stop()# 其他所有线程关闭之后,这一函数才能返回coord.join(threads)

最终实现效果:

在这里插入图片描述

最后

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/127886.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在基于亚马逊云科技的湖仓一体架构上构建数据血缘的探索和实践

背景介绍 随着大数据技术的进步&#xff0c;企业和组织越来越依赖数据驱动的决策。数据的质量、来源及其流动性因此显得非常关键。数据血缘分析为我们提供了一种追踪数据从起点到终点的方法&#xff0c;有助于理解数据如何被转换和消费&#xff0c;同时对数据治理和合规性起到关…

HarmonyOS(二)—— 初识ArkTS开发语言(上)之TypeScript入门

前言 Mozilla创造了JS&#xff0c;Microsoft创建了TS&#xff0c;而Huawei进一步推出了ArkTS。因此在学习使用ArkTS前&#xff0c;需要掌握基本的TS开发技能。 ArkTS介绍 ArkTS是HarmonyOS优选的主力应用开发语言。它在TypeScript&#xff08;简称TS&#xff09;的基础上&am…

奇富科技引领大数据调度革命:高效、稳定、实时诊断

日前&#xff0c;在世界最大的开源基金会 Apache旗下最为活跃的项目之一DolphinScheduler组织的分享活动上&#xff0c;奇富科技的数据平台专家刘坤元应邀为国内外技术工作者献上一场题为《Apache DolphinScheduler在奇富科技的优化实践》的精彩分享&#xff0c;为大数据任务调…

历年网规上午真题笔记(2015年)

解析: 变更控制为“问题识别”——“问题分析与变更描述”——“变更分析与成本计算”——“变更实现”——“修改后的需求” 自动化工具能够帮助变更控制过程更有效地运作,能有效收集、存储、管理变更,工具应该具备的特征如下: 可定义变更请求中的数据可定义变更请求生命…

云原生环境下JAVA应用容器JVM内存如何配置?—— 筑梦之路

Docker环境下的JVM参数非定值配置 —— 筑梦之路_docker jvm设置-CSDN博客 之前简单地记录过一篇&#xff0c;这里在之前的基础上更加细化一下。 场景说明 使用Java开发且设置的JVM堆空间过小时&#xff0c;程序会出现系统内存不足OOM&#xff08;Out of Memory&#xff09;的…

基于SSM的餐饮掌上设备点餐系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

Java,面向对象,抽象类和抽象方法(abstract的使用)

关于抽象类和抽象方法的使用&#xff0c;以Person和student和Teacher为例&#xff0c;若Student类和Teacher继承于Person类&#xff0c;老师和学生都有Person的特征。在一个班级里&#xff0c;只需要创建老师和学生的实例&#xff0c;并不需要创建Person的实例。关于Person的方…

OpenAI将推出ChatGPT Plus会员新功能,有用户反馈将支持上传文件和多模态

&#x1f989; AI新闻 &#x1f680; OpenAI将推出ChatGPT Plus会员新功能&#xff0c;有用户反馈将支持上传文件和多模态 摘要&#xff1a;OpenAI为ChatGPT Plus会员推出了一些新功能&#xff0c;包括上传文件、处理文件和多模态支持。用户不再需要手动选择模式&#xff0c;…

学习使用php实现汉字验证码

学习使用php实现汉字验证码 <?php //开启session &#xff0c;方便验证 session_start(); //创建背景画布 $image imagecreatetruecolor(200, 60); $background imagecolorallocate($image, 255, 255, 255); imagefill($image, 0, 0, $background);//创建背景画布 for ($…

HBase理论与实践-基操与实践

基操 启动&#xff1a; ./bin/start-hbase.sh 连接 ./bin/hbase shell help命令 输入 help 然后 <RETURN> 可以看到一列shell命令。这里的帮助很详细&#xff0c;要注意的是表名&#xff0c;行和列需要加引号。 建表&#xff0c;查看表&#xff0c;插入数据&#…

Android开发知识学习——Kotlin进阶

文章目录 次级构造主构造器init 代码块构造属性data class相等性解构Elvis 操作符when 操作符operatorLambda循环infix 函数嵌套函数注解使用处目标函数简化函数参数默认值扩展函数类型内联函数部分禁用用内联具体化的类型参数抽象属性委托属性委托类委托 Kotlin 标准函数课后题…

Docker 多阶段构建的原理及构建过程展示

Docker多阶段构建是一个优秀的技术&#xff0c;可以显著减少 Docker 镜像的大小&#xff0c;从而加快镜像的构建速度&#xff0c;并减少镜像的传输时间和存储空间。本文将详细介绍 Docker 多阶段构建的原理、用途以及示例。 Docker 多阶段构建的原理 在传统的 Docker 镜像构建…

diffusers-Tasks

https://huggingface.co/docs/diffusers/using-diffusers/unconditional_image_generationhttps://huggingface.co/docs/diffusers/using-diffusers/unconditional_image_generation1.Unconditional image generation 无条件图像生成是一个相对简单的任务。模型仅生成图像&…

能源化工过程-故障诊断数据集初探-田纳西-伊斯曼过程数据集

1. 田纳西-伊斯曼过程(TE)数据集简介 整个TE数据集由训练集和测试集构成,TE集中的数据由22次不同的仿真运行数据构成,TE集中每个样本都有52个观测变量。d00.dat至d21.dat为训练集样本,d00_te.dat至d21_te.dat为测试集样本。d00.dat和d00_te.dat为正常工况下的样本。d00.d…

如何开始开发一个跑腿App系统?

1. 确定需求和功能规划 开始开发之前&#xff0c;需明确系统所需的基本功能&#xff0c;包括用户注册、登录、下单、配送员匹配、订单跟踪等。这些功能需要在系统设计之初明确。 2. 技术选型 选择适合的技术栈。前端可以使用框架如React、Vue.js&#xff0c;后端可选择Node…

创新工具箱!重塑手机页面原型设计体验

在2024年&#xff0c;随着移动设备的普及和用户对移动体验的要求不断提升&#xff0c;手机页面原型设计工具变得越来越重要。在这篇文章中&#xff0c;我将为您推荐几款在2024年非常流行且值得一试的手机页面原型设计工具。 Pixso Pixso是一款基于云端的协作设计工具&#xf…

【已解决】PPT不能转换成PDF文档怎么办?

PPT可以转换成PDF文档&#xff0c;只需要点击PPT菜单页面中的【文件】选项&#xff0c;再点击【导出】即可转换&#xff0c;如果转换时发现【导出】选项不可选&#xff0c;无法完成转换怎么办&#xff1f;以下3种方法可以试试&#xff01; 出现上面这种情况&#xff0c;我们可以…

模糊C均值聚类(FCM)python

目录 一、模糊C均值聚类的原理 二、不使用skfuzzy的python代码 三、 使用skfuzzy的python代码 一、模糊C均值聚类的原理 二、不使用skfuzzy的python代码 import numpy as np import random import matplotlib.pyplot as plt plt.rcParams[font.sans-serif][SimHei] plt.r…

二叉树问题——前/中/后/层遍历问题(递归与栈)

摘要 博文主要介绍二叉树的前/中/后/层遍历(递归与栈)方法 一、前/中/后/层遍历问题 144. 二叉树的前序遍历 145. 二叉树的后序遍历 94. 二叉树的中序遍历 102. 二叉树的层序遍历 103. 二叉树的锯齿形层序遍历 二、二叉树遍历递归解析 // 前序遍历递归LC144_二叉树的前…

Linux的test测试功能

测试文件名的类型&#xff0c;文件是否存在&#xff0c; 文件的权限检测 文件之间的比较 两个整数之间的比较 判断字符串数据 多重条件判定 一个一个来&#xff0c;这个有点多&#xff0c;不过比较有意思&#xff0c;来代码 案例1&#xff0c;判断文件是否存在&#xff…