zoukankan      html  css  js  c++  java
  • python+opencv人脸识别是否戴口罩

    当今疫情情况下,检测是否戴口罩还是比较流行的,然后就搞啦一个检测人脸是否戴口罩的程序。程序调用笔记本摄像头,实时检测人脸是否佩戴口罩。

    一、数据集

    如果数据集大家有,就用自己的。没有的话,也可以找我要啊(3000+戴口罩/1000+不戴口罩)。在此就不分享出来了,我也是找别人要的。

    二、开始上代码

    1、导入keras库

    1 import keras
    2 keras.__version__

      

     2、创建train、test、validation文件夹,并且三个文件夹里面都有have_mask和no_mask文件,运行之后将数据集中的照片放入对应的文件夹中。

     1 import os, shutil
     2 # The path to the directory where the original
     3 # dataset was uncompressed
     4 original_dataset_dir = 'F:\PyCharm\facemask\mask'
     5 
     6 # The directory where we will
     7 # store our smaller dataset
     8 base_dir = 'F:\PyCharm\facemask\mask_and_nomask'
     9 os.mkdir(base_dir)
    10 
    11 # Directories for our training,
    12 # validation and test splits
    13 train_dir = os.path.join(base_dir, 'train')
    14 os.mkdir(train_dir)
    15 validation_dir = os.path.join(base_dir, 'validation')
    16 os.mkdir(validation_dir)
    17 test_dir = os.path.join(base_dir, 'test')
    18 os.mkdir(test_dir)
    19 
    20 # Directory with our training smile pictures
    21 train_smile_dir = os.path.join(train_dir, 'have_mask')
    22 os.mkdir(train_smile_dir)
    23 
    24 # Directory with our training nosmile pictures
    25 train_nosmile_dir = os.path.join(train_dir, 'no_mask')
    26 os.mkdir(train_nosmile_dir)
    27 
    28 # Directory with our validation smile pictures
    29 validation_smile_dir = os.path.join(validation_dir, 'have_mask')
    30 os.mkdir(validation_smile_dir)
    31 
    32 # Directory with our validation nosmile pictures
    33 validation_nosmile_dir = os.path.join(validation_dir, 'no_mask')
    34 os.mkdir(validation_nosmile_dir)
    35 
    36 # Directory with our validation smile pictures
    37 test_smile_dir = os.path.join(test_dir, 'have_mask')
    38 os.mkdir(test_smile_dir)
    39 
    40 # Directory with our validation nosmile pictures
    41 test_nosmile_dir = os.path.join(test_dir, 'no_mask')
    42 os.mkdir(test_nosmile_dir)

     

    3、记数,统计一下各个文件中照片的数量

    1 print('total training smile images:', len(os.listdir(train_smile_dir)))
    2 print('total training nosmile images:', len(os.listdir(train_nosmile_dir)))
    3 print('total validation smile images:', len(os.listdir(validation_smile_dir)))
    4 print('total validation nosmile images:', len(os.listdir(validation_nosmile_dir)))
    5 print('total test smile images:', len(os.listdir(test_smile_dir)))
    6 print('total test nosmile images:', len(os.listdir(test_nosmile_dir)))

     4、构建小型卷积网络

    我们已经为MNIST构建了一个小型卷积网,所以您应该熟悉它们。我们将重用相同的通用结构:我们的卷积网将是一个交替的Conv2D(激活relu)和MaxPooling2D层的堆栈。然而,由于我们处理的是更大的图像和更复杂的问题,因此我们将使我们的网络相应地更大:它将有一个更多的Conv2D + MaxPooling2D阶段。这样既可以扩大网络的容量,又可以进一步缩小特征图的大小,这样当我们到达平坦层时,特征图就不会太大。在这里,由于我们从大小为150x150的输入开始(有点随意的选择),我们在Flatten层之前得到大小为7x7的feature map。

    注意:feature map的深度在网络中逐渐增加(从32到128),而feature map的大小在减少(从148x148到7x7)。这是你会在几乎所有convnets中看到的模式。由于我们解决的是一个二元分类问题,我们用一个单一单元(一个大小为1的稠密层)和一个s型激活来结束网络。这个单元将对网络正在查看一个类或另一个类的概率进行编码。

     1 from keras import layers
     2 from keras import models
     3 
     4 model = models.Sequential()
     5 model.add(layers.Conv2D(32, (3, 3), activation='relu',
     6                         input_shape=(150, 150, 3)))
     7 model.add(layers.MaxPooling2D((2, 2)))
     8 model.add(layers.Conv2D(64, (3, 3), activation='relu'))
     9 model.add(layers.MaxPooling2D((2, 2)))
    10 model.add(layers.Conv2D(128, (3, 3), activation='relu'))
    11 model.add(layers.MaxPooling2D((2, 2)))
    12 model.add(layers.Conv2D(128, (3, 3), activation='relu'))
    13 model.add(layers.MaxPooling2D((2, 2)))
    14 model.add(layers.Flatten())
    15 model.add(layers.Dense(512, activation='relu'))
    16 model.add(layers.Dense(1, activation='sigmoid'))

    5、输出模型各层的参数状况

    1 model.summary()

     6、告知训练时用的优化器、损失函数和准确率评测标准

    1 from keras import optimizers
    2 
    3 model.compile(loss='binary_crossentropy',
    4               optimizer=optimizers.RMSprop(lr=1e-4),
    5               metrics=['acc'])

    7、数据预处理

    在将数据输入到我们的网络之前,应该将数据格式化为经过适当预处理的浮点张量。目前,我们的数据以JPEG文件的形式保存在硬盘上,因此将其导入网络的步骤大致如下:

    • 读取图片文件
    • 解码JPEG内容到RBG像素网格
    • 把它们转换成浮点张量
    • 将像素值(从0到255)缩放到[0,1]区间
     1 from keras.preprocessing.image import ImageDataGenerator
     2 
     3 # All images will be rescaled by 1./255
     4 train_datagen = ImageDataGenerator(rescale=1./255)
     5 test_datagen = ImageDataGenerator(rescale=1./255)
     6 
     7 train_generator = train_datagen.flow_from_directory(
     8         # This is the target directory
     9         train_dir,
    10         # All images will be resized to 150x150
    11         target_size=(150, 150),
    12         batch_size=20,
    13         # Since we use binary_crossentropy loss, we need binary labels
    14         class_mode='binary')
    15 
    16 validation_generator = test_datagen.flow_from_directory(
    17         validation_dir,
    18         target_size=(150, 150),
    19         batch_size=20,
    20         class_mode='binary')

    让我们看看其中一个生成器的输出:它生成150×150 RGB图像的批次(Shape(20,150,150,3))和二进制标签(Shape(20,))。20是每批样品的数量(批次大小)。注意,生成器无限期地生成这些批:它只是无休止地循环目标文件夹中的图像。因此,我们需要在某个点中断迭代循环。

    1 for data_batch, labels_batch in train_generator:
    2     print('data batch shape:', data_batch.shape)
    3     print('labels batch shape:', labels_batch.shape)
    4     break

     使用生成器使我们的模型适合于数据

    1 history = model.fit_generator(
    2       train_generator,
    3       steps_per_epoch=100,
    4       epochs=50,
    5       validation_data=validation_generator,
    6       validation_steps=50)

     保存模型

    1 model.save('F:\PyCharm\facemask\mask_and_nomask\test\mask_and_nomask.h5')

    在训练和验证数据上绘制模型的损失和准确性

     1 import matplotlib.pyplot as plt
     2 
     3 acc = history.history['acc']
     4 val_acc = history.history['val_acc']
     5 loss = history.history['loss']
     6 val_loss = history.history['val_loss']
     7 
     8 epochs = range(len(acc))
     9 
    10 plt.plot(epochs, acc, 'bo', label='Training acc')
    11 plt.plot(epochs, val_acc, 'b', label='Validation acc')
    12 plt.title('Training and validation accuracy')
    13 plt.legend()
    14 
    15 plt.figure()
    16 
    17 plt.plot(epochs, loss, 'bo', label='Training loss')
    18 plt.plot(epochs, val_loss, 'b', label='Validation loss')
    19 plt.title('Training and validation loss')
    20 plt.legend()
    21 plt.show()

     8、数据准确性提高

    1 datagen = ImageDataGenerator(
    2       rotation_range=40,
    3       width_shift_range=0.2,
    4       height_shift_range=0.2,
    5       shear_range=0.2,
    6       zoom_range=0.2,
    7       horizontal_flip=True,
    8       fill_mode='nearest')

    查看提高后的图像

     1 # This is module with image preprocessing utilities
     2 from keras.preprocessing import image
     3 
     4 fnames = [os.path.join(train_smile_dir, fname) for fname in os.listdir(train_smile_dir)]
     5 
     6 # We pick one image to "augment"
     7 img_path = fnames[3]
     8 
     9 # Read the image and resize it
    10 img = image.load_img(img_path, target_size=(150, 150))
    11 
    12 # Convert it to a Numpy array with shape (150, 150, 3)
    13 x = image.img_to_array(img)
    14 
    15 # Reshape it to (1, 150, 150, 3)
    16 x = x.reshape((1,) + x.shape)
    17 
    18 # The .flow() command below generates batches of randomly transformed images.
    19 # It will loop indefinitely, so we need to `break` the loop at some point!
    20 i = 0
    21 for batch in datagen.flow(x, batch_size=1):
    22     plt.figure(i)
    23     imgplot = plt.imshow(image.array_to_img(batch[0]))
    24     i += 1
    25     if i % 4 == 0:
    26         break
    27 
    28 plt.show()

    如果我们使用这种数据增加配置训练一个新的网络,我们的网络将永远不会看到两次相同的输入。然而,它看到的输入仍然是高度相关的,因为它们来自少量的原始图像——我们不能产生新的信息,我们只能混合现有的信息。因此,这可能还不足以完全消除过度拟合。

    为了进一步对抗过拟合,我们还将在我们的模型中增加一个Dropout层,就在密集连接分类器之前:

     1 model = models.Sequential()
     2 model.add(layers.Conv2D(32, (3, 3), activation='relu',
     3                         input_shape=(150, 150, 3)))
     4 model.add(layers.MaxPooling2D((2, 2)))
     5 model.add(layers.Conv2D(64, (3, 3), activation='relu'))
     6 model.add(layers.MaxPooling2D((2, 2)))
     7 model.add(layers.Conv2D(128, (3, 3), activation='relu'))
     8 model.add(layers.MaxPooling2D((2, 2)))
     9 model.add(layers.Conv2D(128, (3, 3), activation='relu'))
    10 model.add(layers.MaxPooling2D((2, 2)))
    11 model.add(layers.Flatten())
    12 model.add(layers.Dropout(0.5))
    13 model.add(layers.Dense(512, activation='relu'))
    14 model.add(layers.Dense(1, activation='sigmoid'))
    15 
    16 model.compile(loss='binary_crossentropy',
    17               optimizer=optimizers.RMSprop(lr=1e-4),
    18               metrics=['acc'])

    用数据增强和退出来训练我们的网络:

     1 train_datagen = ImageDataGenerator(
     2     rescale=1./255,
     3     rotation_range=40,
     4     width_shift_range=0.2,
     5     height_shift_range=0.2,
     6     shear_range=0.2,
     7     zoom_range=0.2,
     8     horizontal_flip=True,)
     9 
    10 # Note that the validation data should not be augmented!
    11 test_datagen = ImageDataGenerator(rescale=1./255)
    12 
    13 train_generator = train_datagen.flow_from_directory(
    14         # This is the target directory
    15         train_dir,
    16         # All images will be resized to 150x150
    17         target_size=(150, 150),
    18         batch_size=32,
    19         # Since we use binary_crossentropy loss, we need binary labels
    20         class_mode='binary')
    21 
    22 validation_generator = test_datagen.flow_from_directory(
    23         validation_dir,
    24         target_size=(150, 150),
    25         batch_size=32,
    26         class_mode='binary')
    27 
    28 history = model.fit_generator(
    29       train_generator,
    30       steps_per_epoch=100,
    31       epochs=150,
    32       validation_data=validation_generator,
    33       validation_steps=50)

    这里程序会跑很久,我跑了几个小时,用GPU跑会快很多很多。

    保存模型在convnet可视化部分使用:

    1 model.save('F:\PyCharm\facemask\mask_and_nomask\test\mask_and_nomask.h5')

    看一下结果:(挺好的)

     1 acc = history.history['acc']
     2 val_acc = history.history['val_acc']
     3 loss = history.history['loss']
     4 val_loss = history.history['val_loss']
     5 
     6 epochs = range(len(acc))
     7 
     8 plt.plot(epochs, acc, 'bo', label='Training acc')
     9 plt.plot(epochs, val_acc, 'b', label='Validation acc')
    10 plt.title('Training and validation accuracy')
    11 plt.legend()
    12 
    13 plt.figure()
    14 
    15 plt.plot(epochs, loss, 'bo', label='Training loss')
    16 plt.plot(epochs, val_loss, 'b', label='Validation loss')
    17 plt.title('Training and validation loss')
    18 plt.legend()
    19 plt.show()

    8、优化提高笑脸图像分类模型精度
    构建卷积网络

     1 from keras import layers
     2 from keras import models
     3 from keras import optimizers
     4 model = models.Sequential()
     5 #输入图片大小是150*150 3表示图片像素用(R,G,B)表示
     6 model.add(layers.Conv2D(32, (3,3), activation='relu', input_shape=(150 , 150, 3)))
     7 model.add(layers.MaxPooling2D((2,2)))
     8 model.add(layers.Conv2D(64, (3,3), activation='relu'))
     9 model.add(layers.MaxPooling2D((2,2)))
    10 model.add(layers.Conv2D(128, (3,3), activation='relu'))
    11 model.add(layers.MaxPooling2D((2,2)))
    12 model.add(layers.Conv2D(128, (3,3), activation='relu'))
    13 model.add(layers.MaxPooling2D((2,2)))
    14 model.add(layers.Flatten())
    15 model.add(layers.Dense(512, activation='relu'))
    16 model.add(layers.Dense(1, activation='sigmoid'))
    17 model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr=1e-4),
    18              metrics=['acc'])
    19 model.summary()

     三、代码测试

     1 import cv2
     2 from keras.preprocessing import image
     3 from keras.models import load_model
     4 import numpy as np
     5 import dlib
     6 from PIL import Image
     7 model = load_model('mask_and_nomask.h5')
     8 detector = dlib.get_frontal_face_detector()
     9 video=cv2.VideoCapture(0)
    10 font = cv2.FONT_HERSHEY_SIMPLEX
    11 def rec(img):
    12     gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    13     dets=detector(gray,1)
    14     if dets is not None:
    15         for face in dets:
    16             left=face.left()
    17             top=face.top()
    18             right=face.right()
    19             bottom=face.bottom()
    20             cv2.rectangle(img,(left,top),(right,bottom),(0,255,0),2)
    21             img1=cv2.resize(img[top:bottom,left:right],dsize=(150,150))
    22             img1=cv2.cvtColor(img1,cv2.COLOR_BGR2RGB)
    23             img1 = np.array(img1)/255.
    24             img_tensor = img1.reshape(-1,150,150,3)
    25             prediction =model.predict(img_tensor)    
    26             print(prediction)
    27             if prediction[0][0]>0.5:
    28                 result='nomask'
    29             else:
    30                 result='mask'
    31             cv2.putText(img, result, (left,top), font, 2, (0, 255, 0), 2, cv2.LINE_AA)
    32         cv2.imshow('mask detector', img)
    33 while video.isOpened():
    34     res, img_rd = video.read()
    35     if not res:
    36         break
    37     rec(img_rd)
    38     if cv2.waitKey(1) & 0xFF == ord('q'):
    39         break
    40 video.release()
    41 cv2.destroyAllWindows()

    这里就不上运行结果了。

    本文转载:https://blog.csdn.net/weixin_45137708/article/details/107142706

  • 相关阅读:
    一段自己写的丑陋的表单验证代码
    简单的星级评价
    有个项目
    好久没写了,重装了系统重新配置的Live Writer,看看效果:
    XmlHttpRequest调用Webservice的一点心得
    局域网共享怎么设置?我想把其中一个电脑的F盘共享?
    TCP/IP协议详解
    input file实现多张图片上传
    .NET C#中如何备份SQL数据库
    CSS中cursor鼠标形状属性列表
  • 原文地址:https://www.cnblogs.com/Clark-Shao/p/15131011.html
Copyright © 2011-2022 走看看