openCV+Python combat practice - bank card number recognition

Table of contents

Project Introduction:

project name:

Specific operation steps and code:

Realize the result display:

The overall display of the code:

Project Introduction:

project name:

        By importing template numbers, identify the numbers on the bank card face and extract the bank card number on the bank card face.

Project process preview:

1. Process the template image and obtain the template number

2. Import bank card image

3. Extract the ROI on the bank card

4. Perform template matching on the binary image of the template number and the ROI

5. Display the matching results on the bank card

Linkage between projects and knowledge:

    Image preprocessing, edge detection, template matching...

Specific operation steps and code:

1. Import toolkit (library)

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

myutils code:

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. Adjust parameters

There are two parameters to process (-i: image to be recognized, -t: template)

#设置参数
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()

After the parameters are adjusted, you need to enter the formal parameter data, which is the template you want to match and the image to be detected. The following operations can be performed in Pycharm:

1. Right-click the file and click Modify Run Configuration (modify the running configuration)

 2. Find Parameters (formal parameter data)

The input is as follows: (modify the data by yourself, the first path is the path of the bank card image to be detected, without Chinese characters and change \ to /, and the second path is the path of the template digital image)

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

 Click Apply-OK

3. Import the template and process it

        (1) Read in the template image

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

 

        (2) The template image is converted to a grayscale image

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

 

        (3) Convert the grayscale image to a binary image

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

        (4) Find the outer contours of all numbers

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

        (5) Draw the outline

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

 

        (6) Sort the found contours to get the contour set

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

        (7) Make each number into a template

#定义一个空字典
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. Import bank card image and process

        (1) Initialize the convolution kernel

cv2.getStructingElement is a function that defines the kernel in cv2. MORPH_CROSS means that the shape of the convolution kernel is a rectangle, and there is also a cross shape MORPH_ELLIPSE. (9, 3) and (5, 5) are the size of the convolution kernel. The default (-1 , -1) as the center point.

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

        (2) Read bank card image

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

 

        (3) Convert bank card image to grayscale image

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

 

 

        (4) Top hat operation for grayscale image

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

 

 

        (5) Using Sobel operator for edge detection

#计算横向梯度 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) The image after Sobel operator operation is closed.

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

        (7) The image after the closed operation is binarized (threshold)

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

 

        (8) The binarized image is closed again

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

 

 

        (9) Find and draw the outline, and filter the outline to get the ROI (according to the W/H of the digital area; and the image size range)

#计算轮廓
#轮廓检测
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)

 filter:


#过滤轮廓
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)

Traverse the four contours to find the position image of the outer contour:

#轮廓排序
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)

 

 

 

 

After binarization:

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

 

 

 

        (10) Sort the ROI, extract each digit in the ROI for template matching, and filter out the most suitable number

Sort the ROIs:

    #检测轮廓并且排序
    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)

 

 

Take the value obtained by template matching, take the largest value out of every 10, and add it to 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)))

Draw the matching result on the face of the bank card 


    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. Display the results

Put the index obtained by template matching into output, then judge the bank card type according to output[0], and finally display the result

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

Realize the result display:

The overall display of the code:

#导入工具包
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)

Guess you like

Origin blog.csdn.net/Crabfishhhhh/article/details/128706845