当前位置:   article > 正文

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

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.初始操作 

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

  1. import cv2
  2. import numpy as np
  3. import os
  4. ##############################
  5. path = 'myData'
  6. images=[]
  7. classNo=[]
  8. ##############################
  9. myList = os.listdir(path)
  10. print("总class:",len(myList))
  11. noOfClasses = len(myList)
  12. print('import class...')
  13. for x in range(0,noOfClasses):
  14. myPiclist = os.listdir(path + '/' + str(x))
  15. for y in myPiclist:
  16. curImg = cv2.imread(path + '/' + str(x) + '/' + y)
  17. curImg = cv2.resize(curImg,(32,32))
  18. images.append(curImg)
  19. classNo.append(x)
  20. print(x,end=' ')
  21. print('')
  22. #print(x)
  23. #print(len(images))
  24. #print(len(classNo))
  25. images = np.array(images)
  26. classNo = np.array(classNo)
  27. print(images.shape) #(10160,32,32,3)

 2.将数据集分为 training testing validation

 添加库

  1. from sklearn.model_selection import train_test_split
  2. import matplotlib.pyplot as plt
  1. numOfSamples=[]
  2. testRatio = 0.2
  3. valRatio = 0.2
  1. X_train,X_test,Y_train,Y_test = train_test_split(images,classNo,test_size=testRatio)
  2. X_train,X_validation,Y_train,Y_validation = train_test_split(X_train,Y_train,test_size= valRatio)
  3. print(X_train.shape)
  4. print(X_test.shape)
  5. print(X_validation.shape)
  6. for x in range (0,noOfClasses):
  7. #print(len(np.where(Y_train == x)[0]))
  8. numOfSamples.append(len(np.where(Y_train == x)[0]))
  9. print(numOfSamples)

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

  1. plt.figure(figsize=(10,5))
  2. plt.bar(range(0,noOfClasses),numOfSamples )
  3. plt.title('No of Images for each Class')
  4. plt.xlabel('Class ID')
  5. plt.ylabel('Number of Images')
  6. 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 表示图像的数量。

  1. def preProcessing(img):
  2. img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  3. img = cv2.equalizeHist(img)
  4. img = img/255
  5. return img
  6. X_train = np.array(list(map(preProcessing,X_train)))
  7. X_test = np.array(list(map(preProcessing,X_test)))
  8. X_validation = np.array(list(map(preProcessing,X_validation)))
  9. X_train = X_train.reshape(X_train.shape[0],X_train.shape[1],X_train.shape[2],1)
  10. X_test = X_test.reshape(X_test.shape[0],X_test.shape[1],X_test.shape[2],1)
  11. 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]
  1. from keras_preprocessing.image import ImageDataGenerator
  2. from keras.utils.np_utils import to_categorical
  1. dataGen = ImageDataGenerator(width_shift_range=0.1,
  2. height_shift_range=0.1,
  3. zoom_range=0.2,
  4. shear_range=0.1,
  5. rotation_range=10)
  6. dataGen.fit(X_train)
  7. Y_train = to_categorical(Y_train,noOfClasses)
  8. Y_test = to_categorical(Y_test,noOfClasses)
  9. 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 设置为一个较小的值。

 创建模型

 所需的库

  1. from keras.models import Sequential
  2. from keras.layers import Dense
  3. from keras.optimizers import Adam
  4. from keras.layers import Dropout,Flatten
  5. from keras.layers.convolutional import Conv2D,MaxPooling2D
