【opencv学习】银行卡的识别

今天做一个小项目,运用已经学到的知识,做一个银行卡的识别。
银行卡的图像如下
请添加图片描述
这个银行卡是的数字模板是
请添加图片描述
现在我的任务是识别中间的16个数字

大致思路是:
1:读取模板,获得每个数字的模板信息
2:读取银行卡图像,分割出中间16个数字的轮廓信息
3:进行图像模板匹配,并在原始图像画出来

代码如下:

import cv2
import numpy as np

dsize = (55, 88)  # 统一尺度

# 展示图像,封装成函数
def cv_show_image(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)  # 等待时间,单位是毫秒,0代表任意键终止
    cv2.destroyAllWindows()


def contours_sort(contours, method=0):
    # x, y, w, h = cv2.boundingRect(contour) 得到某个轮廓的xy坐标和长度和宽度
    if method == 0:
        # 升序,根据 每个轮廓的 外界矩形的 x 坐标位置排序
        contours = sorted(contours, key=lambda x: cv2.boundingRect(x)[0])
    else:
        # 升序,根据 每个轮廓的 外界矩形的 x 坐标位置排序
        contours = sorted(contours, key=lambda x: cv2.boundingRect(x)[0], reverse=True)
    return contours


def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    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 / w
        dim = (width, int(r * h))
    resized = cv2.resize(image, dim, interpolation=inter)
    return resized


# ===========================================================
# ================== 第一部分: 加载模板图片,得到其中的关于数字模板信息
# ===========================================================

template = cv2.imread('images/babn_number_template.png')

# 进行灰度值和二值化转换
template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
# cv_show_image('template_gray', template_gray)

# 形成二值图像,因为要做轮廓检测,行成黑底白字
ret, template_thresh = cv2.threshold(template_gray, 127, 255, cv2.THRESH_BINARY_INV)
# cv_show_image('template_thresh', template_thresh)

