转自:机器学习AI算法工程
项目任务及要求
任务书:要为某家银行设计一套智能卡号识别的系统。
要求:传入一张图片,就自动输出信用卡图片中的数字。
项目实现思路
要实现此项目,首先要知道我们的目标是什么,我们的目标是对银行卡号识别,银行卡号都是数字,因此我们要找到一个模版且模版中有0~9的数字。然后对模版图像中的数字进行定位处理,每一个数字对应一个模版,这样有助于后期进行模版的对照。对模版处理好后,就应对银行卡的图像进行处理,通过对银行卡的一系列处理得到银行卡图像中数字的模版。在进行模版匹配,计算匹配得分,匹配得分最高的就是那个数字,再对数字进行组合、输出得到银行卡号。
模版图像
银行卡图像
项目实现及代码
导入模块
import numpy as np
import argparse # python内置库 不太熟,自行学习
import cv2
import 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、通过闭操作(先膨胀,再腐蚀)将数字连在一起