opencv 之 实战项目 识别银行卡上的数字

OpenCV 之 实战项目:识别银行卡上的数字

引言

在日常生活中,银行卡的识别是一个常见的需求,特别是在金融领域。本实战项目旨在使用 OpenCV 库来识别银行卡上的数字。我们将通过模板匹配的方法,结合图像处理技术,来准确识别银行卡上的数字序列。

项目准备

本项目需要安装 Python 和 OpenCV 库。确保已经安装了必要的库,并准备好银行卡图像和数字模板图像。

        实验素材

opencv 之 实战项目 识别银行卡上的数字_第1张图片

opencv 之 实战项目 识别银行卡上的数字_第2张图片
        定义函数
import cv2

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(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda b:b[1][i],reverse=reverse))
    #zip(*...)使用星号操作符解包排序后的元组列表,并将其重新组合成两个列表:一个包含所有轮廓,另一个包含所有边界框。
    return cnts, boundingBoxes

def resize(image,width=None,height=None ,inter=cv2.INTER_AREA):
    dim = None
    (h, w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r = height / float(h)
        dim = (int(w * r), height)
    else:
        r = width / float(w)
        dim = (width, int(h * r))
    resized=cv2.resize(image,dim,interpolation=inter)    #默认为cV2.INTER_AREA,即面积插值,适用于缩放图像。
    return resized
        传入参数
        opencv 之 实战项目 识别银行卡上的数字_第3张图片
代码详解
  1. 导入库和设置参数
    import numpy as np
    import argparse
    import cv2
    import myutils
    
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--image", required=True, help="path to input image")
    ap.add_argument("-t", "--template", required=True, help="path to template OCR-A image")
    args = vars(ap.parse_args())

    解释:

    • 导入必要的库。
    • 使用 argparse 库来设置命令行参数,包括输入图像路径和模板图像路径。
    • 解析命令行参数并将结果存储在 args 字典中。
  2. 指定信用卡类型
    FIRST_NUMBER = {"3": "American Express",
                    "4": "Visa",
                    "5": "MasterCard",
                    "6": "Discover Card"}

    解释:

    • 定义一个字典,根据银行卡号的第一个数字来确定其类型。
  3. 模板图像处理
    img = cv2.imread(args["template"])
    ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
    _, refCnts, _ = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]
    digits = {}
    for (i, c) in enumerate(refCnts):
        (x, y, w, h) = cv2.boundingRect(c)
        roi = ref[y:y + h, x: x + w]
        roi = cv2.resize(roi, (57, 88))
        digits[i] = roi

    解释:

    • 读取模板图像并转换为灰度图。
    • 将灰度图转换为二值图。
    • 计算模板图像中的轮廓,并按照从左到右的顺序排序。
    • 提取每个数字的 ROI(感兴趣区域),并将其存储在 digits 字典中。
  4. 银行卡图像处理
    image = cv2.imread(args["image"])
    image = myutils.resize(image, width=300)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
    sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
    tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)
    closeX = cv2.morphologyEx(tophat, cv2.MORPH_CLOSE, rectKernel)
    thresh = cv2.threshold(closeX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)
    _, threshCnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = threshCnts
    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 and (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])

    解释:

    • 读取银行卡图像并调整大小。
    • 转换为灰度图。
    • 使用顶帽操作增强图像中的数字区域。
    • 使用形态学闭操作连接数字区域。
    • 计算阈值并进一步处理图像。
    • 计算图像中的轮廓,并筛选出符合条件的数字区域。
    • 将数字区域按照从左到右的顺序排序。
  5. 数字识别
    output = []
    for (i, (gX, gY, gW, gH)) in enumerate(locs):
        groupOutput = []
        group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
        group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
        _, digitCnts, _ = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")[0]
        for c in digitCnts:
            (x, y, w, h) = cv2.boundingRect(c)
            roi = group[y:y + h, x: x + w]
            roi = cv2.resize(roi, (57, 88))
            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)

    解释:

    • 对每个数字区域进行处理,提取每个数字的 ROI。
    • 使用模板匹配计算每个数字区域与模板的匹配得分。
    • 将得分最高的模板对应的数字添加到结果中。
    • 在图像上绘制矩形框和识别结果。
  6. 打印结果
    print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
    print("Credit Card #:{}".format("".join(output)))
    cv2.imshow("Image", image)
    cv2.waitKey(0)

    解释:

    • 打印识别出的信用卡类型和号码。
    • 显示处理后的图像。
  7. 输出结果:
    opencv 之 实战项目 识别银行卡上的数字_第4张图片
总结

通过本实战项目,我们展示了如何使用 OpenCV 进行银行卡上数字的识别。整个过程包括模板图像处理、银行卡图像预处理、数字区域定位、模板匹配以及结果展示。这种技术在金融领域有着广泛的应用,可以帮助自动化处理大量的银行卡识别任务。通过适当的图像处理技术和模板匹配方法,我们可以准确地识别出银行卡上的数字序列。

你可能感兴趣的:(opencv,计算机视觉,人工智能)