diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..50664d6e8 Binary files /dev/null and b/.DS_Store differ diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..fbf14c673 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,41 @@ +#### Issue Number +ISSUE # + + +#### Describe the changes you've made + + +#### Describe if there is any unusual behaviour of your code(Write `NA` if there isn't) + + +#### Additional context (OPTIONAL) + + +#### Test plan (OPTIONAL) + + +#### Checklist + +- [ ] My code follows the code style of this project. +- [ ] I have performed a self-review of my own code. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have commented my code, particularly in hard-to-understand areas. +- [ ] My changes generate no new warnings. +- [ ] I have added tests that prove my fix is effective or that my feature works. +- [ ] The title of my pull request is a short description of the requested changes. diff --git a/Alarm.wav b/Alarm.wav new file mode 100644 index 000000000..c77259e87 Binary files /dev/null and b/Alarm.wav differ diff --git a/ResNet50_v2/Readme.md b/ResNet50_v2/Readme.md new file mode 100644 index 000000000..99812f611 --- /dev/null +++ b/ResNet50_v2/Readme.md @@ -0,0 +1,34 @@ +# Mask Detection using ResNet50 v2 + + +## 🚀  Steps to run the ResNet50 v2 + +- To clone the Repository:
+``` +git clone https://github.com/chandrikadeb7/Face-Mask-Detection.git +``` +- Open terminal. Go into the cloned project directory and type the following command to train the model and create ResNet50_mask_detector.model file
+``` +python3 ResNet50_v2/mask_with_resnet.py --dataset dataset --model "ResNet50_v2/ResNet50_mask_detector.model" +``` + +- To detect face masks in an image type the following command:
+``` +python3 detect_mask_image.py --image images/pic1.jpeg --model ResNet50_v2/ResNet50_mask_detector.model +``` + + +## :key:  Result + +![alt text](Readme_images/Matrix.png) + +### Training Loss and Accuracy +![alt text](Readme_images/Graph.png) + +## :star:  Output +![alt text](Readme_images/output.png) + + +## :star:  Output Video +![alt text](Readme_images/Output.gif) + diff --git a/ResNet50_v2/Readme_images/Graph.png b/ResNet50_v2/Readme_images/Graph.png new file mode 100644 index 000000000..d4ae921a4 Binary files /dev/null and b/ResNet50_v2/Readme_images/Graph.png differ diff --git a/ResNet50_v2/Readme_images/Matrix.png b/ResNet50_v2/Readme_images/Matrix.png new file mode 100644 index 000000000..087c1f1c0 Binary files /dev/null and b/ResNet50_v2/Readme_images/Matrix.png differ diff --git a/ResNet50_v2/Readme_images/Output.gif b/ResNet50_v2/Readme_images/Output.gif new file mode 100644 index 000000000..f77210e5f Binary files /dev/null and b/ResNet50_v2/Readme_images/Output.gif differ diff --git a/ResNet50_v2/Readme_images/output.png b/ResNet50_v2/Readme_images/output.png new file mode 100644 index 000000000..0aaa13b82 Binary files /dev/null and b/ResNet50_v2/Readme_images/output.png differ diff --git a/ResNet50_v2/mask_with_resnet.py b/ResNet50_v2/mask_with_resnet.py new file mode 100644 index 000000000..43cc77173 --- /dev/null +++ b/ResNet50_v2/mask_with_resnet.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- + +from tensorflow.keras.optimizers import Adam +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 tensorflow_hub as hub +import tensorflow as tf +from tensorflow.keras.preprocessing.image import img_to_array +from tensorflow.keras.preprocessing.image import ImageDataGenerator +from tensorflow.keras.preprocessing.image import load_img +from tensorflow.keras import layers +from tensorflow.keras.layers import Input +import argparse +import os +from tensorflow.keras.applications import ResNet50V2 + +ap = argparse.ArgumentParser() +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()) + +print("[INFO] loading images...") +imagePaths = list(paths.list_images(args["dataset"])) +data = [] +labels = [] + +IMG_SIZE = 224 +CHANNELS = 3 +N_LABELS=2 + + +# loop over the image paths +for imagePath in imagePaths: + # extract the class label from the filename + label = imagePath.split(os.path.sep)[-2] + # load the input image (224x224) and preprocess it + image = load_img(imagePath, target_size=(IMG_SIZE, IMG_SIZE)) + image = img_to_array(image) + image = image/255 +#image = preprocess_input(image) + + # update the data and labels lists, respectively + data.append(image) + labels.append(label) + +data = np.array(data, dtype="float32") +labels = np.array(labels) + +lb = LabelBinarizer() +labels = lb.fit_transform(labels) +labels = to_categorical(labels) + +(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") + + +feature_extractor_layer = ResNet50V2(weights="imagenet", include_top=False, + input_tensor=Input(shape=(IMG_SIZE,IMG_SIZE,CHANNELS))) + +feature_extractor_layer.trainable = False + +model = tf.keras.Sequential([ + feature_extractor_layer, + layers.Flatten(name="flatten"), + layers.Dense(1024, activation='relu', name='hidden_layer'), + layers.Dropout(0.5), + layers.Dense(N_LABELS, activation='sigmoid', name='output') +]) + +model.summary() + +LR = 1e-5 # Keep it small when transfer learning +EPOCHS = 20 +BS = 256 + +model.compile( + optimizer=tf.keras.optimizers.Adam(learning_rate=LR), + loss="binary_crossentropy", + metrics=["accuracy"]) + +import time +start = time.time() +history = model.fit(aug.flow(trainX, trainY, batch_size=BS), + steps_per_epoch=len(trainX) // BS, + validation_data=(testX, testY), + epochs=EPOCHS) +print('\nTraining took {}'.format((time.time()-start))) + +print("[INFO] evaluating network...") +predIdxs = model.predict(testX, batch_size=BS) + +predIdxs = np.argmax(predIdxs, axis=1) + +print(classification_report(testY.argmax(axis=1), predIdxs,target_names=lb.classes_)) + +print("[INFO] saving mask detector model...") +model.save(args["model"], save_format="h5") + +N = EPOCHS +plt.style.use("ggplot") +plt.figure() +plt.plot(np.arange(0, N), history.history["loss"], label="train_loss") +plt.plot(np.arange(0, N), history.history["val_loss"], label="val_loss") +plt.plot(np.arange(0, N), history.history["accuracy"], label="accuracy") +plt.plot(np.arange(0, N), history.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"]) diff --git a/app.py b/app.py index 435fbe554..b01ff4d03 100644 --- a/app.py +++ b/app.py @@ -8,6 +8,15 @@ from tensorflow.keras.models import load_model import detect_mask_image +# Setting custom Page Title and Icon with changed layout and sidebar state +st.beta_set_page_config(page_title='Face Mask Detector', page_icon='😷', layout='centered', initial_sidebar_state='expanded') + + +def local_css(file_name): + """ Method for reading styles.css and applying necessary changes to HTML""" + with open(file_name) as f: + st.markdown(f'', unsafe_allow_html=True) + def mask_image(): global RGB_img @@ -85,22 +94,26 @@ def mask_image(): mask_image() def mask_detection(): - st.title("Face mask detection") + local_css("css/styles.css") + st.markdown('

