OpenCV之信用卡识别

跟風遠走 提交于 2020-01-23 19:06:54

前言


在学完OpenCV中对图像的已经基本操作之后,例如彩色空间变换、阈值处理、图像梯度、轮廓检测、最小矩形匹配以及模板匹配。我们肯定非常急切地想去做一些事情,这里的信用卡卡号识别便是基于这些知识来做的!

正文


一.任务说明

在生活中,我们经常会遇到一些需要识别的地方,比如说在道路上的车牌识别、指纹识别、人脸识别等等,在不同的场景中所需要识别的内容也就不同。
在生活中的某一场景中(模拟),我们需要对银行卡卡号进行识别,来减轻我们工作的强度,需要我们设计算法,实现银行卡卡号的识别

二.算法设计

1.数字的模板获取

  • 这里我们的识别算法是根据模板匹配来实现的,在进行处理之前,需要准备与要识别信用卡数字风格差别不大的数字模板;模板的准备就不详细说明了,这也不是重点,模板数字图片如下。
  • 对于准备的模板图片,还要将其中的每一个数字抠出来,保存在一个字典中,便于之后进行模板匹配。
def get_template(path):

    img = cv2.imread(path)    #读取数字模板
    img = cv2.resize(img,(400,64))			#resize到合适的大小

    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)   #灰度处理


    _,gray = cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV)	#阈值处理

    cout,_ = cv2.findContours(gray,cv2.CV_8UC1,cv2.RETR_CCOMP)
#寻找轮廓
    point = []
    for i in cout:
        x, y, w, h = cv2.boundingRect(i)
        point.append((x,y,w,h))
        #将每一个数字对应的坐标保存起来

    point = sorted(point,key=lambda x:x[0],reverse=False)#对坐标进行排序,寻找轮廓时,顺序不是0-9的
    digit = {}
    for i,(x,y,w,h) in enumerate(point):

        digit[i] = cv2.resize(gray[y-2:y+h+2,x-2:x+w+2],(48,64))    #得到每个数字的图像
    return digit   #返回数字模板

2.信用卡卡号提取

  1. 对图片进行一些形态学操作
    1 构造适合的卷积核
    2 灰度处理
    3 礼帽操作
	#构造适合的卷积核
	rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
    sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))

 	gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #礼帽操作
	gray = cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)
  1. 求图形梯度
    梯度操作,在这里非常重要,如果不进行梯度操作,信用卡上面的数字可能提取不全。
 	#求x方向的梯度
 	gradX = cv2.Sobel(gray,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=1)

    gradX = np.absolute(gradX)

    #归一化
    minVal,maxVal = np.min(gradX),np.max(gradX)

    gradX = (255*((gradX-minVal)/(maxVal-minVal)))

    gradX = gradX.astype("uint8")
  1. 重复一些形态学操作
    1 闭操作
    2 阈值处理
    3 闭操作
	gradX = cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)

    _,thresh = cv2.threshold(gradX,127,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)

    thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel,iterations=2)
  1. 然寻找轮廓
    1 将匹配到的轮廓安装适合的太小进行过滤,只保存我们需要的轮廓,数字
    2 然后排序,按照原始顺序进行排列
	group = []
    for i in cout:
        x,y,w,h = cv2.boundingRect(i)
        if(w/h)>3.2 and (w/h)<5:
            if (cv2.contourArea(i))>650 and (cv2.contourArea(i))<1000:
                group.append((x,y,w,h))
    #排序
    group = sorted(group,key=lambda x:x[0],reverse=False)
  1. 进行匹配
    1 提取提取出来的信用卡数字,一一与模板进行匹配,以确定其数字是什么。
 for x,y,w,h in group:
        img = gray[y-5:y+h+5,x-5:x+w+5]
        _, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
        cout, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        tt = []
        for i in cout:
            x,y,w,h = cv2.boundingRect(i)
            tt.append((x,y,w,h))
        tt = sorted(tt,key=lambda x:x[0],reverse=False)
        for x,y,w,h in tt:
            dst = img[y-2:y+h+2,x-2:x+w+2]
            dst = cv2.resize(dst,(48,64))
            sortes = []

            for j,temp in enumerate(digit.values()):
                result = cv2.matchTemplate(dst,temp,cv2.TM_CCOEFF)
                min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
                sortes.append(max_val)

            output.append(str(np.argmax(sortes)))
  1. 最后是画图操作
    for i in range(4):
        put = ""
        for j in range(4):
            put +=output[i*4+j]
        cv2.putText(img,put,(dist[i][0],dist[i][1]-10),cv2.FONT_HERSHEY_SIMPLEX,0.8,(0,0,255),2)

