├── DrowsinessDetectorTraining.ipynb
├── LICENSE
├── README.md
├── data
├── X_test.npy
├── X_train.npy
├── alarm.mp3
├── haarcascade_frontalface_default.xml
├── haarcascade_lefteye_2splits.xml
├── haarcascade_righteye_2splits.xml
├── y_test.npy
└── y_train.npy
├── detect_drowsiness.py
├── model.png
└── preprocess.py
/DrowsinessDetectorTraining.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "DrowsinessDetectorTraining.ipynb",
7 | "provenance": [],
8 | "collapsed_sections": [],
9 | "mount_file_id": "1KYtGylyHjLkJp3XSZPLGyf13qcdMp3XX",
10 | "authorship_tag": "ABX9TyNmR9tKQIBWxlST+06etccL",
11 | "include_colab_link": true
12 | },
13 | "kernelspec": {
14 | "name": "python3",
15 | "display_name": "Python 3"
16 | },
17 | "accelerator": "GPU"
18 | },
19 | "cells": [
20 | {
21 | "cell_type": "markdown",
22 | "metadata": {
23 | "id": "view-in-github",
24 | "colab_type": "text"
25 | },
26 | "source": [
27 | "
"
28 | ]
29 | },
30 | {
31 | "cell_type": "markdown",
32 | "metadata": {
33 | "id": "-XFgqzu2DLl6"
34 | },
35 | "source": [
36 | "Import required Libraries"
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "metadata": {
42 | "id": "2zq6PSRWyQJV"
43 | },
44 | "source": [
45 | "import numpy as np\n",
46 | "import matplotlib.pyplot as plt\n",
47 | "\n",
48 | "from tensorflow.keras.optimizers import RMSprop\n",
49 | "from tensorflow.keras.preprocessing.image import ImageDataGenerator\n",
50 | "from tensorflow.keras.models import Sequential\n",
51 | "from tensorflow.keras.layers import Conv2D\n",
52 | "from tensorflow.keras.layers import MaxPool2D\n",
53 | "from tensorflow.keras.layers import Dropout\n",
54 | "from tensorflow.keras.layers import Dense\n",
55 | "from tensorflow.keras.layers import Flatten\n",
56 | "from tensorflow.keras.layers import Activation\n",
57 | "from tensorflow.keras.utils import plot_model"
58 | ],
59 | "execution_count": null,
60 | "outputs": []
61 | },
62 | {
63 | "cell_type": "markdown",
64 | "metadata": {
65 | "id": "FmoP_4JzGlwY"
66 | },
67 | "source": [
68 | "Load the Preprocessed Dataset"
69 | ]
70 | },
71 | {
72 | "cell_type": "code",
73 | "metadata": {
74 | "id": "cc-yqHv5GquS"
75 | },
76 | "source": [
77 | "X_train = np.load(\"drive/MyDrive/X_train.npy\")\n",
78 | "y_train = np.load(\"drive/MyDrive/y_train.npy\")\n",
79 | "\n",
80 | "X_test = np.load(\"drive/MyDrive/X_test.npy\")\n",
81 | "y_test = np.load(\"drive/MyDrive/y_test.npy\")"
82 | ],
83 | "execution_count": null,
84 | "outputs": []
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {
89 | "id": "Xrez50dxH20t"
90 | },
91 | "source": [
92 | "Hyperparameters and Data Augmentation"
93 | ]
94 | },
95 | {
96 | "cell_type": "code",
97 | "metadata": {
98 | "id": "J7Q50Z6RH_kl"
99 | },
100 | "source": [
101 | "# Hyperparameters\n",
102 | "LEARNING_RATE = 1e-3\n",
103 | "EPOCHS = 15\n",
104 | "BATCH_SIZE = 16"
105 | ],
106 | "execution_count": null,
107 | "outputs": []
108 | },
109 | {
110 | "cell_type": "code",
111 | "metadata": {
112 | "id": "qF8cpg_FIlrc"
113 | },
114 | "source": [
115 | "# Data Augmentation\n",
116 | "data_gen = ImageDataGenerator(\n",
117 | " width_shift_range=0.1,\n",
118 | " height_shift_range=0.1,\n",
119 | " rotation_range=10,\n",
120 | " shear_range=0.1,\n",
121 | " zoom_range=0.2\n",
122 | ")\n",
123 | "data_gen.fit(X_train)"
124 | ],
125 | "execution_count": null,
126 | "outputs": []
127 | },
128 | {
129 | "cell_type": "markdown",
130 | "metadata": {
131 | "id": "zxWBOXnZNdBL"
132 | },
133 | "source": [
134 | "Build the Model"
135 | ]
136 | },
137 | {
138 | "cell_type": "code",
139 | "metadata": {
140 | "id": "ThCgOv-sNgT3"
141 | },
142 | "source": [
143 | "model = Sequential()\n",
144 | "# first CNN layer\n",
145 | "model.add(Conv2D(32, (3, 3), input_shape=(24, 24, 1)))\n",
146 | "model.add(Activation('relu'))\n",
147 | "model.add(MaxPool2D((1, 1)))\n",
148 | "# second CNN layer\n",
149 | "model.add(Conv2D(32, (3, 3)))\n",
150 | "model.add(Activation('relu'))\n",
151 | "model.add(MaxPool2D((1, 1)))\n",
152 | "# third CNN layer\n",
153 | "model.add(Conv2D(64, (3, 3)))\n",
154 | "model.add(Activation('relu'))\n",
155 | "model.add(MaxPool2D((1, 1)))\n",
156 | "model.add(Dropout(0.25))\n",
157 | "# FC -> relu layer\n",
158 | "model.add(Flatten())\n",
159 | "model.add(Dense(128))\n",
160 | "model.add(Activation('relu'))\n",
161 | "model.add(Dropout(0.5))\n",
162 | "# final layer -> sigmoid classification\n",
163 | "model.add(Dense(1))\n",
164 | "model.add(Activation('sigmoid'))"
165 | ],
166 | "execution_count": null,
167 | "outputs": []
168 | },
169 | {
170 | "cell_type": "markdown",
171 | "metadata": {
172 | "id": "OjODITjT09AX"
173 | },
174 | "source": [
175 | "Compile and Visualize the model"
176 | ]
177 | },
178 | {
179 | "cell_type": "code",
180 | "metadata": {
181 | "colab": {
182 | "base_uri": "https://localhost:8080/"
183 | },
184 | "id": "JaYOPZsg1B1K",
185 | "outputId": "be6ce35e-9212-4fe8-c531-742a73d84e90"
186 | },
187 | "source": [
188 | "model.compile(\n",
189 | " optimizer=RMSprop(learning_rate=LEARNING_RATE),\n",
190 | " loss='binary_crossentropy',\n",
191 | " metrics=['accuracy']\n",
192 | ")\n",
193 | "plot_model(model, to_file=\"model.png\", show_shapes=True)\n",
194 | "model.summary()"
195 | ],
196 | "execution_count": null,
197 | "outputs": [
198 | {
199 | "output_type": "stream",
200 | "text": [
201 | "Model: \"sequential_1\"\n",
202 | "_________________________________________________________________\n",
203 | "Layer (type) Output Shape Param # \n",
204 | "=================================================================\n",
205 | "conv2d_3 (Conv2D) (None, 22, 22, 32) 320 \n",
206 | "_________________________________________________________________\n",
207 | "activation_5 (Activation) (None, 22, 22, 32) 0 \n",
208 | "_________________________________________________________________\n",
209 | "max_pooling2d_3 (MaxPooling2 (None, 22, 22, 32) 0 \n",
210 | "_________________________________________________________________\n",
211 | "conv2d_4 (Conv2D) (None, 20, 20, 32) 9248 \n",
212 | "_________________________________________________________________\n",
213 | "activation_6 (Activation) (None, 20, 20, 32) 0 \n",
214 | "_________________________________________________________________\n",
215 | "max_pooling2d_4 (MaxPooling2 (None, 20, 20, 32) 0 \n",
216 | "_________________________________________________________________\n",
217 | "conv2d_5 (Conv2D) (None, 18, 18, 64) 18496 \n",
218 | "_________________________________________________________________\n",
219 | "activation_7 (Activation) (None, 18, 18, 64) 0 \n",
220 | "_________________________________________________________________\n",
221 | "max_pooling2d_5 (MaxPooling2 (None, 18, 18, 64) 0 \n",
222 | "_________________________________________________________________\n",
223 | "dropout_2 (Dropout) (None, 18, 18, 64) 0 \n",
224 | "_________________________________________________________________\n",
225 | "flatten_1 (Flatten) (None, 20736) 0 \n",
226 | "_________________________________________________________________\n",
227 | "dense_2 (Dense) (None, 128) 2654336 \n",
228 | "_________________________________________________________________\n",
229 | "activation_8 (Activation) (None, 128) 0 \n",
230 | "_________________________________________________________________\n",
231 | "dropout_3 (Dropout) (None, 128) 0 \n",
232 | "_________________________________________________________________\n",
233 | "dense_3 (Dense) (None, 1) 129 \n",
234 | "_________________________________________________________________\n",
235 | "activation_9 (Activation) (None, 1) 0 \n",
236 | "=================================================================\n",
237 | "Total params: 2,682,529\n",
238 | "Trainable params: 2,682,529\n",
239 | "Non-trainable params: 0\n",
240 | "_________________________________________________________________\n"
241 | ],
242 | "name": "stdout"
243 | }
244 | ]
245 | },
246 | {
247 | "cell_type": "markdown",
248 | "metadata": {
249 | "id": "5ERjutN819kc"
250 | },
251 | "source": [
252 | "Train the model"
253 | ]
254 | },
255 | {
256 | "cell_type": "code",
257 | "metadata": {
258 | "colab": {
259 | "base_uri": "https://localhost:8080/"
260 | },
261 | "id": "WSmMOqHp1_95",
262 | "outputId": "daec28c6-762c-43dd-f428-71413956af11"
263 | },
264 | "source": [
265 | "history = model.fit_generator(\n",
266 | " data_gen.flow(X_train, y_train, batch_size=BATCH_SIZE),\n",
267 | " validation_data=(X_test, y_test),\n",
268 | " epochs=EPOCHS,\n",
269 | " shuffle=True\n",
270 | ")"
271 | ],
272 | "execution_count": null,
273 | "outputs": [
274 | {
275 | "output_type": "stream",
276 | "text": [
277 | "Epoch 1/15\n",
278 | "78/78 [==============================] - 1s 9ms/step - loss: 0.5009 - accuracy: 0.7650 - val_loss: 0.1874 - val_accuracy: 0.9174\n",
279 | "Epoch 2/15\n",
280 | "78/78 [==============================] - 1s 7ms/step - loss: 0.3452 - accuracy: 0.8598 - val_loss: 0.1942 - val_accuracy: 0.9358\n",
281 | "Epoch 3/15\n",
282 | "78/78 [==============================] - 1s 7ms/step - loss: 0.3056 - accuracy: 0.8849 - val_loss: 0.1368 - val_accuracy: 0.9404\n",
283 | "Epoch 4/15\n",
284 | "78/78 [==============================] - 1s 7ms/step - loss: 0.2280 - accuracy: 0.9182 - val_loss: 0.1439 - val_accuracy: 0.9404\n",
285 | "Epoch 5/15\n",
286 | "78/78 [==============================] - 1s 7ms/step - loss: 0.2239 - accuracy: 0.9238 - val_loss: 0.1345 - val_accuracy: 0.9450\n",
287 | "Epoch 6/15\n",
288 | "78/78 [==============================] - 1s 7ms/step - loss: 0.2079 - accuracy: 0.9360 - val_loss: 0.1142 - val_accuracy: 0.9404\n",
289 | "Epoch 7/15\n",
290 | "78/78 [==============================] - 1s 7ms/step - loss: 0.1860 - accuracy: 0.9327 - val_loss: 0.0711 - val_accuracy: 0.9725\n",
291 | "Epoch 8/15\n",
292 | "78/78 [==============================] - 1s 7ms/step - loss: 0.1547 - accuracy: 0.9546 - val_loss: 0.0829 - val_accuracy: 0.9679\n",
293 | "Epoch 9/15\n",
294 | "78/78 [==============================] - 1s 7ms/step - loss: 0.1434 - accuracy: 0.9489 - val_loss: 0.0739 - val_accuracy: 0.9633\n",
295 | "Epoch 10/15\n",
296 | "78/78 [==============================] - 1s 7ms/step - loss: 0.1177 - accuracy: 0.9611 - val_loss: 0.0988 - val_accuracy: 0.9633\n",
297 | "Epoch 11/15\n",
298 | "78/78 [==============================] - 1s 7ms/step - loss: 0.1214 - accuracy: 0.9595 - val_loss: 0.0987 - val_accuracy: 0.9541\n",
299 | "Epoch 12/15\n",
300 | "78/78 [==============================] - 1s 7ms/step - loss: 0.1192 - accuracy: 0.9643 - val_loss: 0.0868 - val_accuracy: 0.9725\n",
301 | "Epoch 13/15\n",
302 | "78/78 [==============================] - 1s 7ms/step - loss: 0.1071 - accuracy: 0.9619 - val_loss: 0.0457 - val_accuracy: 0.9771\n",
303 | "Epoch 14/15\n",
304 | "78/78 [==============================] - 1s 7ms/step - loss: 0.1248 - accuracy: 0.9660 - val_loss: 0.0363 - val_accuracy: 0.9817\n",
305 | "Epoch 15/15\n",
306 | "78/78 [==============================] - 1s 7ms/step - loss: 0.0849 - accuracy: 0.9733 - val_loss: 0.0184 - val_accuracy: 0.9954\n"
307 | ],
308 | "name": "stdout"
309 | }
310 | ]
311 | },
312 | {
313 | "cell_type": "markdown",
314 | "metadata": {
315 | "id": "Mf7rzzz02lXb"
316 | },
317 | "source": [
318 | "Plot the Results"
319 | ]
320 | },
321 | {
322 | "cell_type": "code",
323 | "metadata": {
324 | "colab": {
325 | "base_uri": "https://localhost:8080/",
326 | "height": 573
327 | },
328 | "id": "2-pobqg_2o75",
329 | "outputId": "f5666140-64e8-4156-da92-b57a414f2ff2"
330 | },
331 | "source": [
332 | "plt.figure(1)\n",
333 | "plt.plot(history.history['accuracy'])\n",
334 | "plt.plot(history.history['val_accuracy'])\n",
335 | "plt.legend(['Training', 'Validation'])\n",
336 | "plt.title('Accuracy')\n",
337 | "plt.xlabel('Epochs')\n",
338 | "plt.figure(2)\n",
339 | "plt.plot(history.history['loss'])\n",
340 | "plt.plot(history.history['val_loss'])\n",
341 | "plt.legend(['Training', 'Validation'])\n",
342 | "plt.title('Loss')\n",
343 | "plt.xlabel('Epochs')\n",
344 | "plt.show()"
345 | ],
346 | "execution_count": null,
347 | "outputs": [
348 | {
349 | "output_type": "display_data",
350 | "data": {
351 | "image/png": "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\n",
352 | "text/plain": [
353 | ""
354 | ]
355 | },
356 | "metadata": {
357 | "tags": [],
358 | "needs_background": "light"
359 | }
360 | },
361 | {
362 | "output_type": "display_data",
363 | "data": {
364 | "image/png": "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\n",
365 | "text/plain": [
366 | ""
367 | ]
368 | },
369 | "metadata": {
370 | "tags": [],
371 | "needs_background": "light"
372 | }
373 | }
374 | ]
375 | },
376 | {
377 | "cell_type": "markdown",
378 | "metadata": {
379 | "id": "UQTZLcI42xti"
380 | },
381 | "source": [
382 | "Save the trained model"
383 | ]
384 | },
385 | {
386 | "cell_type": "code",
387 | "metadata": {
388 | "id": "n3_mh6Bm25kT"
389 | },
390 | "source": [
391 | "model.save(\"trained_model.h5\")"
392 | ],
393 | "execution_count": null,
394 | "outputs": []
395 | }
396 | ]
397 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Ganesh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Drowsiness-Detection-System-CNN-OpenCV
2 | System that can detect the drowsiness of drivers using CNN developed in Python - OpenCV, Keras
3 |
4 | The drowsiness of drivers is one of the main reasons behind road accidents. It is natural for drivers who frequent long routes to doze off when behind the steering wheel. Even stress and lack of sleep can cause drivers to feel drowsy while driving. This project aims to prevent and reduce such accidents by creating a drowsiness detection agent.
5 |
6 | Here, we used Python, OpenCV, and Keras to build a system that can detect the closed eyes of drivers and alert them if ever they fall asleep while driving. Even if the driver’s eyes are closed for a few seconds, this system will immediately inform the driver, thereby preventing terrible road accidents. OpenCV will monitor and collect the driver’s images via a webcam and feed them into the deep learning model that will classify the driver’s eyes as ‘open’ or ‘closed.’
7 |
8 | ## Dataset
9 | The dataset used is a subset of a dataset from [Kaggle](https://www.kaggle.com/serenaraju/yawn-eye-dataset-new)
10 |
11 | ## Model Architecture
12 | 
13 |
14 | ## Steps to execute
15 | ### Step 1
16 | ```
17 | git clone https://github.com/GaneshSparkz/Drowsiness-Detection-System-CNN-OpenCV.git
18 | ```
19 | ### Step 2
20 | ```
21 | cd Drowsiness-Detection-System-CNN-OpenCV
22 | ```
23 | ### Step 3
24 | ```
25 | python detect_drowsiness.py
26 | ```
27 |
--------------------------------------------------------------------------------
/data/X_test.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GaneshSparkz/Drowsiness-Detection-System-CNN-OpenCV/e714cfabc2dee5c42a69127bd90861aff266b231/data/X_test.npy
--------------------------------------------------------------------------------
/data/X_train.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GaneshSparkz/Drowsiness-Detection-System-CNN-OpenCV/e714cfabc2dee5c42a69127bd90861aff266b231/data/X_train.npy
--------------------------------------------------------------------------------
/data/alarm.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GaneshSparkz/Drowsiness-Detection-System-CNN-OpenCV/e714cfabc2dee5c42a69127bd90861aff266b231/data/alarm.mp3
--------------------------------------------------------------------------------
/data/y_test.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GaneshSparkz/Drowsiness-Detection-System-CNN-OpenCV/e714cfabc2dee5c42a69127bd90861aff266b231/data/y_test.npy
--------------------------------------------------------------------------------
/data/y_train.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GaneshSparkz/Drowsiness-Detection-System-CNN-OpenCV/e714cfabc2dee5c42a69127bd90861aff266b231/data/y_train.npy
--------------------------------------------------------------------------------
/detect_drowsiness.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import numpy as np
3 |
4 | from keras.models import load_model
5 | from keras.preprocessing.image import img_to_array
6 | from playsound import playsound
7 | from threading import Thread
8 |
9 |
10 | def start_alarm(sound):
11 | """Play the alarm sound"""
12 | playsound(sound)
13 |
14 |
15 | classes = ['Closed', 'Open']
16 | face_cascade = cv2.CascadeClassifier("data/haarcascade_frontalface_default.xml")
17 | left_eye_cascade = cv2.CascadeClassifier("data/haarcascade_lefteye_2splits.xml")
18 | right_eye_cascade = cv2.CascadeClassifier("data/haarcascade_righteye_2splits.xml")
19 | cap = cv2.VideoCapture(0)
20 | model = load_model("data/trained_model.h5")
21 | count = 0
22 | alarm_on = False
23 | alarm_sound = "data/alarm.mp3"
24 | status1 = ''
25 | status2 = ''
26 |
27 | while True:
28 | _, frame = cap.read()
29 | height = frame.shape[0]
30 | gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
31 | faces = face_cascade.detectMultiScale(gray, 1.3, 5)
32 | for (x, y, w, h) in faces:
33 | cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 1)
34 | roi_gray = gray[y:y+h, x:x+w]
35 | roi_color = frame[y:y+h, x:x+w]
36 | left_eye = left_eye_cascade.detectMultiScale(roi_gray)
37 | right_eye = right_eye_cascade.detectMultiScale(roi_gray)
38 | for (x1, y1, w1, h1) in left_eye:
39 | cv2.rectangle(roi_color, (x1, y1), (x1 + w1, y1 + h1), (0, 255, 0), 1)
40 | eye1 = roi_gray[y1:y1+h1, x1:x1+w1]
41 | eye1 = cv2.resize(eye1, (24, 24))
42 | eye1 = eye1.astype('float') / 255.0
43 | eye1 = img_to_array(eye1)
44 | eye1 = np.expand_dims(eye1, axis=0)
45 | pred1 = model.predict(eye1)
46 | status1 = classes[pred1.argmax(axis=1)[0]]
47 | break
48 |
49 | for (x2, y2, w2, h2) in right_eye:
50 | cv2.rectangle(roi_color, (x2, y2), (x2 + w2, y2 + h2), (0, 255, 0), 1)
51 | eye2 = roi_gray[y2:y2 + h2, x2:x2 + w2]
52 | eye2 = cv2.resize(eye2, (24, 24))
53 | eye2 = eye2.astype('float') / 255.0
54 | eye2 = img_to_array(eye2)
55 | eye2 = np.expand_dims(eye2, axis=0)
56 | pred2 = model.predict(eye2)
57 | status2 = classes[pred2.argmax(axis=1)[0]]
58 | break
59 |
60 | # If the eyes are closed, start counting
61 | if status1 == 'Closed' and status2 == 'Closed':
62 | count += 1
63 | cv2.putText(frame, "Eyes Closed, Frame count: " + str(count), (10, 30), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 1)
64 | # if eyes are closed for 30 consecutive frames, start the alarm
65 | if count >= 30:
66 | cv2.putText(frame, "Drowsiness Alert!!!", (100, height-20), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2)
67 | if not alarm_on:
68 | alarm_on = True
69 | # play the alarm sound in a new thread
70 | t = Thread(target=start_alarm, args=(alarm_sound,))
71 | t.daemon = True
72 | t.start()
73 | else:
74 | cv2.putText(frame, "Eyes Open", (10, 30), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 1)
75 | count = 0
76 | alarm_on = False
77 |
78 | cv2.imshow("Drowsiness Detector", frame)
79 |
80 | if cv2.waitKey(1) & 0xFF == ord('q'):
81 | break
82 |
83 | cap.release()
84 | cv2.destroyAllWindows()
85 |
--------------------------------------------------------------------------------
/model.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GaneshSparkz/Drowsiness-Detection-System-CNN-OpenCV/e714cfabc2dee5c42a69127bd90861aff266b231/model.png
--------------------------------------------------------------------------------
/preprocess.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import os
3 | import numpy as np
4 | from sklearn.preprocessing import LabelBinarizer
5 |
6 |
7 | lb = LabelBinarizer()
8 |
9 | # Preprocess train images
10 | print("[INFO] Preprocessing train images...")
11 | train_dir = "dataset/train"
12 | train_images = []
13 | train_labels = []
14 |
15 | for label in os.listdir(train_dir):
16 | img_dir = train_dir + '/' + label
17 | for filename in os.listdir(img_dir):
18 | image = cv2.imread(img_dir + '/' + filename)
19 | image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
20 | image = cv2.resize(image, (24, 24))
21 | image = image.astype('float') / 255.0
22 | train_images.append(image)
23 | train_labels.append(label)
24 |
25 | X_train = np.array(train_images)
26 | y_train = np.array(train_labels)
27 |
28 | X_train = X_train.reshape(X_train.shape[0], 24, 24, 1)
29 | y_train = lb.fit_transform(y_train)
30 |
31 | np.save('data/X_train.npy', X_train)
32 | np.save('data/y_train.npy', y_train)
33 |
34 | print(len(train_images), "train images...")
35 |
36 |
37 | # Preprocess test images
38 | print("[INFO] Preprocessing test images...")
39 | test_dir = "dataset/test"
40 | test_images = []
41 | test_labels = []
42 |
43 | for label in os.listdir(test_dir):
44 | img_dir = test_dir + '/' + label
45 | for filename in os.listdir(img_dir):
46 | image = cv2.imread(img_dir + '/' + filename)
47 | image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
48 | image = cv2.resize(image, (24, 24))
49 | image = image.astype('float') / 255.0
50 | test_images.append(image)
51 | test_labels.append(label)
52 |
53 | X_test = np.array(test_images)
54 | y_test = np.array(test_labels)
55 |
56 | X_test = X_test.reshape(X_test.shape[0], 24, 24, 1)
57 | y_test = lb.transform(y_test)
58 |
59 | np.save('data/X_test.npy', X_test)
60 | np.save('data/y_test.npy', y_test)
61 |
62 | print(len(test_images), "test images...")
63 | print("Classes:", lb.classes_)
64 |
--------------------------------------------------------------------------------