OpenCV项目3-图像处理之信用卡数字识别


基本思路

  • (1) 先对模板处理, 获取每个数字的模板及其对应的数字标识
  • (2) 再对信用卡处理, 通过一系列预处理操作, 取出信用卡数字区域
  • (3) 然后再取出每一个数字去和模板中的10个数字进行匹配
  • (4) 取概率最大的数字

1.图片显示函数

def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

2.模板读取

import cv2 
import numpy as np
img = cv2.imread('./ocr_a_reference.png') # 读取模板图片
# print(img.shape)
# cv_show('img', img)

3.模板灰度化、二值化

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)

4.模板轮廓计算、绘画、排序

ref_contours, _ = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 
cv2.drawContours(img, ref_contours, -1, (0, 0, 255), 3)  # -1:所有轮廓
# cv_show('img', img)
print(np.array(ref_contours, dtype='object').shape) # 10:表示数字的轮廓 dtype='object':去警告
# 对轮廓按照数字大小进行排序 方便后面使用 排序思路: 根据每个数字的最大外接矩形的x轴坐标进行排序
bounding_boxes = [cv2.boundingRect(c) for c in ref_contours]# 计算每个轮廓的外接矩形
# print(bounding_boxes) # 这一步的顺序是小到大因为计算方法是右到左
# print(sorted(bounding_boxes, key=lambda b: b[0]))
(ref_contours, bounding_boxes) = zip(*sorted(zip(ref_contours, bounding_boxes), key=lambda b: b[1][0])) # *:拆开 zip:一一对应且合并  要把排序之后的外接矩形和轮廓建立对应关系

5.模板取数字、尺寸resize

digits = {}
for (i, c) in enumerate(ref_contours):
    (x, y, w, h) = cv2.boundingRect(c) # 重新计算外接矩形
    roi = ref[y:y + h, x: x + w] # 取出每个数字  roi:region of interest:感兴趣区域
    roi = cv2.resize(roi, (57, 88))# resize:合成合适的大小
    digits[i] = roi
# print(digits)

6.信用卡读取

image = cv2.imread('./credit_card_05.png')
# cv_show('image', image)

7.信用卡尺寸resize

h, w = image.shape[:2]  # 为保证原图不拉伸需要计算出原图的长宽比
width = 300
r = width / w
image = cv2.resize(image, (300, int(h * r)))
# cv_show('image', image)

8.信用卡灰度化、卷积核、形态学顶帽

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# cv_show('gray', gray)
rect_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rect_kernel) # 顶帽突出更明亮的区域
# cv_show('tophat', tophat)

9.信用卡sobel算子

grad_x = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1) # 找出边沿
# print(grad_x)
grad_x = np.absolute(grad_x)  # 对grad_x进行处理 只用x轴方向的梯度
min_val, max_val = np.min(grad_x), np.max(grad_x)# 再把grad_x变成0到255之间的整数
grad_x = ((grad_x - min_val) / (max_val - min_val)) * 255
grad_x = grad_x.astype('uint8')# 修改一下数据类型
# cv_show('grad_x', grad_x)
# grad_y = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=0, dy=1, ksize=-1)
# # print(grad_x)
# grad_y = np.absolute(grad_y) # 对grad_x进行处理
# min_val, max_val = np.min(grad_y), np.max(grad_y) # 再把grad_x变成0到255之间的整数
# grad_y = ((grad_y - min_val) / (max_val - min_val)) * 255
# grad_y = grad_y.astype('uint8') # 修改一下数据类型
# cv_show('grad_y', grad_y)
# cv_show('gray', grad_x + grad_y)

10.信用卡闭操作、全局二值化

grad_x = cv2.morphologyEx(grad_x, cv2.MORPH_CLOSE, rect_kernel) # 先膨胀再腐蚀可把数字连在一起.
# cv_show('gradx', grad_x)
# 通过大津(OTSU)算法找到合适的阈值, 进行全局二值化操作.
_, thresh = cv2.threshold(grad_x, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
# cv_show('thresh', thresh)
sq_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))# 中间还有空洞再来一个闭操作
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sq_kernel)
# cv_show('thresh', thresh)

11.信用卡轮廓计算、绘画、遍历

thresh_contours, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
image_copy = image.copy() # 在原图上画
cv2.drawContours(image_copy, thresh_contours, -1, (0, 0, 255), 3)
# cv_show('img', image_copy)
# 遍历轮廓计算外接矩形, 然后根据实际信用卡数字区域的长宽比, 找到真正的数字区域
locs = []
output = []
for c in thresh_contours:
    (x, y, w, h) = cv2.boundingRect(c)# 计算外接矩形
    ar = w / float(h)# 计算外接矩形的长宽比例
#     print(ar)
    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))# 符合条件的外接矩形留下来
sorted(locs, key=lambda x: x[0])# 对符合要求的轮廓进行从左到右的排序.

12.数字区域抠出、二值化

for (i, (gx, gy, gw, gh)) in enumerate(locs): # 遍历每一个外接矩形, 通过外接矩形可以把原图中的数字抠出来
    group = gray[gy - 5: gy + gh + 5, gx - 5: gx + gw + 5] # 抠出数字区域, 并且加点余量
#     cv_show('group', group)
# 对取出灰色group做全局二值化处理
    group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
#     cv_show('group', group)

13.轮廓计算、排序、尺寸resize

 digit_contours, _ = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    bounding_boxes = [cv2.boundingRect(c) for c in digit_contours] 
    (digit_contours, _) = zip(*sorted(zip(digit_contours, bounding_boxes), key=lambda b: b[1][0]))# 轮廓排序
    group_output = [] #  定义每一组匹配到的数字的存放列表
    for c in digit_contours: # 遍历排好序的轮廓
        (x, y, w, h) = cv2.boundingRect(c) # 找到当前数字的轮廓, resize成合适的大小
        roi = group[y: y + h, x: x + w]# 取出数字
        roi = cv2.resize(roi, (57, 88))
#         cv_show('roi', roi)

14.模板匹配

 scores = []# 定义保存匹配得分的列表
        for (digit, digit_roi) in digits.items():  # items:取出key和值
            result = cv2.matchTemplate(roi,digit_roi, cv2.TM_CCOEFF)
            (_, score, _, _) = cv2.minMaxLoc(result)# 只要最大值即分数
            scores.append(score)
        group_output.append(str(np.argmax(scores)))# 找到分数最高的数字即匹配到的数字

15.轮廓绘制

cv2.rectangle(image, (gx - 5, gy - 5), (gx + gw + 5, gy + gh + 5), (0, 0, 255), 1)

16.数字显示

 cv2.putText(image, ''.join(group_output), (gx, gy - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
    output.extend(group_output)
    cv_show('image', image)

17.命令行识别信用卡数字

python card_number_ocr.py --image credit_card_01.png -t ocr_a_reference.png

在这里插入图片描述

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿值学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值