OpenCV之信用卡識別

前言


在學完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()


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章