Python+OpenCV 识别银行卡卡号

Python+OpenCV 识别银行卡卡号

      今天尝试一下用python+OpenCV,使用模板匹配的方式做个简单地识别银行卡卡号(大部分参考网上的,自己改了一部分,代码写的有点不太好,但是思路很清晰,过段时间可能会写一个C++版本的,在顺便把代码优化一下)。有问题欢迎提问,尽量回复
      完整的代码百度云自行下载,代码里面有好多我调试的代码,已经注释了,有需要的可以打开看看每一步发生了什么。
      链接:https://pan.baidu.com/s/1ZmRUIuN7N8EFXwXf9LcYaQ
      提取码:86c2
      先把原图和处理后的结果放出看看效果
原图
处理后效果
在这里插入图片描述
接下来看看处理思路:

1. 获取原图中的数字区域

     原图灰度处理,二值化,寻找轮廓,画出有效轮廓。这里轮廓有个排序,想想问什么要排序,解释在第二步里面

idCard = cv.imread("image/credit_card_01.png")
showImage("Ori", idCard)
idCard = myutils.resize(idCard, width=300)
gray = cv.cvtColor(idCard, cv.COLOR_BGR2GRAY)
showImage("Gray", gray)
retm, Binary = cv.threshold(gray, 127, 255, cv.THRESH_BINARY)
showImage("Binary", Binary)
threshCnts_, hierarchy = cv.findContours(Binary.copy(), cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
cnts = threshCnts_
curimg = idCard.copy()
locs = []# 存储有效轮廓(数字区域)
# 存放识别的数字
output =[]
for cnt in cnts:
    x, y, w, h = cv.boundingRect(cnt)
    # print(cnt.shape())
    ar = w/float(h)
    print("h为"+str(h)+ "w为"+str(w)+"比例为"+str(ar))
    # 由于所有轮廓并不全是数字区域的,所以这里使用长宽以及比例选出数字区域
    # 判断数字区域
    if ar>3.0 and ar<4.0:
        if (w>40 and w<55)and (h>10 and h<20):
            locs.append((x, y, w, h))
# 通过对每隔轮廓的X值,对数字区域的4个轮廓排序,从左到右
locs = sorted(locs, key=lambda x:x[0])

在这里插入图片描述

     2. 处理模板(这里我直接封装了一个方法,传递一张图片,返回一个字典)

          读取模板图片,灰度处理,二值化,寻找轮廓,画出最小外接矩形,再将轮廓从左到右排序,将对应的轮廓区域和数字存入字典中(注意,这里一定要将这里的轮廓排序,按照每一个轮廓左上角的X轴大小排序,不然每个分割的数字图像和真实数据无法对上,大家可以试试不排序直接存入字典后看看运行后的结果是什么

def refer(image):
    ref = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    showImage("ref", ref)
    ref = cv.threshold(ref, 10, 255, cv.THRESH_BINARY_INV)[1]
    showImage("ref", ref)
    refCnts, hierarchy = cv.findContours(ref, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    cv.drawContours(image, refCnts, -1, (0, 0, 255), 3)
    showImage("img", image)
    refCnts = myutils.sort_contours(refCnts, method="leleft-to-right")[0]
    digits = {}
    for (i, c) in enumerate(refCnts):
        (x, y, w, h) = cv.boundingRect(c)
        roi = ref[y:y+h, x:x+w]
        roi = cv.resize(roi, (57, 88))
        showImage("rio", roi)
        digits[i] = roi
    return digits

在这里插入图片描述

处理完后大致是这样,没有全部列出来,大家自行脑补一下

在这里插入图片描述
 

     3. 模板匹配,获取数字

          步骤一中,已经将银行卡的数字部分提取出来了,分成了4个部分,循环处理这四个部分。
          先获取第一个部分,和步骤二一样,分割出四个单独的图片,再和步骤二返回的字典中的图像进行模板匹配,计算出最合适的图片,并返回字典中图片对应的数字,再接下来就是套娃一样的操作了。最后再将得到的结果写在原图中即可。(注意,第三步和第二步都有一个resize操作,这是让模板匹配的时候两个图片有相同的大小,要不然模板匹配是出现问题

for m in range(len(imgROI)):
    fourMumROI = imgROI[m]
    # showImage("demo", imgsplit)
    fourMumROI = cv.cvtColor(fourMumROI, cv.COLOR_BGR2GRAY)
    # showImage("demo", imgsplit)
    fourMumROI = cv.threshold(fourMumROI, 127
                              , 255, cv.THRESH_BINARY
                              )[1]
    # showImage("demo", imgsplit)
    fourNumCnts, imghierarchy = cv.findContours(fourMumROI, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
    fourNumImg = imgROI[m]
    # cv.drawContours(imgROI[i], fourNumCnts, -1, (0, 0, 255), 1)
    showImage("demo", imgROI[m])
    fourNumCnts = myutils.sort_contours(fourNumCnts, method="leleft-to-right")[0]
    for (i, c) in enumerate(fourNumCnts):
        (x, y, w, h) = cv.boundingRect(c)
        roi = fourNumImg[y:y + h, x:x + w]
        roi = cv.resize(roi, (57, 88))
        roi = cv.cvtColor(roi, cv.COLOR_BGR2GRAY)
        roi = cv.threshold(roi, 127, 255, cv.THRESH_BINARY)[1]
        showImage("roi", roi)
        # 模板匹配得分情况
        scores = []
        for(digit, digROI) in dig.items():
            result = cv.matchTemplate(roi, digROI, cv.TM_CCOEFF)
            (_, score, _,_)  = cv.minMaxLoc(result)
            scores.append(score)
        groupOutput.append(str(np.argmax(scores)))
        # cv.rectangle(idCard, (gX -5, gY -5), (gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)
        printX, printY, printW, printH = locs[0]
        cv.putText(idCard, "".join(groupOutput), (printX, printY-15), cv.FONT_HERSHEY_SIMPLEX,
                0.65, (0, 0, 255), 2)
    print("".join(groupOutput))
    output.extend(groupOutput)

#

cv.imshow("Image", idCard)
cv.waitKey(0)
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值