openCV+Python实战练习——银行卡号识别

目录

项目Introduce:

项目名称:

具体操作步骤以及代码:

实现结果展示:

代码整体展示:

项目Introduce:

项目名称:

        通过导入模板数字,对银行卡面上的数字进行识别,提取出银行卡面上的银行卡号。

项目流程预览:

1.处理模板图像,获取模板数字

2.导入银行卡图像

3.提取银行卡上的ROI

4.将模板数字与ROI二者的二值图像进行模板匹配

5.将匹配结果展示在银行卡上

项目与知识衔接:

    图像预处理、边缘检测、模板匹配......

具体操作步骤以及代码:

1.导入工具包(库)

from imutils import contours
import numpy as np
import argparse  #用于添加参数
import imutils  #依赖numpy
import cv2
import myutils #自设定的一个文件

myutils代码:

import cv2


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 == "top-to-bottom" or method == "bottom-to-top":
        i = 1
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]  # 用一个最小的矩形,把找到的形状包起来x,y,h,w
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda b: b[1][i], reverse=reverse))

    return cnts, boundingBoxes


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)
    return resized

2.调参

有两个参数需要处理(-i : 需要识别的图像、-t :模板)

#设置参数
ap = argparse.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())

#定义银行卡信息
FIRST_NUMBER = {
    '3':'American Express',
    '4':'Viso',
    '5':'MasterCard',
    '6':'Discover Card'
}
#自定义创建窗口函数
def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

参数调完后需要输入形参数据,就是你想进行匹配的模板和待检测图像,Pycharm中可以进行如下操作:

1.右键文件点击Modify Run Configuration(修改运行配置)

 2.找到Parameters(形参数据)

输入如下:(自行修改其中数据,第一个路径为待检测的银行卡图片路径,不含中字且将\改为/,第二个为模板数字图片的路径)

-i D:/works/pyton_pic/credit_card.png -t D:/works/pyton_pic/ocr_a_reference.png

 点击Apply-OK

3.导入模板并处理

        (1)读入模板图像

#读入模板图像
img = cv2.imread(args['template'])
cv_show('img',img)

 

        (2)模板图像转换为灰度图

#灰度处理
ref = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)

 

        (3)灰度图转换为二值图

#二值处理
ref = cv2. threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1] 
#[1]代表取元组的第一位展示(本来应该是ref,TRESHOLD_BINARY_INV双参)
cv_show('ref',ref)

        (4)找到所有数字的外轮廓

#轮廓检测  
refCnts,hierarcy = cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#cv2.RETR_EXTERMAL是只检测外轮廓
#cv2.CHAIN_APPROX_SIMPLE 是保留坐标点

        (5)将轮廓画出

#画出轮廓
cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show('img',img)

        (6)对找到的轮廓排序,得到轮廓集合

#轮廓排序
refCnts = myutils.sort_contours(refCnts,method='left-to=right')[0]

        (7)将每个数字制成一个模板

#定义一个空字典
digits = {}

#遍历轮廓
for (i,c) in enumerate(refCnts):
    (x,y,w,h) = cv2.boundingRect(c)
    roi = ref[y:y+h,x:x+w]
    roi = cv2.resize(roi,(57,88))
    digits[i] = roi
    cv_show('roi',roi)

4.导入银行卡图像并处理

        (1)初始化卷积核

cv2.getStructingElement 是cv2中定义核的一个函数,MORPH_CROSS代表卷积核的形状是矩形,还有交叉形MORPH_ELLIPSE,(9,3)和(5,5)是卷积核的大小,默认(-1,-1)为中心点。

#初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))

        (2)读取银行卡图像

#读取图像
image = cv2.imread(args['image'])
cv_show('image',image)

        (3)银行卡图像转为灰度图

#调整图像的尺寸、并进行图像灰度化
image = myutils.resize(image,width=300)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)

 

        (4)灰度图进行礼帽操作

#礼帽操作,使用(9,3)大小的卷积核
tophat = cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
cv_show('tophat',tophat)

 

        (5)利用Sobel算子进行边缘检测

#计算横向梯度 sobel边缘检测
gradX = cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=-1) #ksize=-1表示采取默认值,默认值为(3,3)
gradX = np.absolute(gradX)#取绝对值
(minVal,maxVal) = (np.min(gradX),np.max(gradX)) #取最大值和最小值
gradX = (255 * ((gradX - minVal)/(maxVal - minVal)))#归一化处理
gradX = gradX.astype('uint8')#把图像从CV_32F转化为uint8
cv_show('gradX',gradX)

        (6)Sobel算子运算后的图像进行闭操作