三 总结

经过这个小项目的实践,让我更加熟悉了一些对图像处理的基本操作,也让我知道了这些基本操作组合起来的威力也是非常大的,也是可以处理实践问题的。
完整代码如下

import cv2
import numpy as np

"""
1. 模板
2. 二值化
3. 开闭操作
4. 轮廓匹配
5. 模板匹配
6. 顶帽
"""

#获取数字模板
def get_template(path):

    img = cv2.imread(path)
    img = cv2.resize(img,(400,64))

    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)


    _,gray = cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV)

    cout,_ = cv2.findContours(gray,cv2.CV_8UC1,cv2.RETR_CCOMP)

    point = []
    for i in cout:
        x, y, w, h = cv2.boundingRect(i)
        point.append((x,y,w,h))

    point = sorted(point,key=lambda x:x[0],reverse=False)
    digit = {}
    for i,(x,y,w,h) in enumerate(point):

        digit[i] = cv2.resize(gray[y-2:y+h+2,x-2:x+w+2],(48,64))
    return digit


def get_digit_area(img,digit):
    #构造卷积核
    rectKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(9,3))
    sqKernel=cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))



    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #礼帽操作
    gray = cv2.morphologyEx(gray,cv2.MORPH_TOPHAT,rectKernel)

    cv2.imshow('a',gray)
    #求x方向的梯度
    gradX = cv2.Sobel(gray,ddepth=cv2.CV_32F,dx=1,dy=0,ksize=1)

    gradX = np.absolute(gradX)

    #归一化
    minVal,maxVal = np.min(gradX),np.max(gradX)

    gradX = (255*((gradX-minVal)/(maxVal-minVal)))

    gradX = gradX.astype("uint8")
    #闭操作
    cv2.imshow("gra",gradX)
    cv2.waitKey(0)
    gradX = cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)

    _,thresh = cv2.threshold(gradX,127,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)

    thresh=cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,sqKernel,iterations=2)


    #寻找轮廓
    cout,_ = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

    group = []
    for i in cout:
        x,y,w,h = cv2.boundingRect(i)
        if(w/h)>3.2 and (w/h)<5:
            if (cv2.contourArea(i))>650 and (cv2.contourArea(i))<1000:
                group.append((x,y,w,h))
    #排序
    group = sorted(group,key=lambda x:x[0],reverse=False)
    output = []
    for x,y,w,h in group:
        img = gray[y-5:y+h+5,x-5:x+w+5]
        _, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
        cout, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        tt = []
        for i in cout:
            x,y,w,h = cv2.boundingRect(i)
            tt.append((x,y,w,h))
        tt = sorted(tt,key=lambda x:x[0],reverse=False)
        for x,y,w,h in tt:
            dst = img[y-2:y+h+2,x-2:x+w+2]
            dst = cv2.resize(dst,(48,64))
            sortes = []

            for j,temp in enumerate(digit.values()):
                result = cv2.matchTemplate(dst,temp,cv2.TM_CCOEFF)
                min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
                sortes.append(max_val)

            output.append(str(np.argmax(sortes)))


    return group,output



def main():
    img = cv2.imread("credit_card_02.png")
    img = cv2.resize(img,(400,250))
    digit = get_template("template.png")
    dist,output = get_digit_area(img,digit)
    for i in range(4):
        put = ""
        for j in range(4):
            put +=output[i*4+j]
        cv2.putText(img,put,(dist[i][0],dist[i][1]-10),cv2.FONT_HERSHEY_SIMPLEX,0.8,(0,0,255),2)
    print(output)
    cv2.imshow("A",img)
    cv2.waitKey(0)

if __name__ == '__main__':
    main()


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!