『工程项目实践』银行卡识别(CTPN+CRNN)

article/2025/11/1 23:02:15

银行卡识别

  • 前言
  • 一、数据预处理
    • 1.1 数据准备
    • 1.2 数据增强
  • 二、训练(CRNN)
  • 三、需要修改的内容
    • 3.1 数据增强
    • 3.2 训练
  • 四、CRNN 结构说明
    • 4.1 CNN
    • 4.2 BiLSTM
    • 4.3 CTC
  • 五、卡号检测
  • 六、BIN码校验
  • 参考链接


前言

  • 对各种银行卡进行卡号识别,CTPN 进行文字定位,CRNN 进行文字识别以及 Web 实现银行卡号码识别
  • 我们国内现在目前用的卡类标准为 ISO/IEC7810:2003 的 ID-1 标准,卡片尺寸是 85.60mm*53.98mm,通过计算长宽比可以得到为 0.623.
  • 先思考一下我们的大致思路: 因为我们最终是要完成卡面信息的识别,我们可以分为两个关键流程:文本检测文本识别

一、数据预处理

1.1 数据准备

  • bankcard_pre 每张图片大小为 120 * 46,图片命名格式为 0000a_0.png
  • 每个原始训练图片包括 4 个字符,待后来进行随机 4~6 个随机拼接形成类似银行卡号的长度。
  • 训练集与验证集的比例是 9:1

1.2 数据增强

  • 先对图像做数据增强,然后再做图像拼接。
  • 随机缩放、平移、颜色变换、模糊处理、噪声,最后进行连接,增强倍数 96 倍
    • noise: 随机在图像中添加 500 个白色点像素;(2次)
    • resize: 在一定范围内非同比例缩放;(4次)
    • colormap: 随机进行颜色变换;(1次)
    • blur: 分别有高斯模糊、均值模糊、中值模糊、双边滤波;(4次)
    • place_img: 上下浮动 10%~20%, 左右浮动 1.5%~2%;(4次)

代码实现:

import os
import numpy as np
from os import getcwd
import cv2
import PIL.Image
import random
import copy
import multiprocessingPATH = 'train_img/'def rand(a=0, b=1):return np.random.rand() * (b - a) + adef rand_resize(img, img_name, count, annotation, jitter=.3):w, h, _ = img.shapenew_ar = w / h * rand(1 - jitter, 1 + jitter) / rand(1 - jitter, 1 + jitter)scale = rand(.25, 2)if new_ar < 1:nh = int(scale * h)nw = int(nh * new_ar)else:nw = int(scale * w)nh = int(nw / new_ar)new_name = img_name[:6] + str(count) + '.png'count = count + 1annotation[PATH + new_name] = annotation[PATH + img_name]new_img = cv2.resize(img, (nh, nw), cv2.INTER_CUBIC)cv2.imwrite(PATH + new_name, new_img)return countdef place_img(img, img_name, count, annotation):H, W, C = img.shapeoffestH = int(rand(int(H * 0.1), int(H * 0.2)))offestW = int(rand(int(W * 0.015), int(W * 0.02)))dst = np.zeros((H, W, C), np.uint8)dst1 = np.zeros((H, W, C), np.uint8)dst2 = np.zeros((H, W, C), np.uint8)dst3 = np.zeros((H, W, C), np.uint8)for i in range(H - offestH):for j in range(W - offestW):dst[i + offestH, j + offestW] = img[i, j]dst1[i, j] = img[i + offestH, j + offestW]dst2[i + offestH, j] = img[i, j + offestW]dst3[i, j + offestW] = img[i + offestH, j]new_name = img_name[:6] + str(count) + '.png'count += 1new_name1 = img_name[:6] + str(count) + '.png'count += 1new_name2 = img_name[:6] + str(count) + '.png'count += 1new_name3 = img_name[:6] + str(count) + '.png'count += 1cv2.imwrite(PATH + new_name, dst)cv2.imwrite(PATH + new_name1, dst1)cv2.imwrite(PATH + new_name2, dst2)cv2.imwrite(PATH + new_name3, dst3)annotation[PATH + new_name] = annotation[PATH + img_name]annotation[PATH + new_name1] = annotation[PATH + img_name]annotation[PATH + new_name2] = annotation[PATH + img_name]annotation[PATH + new_name3] = annotation[PATH + img_name]return countdef colormap(img, img_name, count, annotation):rand_b = rand() + 1rand_g = rand() + 1rand_r = rand() + 1H, W, C = img.shapenew_name = img_name[:6] + str(count) + '.png'count += 1dst = np.zeros((H, W, C), np.uint8)for i in range(H):for j in range(W):(b, g, r) = img[i, j]b = int(b * rand_b)g = int(g * rand_g)r = int(r * rand_r)if b > 255:b = 255if g > 255:g = 255if r > 255:r = 255dst[i][j] = (b, g, r)annotation[PATH + new_name] = annotation[PATH + img_name]cv2.imwrite(PATH + new_name, dst)return countdef blur(img, img_name, count, annotation):img_GaussianBlur = cv2.GaussianBlur(img, (5, 5), 0)img_Mean = cv2.blur(img, (5, 5))img_Median = cv2.medianBlur(img, 3)img_Bilater = cv2.bilateralFilter(img, 5, 100, 100)new_name = img_name[:6] + str(count) + '.png'count += 1new_name1 = img_name[:6] + str(count) + '.png'count += 1new_name2 = img_name[:6] + str(count) + '.png'count += 1new_name3 = img_name[:6] + str(count) + '.png'count += 1annotation[PATH + new_name] = annotation[PATH + img_name]annotation[PATH + new_name1] = annotation[PATH + img_name]annotation[PATH + new_name2] = annotation[PATH + img_name]annotation[PATH + new_name3] = annotation[PATH + img_name]cv2.imwrite(PATH + new_name, img_GaussianBlur)cv2.imwrite(PATH + new_name1, img_Mean)cv2.imwrite(PATH + new_name2, img_Median)cv2.imwrite(PATH + new_name3, img_Bilater)return countdef noise(img, img_name, count, annotation):H, W, C = img.shapenoise_img = np.zeros((H, W, C), np.uint8)for i in range(H):for j in range(W):noise_img[i, j] = img[i, j]for i in range(500):x = np.random.randint(H)y = np.random.randint(W)noise_img[x, y, :] = 255new_name = img_name[:6] + str(count) + '.png'count += 1annotation[PATH + new_name] = annotation[PATH + img_name]cv2.imwrite(PATH + new_name, noise_img)return countdef concat(img, img_name, count, annotation, img_list):# img = cv2.imread(PATH+img_name)H, W, C = img.shapenum = int(rand(4, 6))imgs = random.sample(img_list, num)dst = np.zeros((H, W * (num + 1), C), np.uint8)for h in range(H):for w in range(W):dst[h, w] = img[h, w]new_name = img_name[:6] + str(count) + '.png'count += 1boxes = copy.copy(annotation[PATH + img_name])for i, image_name in enumerate(imgs):image = cv2.imread(PATH + image_name)for h in range(H):for w in range(W):dst[h, W * (i + 1) + w] = image[h, w]for label in annotation[PATH + image_name]:boxes.append(label)cv2.imwrite(PATH + new_name, dst)annotation[PATH + new_name] = boxescount = noise(dst, new_name, count, annotation)  # 1count = noise(dst, new_name, count, annotation)for i in range(4):count = rand_resize(dst, new_name, count, annotation)  # 4count = colormap(dst, new_name, count, annotation)  # 1count = blur(dst, new_name, count, annotation)  # 4count = place_img(dst, new_name, count, annotation)  # 4return countdef main(img, img_name, annotation):count = 1for i in range(5):count = concat(img, img_name, count, annotation, img_list)  # 1print(img_name + "增强完成")if __name__ == '__main__':trainval_percent = 0.2train_percent = 0.8img_list = os.listdir(PATH)manager = multiprocessing.Manager()annotation = manager.dict()for img_name in img_list:boxes = []a = np.linspace(0, 120, 5, dtype=np.int)for i in range(len(a) - 1):if img_name[i] == '_':continueboxes.append(img_name[i])annotation[PATH + img_name] = boxes''' 多进程处理数据,windows下测试出错 '''pool = multiprocessing.Pool(10)for img_name in img_list:img = cv2.imread(PATH + img_name, -1)pool.apply_async(main, (img, img_name, annotation,))pool.close()pool.join()''' 非多进程处理数据 '''# for img_name in img_list:#     img = cv2.imread(PATH + img_name,-1)#     main(img,img_name,annotation)train_file = open('train.txt', 'w')val_file = open('val.txt', 'w')val_split = 0.1rand_index = list(range(len(annotation)))random.shuffle(rand_index)val_index = rand_index[0: int(0.1 * len(annotation))]for i, names in enumerate(annotation.keys()):if i in val_index:val_file.write(names)for label in annotation[names]:val_file.write(" " + str(label))val_file.write('\n')else:train_file.write(names)for label in annotation[names]:train_file.write(" " + str(label))train_file.write('\n')train_file.close()val_file.close()

