Opencv总结4——项目实战-信用卡数字识别

先看效果:

代码资料看本人博客资源。

首先模板是

需要预测的图像是

任务是:使用模板匹配,一定要是数字特别接近的模板,然后匹配银行卡上面的数字。

1.1 模板处理

灰度处理------> 二值处理------> 轮廓处理

python 复制代码
# 灰度图
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
python 复制代码
# 二值图像
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]

RETR_EXTERNAL表示计算外轮廓,计算外接矩形

python 复制代码
# 计算轮廓
#cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标
#返回的list中每个元素都是图像中的一个轮廓
ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# -1 表示画出所有的轮廓
cv2.drawContours(img,refCnts,-1,(0,0,255),3) 
refCnts = myutils.sort_contours(refCnts, method="left-to-right")[0] #排序,从左到右,从上到下

上面调用了sort_contours方法,下面是计算并排序的方法,boundingBoxes 是一个元组,总共包含4个值x,y,h,w,直接按照横坐标x来判断数字在模板中的位置。

python 复制代码
def sort_contours(cnts, method="left-to-right"):
    reverse = False
    i = 0

    if method == "right-to-left" or method == "bottom-to-top":
        reverse = True

    if method == "top-to-bottom" or method == "bottom-to-top":
        i = 1
    boundingBoxes = [cv2.boundingRect(c) for c in cnts] #用一个最小的矩形,把找到的形状包起来x,y,h,w
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda b: b[1][i], reverse=reverse))

在得到10个轮廓之后,进行逐个遍历,c代表每一个轮廓

python 复制代码
# 遍历每一个轮廓
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))

    # 每一个数字对应每一个模板
    digits[i] = roi

1.2 对输入图像进行处理

总体流程:

对图片的处理------灰度处理------> 二值处理------>图像闭操作------>分组提取数字 ------> 切分成每个小的区域------ > 对于每个小区域都进行模板匹配。

信用卡的背景中有很多的干扰项,需要做一些额外的预处理操作

python 复制代码
# 初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
python 复制代码
#读取输入图像,预处理
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)
python 复制代码
#礼帽操作,突出更明亮的区域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel) 
cv_show('tophat',tophat) 
# 
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, #ksize=-1相当于用3*3的
    ksize=-1)

对梯度数据(gradX)进行 归一化 处理,将其数值范围映射到 0-255 的图像 像素 范围,并转换为可显示的整数格式

python 复制代码
gradX = np.absolute(gradX) # 对梯度数组gradX的每一个元素取绝对值。
(minVal, maxVal) = (np.min(gradX), np.max(gradX)) # 计算取绝对值后梯度数组的最小值(minVal)和最大值(maxVal)
gradX = (255 * ((gradX - minVal) / (maxVal - minVal))) # 将梯度值从原来的任意范围(比如[5.2, 189.7])映射到0-255的范围
gradX = gradX.astype("uint8") # 将归一化后的浮点型数组转换为uint8类型(8 位无符号整数,取值范围 0-255)。

print (np.array(gradX).shape) # 打印处理后数组的形状(维度)。
cv_show('gradX',gradX)

接下来就是如何让上面的数字更像一个块,opencv中可以使用闭操作来完成

python 复制代码
#通过闭操作(先膨胀,再腐蚀)将数字连在一起
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel) 
cv_show('gradX',gradX)
python 复制代码
#THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(gradX, 0, 255,
    cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] 
cv_show('thresh',thresh)

再把细碎的小白空填充好就可以了

python 复制代码
#再来一个闭操作

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

# 计算轮廓

thresh_, threshCnts, hierarchy = 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)

我们需要过滤掉数字以外的轮廓

python 复制代码
# 遍历轮廓
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[0])
output = []
python 复制代码
# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):
    # initialize the list of group digits
    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)
    digitCnts = contours.sort_contours(digitCnts,
       method="left-to-right")[0]
python 复制代码
# 计算每一组中的每一个数值
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 = []

    # 在模板中计算每一个得分
    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)))

然后程序就可以输出预测啦。

相关推荐
奔跑中的小象5 小时前
统信UOS + 天数AI卡部署SGLang服务手册
人工智能·uos·sglang·天数智芯
DevSecOps选型指南5 小时前
中国版Mythos,为何是悬镜安全灵脉CodeAI?
人工智能·安全
Shockang5 小时前
LangGraph 状态机实战
人工智能
刹那芳华19925 小时前
循环神经网络的从零开始实现(RNN)
人工智能·rnn·深度学习
阿童木写作5 小时前
跨境图片翻译工具多合一,批量图片视频字幕翻译加智能抠图
人工智能·python·音视频·语音识别
科技之门5 小时前
AI3D从建模到贴图、绑骨和动画的完整流程怎么做?V2Fun完整工作流指南
人工智能·3d·贴图
宇宙第一小趴菜5 小时前
二、机器学习的应用领域和发展史
人工智能·机器学习
前端开发江鸟5 小时前
我写过 MCP Server,却一直以为 MCP 只有 Tool
人工智能
天国梦6 小时前
自习室智能化升级避坑指南:天学网AI智习室方案实测与选型建议
大数据·人工智能
阿里云云原生6 小时前
可用性从 99.9% 跃升至 99.995%:畅捷通如何用 AI 重塑运维底座?
运维·网络·人工智能