opencv 银行卡号识别案例

目录

一.参数设置

二.指定信用卡的类型

三.模板图像中的数字定位处理

1.读取数字模板照片做灰度图处理并进行二值化处理成黑底白字

2.得到所有数字轮廓

3.给所有数字轮廓排序

4.将数字和对应的外接矩形图片即数字图片保存在字典中

四.信用卡的图像处理

1.银行卡图片的基本处理

①读取图片

②通过自定义的方法将图像等比缩放到宽度为300后提取灰度图

③顶帽操作(顶帽=原始图像-开运算结果(先腐蚀后膨胀))

2.找到银行卡图片中的数字边框

①通过闭操作(先膨胀后腐蚀),将数字连在一起

​编辑

②对闭操作后的图进行二值化处理

③对二值化后的黑白图载进行一次闭操作

④找出最后闭操作的图中所有的轮廓

⑤遍历找出的轮廓,找到数字部分像素区域轮廓的最小外接矩形并保存

3.遍历上面得到的每一个轮廓矩形中的数字,再匹配每一个值

①切片获取数字区域

②对数字区域group图片进行二值化处理得到黑底白字

③找出group的中的所有数字外轮廓,再排序

④匹配group中的每一个数值

⑤使用模板匹配,计算匹配得分

⑥在遍历完一个group里的所有数值后直接在银行卡原图片画出该group外界矩阵并在上面写出对应数字

4.遍历所有的数字轮廓矩形后打印结果


本案例根据银行卡的图片识别出银行卡号,效果如下 :

第一个数字用来代表银行卡的类型,在代码中我们可以使用字典来保存

一.参数设置

导入相关库和文件,其中myutils是一个自己创建的工具包,后面会介绍

python 复制代码
import numpy as np
import argparse  # python内置库
import cv2
import myutils

我们使用argparse类来设置参数,只需在运行配置中填入参数即可

python 复制代码
# 设置参数
ap = argparse.ArgumentParser()  #创建 ArgumentParser 对象,这个对象将用于定义和解析命令行参数
ap.add_argument("-i", "--image", required=True,
                help="path to input image")
ap.add_argument("-t", "--template", required=True,
                help="path to template OCR-A image")
args = vars(ap.parse_args())  # vars()是Python中的一个内置函数,用于返回对象的属性和值的字典。

在运行配置中填入-i card1.png -t kahao.pn,args=vars()是Python中的一个内置函数,用于返回对象的属性和值的字典,则args['image']='card1.png',args['template']='kakao.png'

二.指定信用卡的类型

我们直接用字典来保存不同数字对应的银行卡类型

python 复制代码
# 指定信用卡类型
FIRST_NUMBER = {"3": "American Express",
                "4": "Visa",
                "5": "MasterCard",
                "6": "Discover Card"}

自定义一个展示图片的函数减小代码量

python 复制代码
def cv_show(name, img):  # 绘图展示
    cv2.imshow(name, img)
    cv2.waitKey(0)

三.模板图像中的数字定位处理

1.读取数字模板照片做灰度图处理并进行二值化处理成黑底白字

python 复制代码
img=cv2.imread(args['template'])
cv_show('img',img)
python 复制代码
ref=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)
python 复制代码
ref=cv2.threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1]#二值图像黑底白字,方便找到轮廓
cv_show('ref',ref)

cv2.THRESH_BINARY_INV模式像素值大于thresh(10)的变为0,小于thresh的变成255,取索引[1]是因为函数有两个返回结果第二个才是需要的二值图

2.得到所有数字轮廓

cv2.RETR_EXTERNAL模式代表只检测图像的外轮廓,

cv2.CHAIN_APPROX_SIMPLE表示只简单保留轮廓的终点坐标即只保留完整轮廓的其中一部分