二、训练(CRNN)

  • step 1: 传入训练的图像均为 灰度化图像,并且 shape: (32,256)
  • step 2: 预测的 label 长度:img_w / 4(即每 4 个像素分隔有一个 pred,最后采用 ctc_loss 对齐)
  • step 3: 训练指令如下
cd bankcardocr/train
CUDA_VISIBLE_DEVICES=0 python run.py

三、需要修改的内容

3.1 数据增强

  • PATH 的路径
  • train_file 的路径
  • val_file 的路径

3.2 训练

  • weight_save_path 的路径
  • train_txt_path 的路径
  • val_txt_path 的路径

四、CRNN 结构说明

  • 具体实现细节可参考我另一篇博客:CRNN
  • 博客地址:https://blog.csdn.net/libo1004/article/details/111595054

4.1 CNN

CNN: 采用 CNN(类似于 VGG 网络)进行特征提取,提取到的特征以序列方式输出。

# Map2Sequence part
x = Permute((2, 3, 1), name='permute')(conv_otput)  # 64*512*1
rnn_input = TimeDistributed(Flatten(), name='for_flatten_by_time')(x)  # 64*512

4.2 BiLSTM

BLSTM: 特征输入到 BLSTM,输出每个序列代表的值(这个值是一个序列,代表可能出现的值),对输出进行 softmax 操作,计算每个可能出现值得概率。

y = Bidirectional(LSTM(256, kernel_initializer=initializer, return_sequences=True), merge_mode='sum', name='LSTM_1')(rnn_input)  # 64*512
y = BatchNormalization(name='BN_8')(y)
y = Bidirectional(LSTM(256, kernel_initializer=initializer, return_sequences=True), name='LSTM_2')(y)  # 64*512
y_pred = Dense(num_classes, activation='softmax', name='y_pred')(y)

4.3 CTC

CTC: 相当于一个 loss,一个计算概率到实际输出的概率。

五、卡号检测

判断银行卡(储蓄卡,信用卡)的卡号的合法性用到了 Luhn 算法
算法流程如下:

  1. 从右到左给卡号字符串编号,最右边第一位是1,最右边第二位是2,最右边第三位是3….
  2. 从右向左遍历,对每一位字符t执行第三个步骤,并将每一位的计算结果相加得到一个数s。
  3. 对每一位的计算规则:如果这一位是奇数位,则返回t本身,如果是偶数位,则先将t乘以2得到一个数n,如果n是一位数(小于10),直接返回n,否则将n的个位数和十位数相加返回。
  4. 如果s能够整除10,则此号码有效,否则号码无效。

因为最终的结果会对10取余来判断是否能够整除10,所以又叫做模10算法

算法代码:


def luhn_checksum(card_number):def digits_of(n):return [int(d) for d in str(n)]digits = digits_of(card_number)odd_digits = digits[-1::-2]even_digits = digits[-2::-2]checksum = 0checksum += sum(odd_digits)for d in even_digits:return checksum % 10def is_luhn_valid(card_number):return luhn_checksum(card_number) == 0

六、BIN码校验

银行卡号一般是13-19位组成,国内一般是 16,19 位,其中 16 位为信用卡,19 位为储蓄卡,通常情况下都是由 “卡BIN+发卡行自定位+校验位” 这三部分构成,

银行卡的前 6 位用来识别发卡银行或者发卡机构的,称为发卡行识别码,简称为卡BIN。拿出钱包里的卡,会发现如果是只带有银联标注的卡,十有八九都是以62开头的,但是也有例外。

这里边包含一个坑:你知道Bin码的规则,但是你不知道国内银行的BIN码,网上的也大都不全,只能以后慢慢人工扩充。

