Data Science/Machine Learning

CNN과 OpenCV를 활용한 마스크 감지 모델

l._.been 2023. 8. 23. 19:31
728x90
결과물

왼쪽) 첫 모델링의 라벨링을 잘못해서 with_mask로 나와서 labeling을 다시 해서 고침..          오른쪽) 제대로 작동하는 마스크 감지 모델
잘 작동하는 마스크 감지 모델!

활용 기술

코드 설명

1. 라이브러리 및 버전 설정

import cv2,os
import numpy as np
from tensorflow.python.keras.utils import np_utils
import imutils
import pytesseract
import tensorflow as tf
from tensorflow import keras

import matplotlib.pyplot as plt
%matplotlib inline

# pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'

    1) 라이브러리 버전

  • numpy: 1.20.3
  • opencv-python: 4.8.0
  • tensorflow: 2.3.1
  • keras: 2.4.0

   2) 나머지 라이브러리는 없으면 pip install 해주면 됨

 

 

2. 데이터 라벨 만들기

data_path='../data/mask_data'
categories=os.listdir(data_path)
labels=[i for i in range(len(categories))]

print(categories)
label_dict=dict(zip(categories,labels))


# output: ['with_mask', 'without_mask']
  • data_path 경로 설정을 잘 해줘야한다. mask_data 안에 with_mask 폴더와 without_mask 폴더 2개가 담겨져 있어야 한다

 

img = cv2.imread('../data/mask_data/with_mask/601-with-mask.jpg')
plt.imshow(img)
  • with_mask에는 마스크를 쓴 사람의 얼굴 사진들이 모아져 있다.
  • 그 중 601-with-mask.jpg를 불러왔다

 

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(img_gray, cmap = 'gray')
  • 이미지의 색상을 죽이면, 이미지를 처리하는데 드는 비용이 줄기 때문에 BGR에서 GRAY로 변환시켜줘야한다. (cv2.COLOR_BGR2GRAY 사용)

 

img = cv2.imread('../data/mask_data/without_mask/551.jpg')
plt.imshow(img)
  • 이번에는 마스크를 쓰지 않은 사람의 이미지를 불러왔다 ㅎㅎ 수지는 얼굴이 스머프 같아도 이쁘다..

 

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(img_gray, cmap = 'gray')
  • 방금 전, 색상이 많으면 드는 부가적인 처리비용 때문에 색상을 그레이로 맞춰줘야한다

 

3. 데이터 불러오기

data=[]
target=[]

for category in categories: 
    folder_path=os.path.join(data_path,category)
    img_names=os.listdir(folder_path)
        
    for img_name in img_names:
        img_path=os.path.join(folder_path,img_name)
        img=cv2.imread(img_path)

        try:
            gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
            resized=cv2.resize(gray,(100, 100))
            data.append(resized)
            target.append(label_dict[category])

        except Exception as e:
            print('Exception:', e)

 

  • categories에는 ['with_mask', 'without_mask']가 있다
  • folder_path에는 for문을 돌면서 차례로 '../data/mask_data/without_mask'와  '../data/mask_data/without_mask'가 된다.
  • img_names는 folder_path에 접근해서 그 안에 있는 이미지들의 전체를 가리키는데 for문을 돌면서 img_name이 각각의 이미지를 가리키게된다.
  • data에는 각 데이터들의 색을 그레이로 바꾸고 사이즈도 100,100 으로 바꾼 것들을 저장해둔 사진 모음이다

 

data=np.array(data)/255.0
data=np.reshape(data,(data.shape[0], 100, 100, 1))
target=np.array(target)

new_target=np_utils.to_categorical(target)

np.save('data', data)
np.save('target', new_target)
  • 데이터의 사이즈를 맞추는 작업이다.
new_target

'''[output]
array([[1., 0.],
       [1., 0.],
       [1., 0.],
       ...,
       [0., 1.],
       [0., 1.],
       [0., 1.]], dtype=float32) '''
data=np.load('data.npy')
target=np.load('target.npy')

# [output]
# (615, 100, 100, 1)
target.shape

# [output]
# (615, 2)

 

