详解Python OpenCV数字识别案例

前言

实践是检验真理的唯一标准。

因为觉得一板一眼地学习OpenCV太过枯燥,于是在网上找了一个以项目为导向的教程学习。话不多说,动手做起来。

一、案例介绍

提供信用卡上的数字模板:

要求:识别出信用卡上的数字,并将其直接打印在原图片上。虽然看起来很蠢,但既然可以将数字打印在图片上,说明已经成功识别数字,因此也可以将其转换为数字文本保存。车牌号识别等项目的思路与此案例类似。

示例:

原图

处理后的图

二、步骤

大致分为如下几个步骤:

1.模板读入

2.模板预处理,将模板数字分开,并排序

3.输入图像预处理,将图像中的数字部分提取出来

4.将数字与模板数字进行匹配,匹配率最高的即为对应数字。

1、模板读入,以及一些包的导入,函数定义等

import cv2 as cv
import numpy as np
import myutils
def cv_show(name, img):        # 自定义的展示函数
    cv.imshow(name, img)
    cv.waitKey(0)
# 读入模板图
n = 'text'
img = cv.imread("images/ocr_a_reference.png")
# cv_show(n, template)        # 自定义的展示函数,方便显示图片

2、模板预处理,将模板数字分开,并排序

模板的预处理顺序:灰度图,二值化,再进行轮廓检测。需要注意的是openCV检测轮廓时是检测白色边框,因此要将模板图的数字二值化变为白色。

# 模板转换为灰度图
ref = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# cv_show(n, ref)

# 转换为二值图,把数字部分变为白色
ref = cv.threshold(ref, 10, 255, cv.THRESH_BINARY_INV)[1]  # 骚写法,函数多个返回值为元组,这里取第二个返回值
cv_show(n, ref)

# 对模板进行轮廓检测,得到轮廓信息
refCnts, hierarchy = cv.findContours(ref.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
cv.drawContours(img, refCnts, -1, (0, 0, 255), 2)  # 第一个参数为目标图像
# cv_show(n, img)

红色部分即为检测出的轮廓。

接下来进行轮廓排序,因为检测出的轮廓是无序的,因此要按照轮廓的左上角点的x坐标来排序。轮廓排序后按顺序放入字典,则字典中的键值对是正确匹配的,如‘0'对应轮廓0 ,‘1'对应轮廓1。

# 轮廓排序
refCnts = myutils.sort_contours(refCnts)[0]
digits = {}

# 单个轮廓提取到字典中
for (i, c) in enumerate(refCnts):
    (x, y, w, h) = cv.boundingRect(c)
    roi = ref[y:y + h, x:x + w]  # 在模板中复制出轮廓
    roi = cv.resize(roi, (57, 88))  # 改成相同大小的轮廓
    digits[i] = roi  # 此时字典键对应的轮廓即为对应数字。如键‘1'对应轮廓‘1'

至此,模板图处理完毕。

3、输入图像预处理,将图像中的数字部分提取出来

在此步骤中需要将信用卡上的每个数字提取出来,并与上一步得到的模板一一匹配。首先初始化卷积核,方便之后tophat操作以及闭运算操作使用。

# 初始化卷积核
rectKernel = cv.getStructuringElement(cv.MORPH_RECT, (9, 3))
sqKernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))

接下来读入图片,调整图片大小,转换为灰度图。

# 待分析图片读入,预处理
card_image = cv.imread("images/credit_card_01.png")
# cv_show('a', card_image)
card_image = myutils.resize(card_image, width=300)    # 更改图片大小
gray = cv.cvtColor(card_image, cv.COLOR_BGR2GRAY)
# cv_show('gray', gray)

然后进行tophat操作,tophat可以突出图片中明亮的区域,过滤掉较暗的部分:

tophat = cv.morphologyEx(gray, cv.MORPH_TOPHAT, rectKernel)
# cv_show('tophat', tophat)

再通过sobel算子检测边缘,进行一次闭操作,二值化,再进行一次闭操作,填补空洞。

# x方向的Sobel算子
gradX = cv.Sobel(tophat, cv.CV_32F, 1, 0, ksize=3) 

gradX = np.absolute(gradX)  # absolute: 计算绝对值
min_Val, max_val = np.min(gradX), np.max(gradX)
gradX = (255 * (gradX - min_Val) / (max_val - min_Val))
gradX = gradX.astype("uint8")

# 通过闭操作(先膨胀,再腐蚀)将数字连在一起.  将本是4个数字的4个框膨胀成1个框,就腐蚀不掉了
gradX = cv.morphologyEx(gradX, cv.MORPH_CLOSE, rectKernel)
# cv_show('close1', gradX)

# 二值化
thresh = cv.threshold(gradX, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]