python 复制代码
_,refCnts,hierarchy=cv2.findContours(ref,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#RETR_EXTERNAL只检测外轮廓,CHAIN_APPROX_SIMPLE只保留终点坐标
cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show('img',img)

drawContours()方法表示在直接img上画出轮廓,-1表示绘制所有轮廓

3.给所有数字轮廓排序

由于我们前面提取到的所有轮廓refCnts中的轮廓列表并不是和我们图片中的数字一个是按顺序拍好的,所有我们在myutils.py中自定义了一个排序方法sort_contours()来将refCnts列表中的轮廓按对应的数字0,1,2,3,4,5,6,7,8,9排好

python 复制代码
def sort_contours(cnts,method='left-to-right'):
    reverse=False
    i=0
    if method=='right-to-left'or method=='bottom-to-top':
        reverse=True
    if method=='bottom-to-top'or method=='bottom-to-top':
        i=1

    boundingBoxes=[cv2.boundingRect(c) for c in cnts]
    (cnts,boundingBoxes)=zip(*sorted(zip(cnts,boundingBoxes),key=lambda a:a[1][i],reverse=reverse))
    return cnts,boundingBoxes

boundingBoxes=[cv2.boundingRect(c) for c in cnts]是遍历轮廓列表中的所有轮廓,分别得到他们的最小外接矩形后,以列表的形式存储在boundingsBoxes中

sorted(zip(cnts,boundingBoxes),key=lambda a:a[1][i],reverse=reverse)是先将轮廓列表和对应的外接矩阵列表用zip()组和在一组里,然后根据外接 矩阵列表中的第一个元素即外界矩行的x坐标的大小来排序,从小到大排序,对应的轮廓就是从0到9,排序完成之后在用zip()压缩成组返回,最后return轮廓列表和对应的最小外接矩行列表

python 复制代码
refCnts,boundingBoxes= myutils.sort_contours(refCnts, method='left-to-right')

调用方法得到排序后的轮廓列表和对应的最小外接矩形列表

4.将数字和对应的外接矩形图片即数字图片保存在字典中

利用上面返回的最小外接矩形列表通过索引得到对应数字外接矩形的x,y,w和h ,直接在黑底白字的二值图ref上进行切片操作来截取对应的数字图片,最后一遍遍的保存在字典中(键:数字,值:对应的图片)

python 复制代码
digits={}
for i in range(10):
    (x,y,w,h)=boundingBoxes[i]
    roi=ref[y:y+h,x:x+w]
    roi=cv2.resize(roi,(57,88))
    cv_show('roi',roi)
    digits[i]=roi
print(digits)

可以来显示对应的数字图片

四.信用卡的图像处理

1.银行卡图片的基本处理

①读取图片

python 复制代码
image=cv2.imread(args['image'])
cv_show('image',image)

②通过自定义的方法将图像等比缩放到宽度为300后提取灰度图

python 复制代码
def resize(image,width=None,height=None,inter=cv2.INTER_AREA):
    dim=None
    (h,w)=image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r=height/float(h)
        dim=(int(w*r),height)
    else:
        r=width/float(w)
        dim=(width,int(h*r))
    resized=cv2.resize(image,dim,interpolation=inter)#默认为cv2.INTER_AREA,即面积插值适用于缩放图像
    return resized
python 复制代码
image= myutils.resize(image, width=300)
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)

③顶帽操作(顶帽=原始图像-开运算结果(先腐蚀后膨胀))

突出图像中的亮细节,清楚背景图,原因是背景颜色变化小不被腐蚀掉

直接使用 cv2.getStructuringElement()方法生成卷积核(**全是1的矩阵)**一个9*3的一个5*5的

在cv2.morphologyEx()方法中cv2.MORPH_TOPHAT表示顶帽模式卷积核我们选择使用9*3的卷积核对银行卡的灰度图进行顶帽处理

python 复制代码
rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))#初始化卷积核
sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
tophat=cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)#顶帽=原始图像-开运算结果(先腐蚀后膨胀)
cv_show('tophat',tophat)

2.找到银行卡图片中的数字边框

①通过闭操作(先膨胀后腐蚀),将数字连在一起

将之前得到的顶帽后的图片进行闭操作,卷积核选择9*3的

python 复制代码
closeX=cv2.morphologyEx(tophat,cv2.MORPH_CLOSE,rectKernel)
cv_show('closeX',closeX)

②对闭操作后的图进行二值化处理

cv2.THRESH_OTSU会自动寻找适合的阈值,适合双峰,需要把阈值参数设置为0

python 复制代码
#cv2.THRESH_OTSU会自动寻找适合的阈值,适合双峰,需要把阈值参数设置为0
thresh=cv2.threshold(closeX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
cv_show('thresh_1',thresh)

③对二值化后的黑白图载进行一次闭操作

这一次卷积核使用5*5的

python 复制代码
#再来一次闭操作
thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
cv_show('thresh_2',thresh)

④找出最后闭操作的图中所有的轮廓

python 复制代码
_,threshCnts,h=cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts=threshCnts

在初始银行卡图片的副本上画出所有轮廓

python 复制代码
cur_img=image.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3)
cv_show('cur_img',cur_img)

⑤遍历找出的轮廓,找到数字部分像素区域轮廓的最小外接矩形并保存

locs集和用来存放最后符合条件的四块数字区域轮廓的最小外界矩形的x,y,w和h的元组

具体的判定条件,选择合适的区域,根据实际任务