#闭运算
gradX = cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
cv_show('gradX',gradX)

        (7)闭操作后的图像进行二值化(threshold)

#二值处理
thresh = cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
#cv2.cv2.THRESH_OTSU为自动判断合适值代替0
cv_show('thresh',thresh)

        (8)二值化后的图像再次进行闭操作

#闭运算 目的是把区域中的黑色填充成白色
thresh = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
cv_show('thresh-close',thresh)

 

        (9)找出并画出轮廓,对轮廓进行筛选得出ROI(根据数字区域的W/H;以及图像大小范围)

#计算轮廓
#轮廓检测
threshCnts,hierarcy = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#cv2.RETR_EXTERMAL是只检测外轮廓
#cv2.CHAIN_APPROX_SIMPLE 是保留坐标点

#画出轮廓
cur_img = image.copy()
cv2.drawContours(cur_img,threshCnts,-1,(0,0,255),3)
# cv_show('cur_img',cur_img)

 筛选:


#过滤轮廓
locs = []
for(i,c) in enumerate(threshCnts):
    (x,y,w,h) = cv2.boundingRect(c)
    ar = w/float(h)
    if ar>2.5 and ar<4.0:
        if(w>40 and w<55) and(h>10 and h<20):
            locs.append((x,y,w,h))

print(locs)

遍历四个轮廓,找出外界轮廓位置图像:

#轮廓排序
locs = sorted (locs,key = lambda x:x[0])

#对轮廓中的内容进行轮廓检测
output = []
for (i,(gX,gY,gW,gH)) in enumerate(locs):
    groupOutput = []

    group = gray[gY-5:gY+gH+5,gX-5:gX+gW+5]
    # cv_show ('group',group)

 

 

 

 

二值化后:

    #二值处理
    group = cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
    # cv_show('group',group)

 

 

 

        (10)对ROI进行排序,提取ROI中的每一位数字进行模板匹配,筛选出最符合的数字

对ROI进行排序:

    #检测轮廓并且排序
    digitCnts,hierarchy = cv2.findContours(group.copy(),
                                           cv2.RETR_EXTERNAL,
                                           cv2.CHAIN_APPROX_SIMPLE)
    digitCnts = imutils.contours.sort_contours(digitCnts,method = 'left-to-right')[0]
    #提取轮廓矩形获得ROI
    for c in digitCnts:
        (x,y,w,h) = cv2.boundingRect(c)
        roi = group[y:y+h,x:x+w]
        roi = cv2.resize(roi,(57,99))
        cv_show('roi',roi)

 

进行模板匹配获得的数值,取每10个中最大的数值,加入groupOutput:

        #对ROI进行模板匹配
        scores = []
        for (digit,digitROI) in digits.items():
            result = cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)
            (_,score, _, _) = cv2.minMaxLoc(result)
            scores.append(score)
        print(scores)
        groupOutput.append(str(np.argmax(scores)))

将匹配结果画在银行卡面上 


    cv2.rectangle(image,(gX-5,gY-5),(gX+gW+5,gY+gH+5),(0,0,255),1)
    cv2.putText(image,''.join(groupOutput),(gX,gY-15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)
    cv_show('image',image)

5.展示结果

将模板匹配获得的索引放入output,然后根据output[0]判断银行卡类型,最后显示结果

    output.extend(groupOutput)
# print(output)
print(FIRST_NUMBER[output[0]])
print(output)
cv_show('image',image)

实现结果展示:

代码整体展示:

#导入工具包
from imutils import contours
import numpy as np
import argparse
import imutils
import cv2
import myutils

#设置参数
ap = argparse.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())

#定义银行卡信息
FIRST_NUMBER = {
    '3':'American Express',
    '4':'Viso',
    '5':'MasterCard',
    '6':'Discover Card'
}
#自定义创建窗口函数
def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


#处理模板

#读入模板图像
img = cv2.imread(args['template'])
cv_show('img',img)

#灰度处理
ref = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)

#二值处理
ref = cv2. threshold(ref,10,255,cv2.THRESH_BINARY_INV)[1] #[1]代表取元组的第一位展示(本来应该是ref,TRESHOLD_BINARY_INV双参)
cv_show('ref',ref)

