OpenCV 信用卡识别

© Fu Xianjun. All Rights Reserved.

一、使用步骤

1.引入库

代码如下(示例):

import cv2
import numpy as np

2.读入数据

代码如下(示例):

import cv2
import numpy as np

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(cnt) for cnt in cnts]
    (cnts,boundingBoxes) = zip(*sorted(zip(cnts,boundingBoxes),\
                                      key = lambda b: b[1][i],\
                                       reverse=reverse))
    return cnts, boundingBoxes
def cv_show(name,img):#定义一个函数,显示图片
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
   
   
template = cv2.imread("ocr_a_reference.png")#读模板
#cv_show("template",template)
template_gray = cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)#色彩空间转换,转换成灰度图
#cv_show("template_gray",template_gray)
ret, template_binary = cv2.threshold(template_gray,127,255,1)#二值化
cv_show("template_binary",template_binary)
cnts, he = cv2.findContours(template_binary, cv2.RETR_EXTERNAL,\
                           cv2.CHAIN_APPROX_SIMPLE)#查找外轮廓
template_rect = cv2.drawContours(template, cnts, -1,(0,0,255),2)#绘制轮廓
cv_show("template_rect",template_rect)
cnts = sort_contours(cnts)[0]
number = {}
#根据排列的结果,将每个数字截取出来。将每个数字图片所对应的数字对应起来
#这里要注意,对像素值进行取值时,数组的行对应的是图片的y轴,列对应的是图片的x轴
for (i,cnt) in enumerate(cnts):
    (x,y,w,h) = cv2.boundingRect(cnt)
    roi = template_binary[y:y+h, x:x+w]
    roi = cv2.resize(roi, (57,88))
    number[i] = roi
   
cv_show(f"number1",number[3])

#读取信用卡图片
cardImg = cv2.imread('credit_card_01.png')
cardImg = cv2.resize(cardImg,\
                    (300, int(float(300 / cardImg.shape[1]) * cardImg.shape[0])),\
                    interpolation=cv2.INTER_AREA)

cardImg_gray = cv2.cvtColor(cardImg,cv2.COLOR_BGR2GRAY)
cv_show('cardImg_gray',cardImg_gray)

#指定卷积核大小
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
#进行礼帽操作
cardImg_tophat = cv2.morphologyEx(cardImg_gray,cv2.MORPH_TOPHAT,rectKernel)
cv_show('cardImg_tophat',cardImg_tophat)

#使用sobel算子进行边缘检测,这里仅适用x方向的梯度,因为经过实验,使用x,y混合的梯度效果并不理想
sobelx = cv2.Sobel(cardImg_tophat,cv2.CV_64F,1,0, ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
(minX,maxX) = (np.min(sobelx), np.max(sobelx))
sobelx = (255 * ((sobelx - minX) / (maxX - minX)))
sobelx = sobelx.astype('uint8')
cv_show('sobelx',sobelx)

#进行闭运算,使相邻的数字连接起来,这样便于筛选
cardImg_close = cv2.morphologyEx(sobelx,cv2.MORPH_CLOSE,rectKernel)
cv_show('cardImg_close',cardImg_close)

cardImg_binary = cv2.threshold(cardImg_close,0,255,cv2.THRESH_OTSU | cv2.THRESH_BINARY)[1]
cv_show('cardImg_binary',cardImg_binary)

cardImg_close = cv2.morphologyEx(cardImg_binary,cv2.MORPH_CLOSE,sqKernel)
cv_show('cardImg_close',cardImg_close)

#轮廓检测,检测出每一个数字区块
cnts,hierarchy = cv2.findContours(cardImg_close,
                                 cv2.RETR_EXTERNAL,
                                 cv2.CHAIN_APPROX_SIMPLE)
cardImg_cnts = cv2.drawContours(cardImg.copy(),cnts,-1,(0,0,255),2)
cv_show('cardImg_cnts',cardImg_cnts)

#对轮廓进行筛选,根据边框的尺寸仅保留卡号区域
locs = []
for (i,c) in enumerate(cnts):
    (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 = []
#对每个4数字块进行处理
for (i,(x,y,w,h)) in enumerate(locs):
    group_output = []
    group = cardImg_gray[y-5:y + h + 5,x-5:x + w + 5]
    group = cv2.threshold(group, 0,255,cv2.THRESH_OTSU|cv2.THRESH_BINARY)[1]
    cv_show('group',group)
    group_cnts,group_hierarchy = cv2.findContours(group,
                                                  cv2.RETR_EXTERNAL,
                                                  cv2.CHAIN_APPROX_SIMPLE)
    group_cnts = sort_contours(group_cnts,method="left-to-right")[0]
    #分割每个数字
    for cnt in group_cnts:
        (nx,ny,nw,nh) = cv2.boundingRect(cnt)
        roi = group[ny:ny+nh, nx:nx+nw]
        roi = cv2.resize(roi, (57,88))
       
        score = []
        #对每个数字进行模板匹配
        for (number_i,number_roi) in number.items():
            result = cv2.matchTemplate(roi, number_roi,cv2.TM_CCOEFF)
            score_ = cv2.minMaxLoc(result)[1]
           
            score.append(score_)
           
        group_output.append(str(np.argmax(score)))
#绘制每个数字
    cv2.rectangle(cardImg,(x - 5,y - 5),
                 (x + w +5,y + h + 5),(0,0,255),1)
    cv2.putText(cardImg, "".join(group_output),(x, y - 15),
                cv2.FONT_HERSHEY_SIMPLEX,0.65,(0,0,255),2)
    output.append(group_output)
   
cv_show('cardImg',cardImg)

该处使用的url网络请求的数据。


总结

信用卡识别运用到了读取模板、色彩空间转换为灰度图、二值化、查找轮廓、绘制轮廓等操作。在读取信用卡图片时进行了指定卷积和大小、礼帽操作和使用sobel算子进行边缘检测,闭运算等等。闭运算的好处是是相邻的数字连接起来,这样便于筛选;轮廓检测可以检测出每一个数字区块,而对轮廓进行筛选,是根据边框的尺寸仅保留卡号区域。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值