python 复制代码
locs=[]
for (i,c) in enumerate(cnts):
    (x,y,w,h)=cv2.boundingRect(c)
    ar=w/float(h)
    #选择合适的区域,根据实际任务
    if 2.5<ar<4.0:
        if 40<w<55 and 10<h<20:
            locs.append((x,y,w,h))

将符合的轮廓外界矩形从左到右排序,根据x坐标

python 复制代码
locs=sorted(locs,key=lambda x:x[0])

3.遍历上面得到的每一个轮廓矩形中的数字,再匹配每一个值

output列表用来存放最后匹配得到的所有数字

①切片获取数字区域

可以利用上面存储外界矩形信息的列表locs直接在银行卡的灰度图中切片出一块数字区域的外界矩形可以适当增加一些边界

group_output列表存放每一个group中的所有数字

python 复制代码
output=[]
#遍历每一个轮廓中的数字
for (i,(gX,gY,gW,gH)) in enumerate(locs):
    group_output=[]
    group=gray[gY-5:gY+gH+5,gX-5:gX+gW+5]#适当加一点边界
    cv_show('group',group)

这里我们直接将四次遍历后的图片都放出来但实际上是一次循环后才会出来后面的group图片

注意:后续代码的缩进是表示还在此for循环中

②对数字区域group图片进行二值化处理得到黑底白字

python 复制代码
    group=cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
    cv_show('group', group)

③找出group的中的所有数字外轮廓,再排序

python 复制代码
                      
    group_,digitCnts,hierarchy=cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    digitCnts= myutils.sort_contours(digitCnts, method='left-to-right')[0]

④匹配group中的每一个数值

对上面得到的group中的所有数字轮廓进行遍历,得到对应的外接矩形的信息后直接对group进行切片操作获取该数字的图片

python 复制代码
#计算每一组中的每一个数值
    for c in digitCnts:
        #找到当前数值的轮廓,resize成合适的大小
        (x,y,w,h)=cv2.boundingRect(c)
        roi=group[y:y+h,x:x+w]
        roi=cv2.resize(roi,(57,88))
        cv_show('roi',roi)

⑤使用模板匹配,计算匹配得分

遍历前面存储数字和对应图片的字典

cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)在字典中的数字图片匹配当前roi返回结果

scores列表用来存放当前roi对每个字典中的数字图片的得分

python 复制代码
  scores=[]
        #在模板中计算每一个得分
        for (digit,digitROI) in digits.items():
            #模板匹配
            result=cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)
            (_,score,_,_)=cv2.minMaxLoc(result)
            scores.append(score)

往group_output中添加遍历字典后最大得分的索引直接对应相应的数字

python 复制代码
#得到合适的数字
        group_output.append(str(np.argmax(scores)))

⑥在遍历完一个group里的所有数值后直接在银行卡原图片画出该group外界矩阵并在上面写出对应数字

python 复制代码
    cv2.rectangle(image,(gX-5,gY-5),(gX+gW+5,gY+gH+5),(0,0,255),3)
    cv2.putText(image,''.join(group_output),(gX,gY-15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)
    output.extend(group_output)

4.遍历所有的数字轮廓矩形后打印结果

Credit Card Type可以用最开始的银行类型字典来获取,output[0]就是第一位银行卡号

Credit Card就是将output列表的内容用''.join()直接连接起来返回字符串

最后显示识别后的银行卡号图

python 复制代码
print('Credit Card Type:{}'.format(FIRST_NUMBER[output[0]]))
print('Credit Card #:{}'.format(''.join(output)))
cv2.imshow('Image',image)
cv2.waitKey(0)
相关推荐
后端小肥肠3 小时前
公众号卡在 vs 漫画赛道?Coze 一键出稿:输入标题就生成,小白也能冲 10w+
人工智能·aigc·coze
微盛AI企微管家3 小时前
企业微信AI功能升级:选对企业微信服务商协助四大AI场景落地
大数据·人工智能·企业微信
eqwaak03 小时前
科技信息差(9.10)
网络·人工智能·分布式·ar·智能硬件
虫无涯3 小时前
如何使用LangChain的Python库结合DeepSeek进行多轮次对话?
人工智能
mortimer3 小时前
精通BAT脚本:为你的Windows AI项目打造“一键启动”的完美体验
人工智能
Baihai_IDP3 小时前
MCP 是为开发者设计的工具,而非为 LLM 而设
人工智能·面试·llm
IT_陈寒4 小时前
SpringBoot性能翻倍的7个隐藏配置,90%开发者从不知道!
前端·人工智能·后端
深耕AI4 小时前
PyTorch自定义模型结构详解:从基础到高级实践
人工智能·pytorch·python
Twilight-pending4 小时前
计算机系统性能、架构设计、调度策略论文分类体系参考
人工智能·云原生·分类·数据挖掘