opencv+CNN算法实现实时数字识别(完整教程)

 完整代码在文末。

前言

数字识别是计算机视觉领域中的一个重要任务,它涉及将输入的手写数字图像分类为特定的数字。实时数字识别具有广泛的应用,包括手写数字识别、自动识别信用卡号码等。本教程将介绍如何使用 OpenCV(Open Source Computer Vision Library)和卷积神经网络(Convolutional Neural Network,CNN)来实现实时数字识别。

OpenCV 是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法,包括图像处理、特征检测、对象跟踪等功能。CNN 是一种深度学习模型,已被广泛用于图像识别任务,特别是在数字识别方面取得了很大的成功。

通过本教程,您将学习到如何利用 OpenCV 和 CNN 构建一个实时数字识别系统,并了解数字识别背后的基本原理和技术。希望本教程能够帮助您在实践中掌握图像处理和深度学习技术,为您的项目和研究提供帮助和启发

关于CNN的介绍

CNN笔记点此处

Python版本要求 : 3.6 3.7  其他自测。

我所安装的库 :

opencv 4.2.0.32

numpy 1.1.81

sklearn

keras 2.3.1

matplotlib 3.1.3

TensorFlow 2.0.0

训练模型

1.初始操作 

对数据集进行数量导出,并创建数组。

import cv2
import numpy as np
import os

##############################
path = 'myData'
images=[]
classNo=[]
##############################


myList = os.listdir(path)
print("总class:",len(myList))
noOfClasses = len(myList)
print('import class...')
for x in range(0,noOfClasses):
    myPiclist = os.listdir(path + '/' + str(x))
    for y in myPiclist:
        curImg = cv2.imread(path + '/' + str(x) + '/' + y)
        curImg = cv2.resize(curImg,(32,32))
        images.append(curImg)
        classNo.append(x)
    print(x,end=' ')
print('')
    #print(x)
#print(len(images))
#print(len(classNo))
images = np.array(images)
classNo = np.array(classNo)
print(images.shape) #(10160,32,32,3)

 2.将数据集分为 training testing validation

 添加库

from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
numOfSamples=[]
testRatio = 0.2
valRatio = 0.2
X_train,X_test,Y_train,Y_test = train_test_split(images,classNo,test_size=testRatio)
X_train,X_validation,Y_train,Y_validation = train_test_split(X_train,Y_train,test_size= valRatio)
print(X_train.shape)
print(X_test.shape)
print(X_validation.shape)

for x in range (0,noOfClasses):
    #print(len(np.where(Y_train == x)[0]))
    numOfSamples.append(len(np.where(Y_train == x)[0]))
print(numOfSamples)

 用直方图plot出各个ID对应的图片数量

plt.figure(figsize=(10,5))
plt.bar(range(0,noOfClasses),numOfSamples )
plt.title('No of Images for each Class')
plt.xlabel('Class ID')
plt.ylabel('Number of Images')
plt.show()

对图像进行预处理preProcessing

灰度转换-直方图均衡化-归一化

equalizeHist()

直方图均衡化是一种用于增强图像对比度的方法,通过重新分布图像的像素值来扩展其动态范围。 它可以帮助改善图像中的细节和阴影,并增强图像的整体视觉效果。

利用python内置的map函数:

map(function, iterable, ...)

它的作用是对可迭代对象(如列表、元组等)中的每个元素应用一个指定的函数,然后返回一个结果列表。

 reshape:

假设你有一个图像数据 img,形状为 (height, width, channels)

# 例如,一个 32x32 的灰度图像可以表示为 (32, 32, 1),一个 32x32 的 RGB 彩色图像可以表示为 (32, 32, 3)

# 将图像数据重新形状为 (1, height, width, channels),即添加一个批量大小维度 img_reshaped = img.reshape(1, img.shape[0], img.shape[1], img.shape[2])

# 现在 img_reshaped 的形状为 (1, height, width, channels)

