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

本文介绍了如何使用OpenCV和卷积神经网络构建一个实时数字识别系统,包括数据预处理、模型训练、验证和评估,以及在实际应用中的摄像头识别示例。
摘要由CSDN通过智能技术生成

 

前言

数字识别是计算机视觉领域中的一个重要任务,它涉及将输入的手写数字图像分类为特定的数字。实时数字识别具有广泛的应用,包括手写数字识别、自动识别信用卡号码等。本教程将介绍如何使用 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(缩放)

 517b30ac243873d930ce79789401544b.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,目的是先简单测试代码是否准确)

cb060bc35dbf8536122b96e98e24843d.png

 对测试集进行识别,并打印出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()

效果图1b26fedd31f644e192903c9a2734326e.jpg

 

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

 

 

 

车牌识别计算机视觉中的一个重要应用。OpenCV是一个开源的计算机视觉库,其中包含了很多图像处理和机器学习的功能。在OpenCV中,使用卷积神经网络(CNN)进行车牌识别可以实现较高的准确率。 首先,需要收集一大批标记有车牌号码的车牌图像,这些图像将用作训练集。然后,使用OpenCV中的图像增强功能对这些图像进行处理,以增加训练集的多样性和泛化能力。 接下来,使用OpenCV中的卷积神经网络模块进行训练。首先,需要设计CNN的网络结构,包括卷积层、池化层和全连接层等。然后,使用训练集进行网络的训练,并通过反向传播算法不断优化网络参数,使得网络能够较准确地预测车牌号码。 在训练完成后,可以使用OpenCV从摄像头或视频中提取车牌图像,并使用训练好的CNN模型进行预测。对于每个提取到的图像,先进行图像预处理,如裁剪、调整大小、灰度化等,然后输入到CNN中进行预测。通过对CNN输出的概率进行阈值处理,即可判断车牌号码的存在性和具体的字符。 最后,根据识别出的车牌号码,可以进一步进行车牌的信息提取和后续应用,如车辆追踪、停车场管理等。 总之,使用OpenCV中的CNN模块进行车牌识别可以实现较高的准确率。通过收集标记的车牌图像进行训练,设计合适的CNN网络结构,以及对图像进行适当的预处理,可以实现对车牌号码的准确预测。
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值