我这边整理了一份,但是也不全,大概包含有 1300 个 BIN 号,以后再慢慢整理
BIN码
只需要将合法的卡号前6位切片出来进行查询就好了。

参考链接

  1. https://mp.weixin.qq.com/s/22DomsxOm6p9IotQ4XB0_Q
  2. https://mp.weixin.qq.com/s/M_iYGkSDUHbd5gkbr9PDPw

http://chatgpt.dhexx.cn/article/EhAC2l98.shtml

相关文章

【深度学习】YOLOv5 中使用的 CSPNet 是怎么回事

论文&#xff1a;https://arxiv.org/pdf/1911.11929.pdf CSPNet全称是Cross Stage Partial Network&#xff0c;主要从一个比较特殊的角度切入&#xff0c;能够在降低20%计算量的情况下保持甚至提高CNN的能力。 跨阶段局部网络&#xff08;CSPNet&#xff09;是 Wang 等人于 20…

Opencv多语言自然场景文本识别系统(源码&教程)

1. 研究背景 人类在自然场景中可以快速定位并识别看到的文字信息&#xff0c;但是想要计算机做到和人类一样是比较困难的。开发人员一直想要让机器也能识别图像中的文字信息。当然,对于自然场景来说,图像中的信息复杂甚至是低效的,文字旁的物体﹑光影,以及字体颜色、大小、书写…

深度学习CTPN+CRNN模型实现图片内文字的定位与识别(OCR)

1:样本获取 **算法论文:** Synthetic Data for Text Localisation in Natural Images Github: https://github.com/ankush-me/SynthText **词库:** https://pan.baidu.com/s/10anmu 英文词汇 经过处理后得到大约500兆 6000万词组 **字体:** ubntu系统下支持中文的字体&…

ctpn、east阅读要点记录

最近要做一些ocr的事情&#xff0c;阅读了文字定位的相关论文&#xff0c;主要是ctpn和east.下面对这两篇论文的药店进行一个记录。 CTPN ctpn结合了卷积神经网络和循环神经网络。卷机神经网络用于提取图片特征&#xff0c;循环神经网络能够帮助提升对文字的定位和分类的准确…

基于CTPN(tensorflow)+CRNN(pytorch)+CTC的不定长文本检测和识别

文章主要是为了说明在windows平台下调试遇到的问题。 代码地址&#xff1a;https://github.com/Aurora11111/chinese-ocr-pytorch 按照相关说明&#xff0c;安装相关的pytorch和tensorflow&#xff0c;我使用的是python3.7 下载代码后&#xff0c;需要进行修改才能在windows…

OCR文字识别项目(原理)

参考视频&#xff1a; OCR文字识别原理 OCR光学字符识别&#xff1a;提取图像中的文字&#xff0c;并转换为文本形式&#xff0c;供后续NLP使用。 一、CTPN算法&#xff1a;文字检测 二、CRNN算法&#xff1a;文字识别 池化此时为12。才能把特征变为适用于输入到RNN中。

CTPN+CRNN算法端到端实现文字识别的实战开发

本文分享自华为云社区《CTPNCRNN 算法端到端实现文字识别》&#xff0c;作者&#xff1a;HWCloudAI。 OCR介绍 光学字符识别&#xff08;英语&#xff1a;Optical Character Recognition&#xff0c;OCR&#xff09;是指对文本资料的图像文件进行分析识别处理&#xff0c;获取…

OCR入门教程系列(五):OCR实战代码解析

👨‍💻作者简介: CSDN、阿里云人工智能领域博客专家,新星计划计算机视觉导师,百度飞桨PPDE,专注大数据与AI知识分享。✨公众号:GoAI的学习小屋 ,免费分享书籍、简历、导图等,更有交流群分享宝藏资料,关注公众号回复“加群”或➡️链接 加群。 🎉专栏推荐: ➡️ …

制作自己的ctpn数据集

制作自己的ctpn数据集 1、利用label-image标注自己的数据集&#xff0c;保存为.txt文件&#xff0c;结果如下&#xff1a; 上图第一列 0&#xff1a;标签 后面的小数是label—image标注的坐标框位置&#xff08;归一化后的结果&#xff09; 2、ctpn数据集的格式&#xff1a;…

CTPN文本检测与tensorflow实现