4. 학습용 데이터와 검증용 데이터 세트로 분할하기

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Activation,Flatten,Dropout
from tensorflow.keras.layers import Conv2D,MaxPooling2D
from tensorflow.keras.callbacks import ModelCheckpoint
from sklearn.model_selection import train_test_split
from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.python.keras.optimizer_v2 import rmsprop
  • 위와 같이, 라이브러리를 설정해야한다
train_data,test_data,train_target,test_target=train_test_split(data,target, test_size=0.2, random_state=42)
train_data.shape

# [output]
# (492, 100, 100, 1)

 

5. Data augmentation to improve generalization

from tensorflow.keras.preprocessing.image import ImageDataGenerator
aug = ImageDataGenerator(rotation_range=20, 
                         zoom_range=0.2, 
                         width_shift_range=0.2, 
                         height_shift_range=0.2, 
                         shear_range=0.15, 
                         horizontal_flip=True,
                         fill_mode="nearest")
 

Keras ImageDataGenerator and Data Augmentation - PyImageSearch

In today’s tutorial, you will learn how to use Keras’ ImageDataGenerator class to perform data augmentation. I’ll also dispel common confusions surrounding what data augmentation is, why we use data augmentation, and what it does/does not do.

pyimagesearch.com

 

#001 How to read a video and access a webcam with OpenCV in Python?

Step by step guide on how to read, process, display and save a video with OpenCV in Python. Demonstrated using the OpenCV library for video manipulation.

datahacker.rs

 

How to do Hyper-parameters search with Bayesian optimization for Keras model | DLology

Posted by: Chengwei 4 years, 4 months ago (Comments) Compared to more simpler hyperparameter search methods like grid search and random search, Bayesian optimization is built upon Bayesian inference and Gaussian process with an attempts to find the maxim

www.dlology.com

 

6. Hyperparameter Tuning With Bayesian Optimization

* 이 부분은 넘어가도 좋습니다. 최적의 하이퍼파라미터를 얻으려는 과정이기 때문이기에 필수적인 것은 아닙니다.

input_shape=data.shape[1:]
input_shape

# [output]
# (100, 100, 1)

 

def get_model(input_shape, dropout2_rate=0.5):
    model = Sequential()
    model.add(Conv2D(32, kernel_size=(3, 3),
                     activation='relu',
                     input_shape=input_shape,
                     name="conv2d_1"))
    model.add(Conv2D(64, (3, 3), activation='relu', name="conv2d_2"))
    model.add(MaxPooling2D(pool_size=(2, 2), name="maxpool2d_1"))
    model.add(Dropout(0.25, name="dropout_1"))
    model.add(Flatten(name="flatten"))
    model.add(Dense(128, activation='relu', name="dense_1"))
    model.add(Dropout(dropout2_rate, name="dropout_2"))
    model.add(Dense(2, activation='softmax', name="dense_2"))
    return model
def fit_with(input_shape, verbose, dropout2_rate, lr):

    model = get_model(input_shape, dropout2_rate)
    
    optimizer = 'rmsprop'
    model.compile(loss=tf.keras.losses.BinaryCrossentropy(),
                  optimizer=optimizer,
                  metrics=['accuracy'])
    
    model.fit(train_data, train_target, epochs=10,
              batch_size=4, verbose=verbose)

    score = model.evaluate(test_data, test_target, steps=10, verbose=0)
    print('Test loss:', score[0])
    print('Test accuracy:', score[1])
    
    return score[1]
from functools import partial

verbose = 1
fit_with_partial = partial(fit_with, input_shape, verbose)
from bayes_opt import BayesianOptimization

pbounds = {'dropout2_rate': (0.1, 0.5), 'lr': (1e-4, 1e-2)}
 
optimizer = BayesianOptimization(
    f=fit_with_partial,
    pbounds=pbounds,
    verbose=2, 
    random_state=1,
)

optimizer.maximize(init_points=10, n_iter=10)

for i, res in enumerate(optimizer.res):
    print("Iteration {}: \n\t{}".format(i, res))
print(optimizer.max)