😷 Face Mask Detection

', unsafe_allow_html=True) activities = ["Image", "Webcam"] st.set_option('deprecation.showfileUploaderEncoding', False) - choice = st.sidebar.selectbox("Mask Detection on?", activities) + st.sidebar.markdown("# Mask Detection on?") + choice = st.sidebar.selectbox("Choose among the given options:", activities) if choice == 'Image': - st.subheader("Detection on image") - image_file = st.file_uploader("Upload Image", type=['jpg']) # upload image + st.markdown('

Detection on Image

', unsafe_allow_html=True) + st.markdown("### Upload your image here ⬇") + image_file = st.file_uploader("", type=['jpg']) # upload image if image_file is not None: our_image = Image.open(image_file) # making compatible to PIL im = our_image.save('./images/out.jpg') - saved_image = st.image(image_file, caption='image uploaded successfully', use_column_width=True) + saved_image = st.image(image_file, caption='', use_column_width=True) + st.markdown('

Image uploaded successfully!

', unsafe_allow_html=True) if st.button('Process'): st.image(RGB_img, use_column_width=True) if choice == 'Webcam': - st.subheader("Detection on webcam") - st.text("This feature will be avilable soon") + st.markdown('

Detection on Webcam

', unsafe_allow_html=True) + st.markdown('

This feature will be available soon!

', unsafe_allow_html=True) mask_detection() diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 000000000..0bdb7ad89 --- /dev/null +++ b/css/styles.css @@ -0,0 +1,16 @@ +/* Changing body color to dark grey and text color to gainsboro(version of white) */ +body { + color: gainsboro; + background-color: #333; +} + +/* Changing sideline color to light gray and text color to black */ +.sidebar .sidebar-content { + background-color: #c1c1c1; + background-image: none; + color: black; +} + +/* Removing Main Menubar and Footer */ +#MainMenu {visibility: hidden;} +footer {visibility: hidden;} diff --git a/detect_mask_video.py b/detect_mask_video.py index 63f960041..8cd53b1bd 100644 --- a/detect_mask_video.py +++ b/detect_mask_video.py @@ -6,6 +6,7 @@ from tensorflow.keras.preprocessing.image import img_to_array from tensorflow.keras.models import load_model from imutils.video import VideoStream +from playsound import playsound import numpy as np import argparse import imutils @@ -143,6 +144,11 @@ def detect_and_predict_mask(frame, faceNet, maskNet): cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2) cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2) + # Alarm when "No Mask" detected + if mask < withoutMask: + path = os.path.abspath("Alarm.wav") + playsound(path) + # show the output frame cv2.imshow("Frame", frame) key = cv2.waitKey(1) & 0xFF diff --git a/requirements.txt b/requirements.txt index 664b59eaf..73f2440e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,5 @@ scipy==1.4.1 scikit-learn==0.23.1 pillow==7.2.0 streamlit==0.65.2 +playsound +pyobjc