1. 引言 近年来&#xff0c;随着人工智能的发展&#xff0c;文本检测在很多任务中都是一项基本任务&#xff0c;比如广告牌中文字识别、智能驾驶路牌的检测、身份证识别、快递地址识别等。这些任务中首先的一项就是文本检测&#xff0c;即检测出文本在图像中的位置&#xff0c;…

制作自己的CTPN训练集

制作自己的CTPN训练集 使用labelimg工具制作YOLO格式再将其转为CTPN中需要的8个坐标 1.标注框 2.代码生成坐标并保存 import cv2 import os def change_labelimage_to_cptn_data(pictures_file_path, txt_file_path, cptn_data_labels_path):list os.listdir(txt_file_pat…

【文本检测与识别-白皮书-3.1】第四节:算法模型 2

CTPN CTPN&#xff0c;全称是“Detecting Text in Natural Image with Connectionist Text Proposal Network”&#xff08;基于连接预选框网络的文本检测&#xff09;。CTPN直接在卷积特征映射中检测一系列精细比例的文本建议中的文本行。CTPN开发了一个垂直锚定机制&#xf…

CPTN代码运行报错

Windows10 系统运行 github上给的是linux操作系统指令 因为我是Windows10 的系统&#xff0c;不能通过setup的指令得到所需文件&#xff0c;后面根据https://github.com/eragonruan/text-detection-ctpn/issues/359的方法到第4步报错 错误1&#xff1a; 找不到cl.exe&#x…

JAVA项目实战开发电商项目案例(十)订单与支付模块

文章目录 1项目架构2项目采用技术3订单与支付模块功能演示4如何开发支付宝的支付模块以及订单模块4.1首先需要编写前端页面以及JS文件4.2其次需要编写JAVA后台接口4.3支付模块分析4.4订单模块分析5代码分析6个人说明7 [我的个人网站](http://www.liph.fun)8获取源码 此次电商系…

Java 项目实战 坦克大战 (0)--前言

做了有一个星期了&#xff0c;java语言太强大了&#xff0c;也算是学得最认真的一门语言了&#xff0c;本次课设花的心思也就比较多了。关键总是追求完美总是想原创&#xff0c;最终做出来效果不错&#xff0c;但感觉代码逻辑很乱&#xff0c;今天开始就好好整理一番&#xff0…

Java项目实战第11天:搜索功能的实现

目录 一、sql语句动态拼接二、前后台代码编写三、搜索框数据回填最后 今天是刘小爱自学Java的第110天。 感谢你的观看&#xff0c;谢谢你。 话不多说&#xff0c;开始今天的学习&#xff1a; 事先说明&#xff1a;关于今天的搜索功能实现。 并没有使用到倒排索引这样的主流搜…

【CSDN最全java项目实战500篇】练手/项目经验/毕设刚需

免费精选&#xff01;强烈建议收藏&#xff01;学完这一套直接进大厂&#xff08;附配套源码&资料&#xff09; C站&#xff08;CSDN&#xff09;软件工程师能力认证&#xff0c;已上线70天&#xff0c;下图300所高校的小伙伴们都已经预约、完成C认证&#xff0c;就等你来啦…

Java项目开发实战入门 PDF 扫描完整版

内容介绍 《Java项目开发实战入门》以一起来画画、通讯录系统、明日彩票预测系统、小小五子棋、企业进销存管理系统、企业QQ&#xff08;局域网版&#xff09;、九宫格记忆网和铭成在线考试系统8个精选项目为案例&#xff0c;从趣味性和实际应用角度出发&#xff0c;采用了当前…

全站最全实战的Java项目(附源码)

嗨喽&#xff0c;大家好&#xff0c;今天又要给大家整一波福利了&#xff01; 不管我们要学习哪种语言都希望能第一时间看到成效&#xff0c;能做出实际的东西来&#xff0c;那么这里所说的实际东西当然就是项目啦&#xff01;不用我说大家也知道&#xff0c;学编程语言不做项…

java项目实战之404错误原因总结

java项目实战之404错误原因总结 第一个原因可能是你的URL写错了&#xff0c;正确的URL应该这么写 localhost:8080/项目名称/对应的目录或者映射 好好检查检查是否是拼写错误&#xff0c;或者多了什么&#xff0c;少了什么 第二个原因可能是你的Spring配置文件写错了 一般都…