基于机器视觉的银行卡识别系统 - 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 python
    
    from __future__ import absolute_import
    from __future__ import division
    from __future__ import print_function
    import argparse
    import os
    import cv2
    import matplotlib.pyplot as plt
    import numpy as np
    import tensorflow as tf
    from lib.config import config as cfg
    from lib.utils.nms_wrapper import nms
    from lib.utils.test import im_detect
    from lib.nets.vgg16 import vgg16
    from lib.utils.timer import Timer
    
    os.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:
            return
    
        im = 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.shape
                width = 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 image
        im_file = os.path.join(cfg.FLAGS2["data_dir"], 'demo', image_name)
        im = cv2.imread(im_file)
        # Detect all object classes and regress object bounds
        timer = 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 class
        CONF_THRESH = 0.1
        NMS_THRESH = 0.1
        for cls_ind, cls in enumerate(CLASSES[1:]):
            cls_ind += 1  # because we skipped background
            cls_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 args



    if __name__ == '__main__':
        args = parse_args()
    
        # model path
        demonet = args.demo_net
        dataset = 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 config
        tfconfig = tf.ConfigProto(allow_soft_placement=True)
        tfconfig.gpu_options.allow_growth = True
    
        # init session
        sess = tf.Session(config=tfconfig)
        # load network
        if demonet == 'vgg16':
            net = vgg16(batch_size=1)
        # elif demonet == 'res101':
            # net = resnetv1(batch_size=1, num_layers=101)
        else:
            raise NotImplementedError
        net.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 os
    import tensorflow as tf
    from PIL import Image
    from nets2 import nets_factory
    import numpy as np
    import 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"
    
    # placeholder
    x = 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必须确定shape
        image = tf.reshape(image, [224, 224])
        # 图片预处理
        image = tf.cast(image, tf.float32) / 255.0
        image = tf.subtract(image, 0.5)
        image = tf.multiply(image, 2.0)
        # 获取label
        label0 = 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

水果FL Studio21.2体验版下载安装教程(增加云服务功能)

FL Cloud 音效库包含开放版权的Loop和采样&#xff0c;以及来自 FL Studio 著名用户的艺术家独家内容。更新后&#xff0c;现在还可以使用人工智能辅助母带处理和数字发行功能来制作音轨。FL Studio 由最初的 "Fruity Loops" DAW 发展而来&#xff0c;25 年来&#x…

非母语玩家如何撰写英文研究性论文:2 Methodology

参考书——《Science Research Writing for non-native Speakers of English》 文章目录 1 Structure 结构2 语法和写作技巧2.1 Passives and Tense Pairs: 被动语态以及时态对2.2 a与the的使用方法2.3 Adverbs and adverb location: 副词及其位置 3 Build a Model——构建Meth…

Linux系统封装ISO镜像(自动安装)

一、准备一个系统 centos7或者centos8都可以;最小化或者桌面版的都可以,自行选择 二、安装自定义镜像工具 yum -y install createrepo mkisofs openssl rsync syslinux三、挂载镜像 创建挂载点 mkdir /mnt/cdrommount /dev/sr0 /mnt/cdrom四、同步 /mnt/cdrom/ 下的文件到 …

基于深度学习的安全帽识别检测系统(python OpenCV yolov5)

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、研究的内容与方法二、基于深度学习的安全帽识别算法2.1 深度学习2.2 算法流程2.3 目标检测算法2.3.1 Faster R-CNN2.3.2 SSD2.3.3 YOLO v3 三 实验与结果分析3.1 实验数据集3.1.1 实验数据集的构建3.1.2 数据…

【Python】Python语法速成

目录 一、Python中的概念 二、Python和C/C++中的一些不同点 三、分支语句 四、for循环 五、函数 六、列表[]

CTB810 HN800 58914444 NDPI-02 DSTC190

CTB810 HN800 58914444 NDPI-02 DSTC190 控制微系统公司宣布推出SCADASense 4203&#xff0c;这是一款高精度集成气体流量计算机&#xff0c;集成了多变量传感器和完整的SCADAPack PLC。作为SCADASense系列流量和压力变送器的最新成员&#xff0c;4203设计用于各种过程控制应…

微信小程序的踩坑记录

问题记录&#xff1a; 嵌套太深 导致不起作用 点击我的工单 但是打印的结果值却是我的问题 没有点到我的工单上边去 原因&#xff1a;图片粘连在一起 解决方案:给图片100% 达到父元素的100% 最后成功蓝色的不粘连

innovus:命令返回列表元素超过显示上限如何解决

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 相关文章链接&#xff1a; innovus IMPSP-270 place阶段lib_cell找不到可放置位置问题 all_fanout等命令&#xff0c;返回列表太长&#xff0c;超过显示上限&#xff08;默认…

ubuntu 22.04 源码安装 apollo 8.0