在深度学习中,对图像数据进行处理时,通常会引入一个批量大小(batch size)维度。这个批量大小维度表示在一次模型的训练或推理过程中同时处理的图像数量。

例如,假设你有一个包含多张图像的数据集,每张图像的形状为 (height, width, channels),如果你想一次性输入整个数据集进行训练,那么你可以将这些图像堆叠在一起,形成一个新的张量,其中第一个维度表示批量中的图像数量。

所以,当你将图像数据重新形状为 (1, height, width, channels) 时,添加的第一个维度 1 就表示批量大小为 1,即在这个批量中包含了一张图像。如果你有多张图像,你可以将批量大小设置为对应的图像数量,比如 (n, height, width, channels),其中 n 表示图像的数量。

def preProcessing(img):
    img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    img = cv2.equalizeHist(img)
    img = img/255
    return img

X_train = np.array(list(map(preProcessing,X_train)))
X_test = np.array(list(map(preProcessing,X_test)))
X_validation = np.array(list(map(preProcessing,X_validation)))

X_train = X_train.reshape(X_train.shape[0],X_train.shape[1],X_train.shape[2],1)
X_test = X_test.reshape(X_test.shape[0],X_test.shape[1],X_test.shape[2],1)
X_validation = X_validation.reshape(X_validation.shape[0],X_validation.shape[1],X_validation.shape[2],1)

对图像进行augment 使它跟容易generic 

如  rotation(旋转),translation(平移),zoom(缩放)

 ac367d2141764b47a6f5a12b24a3e44b.png

然后,在训练模型时,你可以使用 datagen.flow() 方法生成增强后的批量数据。在后文会使用,请注意观察。

to_categorical():

to_categorical 函数是 Keras 中的一个实用函数,用于将类标签转换为 one-hot 编码表示。在深度学习中,通常将类标签表示为整数形式,例如 0、1、2 等,但在某些情况下,我们需要将这些类标签转换为 one-hot 编码的形式,以便于神经网络的训练。

转换方法:在 one-hot 编码中,每个类别被表示为一个向量,其中只有一个元素为 1,其余元素均为 0。具体地说,如果有 N 个不同的类别,那么每个类别都会被表示为一个长度为 N 的向量,其中只有一个元素为 1,表示该样本属于这个类别,其他元素均为 0,表示不属于该类别。

例如,假设有三个类别:猫、狗和鸟,可以将它们表示为以下 one-hot 编码:

  • 猫:[1, 0, 0]
  • 狗:[0, 1, 0]
  • 鸟:[0, 0, 1]
from keras_preprocessing.image import ImageDataGenerator
from keras.utils.np_utils import  to_categorical
dataGen = ImageDataGenerator(width_shift_range=0.1,
                             height_shift_range=0.1,
                             zoom_range=0.2,
                             shear_range=0.1,
                             rotation_range=10)

dataGen.fit(X_train)

Y_train = to_categorical(Y_train,noOfClasses)
Y_test = to_categorical(Y_test,noOfClasses)
Y_validation = to_categorical(Y_validation,noOfClasses)

 关于CNN:

  1. batchSizeVal(批量大小)批量大小指的是在训练过程中一次传递给神经网络的样本数量。在每个训练步骤中,模型将同时处理 batchSizeVal 个样本。较大的批量大小可能会提高训练速度,但也可能增加内存需求和计算负担。通常,批量大小的选择是根据你的硬件配置和数据集的大小来确定的。较常见的批量大小值包括 32、64、128、256 等。

  2. epochsVal(迭代次数)一个 epoch 表示将整个训练数据集在神经网络中训练一次的过程。epochsVal 参数指定了训练过程中数据集将被遍历的次数。训练多个 epochs 可以帮助模型更好地学习数据的模式和特征,从而提高模型的性能。然而,过多的 epochs 也可能导致过拟合,即模型在训练数据上表现良好,但在测试数据上表现不佳。

  3. stepsPerEpochVal(每个 epoch 的步数):stepsPerEpochVal 参数指定了在一个 epoch 中模型执行的训练步数。在每个 epoch 中,数据集通常会被分成多个批次进行训练,stepsPerEpochVal 就是指定每个 epoch 中有多少个批次。通常,stepsPerEpochVal 的值等于数据集的样本总数除以批量大小,以确保在一个 epoch 中训练数据集的所有样本。但如果数据集很大,为了加快训练速度,可以将 stepsPerEpochVal 设置为一个较小的值。

 创建模型

 所需的库

