《OpenCV计算机视觉实战项目》——银行卡号识别
项目任务及要求[*]任务书: 要为某家银行设计一套智能卡号识别的系统。
[*]要求:传入一张图片,就主动输出信用卡图片中的数字。
项目实现思绪
[*]要实现此项目,首先要知道我们的目标是什么,我们的目标是对银行卡号识别,银行卡号都是数字,因此我们要找到一个模版且模版中有0~9的数字。然后对模版图像中的数字举行定位处理处罚,每一个数字对应一个模版,如许有助于后期举行模版的对照。对模版处理处罚好后,就应对银行卡的图像举行处理处罚,通过对银行卡的一系列处理处罚得到银行卡图像中数字的模版。在举行模版匹配,计算匹配得分,匹配得分最高的就是那个数字,再对数字举行组合、输出得到银行卡号。、
模版图像
https://i-blog.csdnimg.cn/direct/895649d0968149daa23cb8520118f2c2.png
银行卡图像
https://i-blog.csdnimg.cn/direct/7e2fb48ed684463fbcea1afb3b0654eb.png
项目实现及代码
导入模块
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 =
# 将轮廓和其对应的外接矩形打包在一起,然后根据 lambda 函数指定的规则进行排序
# b 是 (cnt, boundingBox) 元组,b 是外接矩形,b 表示根据 i 所指定的维度(i = 0 为水平方向,i = 1 为垂直方向)
# 根据 reverse 决定是否逆序排序
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b: b, 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来展示图像。
[*]导入参数
[*]https://i-blog.csdnimg.cn/direct/510b08ef67234d2c86539f8afc01abd5.png
[*]https://i-blog.csdnimg.cn/direct/641d5b21b2704af2a78c9019ff00474f.png
代码:
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)
对模版图像中数字的定位处理处罚
[*]导入图片
[*]将图片转化为灰度图
[*]再将灰度图再转化为二值图
[*]计算图像轮廓得到图像外轮廓和终点坐标,并再图像中画出
[*]将得到的轮廓,按从左到到右,从上到下排序
[*]通过遍历得到每一个数字对应的像素值
https://i-blog.csdnimg.cn/direct/0f3067bd500f416b9ee1d1d9bead3837.png
代码:
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)# 二值图像
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")# 排序,从左到右,从上到下
digits = {}# 保存模板中每个数字对应的像素值
for (i, c) in enumerate(refCnts):# 遍历每一个轮廓
(x, y, w, h) = cv2.boundingRect(c)# 计算外接矩形并且resize成合适大小
roi = ref
roi = cv2.resize(roi, (57, 88))# 缩放到指定的大小
digits = roi# 每一个数字对应每一个模板
银行卡的图像处理处罚
读取输入图像,预处理处罚
[*]输入图像
[*]重新设置图像巨细
[*]转化为灰度图
[*]初始化卷积核
[*]举行顶帽和开运算
https://i-blog.csdnimg.cn/direct/d19b196ec5d748f6b75349abff23b652.png
代码:
# 读取输入图像,预处理
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)
找到数字边框
[*]通过闭操作(先膨胀,再腐蚀)将数字连在一起并举行二值化处理处罚。
[*]再重复一次上述操作。
[*]计算轮廓并画出
[*]遍历轮廓,根据条件找到数字部门像素地区
[*]遍历每一个轮廓中的数字,得到每一个数字模版
https://i-blog.csdnimg.cn/direct/3c50218aed1046eda5a3eff501914ec8.png
代码:
# 1、通过闭操作(先膨胀,再腐蚀)将数字连在一起
closeX = cv2.morphologyEx(tophat, cv2.MORPH_CLOSE, rectKernel)
cv_show('gradX', closeX)
# THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(closeX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv_show('thresh', thresh)
# 再来一个闭操作
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)# 再来一个闭操作
cv_show('thresh1', thresh)
# 计算轮廓
_, threshCnts, h = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = threshCnts
cur_img = image.copy()
cv2.drawContours(cur_img, cnts, -1, (0, 0, 255), 3)
cv_show('img', cur_img)
# 遍历轮廓,找到数字部分像素区域
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)
output = []
# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):
groupOutput = []
group = gray# 适当加一点边界
cv_show('group', group)
# 预处理
group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
cv_show('group', group)
# 计算每一组的轮廓
group_, digitCnts, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")
# 计算每一组中的每一个数值
for c in digitCnts:
# 找到当前数值的轮廓,resize成合适的的大小
(x, y, w, h) = cv2.boundingRect(c)
roi = group
roi = cv2.resize(roi, (57, 88))
cv_show('roi', roi)
使用模版匹配,计算匹配得分
[*]通过遍历后得到每一组的数字的模版
[*]通过模版匹配得到每个数字的值,得到最合适的数字
代码:
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)))
画出并打印结果
https://i-blog.csdnimg.cn/direct/5e28a2f70aef41a0ad465afa39c40ab5.png
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]