openCV实践项目:银行卡卡号识别_thresh,ref= cv2(2)

cv2.findContours(img,mode,method)

  • RETR_EXTERNAL :只检索最外面的轮廓;( 本次使用)
  • RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
  • RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
  • RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;(常用,推荐)

method:轮廓逼近方法

  • CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
  • CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。
绘制轮廓

cv2.drawContours(draw_img, refCnts, -1, (0, 0, 255), 2)

  • draw_img:要绘制的图片,会在该图片上直接进行修改。
  • refCnts: 轮廓
  • 其它:-1指全部轮廓,0为最后一个轮廓,(0,0,255)颜色,2粗细。
排序

refCnts = contours.sort_contours(refCnts, method=“left-to-right”)[0]

  • 返回排序后的轮廓。
礼帽操作

tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)

  • 原图-开运算,本次实验用它获得我们想要保留的部分。
  • 开运算:先腐蚀后膨胀。
闭运算

gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)

  • 先膨胀后腐蚀,本次实验目的是将每组数“模糊处理”使其连在一起。
模板匹配

res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)

  • 模板匹配和卷积原理很像,假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)。
  • TM_SQDIFF:计算平方不同,计算出来的值越小,越相关
  • TM_CCORR:计算相关性,计算出来的值越大,越相关
  • TM_CCOEFF:计算相关系数,计算出来的值越大,越相关
  • TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关
  • TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关
  • TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

  • 最小值最大值及其坐标位置,具体看模板匹配使用的方法是什么。
更多初级知识点:

openCV第三篇_老师我作业忘带了的博客-CSDN博客

三、代码部分

3.1 代码讲解

3.1.1 处理模板
  • 导包
import cv2
import numpy as np
from imutils import contours # 排序操作,也可以不用。
  • 定义绘图展示函数
def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0) # 按键结束
    cv2.destroyAllWindows()

  • 模板读取、灰度、二值化
# 读取模板图像
img = cv2.imread('ocr_a_reference.png')

# 转换为灰度图 也可读取时直接转换
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二值图像
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]

  • 轮廓检测、排序
# 轮廓检测
refCnts, hierarchy = cv2.findContours(ref, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
'''
draw_img = img.copy()
cv2.drawContours(draw_img, refCnts, -1, (0, 0, 255), 2) # 第0个轮廓是9 第1个轮廓是8......
cv_show('draw_img',draw_img)
'''

# 排序(倒序操作) 得到正序0-9的轮廓
refCnts = sorted(refCnts,key=lambda b: b[0][0][0], reverse=False)

  • 遍历对这10个轮廓,做外接矩形,对外接矩形区域在二值化图ref上做切片,即把他们一个个抠出来,保存在 digits 字典中。
digits = {}

# 遍历每一个轮廓
for (i, c) in enumerate(refCnts):
    # 计算外接矩形并且resize成合适大小
    (x, y, w, h) = cv2.boundingRect(c)
    roi = ref[y:y + h, x:x + w]
    roi = cv2.resize(roi, (57, 88))

    # 每一个数字对应每一个模板,此时模板中的10个数字分别被保存到了字典中
    digits[i] = roi
3.1.2 处理银行卡
  • 初始化卷积核,读取输入图像。
# 初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

# 读入银行卡
image = cv2.imread('./images/credit_card_01.png')

  • 统一大小,这里建议让它变小一点,处理像素少一点,后面闭运算让其模糊也方便一些。
set_width = 300 # 自己设定 这里我统一了宽度
rate = set_width/image.shape[:2][1]
image = cv2.resize(image,(0,0),fx=rate,fy=rate)
  • 转为灰度图
# 同样也可以在第一步完成
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

  • 礼帽,突出更明亮的区域,可以看到此时银行卡后面的花纹基本已经消失了。 。
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)

  • 梯度运算,这里使用Sobel算子,只进行了x方向计算。前面的礼帽操作是的我们梯度运算结果更干净些。
# ksize=-1相当于用3*3的
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)

gradX = np.absolute(gradX) # 绝对值,白-黑 黑-白
# 或者写为 cv2.convertScaleAbs(sobelx)

# 归一化处理
(minVal, maxVal) = (np.min(gradX), np.max(gradX))
# gradX与最小值之间的距离占区间长度的几分之几
gradX = (255 * ((gradX - minVal) / (maxVal - minVal)))  
gradX = gradX.astype("uint8")

  • 闭运算、二值化、闭运算
# 闭运算 把银行卡卡号那里弄模糊
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)

# 二值化,用于之后轮廓检测。
thresh = cv2.threshold(gradX, 0, 255,
                       cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]

# 再来一个闭操作
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel)  

  • 轮廓检测
threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                                                  cv2.CHAIN_APPROX_SIMPLE)
'''
cur_img = image.copy()
cv2.drawContours(cur_img, threshCnts, -1, (0, 0, 255), 3)
cv_show('img', cur_img)
'''

  • 遍历所有轮廓,得到想要的四组数字,并排序。
locs = []

# 遍历轮廓
for (i, c) in enumerate(threshCnts):
    # 计算矩形
    (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))


# 将符合的这四组轮廓按x从左到右排序
locs = sorted(locs, key=lambda x: x[0])
  • 遍历这四组数
output = []

# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):
    groupOutput = []

    # 根据坐标提取每一个组
    group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]
    cv_show('group', group)
    # 预处理
    group = cv2.threshold(group, 0, 255,
                          cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    cv_show('group', group)
    # 计算每一组的轮廓
    # group_, 
    digitCnts, hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL,
                                                    cv2.CHAIN_APPROX_SIMPLE)
    
    # 就是个排序 真正的顺序我们都知道,可以自己用sort函数
    digitCnts = contours.sort_contours(digitCnts,
                                       method="left-to-right")[0]
 
    # 计算每一组中的每一个数值
    for c in digitCnts:
        # 找到当前数值的轮廓,resize成合适的的大小
        (x, y, w, h) = cv2.boundingRect(c)
        roi = group[y:y + h, x:x + w]
        roi = cv2.resize(roi, (57, 88))
        cv_show('roi', roi)

        # 计算匹配得分
        scores = []

        # 在模板中计算每一个得分  字典digits记录了模板0-9
        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)))
        
    # 画出来
    cv2.rectangle(image, (gX - 5, gY - 5),
                  (gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)
    cv2.putText(image, "".join(groupOutput), (gX, gY - 15),
                cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)

    # 得到结果
    output.extend(groupOutput)

  • 输出结果
print("Credit Card #: {}".format("".join(output)))
# cv_show("Image", image)

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

oin(output)))

cv_show(“Image”, image)





[外链图片转存中...(img-vQvhvovk-1714158603058)]
[外链图片转存中...(img-6qjGq83J-1714158603058)]
[外链图片转存中...(img-F0S9UcgQ-1714158603058)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值