#轮廓检测
refCnts,hierarcy = cv2.findContours(ref.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#cv2.RETR_EXTERMAL是只检测外轮廓
#cv2.CHAIN_APPROX_SIMPLE 是保留坐标点

#画出轮廓
cv2.drawContours(img,refCnts,-1,(0,0,255),3)
cv_show('img',img)
# print(np.array(refCnts).shape)

#轮廓排序
refCnts = myutils.sort_contours(refCnts,method='left-to=right')[0]

#定义一个空字典
digits = {}

#遍历轮廓
for (i,c) in enumerate(refCnts):
    (x,y,w,h) = cv2.boundingRect(c)
    roi = ref[y:y+h,x:x+w]
    roi = cv2.resize(roi,(57,88))
    digits[i] = roi
    cv_show('roi',roi)



#处理图像
#初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))

#读取图像
image = cv2.imread(args['image'])
cv_show('image',image)

#调整图像的尺寸、并进行图像灰度化
image = myutils.resize(image,width=300)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
cv_show('gray',gray)

#礼帽操作,使用(9,3)大小的卷积核
tophat = cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
cv_show('tophat',tophat)

#计算横向梯度 sobel边缘检测
gradX = cv2.Sobel(tophat,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=-1) #ksize=-1表示采取默认值,默认值为(3,3)
gradX = np.absolute(gradX)#取绝对值
(minVal,maxVal) = (np.min(gradX),np.max(gradX)) #取最大值和最小值
gradX = (255 * ((gradX - minVal)/(maxVal - minVal)))#归一化处理
gradX = gradX.astype('uint8')#把图像从CV_32F转化为uint8
cv_show('gradX',gradX)

#闭运算
gradX = cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
cv_show('gradX',gradX)

#二值处理
thresh = cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
#cv2.cv2.THRESH_OTSU为自动判断合适值代替0
cv_show('thresh',thresh)

#闭运算 目的是把区域中的黑色填充成白色
thresh = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel)
cv_show('thresh-close',thresh)
#计算轮廓
#轮廓检测
threshCnts,hierarcy = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#cv2.RETR_EXTERMAL是只检测外轮廓
#cv2.CHAIN_APPROX_SIMPLE 是保留坐标点

#画出轮廓
cur_img = image.copy()
cv2.drawContours(cur_img,threshCnts,-1,(0,0,255),3)
cv_show('cur_img',cur_img)

#过滤轮廓
locs = []
for(i,c) in enumerate(threshCnts):
    (x,y,w,h) = cv2.boundingRect(c)
    ar = w/float(h)
    if ar>2.5 and ar<4.0:
        if(w>40 and w<55) and(h>10 and h<20):
            locs.append((x,y,w,h))

# print(locs)

#轮廓排序
locs = sorted (locs,key = lambda x:x[0])

#对轮廓中的内容进行轮廓检测
output = []
for (i,(gX,gY,gW,gH)) in enumerate(locs):
    groupOutput = []

    group = gray[gY-5:gY+gH+5,gX-5:gX+gW+5]
    cv_show ('group',group)
    #二值处理
    group = cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
    cv_show('group',group)
    #检测轮廓并且排序
    digitCnts,hierarchy = cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    digitCnts = imutils.contours.sort_contours(digitCnts,method = 'left-to-right')[0]
    #提取轮廓矩形获得ROI
    for c in digitCnts:
        (x,y,w,h) = cv2.boundingRect(c)
        roi = group[y:y+h,x:x+w]
        roi = cv2.resize(roi,(57,99))
        cv_show('roi',roi)
        #对ROI进行模板匹配
        scores = []
        for (digit,digitROI) in digits.items():
            result = cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)
            (_,score, _, _) = cv2.minMaxLoc(result)
            scores.append(score)
        print(scores)
        groupOutput.append(str(np.argmax(scores)))

    cv2.rectangle(image,(gX-5,gY-5),(gX+gW+5,gY+gH+5),(0,0,255),1)
    cv2.putText(image,''.join(groupOutput),(gX,gY-15),cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)
    cv_show('image',image)
    output.extend(groupOutput)
# print(output)
print(FIRST_NUMBER[output[0]])
print(output)
cv_show('image',image)

猜你喜欢

转载自blog.csdn.net/Crabfishhhhh/article/details/128706845