# 闭操作,填补空洞
thresh = cv.morphologyEx(thresh, cv.MORPH_CLOSE, sqKernel)
# cv_show('close2', thresh)

之后就可以查找轮廓了。

threshCnts = cv.findContours(thresh.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]
card_copy = card_image.copy()
cv.drawContours(card_copy, threshCnts, -1, (0, 0, 255), 2)
cv_show('Input_Contours', card_copy)

4、模板匹配

将模板数字和待识别的图片都处理好后,就可以进行匹配了。

locs = []  # 存符合条件的轮廓
for i, c in enumerate(threshCnts):
    # 计算矩形
    x, y, w, h = cv.boundingRect(c)

    ar = w / float(h)
    # 选择合适的区域,根据实际任务来,这里的基本都是四个数字一组
    if 2.5 < ar < 4.0:
        if (40 < w < 55) and (10 < h < 20):
            # 符合的留下来
            locs.append((x, y, w, h))

# 将符合的轮廓从左到右排序
locs = sorted(locs, key=lambda x: x[0])

接下来,遍历每一个大轮廓,每个大轮廓中有四个数字,对应四个小轮廓。将小轮廓与模板匹配。

output = []  # 存正确的数字
for (i, (gx, gy, gw, gh)) in enumerate(locs):  # 遍历每一组大轮廓(包含4个数字)
    groupOutput = []

    # 根据坐标提取每一个组(4个值)
    group = gray[gy - 5:gy + gh + 5, gx - 5:gx + gw + 5]  # 往外扩一点
    # cv_show('group_' + str(i), group)
    # 预处理
    group = cv.threshold(group, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]  # 二值化的group
    # cv_show('group_'+str(i),group)
    # 计算每一组的轮廓 这样就分成4个小轮廓了
    digitCnts = cv.findContours(group.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]
    # 排序
    digitCnts = myutils.sort_contours(digitCnts, method="left-to-right")[0]

# 计算并匹配每一组中的每一个数值
    for c in digitCnts:  # c表示每个小轮廓的终点坐标
        z = 0
        # 找到当前数值的轮廓,resize成合适的的大小
        (x, y, w, h) = cv.boundingRect(c)  # 外接矩形
        roi = group[y:y + h, x:x + w]  # 在原图中取出小轮廓覆盖区域,即数字
        roi = cv.resize(roi, (57, 88))
        # cv_show("roi_"+str(z),roi)

        # 计算匹配得分: 0得分多少,1得分多少...
        scores = []  # 单次循环中,scores存的是一个数值 匹配 10个模板数值的最大得分

        # 在模板中计算每一个得分
        # digits的digit正好是数值0,1,...,9;digitROI是每个数值的特征表示
        for (digit, digitROI) in digits.items():
            # 进行模板匹配, res是结果矩阵
            res = cv.matchTemplate(roi, digitROI, cv.TM_CCOEFF)  # 此时roi是X digitROI是0 依次是1,2.. 匹配10次,看模板最高得分多少
            Max_score = cv.minMaxLoc(res)[1]  # 返回4个,取第二个最大值Maxscore
            scores.append(Max_score)  # 10个最大值
        # print("scores:",scores)
        # 得到最合适的数字
        groupOutput.append(str(np.argmax(scores)))  # 返回的是输入列表中最大值的位置
        z = z + 1
# 画出来
    cv.rectangle(card_image, (gx - 5, gy - 5), (gx + gw + 5, gy + gh + 5), (0, 0, 255), 1)  # 左上角,右下角
# putText参数:图片,添加的文字,左上角坐标,字体,字体大小,颜色,字体粗细
    cv.putText(card_image, "".join(groupOutput), (gx, gy - 15), cv.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)

最后将其打印出来,任务就完成了。

cv.imshow("Output_image_"+str(i), card_image)
cv.waitKey(0)

总结

信用卡识别的案例用到了图像处理的一些基本操作,对刚上手CV的人来说还是比较友好的。

以上就是详解Python OpenCV数字识别案例的详细内容,更多关于Python OpenCV数字识别案例的资料请关注我们其它相关文章!

(0)

