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

news2024/11/15 8:47:57

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

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

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

相关文章

基于麒麟服务器V10的.NET部署、运行 + 金仓数据库

一言而论&#xff1a;基于麒麟服务器V10的.NET部署、运行&#xff0c;涉及的信创产品有麒麟、金仓&#xff0c;使用了.NET 6 API 文章目录 前言环境硬件环境软件环境 麒麟安装.NET麒麟安装金仓数据库.NET与KES通讯麒麟部署.NET总结参考资料 前言 紧跟着笔者的上一篇文章《银河…

使用HandlerInterceptor 中注入其他service时为null分析及解决

一情况分析 1.1 拦截器代码 public class ServerInterceptor implements HandlerInterceptor {private static final Logger _logger LoggerFactory.getLogger(ServerInterceptor.class);PrintWriter out;JSONObject res new JSONObject();AutowiredUserInfoLoginService u…

我也惊呆了!原来软件开发根本不需要会编码

一、前言 众所周知&#xff0c;完成一个大型的企业级系统&#xff0c;公司往往需要大量的人力做支持后盾&#xff0c;例如需要需求分析师、数据库管理员、前台美工、后台程序员、测试人员等。在快速发展中的企业&#xff0c;尤其是中小企业&#xff0c;都是一个萝卜多个坑&…

【软件推荐】屏蔽手机开屏广告

有时博客内容会有变动&#xff0c;首发博客是最新的&#xff0c;其他博客地址可能未同步&#xff0c;请认准https://blog.zysicyj.top 首发博客地址 软件介绍 李跳跳APP是一款强大的手机软件弹窗广告跳过软件。通常我们使用的广告拦截软件是通过直接代理网络来过滤广告&#xf…

AI改写-AI改写可以迅速生成新的文章有什么弊端吗?

大家好&#xff0c;今天我们要聊一聊一个近年来备受热议的话题&#xff1a;147SEO改写。现在人工智能技术已经发展到了可以帮助我们改写文章的程度。这听起来似乎很神奇&#xff0c;但也引发了一些深思。我们将在本文中讨论这个话题&#xff0c;看看AI改写究竟是一种利好还是一…

SAP CRM 模块:概述,体系结构

前言 CRM 代表“客户关系管理”&#xff0c;是一组有助于以有组织的方式管理客户关系的方法和工具。 在当今竞争激烈的商业环境中&#xff0c;顶级公司的注意力越来越集中于其最有价值的资产– 客户。 因此&#xff0c;这些公司需要一种合适的软件解决方案来迎合其客户&#…

华为云云耀云服务器L实例评测|云耀云服务器购买流程与功能介绍

目录 概述什么是云耀云服务器L实例功能概述 技术参数处理器和内存存储和网络GPU加速 强大的计算能力高性能计算集群大规模并行计算 灵活可扩展的存储本地SSD存储产品购买流程 概述 什么是云耀云服务器L实例 云耀云服务器L实例是新一代开箱即用、面向中小企业和开发者打造的全新…

NFT Insider#107:The Sandbox和Unstoppable Domains合作,YGG“超级任务”冠军诞生

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟世界类&#…

xxl-job-代码创建任务执行本地命令+解决报错

问题描述 因为环境受限&#xff0c;所以我的mysql和xxl-job-admin是放在docker里的&#xff0c;执行器是放在本地的&#xff0c;要执行的命令也需要本地环境。 本文将记录相关配置、实现过程和遇到的问题及解决方案。 配置 xxl-job-admin配置 xxl-job-admin放在docker容器…

虚拟机批量备份时缩短备份窗口的方法之一:串/并行快照

一条备份任务中是可以同时备份多个虚拟机的&#xff0c;虚拟机在备份的时候&#xff0c;需要对其进行打快照来保证数据的一致性。 对虚拟机进行打快照&#xff0c;需要消耗一定的时间&#xff0c;当虚拟机开启时&#xff0c;虚拟机的内存状态也会被快照下来&#xff0c;因此快…

无涯教程-JavaScript - INDIRECT函数

描述 INDIRECT函数返回由文本字符串指定的引用。 如果您在Excel公式中键入引用B1,则Excel会理解这引用了单元格B1。但是,Excel无法将文本字符串" B1"理解为引用。因此,如果单元格引用采用文本字符串的形式,则需要使用INDIRECT函数将其转换为实际的单元格引用。 立…

SpringMvc---编码过滤器(解决乱码问题)

目录 一、介绍 二、字符编码过滤器 一、介绍 在传递参数时&#xff0c;tomcat8以上能处理get请求的中文乱码&#xff0c;danshibunengqingqiupost请求的中文乱码。 二、字符编码过滤器 对于出现的中文乱码问题&#xff0c;SpringMvc提供了处理中文乱码的过滤器&#xff0c;在…

短视频矩阵系统源码技术独立部署搭建

一、矩阵系统源码主要有三种框架&#xff1a; 矩阵系统源码主要有三种框架&#xff1a;Matplotlib、NumPy和SciPy。Matplotlib是一个用于制图的库&#xff0c;可用于绘制各种类型的图表&#xff0c;包括线图、散点图、柱状图等。NumPy是用于处理大型多维数组和矩阵的库&#x…

Canvas 低代码工具,多人自研开发全流程优化|ModelWhale 版本更新

白露时节、秋雨殷勤&#xff0c;ModelWhale 也迎来了新一轮的版本更新&#xff0c;多层面持续优化你的使用体验。 本次更新中&#xff0c;ModelWhale 主要进行了以下功能迭代&#xff1a; 优化 Canvas 多人自研开发流程&#xff08;团队版✓&#xff09; 新增 Canvas 组件历史…

AIGC 设计能替代真正的设计师设计吗?

AIGC 设计能替代真正的设计师设计吗&#xff1f; 目录 一、写在前面的话 二、AIGC 设计能替代真正的设计师吗&#xff1f; 1.1、传统设计师设计 1.2、AIGC设计 1.3、相关概念 1.4、观点分析 &#xff08;1&#xff09;、审美角度 &#xff08;2&#xff09;、版权角度 …

2023十大杰出外盘黄金交易APP平台最新排名

黄金&#xff0c;作为全球最重要的避险资产之一&#xff0c;一直备受投资者青睐。随着科技的发展&#xff0c;手机炒黄金APP平台逐渐成为投资者的新选择。本文将为您介绍“2023十大杰出外盘黄金交易APP平台最新排名”&#xff0c;帮助您选择合适的平台进行黄金投资。 本次排名…

埃文科技受邀出席“安全堤坝”技术论坛

2023年9月11日&#xff0c;2023年国家网络安全宣传周河南省活动开幕式暨河南省网络文明大会在开封博物馆开幕。由CCF YOCSEF郑州举办的“聚焦数据交易监管技术&#xff0c;筑牢数据交易‘安全堤坝’”技术论坛在开封市博物馆二楼会议厅举行。埃文科技总经理王永博士与副总经理武…

【深度学习】 Python 和 NumPy 系列教程(廿六):Matplotlib详解:3、多子图和布局:subplots()函数

目录 一、前言 二、实验环境 三、Matplotlib详解 1、2d绘图类型 2、3d绘图类型 3、多子图和布局 1. subplot()函数 2. subplots()函数 简单示例 一、前言 Python是一种高级编程语言&#xff0c;由Guido van Rossum于1991年创建。它以简洁、易读的语法而闻名&#xff0…

汽车电子 -- PCAN View 安装与使用

一、PCAN-View 简介 参看&#xff1a;PCAN-View PCAN View 是显示CAN和CAN FD报文的Window软件 PCAN-View 功能概述 PCAN-View for Windows软件是一款简便的CAN监视软件&#xff0c;可用于显示、发送、和记录CAN数据通讯。可手动和定期发送报文&#xff0c;用户可决定比特率…

ZABBIX 6.4官方安装文档

一、官网地址 Zabbix&#xff1a;企业级开源监控解决方案 二、下载 1.选择您Zabbix服务器的平台 2. Install and configure Zabbix for your platform a. Install Zabbix repository # rpm -Uvh https://repo.zabbix.com/zabbix/6.4/rhel/8/x86_64/zabbix-release-6.4-1.el8…