from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam
from keras.layers import Dropout,Flatten
from keras.layers.convolutional import  Conv2D,MaxPooling2D
imageDimensions = [32,32,3]
def myModel():
    noOfFilters = 60
    sizeOfFilter1 = (5,5)
    sizeOfFilter2 = (3,3)
    sizeOfPool = (2,2)
    noOfNode = 500

    model = Sequential()
    model.add((Conv2D(noOfFilters, sizeOfFilter1, input_shape=(imageDimensions[0],
                                                               imageDimensions[1],
                                                               1),activation='relu')))
    model.add((Conv2D(noOfFilters, sizeOfFilter1, activation='relu')))
    model.add(MaxPooling2D(pool_size=sizeOfPool))
    model.add((Conv2D(noOfFilters // 2, sizeOfFilter2, activation='relu')))
    model.add((Conv2D(noOfFilters // 2,sizeOfFilter2, activation='relu')))
    model.add(MaxPooling2D(pool_size=sizeOfPool))
    model.add(Dropout(0.5))

    model.add(Flatten())
    model.add(Dense(noOfNode, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(noOfClasses, activation='softmax'))
    model.compile(Adam(lr=0.001),loss='categorical_crossentropy',
                  metrics=['accuracy'])
    return model
#显示模型情况
model = myModel()
print(model.summary())
要想在训练的过程中观察模型训练的情况,代码如下
batchSizeVal = 50
epochsVal = 10
stepsPerEpochVal = 2000

history = model.fit_generator(dataGen.flow(X_train,Y_train,
                              batch_size= batchSizeVal),
                              steps_per_epoch=stepsPerEpochVal,
                              epochs=epochsVal,
                              validation_data=(X_validation,Y_validation),
                              shuffle =1 )

 将训练结果loss和accuracy分别plot出来

plt.figure(1)
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.legend(['training','validation'])
plt.title('Loss')
#plt.xlim(0, 1)
#plt.ylim(0,3)
plt.xlabel('epoch')

plt.figure(2)
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.legend(['training','validation'])
plt.title('Accuracy')
plt.xlabel('epoch')
#plt.xlim(0, 1)
plt.show()

 结果如图(结果图为epoch为2,目的是先简单测试代码是否准确)

 对测试集进行识别,并打印出loss 和 accuracy

score = model.evaluate(X_test,Y_test,verbose=0)
print('Test Score=',score[0])
print('Test Accuracy=',score[1])

 训练完成后,利用pickle模块,这个模块可以用来序列化(即将对象转换为字节流)和反序列化(即从字节流重新构建对象)Python 对象。

pickle_out = open("model_trained.p","wb")#write byte将文件名字命名为model_train.p
pickle.dump(model,pickle_out )#作用是将model对象序列化并保存到名为pick_out的文件中。
pickle_out.close()

运行模型

摄像头类

接下来是最后的工程——开启摄像头,实时预测摄像头每一帧的数据

import numpy as np
import cv2
import pickle

################################
width = 640
height = 480
threshold = 0.6
################################

cap = cv2.VideoCapture(0)
cap.set(3,width)
cap.set(4,height)

然后打开模型文件

由我们前面提到的preProcessing函数,对摄像头的图像进行预处理 


pickle_in = open("model_trained.p","rb")
model = pickle.load(pickle_in)

def preProcessing(img):
    img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    img = cv2.equalizeHist(img)
    img = img/255
    return img
while True:
    ret, imgOriginal = cap.read()
    img = np.asarray(imgOriginal)
    img = cv2.resize(img, (32, 32))
    img = preProcessing(img)
    #cv2.imshow("Processed Image", img)

 将img.reshape一下传入模型里面进行预测,和前面对数据库进行reshape操作一样

最后在图像上显示 置信度和数字 完工。


    img = img.reshape(1,32,32,1)
    #Predict
    classIndex = int(model.predict_classes(img))
    print(classIndex) #数字
    predictions = model.predict(img) #置信度
    probVal = np.amax(predictions) #最大的置信度
    print(classIndex, probVal) 
    if probVal > threshold :
        cv2.putText(imgOriginal, str(classIndex) + " " +str(probVal),(50,50), cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),1)

    cv2.imshow("Original Image", imgOriginal)

    if cv2.waitKey(1)& 0xff ==ord('q'):
        break

图片类

最后附带对图片的单独识别的源代码,代码与实时监测基本一致

import cv2
import numpy as np
import pickle

def preProcessing(img):
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img = cv2.equalizeHist(img)
    img = img / 255
    return img

imgOriginal = cv2.imread('number3.png')
img = cv2.resize(imgOriginal, (32, 32))
img_processed = preProcessing(img)
img_processed = img_processed.reshape(1, 32, 32, 1)

pickle_in = open("model_trained.p", "rb")
model = pickle.load(pickle_in)

classIndex = int(model.predict_classes(img_processed))
predictions = model.predict(img_processed)
probVal = np.amax(predictions)


cv2.putText(imgOriginal, str(classIndex) + " " + str(probVal), (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)

# Show the image
cv2.imshow("img", imgOriginal)
cv2.waitKey(0)
cv2.destroyAllWindows()

到这里就结束了,如果你有任何疑惑欢迎评论告诉我,如果有什么错误的地方,鄙人不吝赐教。源代码和数据集有需要可以评论。

  • 47
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
OpenCV(Open Source Computer Vision Library)是一款开源的计算机视觉库,专门为图像和视频处理任务设计,广泛应用于学术研究、工业应用以及个人项目中。以下是关于OpenCV的详细介绍: 历史与发展 起源:OpenCV于1999年由英特尔公司发起,旨在促进计算机视觉技术的普及和商业化应用。该项目旨在创建一个易于使用、高效且跨平台的库,为开发者提供实现计算机视觉算法所需的基础工具。 社区与支持:随着时间的推移,OpenCV吸引了全球众多开发者和研究人员的参与,形成了活跃的社区。目前,OpenCV由非盈利组织OpenCV.org维护,并得到了全球开发者、研究机构以及企业的持续贡献和支持。 主要特点 跨平台:OpenCV支持多种操作系统,包括但不限于Windows、Linux、macOS、Android和iOS,确保代码能够在不同平台上无缝运行。 丰富的功能:库中包含了数千个优化过的函数,涵盖了计算机视觉领域的诸多方面,如图像处理(滤波、形态学操作、色彩空间转换等)、特征检测与描述(如SIFT、SURF、ORB等)、物体识别与检测(如Haar级联分类器、HOG、DNN等)、视频分析、相机校正、立体视觉、机器学习(SVM、KNN、决策树等)、深度学习(基于TensorFlow、PyTorch后端的模型加载与部署)等。 高效性能:OpenCV代码经过高度优化,能够利用多核CPU、GPU以及特定硬件加速(如Intel IPP、OpenCL等),实现高速图像处理和实时计算机视觉应用。 多语言支持:尽管OpenCV主要使用C++编写,但它提供了丰富的API绑定,支持包括C、Python、Java、MATLAB、JavaScript等多种编程语言,方便不同领域的开发者使用。 开源与免费:OpenCV遵循BSD开源许可证发布,用户可以免费下载、使用、修改和分发库及其源代码,无需担心版权问题。 架构与核心模块 OpenCV的架构围绕核心模块构建,这些模块提供了不同层次的功能: Core:包含基本的数据结构(如cv::Mat用于图像存储和操作)、基本的图像和矩阵操作、数学函数、文件I/O等底层功能。 ImgProc:提供图像预处理、滤波、几何变换、形态学操作、直方图计算、轮廓发现与分析等图像处理功能。 HighGui:提供图形用户界面(GUI)支持,如图像和视频的显示、用户交互(如鼠标事件处理)以及简单的窗口管理。 VideoIO:负责视频的读写操作,支持多种视频格式和捕获设备。 Objdetect:包含预训练的对象检测模型(如Haar级联分类器用于人脸检测)。 Features2D:提供特征点检测(如SIFT、ORB)与描述符计算、特征匹配与对应关系估计等功能。 Calib3d:用于相机标定、立体视觉、多视图几何等问题。 ML:包含传统机器学习算法,如支持向量机(SVM)、K近邻(KNN)、决策树等。 DNN:深度神经网络模块,支持导入和运行预训练的深度学习模型,如卷积神经网络(CNN)。 应用领域 OpenCV广泛应用于: 科研与教育:作为计算机视觉教学和研究的基础工具,OpenCV简化了算法原型开发与验证过程。 工业自动化:在视觉检测、机器人导航、产品质量控制等工业场景中,OpenCV用于实时图像分析与决策。 安防监控:用于人脸识别、行人检测、行为分析等智能监控系统。 医疗影像分析:在医疗领域,OpenCV可用于医学图像处理、病灶检测、诊断辅助等应用。 自动驾驶:在车辆视觉感知系统中,OpenCV用于道路标志识别、障碍物检测、车道线识别等任务。 多媒体应用:如图像编辑软件、AR/VR应用、游戏开发等,利用OpenCV进行图像和视频处理。 物联网与嵌入式系统:在资源受限的嵌入式设备上,OpenCV提供轻量级的计算机视觉解决方案。 学习与社区资源 OpenCV拥有丰富的官方文档、教程、示例代码以及活跃的开发者社区,包括GitHub、StackOverflow、官方论坛等,为学习和使用OpenCV提供了有力支持。此外,有许多书籍、在线课程、博客文章和研讨会专门讲解OpenCV的使用和计算机视觉技术。 综上所述,OpenCV作为一款功能强大、高效、跨平台且开源的计算机视觉库,为开发者提供了实现各类图像和视频处理任务所需的工具箱,其广泛的应用领域和活跃的社区支持使之成为计算机视觉领域不可或缺的开发工具。
车牌识别计算机视觉中的一个重要应用。OpenCV是一个开源的计算机视觉库,其中包含了很多图像处理和机器学习的功能。在OpenCV中,使用卷积神经网络(CNN)进行车牌识别可以实现较高的准确率。 首先,需要收集一大批标记有车牌号码的车牌图像,这些图像将用作训练集。然后,使用OpenCV中的图像增强功能对这些图像进行处理,以增加训练集的多样性和泛化能力。 接下来,使用OpenCV中的卷积神经网络模块进行训练。首先,需要设计CNN的网络结构,包括卷积层、池化层和全连接层等。然后,使用训练集进行网络的训练,并通过反向传播算法不断优化网络参数,使得网络能够较准确地预测车牌号码。 在训练完成后,可以使用OpenCV从摄像头或视频中提取车牌图像,并使用训练好的CNN模型进行预测。对于每个提取到的图像,先进行图像预处理,如裁剪、调整大小、灰度化等,然后输入到CNN中进行预测。通过对CNN输出的概率进行阈值处理,即可判断车牌号码的存在性和具体的字符。 最后,根据识别出的车牌号码,可以进一步进行车牌的信息提取和后续应用,如车辆追踪、停车场管理等。 总之,使用OpenCV中的CNN模块进行车牌识别可以实现较高的准确率。通过收集标记的车牌图像进行训练,设计合适的CNN网络结构,以及对图像进行适当的预处理,可以实现对车牌号码的准确预测。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值