# [output]
# {'target': 0.8048780560493469, 'params': {'dropout2_rate': 0.2669219209468508, 'lr': 0.005631029301612942}}

 

 

7. Build the CNN model ⭐️⭐️⭐️

model=Sequential()
model.add(Conv2D(32,kernel_size=(3,3),input_shape=data.shape[1:], activation='relu'))
model.add(Conv2D(64,(3,3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128,activation='relu'))
model.add(Dropout(0.1942))
model.add(Dense(2, activation='softmax'))
opt = keras.optimizers.Adam(learning_rate=0.0001)

model.compile(loss='binary_crossentropy',
              optimizer=opt,
              metrics=['accuracy'])
early_stopping = EarlyStopping(monitor='val_loss', patience=50)
checkpoint = ModelCheckpoint(
    '{epoch:03d}-{val_loss:.4f}.model',
    monitor='val_loss',
    verbose=0,
    save_best_only=True,
    mode='auto')

 

8. Train the model

history=model.fit(aug.flow(train_data, train_target), 
                  epochs=100, 
                  batch_size=4,
                  callbacks=[checkpoint, early_stopping],
                  validation_data=(test_data, test_target))

print(model.evaluate(test_data,test_target))
model.summary()

 

9. Evaluate the model : best model

%matplotlib inline
import matplotlib.pyplot as plt

fig, loss_ax = plt.subplots(figsize=(10,6))
acc_ax = loss_ax.twinx()

acc_ax.plot(history.history['accuracy'], 'b', label='train acc')
acc_ax.plot(history.history['val_accuracy'], 'g', label='val acc')

loss_ax.plot(history.history['loss'], 'y', label='train loss')
loss_ax.plot(history.history['val_loss'], 'r', label='val loss')

loss_ax.set_xlabel('epoch')
loss_ax.set_ylabel('loss')
acc_ax.set_ylabel('accuray')

acc_ax.legend(loc='upper left', bbox_to_anchor=(1.15, 0.5))
loss_ax.legend(loc='lower left', bbox_to_anchor=(1.15, 0.5))

plt.show()

 

10. COVID-19 face mask detector in real-time video streams with OpenCV

import cv2
import numpy as np
from tensorflow.keras.models import load_model

labels_dict={0:'with_mask', 1:'without_mask'}
color_dict={0:(0,255,0),1:(0,0,255)}
#video stream source : webcam or recorded video 

source=cv2.VideoCapture(0)
# video output

fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
out = cv2.VideoWriter('output.avi', fourcc, 20, (640,480))
# warning sound in case of without_mask

import pygame, sys
from pygame import mixer

pygame.init()
pygame.mixer.init()

sound = mixer.Sound('alarm.wav')
# face recognition/classifier : haar feature
face_clsfr=cv2.CascadeClassifier(cv2.data.haarcascades +'haarcascade_frontalface_default.xml')

# face mask detector
model = load_model('095-0.3700.model')

while(True):

    ret,img=source.read()
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    faces=face_clsfr.detectMultiScale(gray,1.3,5)  

    for x,y,w,h in faces:
    
        face_img=gray[y:y+w,x:x+w]
        resized=cv2.resize(face_img,(100,100))
        normalized=resized/255.0
        reshaped=np.reshape(normalized,(1,100,100,1))
        result=model.predict(reshaped)

        label=np.argmax(result,axis=1)[0]
      
        cv2.rectangle(img,(x,y),(x+w,y+h),color_dict[label],2)
        cv2.rectangle(img,(x,y-40),(x+w,y),color_dict[label],-1)
        
        if(labels_dict[label] == 'with_mask'):
            print("No Beep")
        else:
            sound.play()
            print("Beep")   
        
        cv2.putText(
          img, "{}: {:.2f}%".format(labels_dict[label], np.max(result) * 100),            
          (x, y-10),
          cv2.FONT_HERSHEY_SIMPLEX,0.6,(255,255,255),2)
        
        
    cv2.imshow('LIVE',img)
    out.write(img)
    
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

source.release()
out.release()

cv2.destroyAllWindows()
cv2.waitKey(1)
cv2.waitKey(1)

 

 

* 무단 복제 금지 *