Qua thử nghiệm mô phỏng và đánh giá nhóm nghiên cứu đã nhận thấy được những hạn chế của hệ thống, nhưng vì giới hạn của đề tài và trong phạm vi nghiên cứu của đồ án môn học cũng như thời gian nghiên cứu còn ngắn, nhóm nghiên cứu chưa thể hoàn thiện sản phẩm một cách tối ưu nhất. Vì vậy nhóm đã đưa ra một số phương hướng phát triển cho hệ thống như sau:
Sử dụng camera có chất lượng tốt hơn, lắp đặt thêm một số thiết bị ánh sáng hỗ trợ giúp cho hệ thống nhận diện chính xác hơn và có thể nhận diện được vào buổi tối. Sử dụng bộ vi xử lý cao cấp hơn như Raspberry pi cho kết quả xử lý chính xác hơn. Tối ưu code hơn và có thể mở rộng cho hệ thống thêm một số chức năng như nhận diện khuôn mặt kết hợp đo thân nhiệt.
52
TÀI LIỆU THAM KHẢO
[1] [2] [3] [4] [5] [6]
Ts. Nguyễn Ngọc Giang, “Đường vào lập trình Python”, Nxb Đại học Quốc Gia Hà Nội, 2020.
Ths. Nguyễn Thanh Hải, “Giáo trình xử lý ảnh”, Nxb Đại học Quốc Gia TP. Hồ Chí Minh,2014.
Academy, TechExp, “Learn Coding Programs with Python”, Nxb Amazon Kindle Edition, 2021.
Mar, Lutz, “Learning Python, 5th Edition”, Nxb O'Reilly Media, 2013. Nguyễn Thanh Thủy, Lương Mạnh Bá, “Nhập Môn xử lý ảnh”, Nxb Đại học Bách khoa Hà Nội, 2008.
Ts. Hồ Văn Sung, “Xử Lý Ảnh Với Arduino Và Raspberry”, Nxb Khoa học và kỹ thuật, 2007.
53
PHỤ LỤC
Bản vẽ thiết kế Barrie:
57 Code chương trình train model nhận diện khẩu trang #import các thư viện cần thiết
from tensorflow.keras.preprocessing.image import ImageDataGenerator from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras.layers import AveragePooling2D from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten from tensorflow.keras.layers import Dense from tensorflow.keras.layers import Input from tensorflow.keras.models import Model from tensorflow.keras.optimizers import Adam
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.preprocessing.image import load_img from tensorflow.keras.utils import to_categorical
from sklearn.preprocessing import LabelBinarizer from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from imutils import paths
import matplotlib.pyplot as plt import numpy as np
import argparse import os
#Tạo đường dẫn tới thư mục dữ liệu dataset ap = argparse.ArgumentParser()
58 ap.add_argument("-d", "--dataset", required=True, help="path to input dataset")
ap.add_argument("-p", "--plot", type=str, default="plot.png", help="path to output loss/accuracy plot")
ap.add_argument("-m", "--model", type=str, default="mask_detector.model",
help="path to output face mask detector model") args = vars(ap.parse_args())
#Xác định cái thông số phục vụ quá trình train model INIT_LR = 1e-4
EPOCHS = 20 BS = 32
#Lấy danh sách ảnh trong thư mục chứa dữ liệu print("đang load ảnh")
imagePaths = list(paths.list_images(args["dataset"])) data = []
labels = []
#Lặp lại nhiều lần với 1 hình ảnh for imagePath in imagePaths: #Trích xuất nhãn dán từ tên tệp
label = imagePath.split(os.path.sep)[-2] #Tải và xử lí ảnh đầu vào
image = load_img(imagePath, target_size=(224, 224)) image = img_to_array(image)
59
#Cập nhật dữ liệu hình ảnh và dán nhãn tương úng cho ảnh data.append(image)
labels.append(label)
#Chuyễn đổi dữ liệu sang dạng mảng data = np.array(data, dtype="float32") labels = np.array(labels)
lb = LabelBinarizer()
labels = lb.fit_transform(labels) labels = to_categorical(labels)
#Tập dữ liệu phục vụ quá trình train model (chiếm 75%)
#Tập dữ liệu phục vụ quá trình thử nghiệm cuối cùng – Testing set (chiếm 25%) (trainX, testX, trainY, testY) = train_test_split(data, labels,
test_size=0.20, stratify=labels, random_state=42) aug = ImageDataGenerator( rotation_range=20, zoom_range=0.15, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.15, horizontal_flip=True, fill_mode="nearest")
baseModel = MobileNetV2(weights="imagenet", include_top=False, input_tensor=Input(shape=(224, 224, 3)))
headModel = baseModel.output
60 headModel = Flatten(name="flatten")(headModel) headModel = Dense(128, activation="relu")(headModel) headModel = Dropout(0.5)(headModel)
headModel = Dense(2, activation="softmax")(headModel) model = Model(inputs=baseModel.input, outputs=headModel) for layer in baseModel.layers:
layer.trainable = False #Biên dịch model
print("Đang biên dịch model")
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS) model.compile(loss="binary_crossentropy", optimizer=opt, metrics=["accuracy"])
# Bắt đầu training print("đang training") H = model.fit(
aug.flow(trainX, trainY, batch_size=BS), steps_per_epoch=len(trainX) // BS, validation_data=(testX, testY), validation_steps=len(testX) // BS, epochs=EPOCHS)
# Đưa ra dự đoán về model qua các thông số print("các thông số về độ chính xác")
predIdxs = model.predict(testX, batch_size=BS) #Đưa ra dự đoán gần đúng cho các nhãn dán predIdxs = np.argmax(predIdxs, axis=1)
61
print(classification_report(testY.argmax(axis=1), predIdxs, target_names=lb.classes_))
# lưu model dưới dạng file đuôi .model print("Đang lưu model")
model.save(args["model"], save_format="h5") # XUất ra biểu đồ thể hiện sự chính xác của model N = EPOCHS
plt.style.use("ggplot") plt.figure()
plt.plot(np.arange(0, N), H.history["loss"], label="train_loss") plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, N), H.history["accuracy"], label="train_accuracy") plt.plot(np.arange(0, N), H.history["val_accuracy"], label="val_accuracy") plt.title("Training Loss and Accuracy")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy") plt.legend(loc="lower left") plt.savefig(args["plot"])
#Code trương trình chính nhận diện và cảnh báo người đeo khẩu trang: #import các thư viện cần thiết
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.models import load_model from imutils.video import VideoStream
62 import numpy as np import argparse import imutils import time import cv2 import os #import serial #Arduino_serial = serial.Serial('COM3',9600) #s = Arduino_serial.readline()
def detect_and_predict_mask(frame, faceNet, maskNet): #lấy kích thước khung ảnh
(h, w) = frame.shape[:2]
blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), (104.0, 177.0, 123.0))
faceNet.setInput(blob)
detections = faceNet.forward()
# khởi tạo danh sách các khuôn mặt, vị trí tương ứng của chúng # Danh sách các dự đoán về mạng khẩu trang
faces = [] locs = [] preds = []
#lặp lại nhiều lần các phát hiện
for i in range(0, detections.shape[2]): confidence = detections[0, 0, i, 2]
63
# Lọc ra các phát hiện yếu bằng cách đảm bảo độ tin cậy là lớn hơn độ tin cậy tối thiểu(0.8)
if confidence > args["confidence"]:
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) (startX, startY, endX, endY) = box.astype("int") (startX, startY) = (max(0, startX), max(0, startY)) (endX, endY) = (min(w - 1, endX), min(h - 1, endY))
# Trích xuất ảnh vùng khuôn mặt, chuyển đổi nó từ BGR sang RGB, thay đổi kích thướng thành 224x224 và xử lí nó
face = frame[startY:endY, startX:endX]
face = cv2.cvtColor(face, cv2.COLOR_BGR2RGB) face = cv2.resize(face, (224, 224))
face = img_to_array(face) face = preprocess_input(face)
#Vẽ các viền xung quanh các khuôn mặt được phát hiện faces.append(face)
locs.append((startX, startY, endX, endY))
#Nếu đã phát hiện được có ít nhất 1 khuôn mặt thì tiến hành nhận diện xem có đang đeo khẩu trang hay không
if len(faces) > 0:
faces = np.array(faces, dtype="float32")
preds = maskNet.predict(faces, batch_size=32) return (locs, preds)
ap = argparse.ArgumentParser()
64 default="face_detector",
help="path to face detector model directory") ap.add_argument("-m", "--model", type=str, default="mask_detector.model",
help="path to trained face mask detector model")
ap.add_argument("-c", "--confidence", type=float, default=0.5, help="minimum probability to filter weak detections") args = vars(ap.parse_args())
#Tải mô hình nhận diện khuôn mặt
print("Đang load model nhận diện khuôn mặt người")
prototxtPath = os.path.sep.join([args["face"], "deploy.prototxt"]) weightsPath = os.path.sep.join([args["face"],
"res10_300x300_ssd_iter_140000.caffemodel"]) faceNet = cv2.dnn.readNet(prototxtPath, weightsPath) #Tải mô hình nhận diện khẩu trang
print("đang load model nhận diện có đeo khẩu trang hay không") maskNet = load_model(args["model"])
# Khời tạo luồng video và cho phép máy ảnh hay webcam hoạt động print("Bắt đầu khởi động vào webcam lấy hình ảnh")
vs = VideoStream(src=0).start() time.sleep(2.0)
# lặp lại liên tục các khung hình trong video while True:
# lấy khung hình từ luồng video theo chuỗi và thay đổi kích thước để có chiều rộng tối đa là 400 pixel
65 frame = vs.read()
frame = imutils.resize(frame, width=800)
# Phát hiện xem họ có đang đeo khẩu trang hay không
(locs, preds) = detect_and_predict_mask(frame, faceNet, maskNet) has_mask = True
for (box, pred) in zip(locs, preds):
#Dự đoán vùng khuôn mặt đã được giới hạn (startX, startY, endX, endY) = box
(mask, withoutMask) = pred if mask > withoutMask: label = "Mask" color = (0, 255, 0) #Arduino_serial.write('0'.encode()) else: has_mask = False label = "No Mask" color = (0, 0, 255)
#Arduino_serial.write('1'.encode())
cv2.putText(frame, label, (startX-50, startY - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2) if has_mask:
Arduino_serial.write('0'.encode()) else:
66 #hiển thị khung ảnh lên màn hình
cv2.imshow("Nhận diện khẩu trang", frame) key = cv2.waitKey(1) & 0xFF
#Nhấn Q để thoát vòng lặp if key == ord("q"):
break
cv2.destroyAllWindows() vs.stop()
#Code chương trình điều khiển đèn và loa trên phần mềm Arduino: const int led=13;
int value=0; void setup() {
Serial.begin(9600); pinMode(led, OUTPUT); digitalWrite (led, LOW);
Serial.println("Connection established..."); } void loop() { while (Serial.available()) { value = Serial.read(); }
67 if (value == '1')
digitalWrite (led, HIGH); else if (value == '0')
digitalWrite (led, LOW); }