关于opencv的实战——银行卡号识别

首先我们先来引入我们所需要的库和我们定义的图像显示(方便):

import cv2
import numpy as np
import imutils
from imutils import contours

#显示图像
def cv_show(img,name="image"):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyWindow(name)

 其次我们来引入银行卡数字的模板并进行预处理操作:

 关于opencv的实战——银行卡号识别_第1张图片

template=cv2.imread('TT.jpg')
# cv_show(template)
#化为灰度图
ref_template=cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
# cv_show(ref_template)
#化为二值图
ref_template=cv2.threshold(ref_template,10,255,cv2.THRESH_BINARY_INV)[1]
# cv_show(ref_template)

#轮廓检测
##findContours 只接受二值图   RETR_EXTERNAL 只检测外轮廓   CHAIN_APPROX_SIMPLE 只保留终点坐标
BIT,refCnts,hierarchy=cv2.findContours(ref_template.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(template,refCnts,-1,(0,0,255),3)
# cv_show(template)
# print(np.array(refCnts).shape)
#轮廓排序
refCnts=contours.sort_contours(refCnts,method="left-to-right")[0]
# print(refCnts)

digits={}
for (i,c) in enumerate(refCnts):
    #计算外接矩形
    (x,y,w,h)=cv2.boundingRect(c)
    roi=ref_template[y:y+h,x:x+w]
    #resize成合适大小
    roi=cv2.resize(roi,(57,88))
     # cv_show(roi)
    #每个数字对应一个模板
    digits[i]=roi

 接下来把我们需要识别的银行卡引入并进行处理:

关于opencv的实战——银行卡号识别_第2张图片

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

#读取输入图像
image=cv2.imread('T1.jpg')

# cv_show(image)
image=imutils.resize(image,width=300)
image_gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# cv_show(image_gray)

#tophat顶帽操作,突出明亮区域
image_tophat=cv2.morphologyEx(image_gray,cv2.MORPH_TOPHAT,rectKernel)
# cv_show(image_tophat)

#计算梯度  使得轮廓更加清晰
gradX=cv2.Sobel(image_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")
# print(np.array(gradX).shape)
# cv_show(gradX)

#闭操作(先膨胀后腐蚀)把数字连在一起
gradX=cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
# cv_show(gradX)

#二值化
image_thresh=cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
# cv_show(image_thresh)

#二值化后再次闭操作
image_thresh=cv2.morphologyEx(image_thresh,cv2.MORPH_CLOSE,sqKernel)
# cv_show(image_thresh)

#计算轮廓
BITT,threshCnts,hierarchy=cv2.findContours(image_thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)


cv2.drawContours(image.copy(),threshCnts,-1,(0,0,255),1)
# cv_show(image)

 最后就是我们来匹配银行卡模板和数字模板的:

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))
locs=sorted(locs,key=lambda x:x[0])
output=[]

for (i,(gx,gy,gw,gh)) in enumerate(locs):# gx,gy,gw,gh 代表 4000 这一片区域
    groupOutput=[]
    #提取每一组数字(一组包括4个数字)
    group=image_gray[gy-5:gy+gh+5,gx-5:gx+gw+5]
    # cv_show(group)

    group=cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
    # cv_show(group)

    B,digitsCnts,A=cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    digitsCnts=imutils.contours.sort_contours(digitsCnts,method="left-to-right")[0]
    # print(digitsCnts)
    for c in digitsCnts:  #遍历每一个数字   如4000  依次遍历4、0、0、0
        (x,y,w,h)=cv2.boundingRect(c)
        # print((x,y,w,h))
        roi=group[y:y+h,x:x+w]
        #把匹配图像设置成模板图像一致大小
        roi=cv2.resize(roi,(57,88))
        # cv_show(roi)

        #计算匹配得分
        scores=[]

        for (digit,digitROI) in digits.items():
            #模板匹配
            result=cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)
            (_,score,_,_)=cv2.minMaxLoc(result)
            scores.append(score)

        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)

    output.extend(groupOutput)

cv_show(image)
print("".join(output))

 

 最后所显示的结果。

完整代码奉上:

import cv2
import numpy as np
import imutils
from imutils import contours

#显示图像
def cv_show(img,name="image"):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyWindow(name)


template=cv2.imread('TT.jpg')
# cv_show(template)
#化为灰度图
ref_template=cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)
# cv_show(ref_template)
#化为二值图
ref_template=cv2.threshold(ref_template,10,255,cv2.THRESH_BINARY_INV)[1]
# cv_show(ref_template)

#轮廓检测
##findContours 只接受二值图   RETR_EXTERNAL 只检测外轮廓   CHAIN_APPROX_SIMPLE 只保留终点坐标
BIT,refCnts,hierarchy=cv2.findContours(ref_template.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(template,refCnts,-1,(0,0,255),3)
# cv_show(template)
# print(np.array(refCnts).shape)
#轮廓排序
refCnts=contours.sort_contours(refCnts,method="left-to-right")[0]
# print(refCnts)

digits={}
for (i,c) in enumerate(refCnts):
    #计算外接矩形
    (x,y,w,h)=cv2.boundingRect(c)
    roi=ref_template[y:y+h,x:x+w]
    #resize成合适大小
    roi=cv2.resize(roi,(57,88))
     # cv_show(roi)
    #每个数字对应一个模板
    digits[i]=roi

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

#读取输入图像
image=cv2.imread('T1.jpg')

# cv_show(image)
image=imutils.resize(image,width=300)
image_gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# cv_show(image_gray)

#tophat顶帽操作,突出明亮区域
image_tophat=cv2.morphologyEx(image_gray,cv2.MORPH_TOPHAT,rectKernel)
# cv_show(image_tophat)

#计算梯度  使得轮廓更加清晰
gradX=cv2.Sobel(image_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")
# print(np.array(gradX).shape)
# cv_show(gradX)

#闭操作(先膨胀后腐蚀)把数字连在一起
gradX=cv2.morphologyEx(gradX,cv2.MORPH_CLOSE,rectKernel)
# cv_show(gradX)

#二值化
image_thresh=cv2.threshold(gradX,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
# cv_show(image_thresh)

#二值化后再次闭操作
image_thresh=cv2.morphologyEx(image_thresh,cv2.MORPH_CLOSE,sqKernel)
# cv_show(image_thresh)

#计算轮廓
BITT,threshCnts,hierarchy=cv2.findContours(image_thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)


cv2.drawContours(image.copy(),threshCnts,-1,(0,0,255),1)
# cv_show(image)


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))
locs=sorted(locs,key=lambda x:x[0])
output=[]

for (i,(gx,gy,gw,gh)) in enumerate(locs):# gx,gy,gw,gh 代表 4000 这一片区域
    groupOutput=[]
    #提取每一组数字(一组包括4个数字)
    group=image_gray[gy-5:gy+gh+5,gx-5:gx+gw+5]
    # cv_show(group)

    group=cv2.threshold(group,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]
    # cv_show(group)

    B,digitsCnts,A=cv2.findContours(group.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    digitsCnts=imutils.contours.sort_contours(digitsCnts,method="left-to-right")[0]
    # print(digitsCnts)
    for c in digitsCnts:  #遍历每一个数字   如4000  依次遍历4、0、0、0
        (x,y,w,h)=cv2.boundingRect(c)
        # print((x,y,w,h))
        roi=group[y:y+h,x:x+w]
        #把匹配图像设置成模板图像一致大小
        roi=cv2.resize(roi,(57,88))
        # cv_show(roi)

        #计算匹配得分
        scores=[]

        for (digit,digitROI) in digits.items():
            #模板匹配
            result=cv2.matchTemplate(roi,digitROI,cv2.TM_CCOEFF)
            (_,score,_,_)=cv2.minMaxLoc(result)
            scores.append(score)

        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)

    output.extend(groupOutput)

cv_show(image)
print("".join(output))

 不同版本的findContours函数可能会有不同的使用方法,有些高版本的只需要两个返回值。

以上所用的都是以前opencv所学的知识,也可能会有一点没有学到的,

 关于opencv的实战——银行卡号识别_第3张图片

 

你可能感兴趣的:(opencv,opencv,学习,python)