对于其他的关于GPU的安装包需求&#xff0c;这里不再列出&#xff0c;因为我之前安装过&#xff0c;偷个懒就不写了&#xff0c;哈哈哈哈1, 安装docker 安装docker命令(这里的安装命令都是在docker官网,还有安装包)&#xff1a; 1&#xff0c; 设置docker的apt仓库 # Add Do…

一张动图告诉你,输入网址之后,发生了什么事情?

让我们一步一步地来看这个过程。 步骤1&#xff1a; 用户在浏览器中输入一个URL&#xff08;比如www.bytebytego.com&#xff09;&#xff0c;然后按下回车键。首先&#xff0c;我们需要将这个URL转换成一个IP地址。通常&#xff0c;这个映射关系会被存储在缓存中&#xff0…

CVE-2021-41773/42013 apache路径穿越漏洞

影响范围 CVE-2021-41773 Apache HTTP server 2.4.49 CVE-2021-42013 Apache HTTP server 2.4.49/2.4.50 漏洞原理 Apache HTTP Server 2.4.49版本使用的ap_normalize_path函数在对路径参数进行规范化时会先进行url解码&#xff0c;然后判断是否存在…/的路径穿越符&#xf…

【项目管理】生命周期风险评估

规划阶段目标&#xff1a;识别系统的业务战略&#xff0c;以支撑系统的安全需求及安全战略 规划阶段评估重点&#xff1a;1、本阶段不需要识别资产和脆弱性&#xff1b;2、应根据被评估对象的应用对象、应用环境、业务状况、操作要求等方面识别威胁&#xff1b; 设计阶段目标…

GameGPT:使用AI实现游戏开发自动化

使用多代理基于AI开发游戏的这种方法果真切实可行吗&#xff1f;如今&#xff0c;从事游戏开发如同走钢丝。游戏行业处于一种怪异的境地&#xff1a;游戏变得越来越酷&#xff0c;越来越有开创性&#xff0c;但同时也变得越来越让人头疼&#xff1a;更大的团队、更长的工作时间…

GoLong的学习之路(十一)语法之标准库 fmt.Printf的使用

上回书说到&#xff0c;函数&#xff0c;说了函数是如何实现的&#xff0c;高级函数有哪几种调用方式&#xff0c;本章我将介绍fmt 标准库中我常用的一些函数。 文章目录 fmtfmt的向外输出print格式化占位通用占位符布尔类型占位整型占位浮点数与复数字符串和[]byte指针宽度表示…

科技云报道:打造生成式AI应用,什么才是关键?

科技云报道原创。 生成式AI作为当前人工智能的前沿领域&#xff0c;全球多家科技企业都在加大生成式AI的研发投入力度。 随着技术、产品及应用等方面不断推出重要成果&#xff0c;如今有更多的行业用户在思考该如何将生成式AI应用落地。 但开发生成式AI应用是一个充满挑战的…

线段树 区间赋值 + 区间加减 + 求区间最值

线段树好题&#xff1a;P1253 扶苏的问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 区间赋值 区间加减 求区间最大。 对于区间赋值和区间加减来说&#xff0c;需要两个懒标记&#xff0c;一个表示赋值cover&#xff0c;一个表示加减add。 区间赋值的优先级大于区间加…

No authorization token was found

今天遇到了一个问题&#xff0c;我把前后端逻辑都理了一遍&#xff0c;开始怀疑后端&#xff0c;后端肯定没错了&#xff0c;把前端理了一遍&#xff0c;ok前后端没错&#xff0c;我错。登录哪里需要的token&#xff1f;&#xff1f;&#xff1f;&#xff1f;把我搞懵逼了。 测…

出租屋智能视频监控系统方案:全面保卫租客安全

除了我们常见的家庭、社区、园区等智能监控&#xff0c;出租房作为很多人的暂住所也极易发生盗窃等事件&#xff0c;为保障大众租户的财产安全&#xff0c;旭帆科技特地针对出租屋制定了智能监控系统方案。 1、安装智能安防摄像头 高清晰度、夜视功能良好的智能摄像头&#xf…

CSS 滚动驱动动画与 @keyframes 新语法

CSS 滚动驱动动画与 keyframes 在 CSS 滚动驱动动画相关的属性出来之后, keyframes 也迎来变化. 以前, keyframes 的值可以是 from, to, 或者百分数. 现在它多了一种属性的值 <timeline-range-name> <percentage> 建议先了解 animation-range 不然你会对 timeli…

Matlab中的app设计

1.窗口焦点问题&#xff1a; 窗口焦点问题&#xff1a;确保你的应用程序窗口正常处于焦点状态。有时&#xff0c;其他窗口的弹出或焦点切换可能导致应用程序最小化。点击应用程序窗口以确保它处于焦点状态。 窗口管理&#xff1a;确保你的 MATLAB 或操作系统没有未处理的错误或…