2019年中國軟杯-基於深度學習的銀行卡號識別系統


  這次比賽,雖然沒有挺進決賽,但是整個比賽的過程讓自己成長了很多,也明白了很多

  首先這次比賽,名為“基於深度學習的銀行卡號識別系統”,所以我們組在每個環節就是用的深度學習的內容(雖然有很多的圖像處理技術可以直接做初期的銀行卡的處理,但是我們毅然決然的選擇了整個過程使用深度學習的技術),我們這也是第一次這么系統的接觸深度學習,在這之前,可以說是對深度學習就是一無所知,就是一竅不通,深度學習不僅僅應用的計算機知識,不僅僅是敲代碼的能力,同時更需要你的數學知識(如果你想深層次的接觸深度學習的話,僅僅應用深度學習現成的模型的話,了解模型的原理和代碼的含義就行了)

  我們小組對這方面的知識不是很全面,但是通過我們一段時間的學習還是有所突破

  下面就說一下我們小組對整個比賽的的流程

  (嘗試過很多的方法,想直接對我們的銀行卡進行長字符的識別,但是我們的訓練集實在是太小了,所以還是走了把銀行卡號切成單字符進行單字符的識別的方法(這種方法就是在時間和空間上比較浪費))

  1.首先就是將整張銀行卡號里面的銀行卡號部分進行識別,且分出來,這一個環節我們用的技術就是faster-rcnn的方法

  (詳細代碼不在這里粘了,有需要的可以在下面的Github進行下載)

https://github.com/H-Designer/DeepLearning-Bank_Card_OCR

  將目標識別部分的銀行卡號部門且分出來,進行保存

  主程序的代碼如下:

  

#!/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()

 

  

效果圖如下:

 

 

  2.將切分出來的圖片進行保存,然后就是將其進行切分:

  主程序的代碼和上面第一步的步驟原理是相同的,不同的就是訓練集的不同設置 

  效果圖如下:

 

 

3、最后一部就是訓練一些單字符的 圖片,然后保存模型,然后對切分出來的 單字符進行識別

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)

這里就是對單字符進行識別

在一步對單字符進行識別,但是需要的就是要知道每個圖片的順序,所以,在前面就要知道每個圖片的坐標順序,然后進行保存,然后根據坐標順序挨個進行識別

 

這就是整個銀行卡識別的思想和流程,我將項目代碼上傳到github,有需要的可以進行下載,訓練的模型就不上傳了,需要的按照文件執行一下,保存的模型的文件夾自己設置,在代碼里面引用模型的時候,自己設置就好了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM