专栏名称: 新机器视觉
最前沿的机器视觉与计算机视觉技术
目录
相关文章推荐
南方人物周刊  ·  中国队逐渐告别“冰强雪弱” ·  13 小时前  
南方人物周刊  ·  200份开工好礼免费送,助你满血复活! ·  22 小时前  
南方人物周刊  ·  冯骥 我们只是一群人在做自己喜欢的事情 | ... ·  昨天  
每日人物  ·  4亿人都在用的必需品,集体“塌房”? ·  3 天前  
51好读  ›  专栏  ›  新机器视觉

揭秘!OpenCV 如何快速准确地识别银行卡号?

新机器视觉  · 公众号  ·  · 2025-01-17 14:58

正文

转自:机器学习AI算法工程


项目任务及要求

任务书:要为某家银行设计一套智能卡号识别的系统。

要求:传入一张图片,就自动输出信用卡图片中的数字。

项目实现思路

要实现此项目,首先要知道我们的目标是什么,我们的目标是对银行卡号识别,银行卡号都是数字,因此我们要找到一个模版且模版中有0~9的数字。然后对模版图像中的数字进行定位处理,每一个数字对应一个模版,这样有助于后期进行模版的对照。对模版处理好后,就应对银行卡的图像进行处理,通过对银行卡的一系列处理得到银行卡图像中数字的模版。在进行模版匹配,计算匹配得分,匹配得分最高的就是那个数字,再对数字进行组合、输出得到银行卡号。

模版图像

银行卡图像


项目实现及代码

导入模块


import numpy as npimport argparse  # python内置库  不太熟,自行学习import cv2import myutils


其中myutils包需要自己创建,再项目目录创建一个名叫myutils .py文件 就行了,其中两个函数分别用来进行排序和改变图像大小,内容为:

import cv2

def sort_contours(cnts, method='left-to-right'): # 初始化 reverse 为 False,表示默认不使用逆序排序 reverse = False # 初始化 i 为 0,用于后续选择排序依据的维度 i = 0
# 如果排序方法是 right-to-left 或 bottom-to-top,则设置为逆序排序 if method == 'right-to-left' or method == 'bottom-to-top': reverse = True # 如果排序方法是 top-to-bottom 或 bottom-to-top,则选择 i 为 1,表示按垂直维度排序 if method == 'top-to-bottom' or method == 'bottom-to-top': i = 1 # 计算每个轮廓的外接矩形,并存储在 boundingBoxes 列表中 boundingBoxes = [cv2.boundingRect(c) for c in cnts] # 将轮廓和其对应的外接矩形打包在一起,然后根据 lambda 函数指定的规则进行排序 # b 是 (cnt, boundingBox) 元组,b[1] 是外接矩形,b[1][i] 表示根据 i 所指定的维度(i = 0 为水平方向,i = 1 为垂直方向) # 根据 reverse 决定是否逆序排序 (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes), key=lambda b: b[1][i], reverse=reverse)) # 返回排序好的轮廓和外接矩形 return cnts, boundingBoxes

def resize(image, width=None, height=None, inter=cv2.INTER_AREA): # 初始化 dim 为 None,用于存储调整后的图像尺寸 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)) # 使用 cv2.resize 函数根据 dim 和指定的插值方法对图像进行缩放 resized = cv2.resize(image, dim, interpolation=inter) # 返回缩放后的图像 return resized


设置参数

  • 通过导入argparse模块

    • 创建 ArgumentParser 对象。

    • 添加参数。

    • 解析命令行参数。

  • 并指定银行卡类型,便于后期从字典中查找。

  • 创建一个函数cv_show来展示图像。

  • 导入参数



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())  # vars()是Python中的一个内置函数,用于返回对象的属性和值的字典。# 指定信用卡类型FIRST_NUMBER = {"3": "American Express",                "4": "Visa",                "5": "MasterCard",                "6": "Discover Card"}def cv_show(name, img):  # 绘图展示    cv2.imshow(name, img)    cv2.waitKey(0)

对模版图像中数字的定位处理

  • 导入图片

  • 将图片转化为灰度图

  • 再将灰度图再转化为二值图

  • 计算图像轮廓得到图像外轮廓和终点坐标,并再图像中画出

  • 将得到的轮廓,按从左到到右,从上到下排序

  • 通过遍历得到每一个数字对应的像素值

img = cv2.imread(args["template"])cv_show('img', img)ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度图cv_show('ref', ref)ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]  # 二值图像cv_show('ref', ref)# 计算轮廓:cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),#   cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cv2.drawContours(img, refCnts, -1, (0, 0, 255), 3)cv_show('img', img)refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0]  # 排序,从左到右,从上到下digits = {}  # 保存模板中每个数字对应的像素值for (i, c) in enumerate(refCnts):  # 遍历每一个轮廓    (x, y, w, h) = cv2.boundingRect(c)  # 计算外接矩形并且resize成合适大小    roi = ref[y:y + h, x:x + w]    roi = cv2.resize(roi, (57, 88))  # 缩放到指定的大小    digits[i] = roi  # 每一个数字对应每一个模板


银行卡的图像处理

读取输入图像,预处理

  • 输入图像

  • 重新设置图像大小

  • 转化为灰度图

  • 初始化卷积核

  • 进行顶帽和开运算


# 读取输入图像,预处理image = cv2.imread(args["image"])cv_show('image', image)image = myutils.resize(image, width=300)  # 设置图像的大小gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)cv_show('gray', gray)# 顶帽操作,突出图像中的亮细节,清除背景图,原因是背景颜色变化小,不被腐蚀掉。rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))  # 初始化卷积核sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)  # 顶帽 = 原始图像 - 开运算结果(先腐蚀后膨胀)open = cv2.morphologyEx(gray, cv2.MORPH_OPEN, rectKernel)  # 顶帽 = 原始图像 - 开运算结果(先腐蚀后膨胀)cv_show('open', open)cv_show('tophat', tophat)


找到数字边框

  • 通过闭操作(先膨胀,再腐蚀)将数字连在一起并进行二值化处理。

  • 再重复一次上述操作。

  • 计算轮廓并画出

  • 遍历轮廓,根据条件找到数字部分像素区域

  • 遍历每一个轮廓中的数字,得到每一个数字模版


# 1、通过闭操作(先膨胀,再腐蚀)将数字连在一起






请到「今天看啥」查看全文