imageDimensions = [32,32,3]
  1. def myModel():
  2. noOfFilters = 60
  3. sizeOfFilter1 = (5,5)
  4. sizeOfFilter2 = (3,3)
  5. sizeOfPool = (2,2)
  6. noOfNode = 500
  7. model = Sequential()
  8. model.add((Conv2D(noOfFilters, sizeOfFilter1, input_shape=(imageDimensions[0],
  9. imageDimensions[1],
  10. 1),activation='relu')))
  11. model.add((Conv2D(noOfFilters, sizeOfFilter1, activation='relu')))
  12. model.add(MaxPooling2D(pool_size=sizeOfPool))
  13. model.add((Conv2D(noOfFilters // 2, sizeOfFilter2, activation='relu')))
  14. model.add((Conv2D(noOfFilters // 2,sizeOfFilter2, activation='relu')))
  15. model.add(MaxPooling2D(pool_size=sizeOfPool))
  16. model.add(Dropout(0.5))
  17. model.add(Flatten())
  18. model.add(Dense(noOfNode, activation='relu'))
  19. model.add(Dropout(0.5))
  20. model.add(Dense(noOfClasses, activation='softmax'))
  21. model.compile(Adam(lr=0.001),loss='categorical_crossentropy',
  22. metrics=['accuracy'])
  23. return model
  1. #显示模型情况
  2. model = myModel()
  3. print(model.summary())
要想在训练的过程中观察模型训练的情况,代码如下
  1. batchSizeVal = 50
  2. epochsVal = 10
  3. stepsPerEpochVal = 2000
  4. history = model.fit_generator(dataGen.flow(X_train,Y_train,
  5. batch_size= batchSizeVal),
  6. steps_per_epoch=stepsPerEpochVal,
  7. epochs=epochsVal,
  8. validation_data=(X_validation,Y_validation),
  9. shuffle =1 )

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

  1. plt.figure(1)
  2. plt.plot(history.history['loss'])
  3. plt.plot(history.history['val_loss'])
  4. plt.legend(['training','validation'])
  5. plt.title('Loss')
  6. #plt.xlim(0, 1)
  7. #plt.ylim(0,3)
  8. plt.xlabel('epoch')
  9. plt.figure(2)
  10. plt.plot(history.history['accuracy'])
  11. plt.plot(history.history['val_accuracy'])
  12. plt.legend(['training','validation'])
  13. plt.title('Accuracy')
  14. plt.xlabel('epoch')
  15. #plt.xlim(0, 1)
  16. plt.show()

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

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

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

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

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

运行模型

摄像头类

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

  1. import numpy as np
  2. import cv2
  3. import pickle
  4. ################################
  5. width = 640
  6. height = 480
  7. threshold = 0.6
  8. ################################
  9. cap = cv2.VideoCapture(0)
  10. cap.set(3,width)
  11. cap.set(4,height)

然后打开模型文件

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

  1. pickle_in = open("model_trained.p","rb")
  2. model = pickle.load(pickle_in)
  3. def preProcessing(img):
  4. img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
  5. img = cv2.equalizeHist(img)
  6. img = img/255
  7. return img
  1. while True:
  2. ret, imgOriginal = cap.read()
  3. img = np.asarray(imgOriginal)
  4. img = cv2.resize(img, (32, 32))
  5. img = preProcessing(img)
  6. #cv2.imshow("Processed Image", img)

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

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

  1. img = img.reshape(1,32,32,1)
  2. #Predict
  3. classIndex = int(model.predict_classes(img))
  4. print(classIndex) #数字
  5. predictions = model.predict(img) #置信度
  6. probVal = np.amax(predictions) #最大的置信度
  7. print(classIndex, probVal)
  8. if probVal > threshold :
  9. cv2.putText(imgOriginal, str(classIndex) + " " +str(probVal),(50,50), cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),1)
  10. cv2.imshow("Original Image", imgOriginal)
  11. if cv2.waitKey(1)& 0xff ==ord('q'):
  12. break

图片类

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

  1. import cv2
  2. import numpy as np
  3. import pickle
  4. def preProcessing(img):
  5. img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  6. img = cv2.equalizeHist(img)
  7. img = img / 255
  8. return img
  9. imgOriginal = cv2.imread('number3.png')
  10. img = cv2.resize(imgOriginal, (32, 32))
  11. img_processed = preProcessing(img)
  12. img_processed = img_processed.reshape(1, 32, 32, 1)
  13. pickle_in = open("model_trained.p", "rb")
  14. model = pickle.load(pickle_in)
  15. classIndex = int(model.predict_classes(img_processed))
  16. predictions = model.predict(img_processed)
  17. probVal = np.amax(predictions)
  18. cv2.putText(imgOriginal, str(classIndex) + " " + str(probVal), (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
  19. # Show the image
  20. cv2.imshow("img", imgOriginal)
  21. cv2.waitKey(0)
  22. cv2.destroyAllWindows()

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/679023
推荐阅读
相关标签
  

闽ICP备14008679号