相关推荐

  • Python开发之基于模板匹配的信用卡数字识别功能

    环境介绍 Python 3.6 + OpenCV 3.4.1.15 原理介绍 首先,提取出模板中每一个数字的轮廓,再对信用卡图像进行处理,提取其中的数字部分,将该部分数字与模板进行匹配,即可得到结果. 模板展示 完整代码 # !/usr/bin/env python # -*- coding: utf-8 -*- # @Time: 2020/1/11 14:57 # @Author: Martin # @File: utils.py # @Software:PyCharm import cv2

  • python opencv实现信用卡的数字识别

    本项目利用python以及opencv实现信用卡的数字识别 前期准备 导入工具包 定义功能函数 模板图像处理 读取模板图像 cv2.imread(img) 灰度化处理 cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 二值化 cv2.threshold() 轮廓 - 轮廓 信用卡图像处理 读取信用卡图像 cv2.imread(img) 灰度化处理 cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 礼帽处理 cv2.morphologyEx(gray

  • python神经网络编程实现手写数字识别

    本文实例为大家分享了python实现手写数字识别的具体代码,供大家参考,具体内容如下 import numpy import scipy.special #import matplotlib.pyplot class neuralNetwork: def __init__(self,inputnodes,hiddennodes,outputnodes,learningrate): self.inodes=inputnodes self.hnodes=hiddennodes self.onodes

  • Python利用逻辑回归模型解决MNIST手写数字识别问题详解

    本文实例讲述了Python利用逻辑回归模型解决MNIST手写数字识别问题.分享给大家供大家参考,具体如下: 1.MNIST手写识别问题 MNIST手写数字识别问题:输入黑白的手写阿拉伯数字,通过机器学习判断输入的是几.可以通过TensorFLow下载MNIST手写数据集,通过import引入MNIST数据集并进行读取,会自动从网上下载所需文件. %matplotlib inline import tensorflow as tf import tensorflow.examples.tutori

  • Python(TensorFlow框架)实现手写数字识别系统的方法

    手写数字识别算法的设计与实现 本文使用python基于TensorFlow设计手写数字识别算法,并编程实现GUI界面,构建手写数字识别系统.这是本人的本科毕业论文课题,当然,这个也是机器学习的基本问题.本博文不会以论文的形式展现,而是以编程实战完成机器学习项目的角度去描述. 项目要求:本文主要解决的问题是手写数字识别,最终要完成一个识别系统. 设计识别率高的算法,实现快速识别的系统. 1 LeNet-5模型的介绍 本文实现手写数字识别,使用的是卷积神经网络,建模思想来自LeNet-5,如下图所示

  • PyTorch CNN实战之MNIST手写数字识别示例

    简介 卷积神经网络(Convolutional Neural Network, CNN)是深度学习技术中极具代表的网络结构之一,在图像处理领域取得了很大的成功,在国际标准的ImageNet数据集上,许多成功的模型都是基于CNN的. 卷积神经网络CNN的结构一般包含这几个层: 输入层:用于数据的输入 卷积层:使用卷积核进行特征提取和特征映射 激励层:由于卷积也是一种线性运算,因此需要增加非线性映射 池化层:进行下采样,对特征图稀疏处理,减少数据运算量. 全连接层:通常在CNN的尾部进行重新拟合,减

  • Python+Opencv实现数字识别的示例代码

    一.什么是数字识别?   所谓的数字识别,就是使用算法自动识别出图片中的数字.具体的效果如下图所示: 上图展示了算法的处理效果,算法能够自动的识别到LCD屏幕上面的数字,这在现实场景中具有很大的实际应用价值.下面我们将对它的实现细节进行详细解析. 二.如何实现数字识别?   对于数字识别这个任务而言,它并不是一个新的研究方向,很久之前就有很多的学者们在关注这个问题,并提出了一些可行的解决方案,本小节我们将对这些方案进行简单的总结. 方案一:使用现成的OCR技术. OCR,即文字识别,它是一个比较

  • 详解PyTorch手写数字识别(MNIST数据集)

    MNIST 手写数字识别是一个比较简单的入门项目,相当于深度学习中的 Hello World,可以让我们快速了解构建神经网络的大致过程.虽然网上的案例比较多,但还是要自己实现一遍.代码采用 PyTorch 1.0 编写并运行. 导入相关库 import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torchvision import datasets, t

  • 详解Python OpenCV数字识别案例

    前言 实践是检验真理的唯一标准. 因为觉得一板一眼地学习OpenCV太过枯燥,于是在网上找了一个以项目为导向的教程学习.话不多说,动手做起来. 一.案例介绍 提供信用卡上的数字模板: 要求:识别出信用卡上的数字,并将其直接打印在原图片上.虽然看起来很蠢,但既然可以将数字打印在图片上,说明已经成功识别数字,因此也可以将其转换为数字文本保存.车牌号识别等项目的思路与此案例类似. 示例: 原图 处理后的图 二.步骤 大致分为如下几个步骤: 1.模板读入 2.模板预处理,将模板数字分开,并排序 3.输入

  • 详解Python+opencv裁剪/截取图片的几种方式

    前言 在计算机视觉任务中,如图像分类,图像数据集必不可少.自己采集的图片往往存在很多噪声或无用信息会影响模型训练.因此,需要对图片进行裁剪处理,以防止图片边缘无用信息对模型造成影响.本文介绍几种图片裁剪的方式,供大家参考. 一.手动单张裁剪/截取 selectROI:选择感兴趣区域,边界框框选x,y,w,h selectROI(windowName, img, showCrosshair=None, fromCenter=None): . 参数windowName:选择的区域被显示在的窗口的名字

  • 详解python opencv图像混合算术运算

    目录 图片相加 cv2.add() 按位运算 图片相加 cv2.add() 要叠加两张图片,可以用 cv2.add() 函数,相加两幅图片的形状(高度 / 宽度 / 通道数)必须相同.         numpy中可以直接用res = img + img1相加,但这两者的结果并不相同(看下边代码):         add()两个图片进行加和,大于255的使用255计数.         numpy会对结果取256(相当于255+1)的模: import numpy as np import c

  • 详解Python+OpenCV进行基础的图像操作

    目录 介绍 形态变换 腐蚀 膨胀 创建边框 强度变换 对数变换 线性变换 去噪彩色图像 使用直方图分析图像 介绍 众所周知,OpenCV是一个用于计算机视觉和图像操作的免费开源库. OpenCV 是用 C++ 编写的,并且有数千种优化的算法和函数用于各种图像操作.很多现实生活中的操作都可以使用 OpenCV 来解决.例如视频和图像分析.实时计算机视觉.对象检测.镜头分析等. 许多公司.研究人员和开发人员为 OpenCV 的创建做出了贡献.使用OpenCV 很简单,而且 OpenCV 配备了许多工

  • 详解Python+OpenCV实现图像二值化

    目录 一.图像二值化 1.效果 2.源码 二.图像二值化(调节阈值) 1.源码一 2.源码二 一.图像二值化 1.效果 2.源码 import cv2 import numpy as np import matplotlib.pyplot as plt # img = cv2.imread('test.jpg') #这几行是对图像进行降噪处理,但事还存在一些问题. # dst = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21) # plt

  • 详解Python OpenCV图像分割算法的实现

    目录 前言 1.图像二值化 2.自适应阈值分割算法 3.Otsu阈值分割算法 4.基于轮廓的字符分离 4.1轮廓检测 4.2轮廓绘制 4.3包围框获取 4.4矩形绘制 前言 图像分割是指根据灰度.色彩.空间纹理.几何形状等特征把图像划分成若干个互不相交的区域. 最简单的图像分割就是将物体从背景中分割出来 1.图像二值化 cv2.threshold是opencv-python中的图像二值化方法,可以实现简单的分割功能. retval, dst = cv2.threshold(src, thresh

  • 详解python OpenCV学习笔记之直方图均衡化

    本文介绍了python OpenCV学习笔记之直方图均衡化,分享给大家,具体如下: 官方文档 – https://docs.opencv.org/3.4.0/d5/daf/tutorial_py_histogram_equalization.html 考虑一个图像,其像素值仅限制在特定的值范围内.例如,更明亮的图像将使所有像素都限制在高值中.但是一个好的图像会有来自图像的所有区域的像素.所以你需要把这个直方图拉伸到两端(如下图所给出的),这就是直方图均衡的作用(用简单的话说).这通常会改善图像的

  • 详解python的数字类型变量与其方法

    前言 python数据类型是不允许改变的,这就意味着如果改变 Number 数据类型的值,将重新分配内存空间.下面话不多说,来看看详细的介绍吧. 以下实例在变量赋值时 Number 对象将被创建: var1 = 1 var2 = 10 您也可以使用del语句删除一些 Number 对象引用. 您可以通过使用del语句删除单个或多个对象,例如: del var del var_a, var_b Python 支持四种不同的数值类型: 整型(Int)               - 通常被称为是整型

  • 详解python opencv、scikit-image和PIL图像处理库比较

    进行深度学习时,对图像进行预处理的过程是非常重要的,使用pytorch或者TensorFlow时需要对图像进行预处理以及展示来观看处理效果,因此对python中的图像处理框架进行图像的读取和基本变换的掌握是必要的,接下来python中几个基本的图像处理库进行纵向对比. 项目地址:https://github.com/Oldpan/Pytorch-Learn/tree/master/Image-Processing 比较的图像处理框架: PIL scikit-image opencv-python

  • 详解Python Opencv和PIL读取图像文件的差别

    前言 之前在进行深度学习训练的时候,偶然发现使用PIL读取图片训练的效果要比使用python-opencv读取出来训练的效果稍好一些,也就是训练更容易收敛.可能的原因是两者读取出来的数据转化为pytorch中Tensor变量稍有不同,这里进行测试. 之后的代码都导入了: from PIL import Image import matplotlib.pyplot as plt import numpy as np import torch import cv2 测试 使用PIL和cv2读取图片时

随机推荐