CNN과 OpenCV를 활용한 마스크 감지 모델
결과물
활용 기술
코드 설명
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")
- data augmentation과 관련된 레퍼런스
- 1) Keras ImageDataGenerator and Data Augmentation :
https://www.pyimagesearch.com/2019/07/08/keras-imagedatagenerator-and-data-augmentation/
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
- 2) Read a video and access a webcam with OpenCV in Python :
http://datahacker.rs/001-how-to-read-a-video-and-access-a-webcam-with-opencv-in-python/
#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
- 3) How to do Hyper-parameters search with Bayesian optimization for Keras model
https://www.dlology.com/blog/how-to-do-hyperparameter-search-with-baysian-optimization-for-keras-model/
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)
* 무단 복제 금지 *