# 进行轮廓提取,得到数字的信息,RETR_EXTERNAL 就是只是需要外轮廓。
template_contours, hierarchy = cv2.findContours(template_thresh,
                                                cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 将轮廓排序,位置从小到大就是数字的信息
template_contours = contours_sort(template_contours)

# 遍历模板,使用cv2.boudingRect获得轮廓的位置,提取位置对应的图片,与数字结合构造成模板字典
dict_template = {}
for i, contour in enumerate(template_contours):
    # 画出其外接矩阵,获得其位置信息
    x, y, w, h = cv2.boundingRect(contour)
    template_img = template_thresh[y:y + h, x:x + w]
    # 使用cv2.resize变化模板的大小
    template_img = cv2.resize(template_img, dsize)
    # cv_show_image('template_img{}'.format(i), template_img)
    dict_template[i] = template_img  # 获得当前图像的位置和ROI区域,并且保存了下来这个区域

# ===========================================================
# ================== 第二部分: 加载目标需要检测的银行卡
# ===========================================================

bankcard = cv2.imread('images/bank_card.png')
bankcard_h, bankcard_w, bankcard_c = bankcard.shape  # 得到目标图像的长宽信息

# 进行灰度值和二值化转换
bankcard_gray = cv2.cvtColor(bankcard, cv2.COLOR_BGR2GRAY)
# cv_show_image('bankcard_gray', bankcard_gray)

# 形成二值图像,因为要做轮廓检测,行成黑底白字
ret, bankcard_thresh = cv2.threshold(bankcard_gray, 127, 255, cv2.THRESH_BINARY)
# cv_show_image('bankcard_thresh', bankcard_thresh)

# 目标图像很明显有一些小毛刺,因此我们可以做个开运算来取消毛刺儿。
kernel = np.ones((3, 3), np.uint8)
bankcard_open = cv2.morphologyEx(bankcard_thresh, cv2.MORPH_OPEN, kernel, iterations=1)
cv_show_image('bankcard_open', bankcard_open)

# 使用cv2.findContours进行轮廓的识别,还是只取外轮廓。
bankcard_contours, hierarchy = cv2.findContours(bankcard_open, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
banck_card_cnts = []
draw_img = bankcard.copy()  # 阶段性测试查看使用
# 循环轮廓,将在某个区域的contours加入
for i, contour in enumerate(bankcard_contours):
    x, y, w, h = cv2.boundingRect(contour)
    # 数字的x 坐标在 一定的位置范围
    if 0.5 * bankcard_h < y < 0.6 * bankcard_h:  # 目测的,数字在这个该范围内
        banck_card_cnts.append((x, y, w, h))
        draw_img = cv2.rectangle(draw_img, pt1=(x, y), pt2=(x + w, y + h), color=(0, 0, 255),
                                 thickness=2)  # 画出这个矩形,会在原图上画
cv_show_image('rectangle_contours_img', draw_img)
del draw_img

# ===========================================================
# ================== 第三部分: 进行目标匹配并画出来
# ===========================================================

draw_img = bankcard.copy()  # 阶段性测试查看使用
for i, locs in enumerate(banck_card_cnts):

    x, y, w, h = locs[:]  # 保留了在原始图像的位置信息
    dst_img = bankcard_thresh[y:y + h, x:x + w]  # 获得当前图像的位置和ROI区域
    dst_img = cv2.resize(dst_img, dsize)  # 进行resize和模板大小一样,统一size,方便匹配
    # cv_show_image('rectangle_contours_img', dst_img)

    tm_vals = {}
    for number, temp_img in dict_template.items():
        # 模板匹配,采用计算相关性系数,值越大越相关,带有归一化
        res = cv2.matchTemplate(dst_img, temp_img, cv2.TM_CCOEFF_NORMED)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
        tm_vals[number] = max_val

    # 计算出哪个更加匹配,采用计算相关性系数,值越大越相关,因此找出最大的那个数值的key
    number_tm = max(tm_vals, key=tm_vals.get)

    # 在图像上画出结果来
    draw_img = cv2.rectangle(draw_img, pt1=(x, y), pt2=(x + w, y + h), color=(0, 0, 255),
                             thickness=2)  # 画出这个矩形,会在原图上画
    cv2.putText(draw_img, str(number_tm), (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.65,
                color=(0, 0, 255), thickness=2)

cv_show_image('final_result', draw_img)
del draw_img

效果如下:
找到数值模板图片的轮廓
请添加图片描述
找到银行卡图片的轮廓
请添加图片描述
最终的匹配结果是
请添加图片描述

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于OpenCV银行卡识别可以通过以下步骤实现: 1.读取图像并将其转换为灰度图像和二进制图像。 ```python import cv2 import matplotlib.pyplot as plt def read(img, thresh=127, inv=False): origin = cv2.imread(img) gray = cv2.imread(img, 0) binary = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY_INV if inv else cv2.THRESH_BINARY)[1] return origin, gray, binary ``` 2.将图像中的银行卡区域提取出来。 ```python def extract_card(img): _, contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key=cv2.contourArea, reverse=True) for contour in contours: perimeter = cv2.arcLength(contour, True) approx = cv2.approxPolyDP(contour, 0.02 * perimeter, True) if len(approx) == 4: x, y, w, h = cv2.boundingRect(contour) return x, y, w, h ``` 3.将银行卡区域与模板进行匹配,找到银行卡号码的位置。 ```python def match_template(img, template): res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED) _, max_val, _, max_loc = cv2.minMaxLoc(res) return max_val, max_loc ``` 4.将银行卡号码数字割出来,并与模板比较,选出相似度最高的答案。 ```python def extract_number(img, x, y, w, h): number_img = img[y:y+h, x:x+w] number_img = cv2.resize(number_img, (w*5, h*5)) _, number_img = cv2.threshold(number_img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) number_img = cv2.resize(number_img, (w, h)) return number_img def match_number(number_img, templates): max_val = 0 max_index = 0 for i, template in enumerate(templates): val, _ = match_template(number_img, template) if val > max_val: max_val = val max_index = i return max_index ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值