all files
Browse files- README.md +1 -12
- additional/requirements.txt +94 -0
- app.py +195 -0
- audio/wake_up.wav +0 -0
- audio_handling.py +93 -0
- drowsy_detection.py +266 -0
- environment.yml +129 -0
- haarcascade_frontalface_default.xml +0 -0
- packages.txt +1 -0
- requirements.txt +94 -0
README.md
CHANGED
|
@@ -1,12 +1 @@
|
|
| 1 |
-
|
| 2 |
-
title: Aps
|
| 3 |
-
emoji: 💻
|
| 4 |
-
colorFrom: gray
|
| 5 |
-
colorTo: indigo
|
| 6 |
-
sdk: streamlit
|
| 7 |
-
sdk_version: 1.17.0
|
| 8 |
-
app_file: app.py
|
| 9 |
-
pinned: false
|
| 10 |
-
---
|
| 11 |
-
|
| 12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
+
# aps-streamlit-share
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
additional/requirements.txt
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
absl-py==1.4.0
|
| 2 |
+
aioice==0.7.6
|
| 3 |
+
aiortc==1.4.0
|
| 4 |
+
altair==4.2.2
|
| 5 |
+
attrs==22.2.0
|
| 6 |
+
av==10.0.0
|
| 7 |
+
blinker==1.5
|
| 8 |
+
cachetools==5.3.0
|
| 9 |
+
certifi==2022.12.7
|
| 10 |
+
cffi==1.15.1
|
| 11 |
+
charset-normalizer==3.0.1
|
| 12 |
+
click==8.1.3
|
| 13 |
+
colorama==0.4.6
|
| 14 |
+
contourpy==1.0.7
|
| 15 |
+
cryptography==38.0.4
|
| 16 |
+
cycler==0.11.0
|
| 17 |
+
decorator==5.1.1
|
| 18 |
+
Deprecated==1.2.13
|
| 19 |
+
dlib
|
| 20 |
+
dnspython==2.3.0
|
| 21 |
+
entrypoints==0.4
|
| 22 |
+
flatbuffers==23.1.21
|
| 23 |
+
fonttools==4.38.0
|
| 24 |
+
gcloud==0.18.3
|
| 25 |
+
gitdb==4.0.10
|
| 26 |
+
GitPython==3.1.30
|
| 27 |
+
google-crc32c==1.5.0
|
| 28 |
+
googleapis-common-protos==1.58.0
|
| 29 |
+
httplib2==0.21.0
|
| 30 |
+
idna==3.4
|
| 31 |
+
importlib-metadata==6.0.0
|
| 32 |
+
imutils==0.5.4
|
| 33 |
+
Jinja2==3.1.2
|
| 34 |
+
jsonschema==4.17.3
|
| 35 |
+
jwcrypto==1.4.2
|
| 36 |
+
kiwisolver==1.4.4
|
| 37 |
+
markdown-it-py==2.1.0
|
| 38 |
+
MarkupSafe==2.1.2
|
| 39 |
+
matplotlib==3.6.3
|
| 40 |
+
mdurl==0.1.2
|
| 41 |
+
mediapipe==0.9.1.0
|
| 42 |
+
netifaces==0.11.0
|
| 43 |
+
numpy==1.24.1
|
| 44 |
+
oauth2client==4.1.3
|
| 45 |
+
opencv-contrib-python==4.7.0.68
|
| 46 |
+
opencv-python==4.7.0.68
|
| 47 |
+
packaging==23.0
|
| 48 |
+
pandas==1.5.3
|
| 49 |
+
Pillow==9.4.0
|
| 50 |
+
protobuf==3.20.3
|
| 51 |
+
pyarrow==11.0.0
|
| 52 |
+
pyasn1==0.4.8
|
| 53 |
+
pyasn1-modules==0.2.8
|
| 54 |
+
pycparser==2.21
|
| 55 |
+
pycryptodome==3.17
|
| 56 |
+
pydeck==0.8.0
|
| 57 |
+
pydub==0.25.1
|
| 58 |
+
pyee==9.0.4
|
| 59 |
+
Pygments==2.14.0
|
| 60 |
+
pylibsrtp==0.8.0
|
| 61 |
+
pymongo==4.3.3
|
| 62 |
+
Pympler==1.0.1
|
| 63 |
+
pyOpenSSL==23.0.0
|
| 64 |
+
pyparsing==3.0.9
|
| 65 |
+
Pyrebase4==4.6.0
|
| 66 |
+
pyrsistent==0.19.3
|
| 67 |
+
python-dateutil==2.8.2
|
| 68 |
+
python-jwt==4.0.0
|
| 69 |
+
pytz==2022.7.1
|
| 70 |
+
pytz-deprecation-shim==0.1.0.post0
|
| 71 |
+
requests==2.28.2
|
| 72 |
+
requests-toolbelt==0.10.1
|
| 73 |
+
rich==13.3.1
|
| 74 |
+
rsa==4.9
|
| 75 |
+
scipy==1.10.0
|
| 76 |
+
semver==2.13.0
|
| 77 |
+
six==1.16.0
|
| 78 |
+
smmap==5.0.0
|
| 79 |
+
streamlit==1.17.0
|
| 80 |
+
streamlit-nested-layout==0.1.1
|
| 81 |
+
streamlit-option-menu==0.3.2
|
| 82 |
+
streamlit-webrtc==0.44.2
|
| 83 |
+
toml==0.10.2
|
| 84 |
+
toolz==0.12.0
|
| 85 |
+
tornado==6.2
|
| 86 |
+
typing_extensions==4.4.0
|
| 87 |
+
tzdata==2022.7
|
| 88 |
+
tzlocal==4.2
|
| 89 |
+
urllib3==1.26.14
|
| 90 |
+
validators==0.20.0
|
| 91 |
+
watchdog==2.2.1
|
| 92 |
+
wincertstore==0.2
|
| 93 |
+
wrapt==1.14.1
|
| 94 |
+
zipp==3.12.0
|
app.py
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import threading
|
| 3 |
+
|
| 4 |
+
import av
|
| 5 |
+
import bcrypt
|
| 6 |
+
import pymongo
|
| 7 |
+
import streamlit as st
|
| 8 |
+
from streamlit_option_menu import option_menu
|
| 9 |
+
from streamlit_webrtc import VideoHTMLAttributes, webrtc_streamer
|
| 10 |
+
from twilio.rest import Client
|
| 11 |
+
|
| 12 |
+
from audio_handling import AudioFrameHandler
|
| 13 |
+
from drowsy_detection import VideoFrameHandler
|
| 14 |
+
|
| 15 |
+
# Define the audio file to use.
|
| 16 |
+
alarm_file_path = os.path.join("audio", "wake_up.wav")
|
| 17 |
+
logged_in = False
|
| 18 |
+
|
| 19 |
+
def update_sliders():
|
| 20 |
+
slider_wait = 1.0
|
| 21 |
+
eye_thresh = 0.18
|
| 22 |
+
lip_thresh = 0.2
|
| 23 |
+
|
| 24 |
+
client = pymongo.MongoClient("mongodb+srv://admin:Admin123@aps.agcjjww.mongodb.net/?retryWrites=true&w=majority")
|
| 25 |
+
db = client["aps-db"]
|
| 26 |
+
slider_values = db["slider-values"]
|
| 27 |
+
|
| 28 |
+
if slider_wait != WAIT_TIME:
|
| 29 |
+
slider_values.update_one({"slider_name": "Wait_Time"}, {"$set": {"value": WAIT_TIME}}, upsert=True)
|
| 30 |
+
if eye_thresh != EAR_THRESH:
|
| 31 |
+
slider_values.update_one({"slider_name": "Eye_Threshold"}, {"$set": {"value": EAR_THRESH}}, upsert=True)
|
| 32 |
+
if lip_thresh != LIP_THRESH:
|
| 33 |
+
slider_values.update_one({"slider_name": "Lip_Threshold"}, {"$set": {"value": LIP_THRESH}}, upsert=True)
|
| 34 |
+
|
| 35 |
+
# Streamlit Components
|
| 36 |
+
st.set_page_config(
|
| 37 |
+
page_title="Drowsiness Detection | APS",
|
| 38 |
+
page_icon="https://framerusercontent.com/modules/466qV2P53XLpEfUjjmZC/FNnZTYISEsUGPpjII54W/assets/VebAVoINVBFxBTpsrQVLHznVo.png",
|
| 39 |
+
initial_sidebar_state="expanded",
|
| 40 |
+
layout="wide",
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
menu_choice = option_menu(
|
| 44 |
+
menu_title=None,
|
| 45 |
+
options=["Home", "Login", "Signup", "OTP Login", "About"],
|
| 46 |
+
icons=["house", "box-arrow-in-right", "pencil-square","telephone", "question-circle"],
|
| 47 |
+
menu_icon="cast",
|
| 48 |
+
default_index=0,
|
| 49 |
+
orientation="horizontal",
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
if menu_choice == "Home":
|
| 53 |
+
st.title("Drowsiness Detection")
|
| 54 |
+
with st.container():
|
| 55 |
+
c1, c2, c3 = st.columns(spec=[1, 1, 1])
|
| 56 |
+
with c1:
|
| 57 |
+
# The amount of time (in seconds) to wait before sounding the alarm.
|
| 58 |
+
WAIT_TIME = st.slider("Time to wait before sounding alarm:", 0.0, 5.0, 1.0, 0.25)
|
| 59 |
+
|
| 60 |
+
with c2:
|
| 61 |
+
# Lowest valid value of Eye Aspect Ratio. Ideal values [0.15, 0.2].
|
| 62 |
+
EAR_THRESH = st.slider("Eye Aspect Ratio threshold:", 0.0, 0.4, 0.18, 0.01)
|
| 63 |
+
|
| 64 |
+
with c3:
|
| 65 |
+
# Lip threshold to detect yawning
|
| 66 |
+
LIP_THRESH = st.slider("Lip threshold:", 0.0, 0.4, 0.2, 0.01)
|
| 67 |
+
LIP_THRESH = LIP_THRESH*100
|
| 68 |
+
|
| 69 |
+
thresholds = {
|
| 70 |
+
"EAR_THRESH": EAR_THRESH,
|
| 71 |
+
"WAIT_TIME": WAIT_TIME,
|
| 72 |
+
"LIP_THRESH": LIP_THRESH
|
| 73 |
+
}
|
| 74 |
+
update_sliders()
|
| 75 |
+
|
| 76 |
+
# For streamlit-webrtc
|
| 77 |
+
video_handler = VideoFrameHandler()
|
| 78 |
+
audio_handler = AudioFrameHandler(sound_file_path=alarm_file_path)
|
| 79 |
+
|
| 80 |
+
lock = threading.Lock() # For thread-safe access & to prevent race-condition.
|
| 81 |
+
shared_state = {"play_alarm": False} # Shared state between callbacks.
|
| 82 |
+
|
| 83 |
+
def video_frame_callback(frame: av.VideoFrame):
|
| 84 |
+
frame = frame.to_ndarray(format="bgr24") # Decode and convert frame to RGB
|
| 85 |
+
|
| 86 |
+
frame, play_alarm = video_handler.process(frame, thresholds) # Process frame
|
| 87 |
+
with lock:
|
| 88 |
+
shared_state["play_alarm"] = play_alarm # Update shared state
|
| 89 |
+
|
| 90 |
+
return av.VideoFrame.from_ndarray(frame, format="bgr24") # Encode and return BGR frame
|
| 91 |
+
|
| 92 |
+
def audio_frame_callback(frame: av.AudioFrame):
|
| 93 |
+
with lock: # access the current “play_alarm” state
|
| 94 |
+
play_alarm = shared_state["play_alarm"]
|
| 95 |
+
|
| 96 |
+
new_frame: av.AudioFrame = audio_handler.process(frame, play_sound=play_alarm)
|
| 97 |
+
return new_frame
|
| 98 |
+
|
| 99 |
+
ctx = webrtc_streamer(
|
| 100 |
+
key="drowsiness-detection",
|
| 101 |
+
video_frame_callback=video_frame_callback,
|
| 102 |
+
audio_frame_callback=audio_frame_callback,
|
| 103 |
+
rtc_configuration={"iceServers": [{"urls": ["stun:stun.l.google.com:19302"]}]}, # Add this to config for cloud deployment.
|
| 104 |
+
media_stream_constraints={"video": {"height": {"ideal": 480}}, "audio": True},
|
| 105 |
+
video_html_attrs=VideoHTMLAttributes(autoPlay=True, controls=False, muted=False),
|
| 106 |
+
)
|
| 107 |
+
|
| 108 |
+
#handling login
|
| 109 |
+
|
| 110 |
+
if menu_choice == "Login":
|
| 111 |
+
st.text('Login')
|
| 112 |
+
email = st.text_input('Enter email')
|
| 113 |
+
password = st.text_input('Enter password', type="password")
|
| 114 |
+
if st.button('Login'):
|
| 115 |
+
try:
|
| 116 |
+
client = pymongo.MongoClient("mongodb+srv://admin:Admin123@aps.agcjjww.mongodb.net/?retryWrites=true&w=majority")
|
| 117 |
+
db = client["aps-db"]
|
| 118 |
+
users = db["users"]
|
| 119 |
+
user = users.find_one({"email": email})
|
| 120 |
+
if user:
|
| 121 |
+
if bcrypt.checkpw(password.encode(), user["password"]):
|
| 122 |
+
st.success("Successfully logged in!")
|
| 123 |
+
menu_choice = "Home"
|
| 124 |
+
os.environ["email"] = email
|
| 125 |
+
os.environ["user_id"] = str(user["_id"])
|
| 126 |
+
os.environ["logged_in"] = "True"
|
| 127 |
+
else:
|
| 128 |
+
st.error("Invalid password")
|
| 129 |
+
else:
|
| 130 |
+
st.error("Email not found")
|
| 131 |
+
except Exception as e:
|
| 132 |
+
st.error("An error occurred: {}".format(str(e)))
|
| 133 |
+
|
| 134 |
+
if menu_choice == "Signup":
|
| 135 |
+
st.text('Signup')
|
| 136 |
+
email = st.text_input('Enter email')
|
| 137 |
+
password = st.text_input('Enter password', type="password")
|
| 138 |
+
if st.button('Signup'):
|
| 139 |
+
try:
|
| 140 |
+
client = pymongo.MongoClient("mongodb+srv://admin:Admin123@aps.agcjjww.mongodb.net/?retryWrites=true&w=majority")
|
| 141 |
+
db = client["aps-db"]
|
| 142 |
+
users = db["users"]
|
| 143 |
+
if users.find_one({"email": email}):
|
| 144 |
+
st.error("Email already exists")
|
| 145 |
+
else:
|
| 146 |
+
hashed_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
|
| 147 |
+
users.insert_one({"email": email, "password": hashed_password})
|
| 148 |
+
st.success("Successfully signed up!")
|
| 149 |
+
except Exception as e:
|
| 150 |
+
st.error("An error occurred: {}".format(str(e)))
|
| 151 |
+
|
| 152 |
+
#phone number login
|
| 153 |
+
account_sid = "AC97fd9a03c4637fe246adcecc613bb153"
|
| 154 |
+
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
|
| 155 |
+
verify_sid = "VA629a29a82eedcde1e6c89e5f586fdbfd"
|
| 156 |
+
|
| 157 |
+
if menu_choice == "OTP Login":
|
| 158 |
+
st.text("Please enter country code followed by phone number")
|
| 159 |
+
st.text("For example: +919255520023")
|
| 160 |
+
verified_number = st.text_input("Enter your phone number")
|
| 161 |
+
|
| 162 |
+
client = Client(account_sid, auth_token)
|
| 163 |
+
otp_sent = False
|
| 164 |
+
if st.button("Send OTP"):
|
| 165 |
+
verification = client.verify.v2.services(verify_sid) \
|
| 166 |
+
.verifications \
|
| 167 |
+
.create(to=verified_number, channel="sms")
|
| 168 |
+
if (verification.status == "pending" or verification.status == "started"):
|
| 169 |
+
st.success("OTP sent successfully to " + verified_number)
|
| 170 |
+
otp_sent = True
|
| 171 |
+
else:
|
| 172 |
+
st.error("Error sending OTP")
|
| 173 |
+
|
| 174 |
+
otp_code = st.text_input("Please enter the OTP:",type="password")
|
| 175 |
+
if st.button("Verify OTP"):
|
| 176 |
+
verification_check = client.verify.v2.services(verify_sid) \
|
| 177 |
+
.verification_checks \
|
| 178 |
+
.create(to=verified_number, code=otp_code)
|
| 179 |
+
if (verification_check.status == "approved"):
|
| 180 |
+
st.success("OTP Verified")
|
| 181 |
+
client = pymongo.MongoClient("mongodb+srv://admin:Admin123@aps.agcjjww.mongodb.net/?retryWrites=true&w=majority")
|
| 182 |
+
db = client["aps-db"]
|
| 183 |
+
users = db["users"]
|
| 184 |
+
users.insert_one({"phone": verified_number})
|
| 185 |
+
else:
|
| 186 |
+
st.error("OTP Verification Failed")
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
hide_streamlit_style = """
|
| 190 |
+
<style>
|
| 191 |
+
#MainMenu {visibility: hidden;}
|
| 192 |
+
footer {visibility: hidden;}
|
| 193 |
+
</style>
|
| 194 |
+
"""
|
| 195 |
+
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
|
audio/wake_up.wav
ADDED
|
Binary file (28.9 kB). View file
|
|
|
audio_handling.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import av
|
| 2 |
+
import numpy as np
|
| 3 |
+
from pydub import AudioSegment
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class AudioFrameHandler:
|
| 7 |
+
"""To play/pass custom audio based on some event"""
|
| 8 |
+
|
| 9 |
+
def __init__(self, sound_file_path: str = ""):
|
| 10 |
+
|
| 11 |
+
self.custom_audio = AudioSegment.from_file(file=sound_file_path, format="wav")
|
| 12 |
+
self.custom_audio_len = len(self.custom_audio)
|
| 13 |
+
|
| 14 |
+
self.ms_per_audio_segment: int = 20
|
| 15 |
+
self.audio_segment_shape: tuple
|
| 16 |
+
|
| 17 |
+
self.play_state_tracker: dict = {"curr_segment": -1} # Currently playing segment
|
| 18 |
+
self.audio_segments_created: bool = False
|
| 19 |
+
self.audio_segments: list = []
|
| 20 |
+
|
| 21 |
+
def prepare_audio(self, frame: av.AudioFrame):
|
| 22 |
+
raw_samples = frame.to_ndarray()
|
| 23 |
+
sound = AudioSegment(
|
| 24 |
+
data=raw_samples.tobytes(),
|
| 25 |
+
sample_width=frame.format.bytes,
|
| 26 |
+
frame_rate=frame.sample_rate,
|
| 27 |
+
channels=len(frame.layout.channels),
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
self.ms_per_audio_segment = len(sound)
|
| 31 |
+
self.audio_segment_shape = raw_samples.shape
|
| 32 |
+
|
| 33 |
+
self.custom_audio = self.custom_audio.set_channels(sound.channels)
|
| 34 |
+
self.custom_audio = self.custom_audio.set_frame_rate(sound.frame_rate)
|
| 35 |
+
self.custom_audio = self.custom_audio.set_sample_width(sound.sample_width)
|
| 36 |
+
|
| 37 |
+
self.audio_segments = [
|
| 38 |
+
self.custom_audio[i : i + self.ms_per_audio_segment]
|
| 39 |
+
for i in range(0, self.custom_audio_len - self.custom_audio_len % self.ms_per_audio_segment, self.ms_per_audio_segment)
|
| 40 |
+
]
|
| 41 |
+
self.total_segments = len(self.audio_segments) - 1 # -1 because we start from 0.
|
| 42 |
+
|
| 43 |
+
self.audio_segments_created = True
|
| 44 |
+
|
| 45 |
+
def process(self, frame: av.AudioFrame, play_sound: bool = False):
|
| 46 |
+
|
| 47 |
+
"""
|
| 48 |
+
Takes in the current input audio frame and based on play_sound boolean value
|
| 49 |
+
either starts sending the custom audio frame or dampens the frame wave to emulate silence.
|
| 50 |
+
|
| 51 |
+
For eg. playing a notification based on some event.
|
| 52 |
+
"""
|
| 53 |
+
|
| 54 |
+
if not self.audio_segments_created:
|
| 55 |
+
self.prepare_audio(frame)
|
| 56 |
+
|
| 57 |
+
raw_samples = frame.to_ndarray()
|
| 58 |
+
_curr_segment = self.play_state_tracker["curr_segment"]
|
| 59 |
+
|
| 60 |
+
if play_sound:
|
| 61 |
+
if _curr_segment < self.total_segments:
|
| 62 |
+
_curr_segment += 1
|
| 63 |
+
else:
|
| 64 |
+
_curr_segment = 0
|
| 65 |
+
|
| 66 |
+
sound = self.audio_segments[_curr_segment]
|
| 67 |
+
|
| 68 |
+
else:
|
| 69 |
+
if -1 < _curr_segment < self.total_segments:
|
| 70 |
+
_curr_segment += 1
|
| 71 |
+
sound = self.audio_segments[_curr_segment]
|
| 72 |
+
else:
|
| 73 |
+
_curr_segment = -1
|
| 74 |
+
sound = AudioSegment(
|
| 75 |
+
data=raw_samples.tobytes(),
|
| 76 |
+
sample_width=frame.format.bytes,
|
| 77 |
+
frame_rate=frame.sample_rate,
|
| 78 |
+
channels=len(frame.layout.channels),
|
| 79 |
+
)
|
| 80 |
+
sound = sound.apply_gain(-100)
|
| 81 |
+
|
| 82 |
+
self.play_state_tracker["curr_segment"] = _curr_segment
|
| 83 |
+
|
| 84 |
+
channel_sounds = sound.split_to_mono()
|
| 85 |
+
channel_samples = [s.get_array_of_samples() for s in channel_sounds]
|
| 86 |
+
|
| 87 |
+
new_samples = np.array(channel_samples).T
|
| 88 |
+
|
| 89 |
+
new_samples = new_samples.reshape(self.audio_segment_shape)
|
| 90 |
+
new_frame = av.AudioFrame.from_ndarray(new_samples, layout=frame.layout.name)
|
| 91 |
+
new_frame.sample_rate = frame.sample_rate
|
| 92 |
+
|
| 93 |
+
return new_frame
|
drowsy_detection.py
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import time
|
| 3 |
+
|
| 4 |
+
import cv2
|
| 5 |
+
import dlib
|
| 6 |
+
import mediapipe as mp
|
| 7 |
+
import numpy as np
|
| 8 |
+
import pymongo
|
| 9 |
+
import pyrebase
|
| 10 |
+
import streamlit as st
|
| 11 |
+
from bson.objectid import ObjectId
|
| 12 |
+
from imutils import face_utils
|
| 13 |
+
from mediapipe.python.solutions.drawing_utils import \
|
| 14 |
+
_normalized_to_pixel_coordinates as denormalize_coordinates
|
| 15 |
+
from scipy.spatial import distance as dist
|
| 16 |
+
|
| 17 |
+
config = {"apiKey": "AIzaSyCNPBcskQFs2tn5UfdFbP8LzbnEMIarsWc",
|
| 18 |
+
"authDomain": "aps-csia.firebaseapp.com",
|
| 19 |
+
"databaseURL": "https://aps-csia-default-rtdb.asia-southeast1.firebasedatabase.app/",
|
| 20 |
+
"projectId": "aps-csia",
|
| 21 |
+
"storageBucket": "aps-csia.appspot.com",
|
| 22 |
+
"messagingSenderId": "1069559357849",
|
| 23 |
+
"appId": "1:1069559357849:web:39e9d0139d42a206973308",
|
| 24 |
+
"measurementId": "G-FVTG7XGLN7"}
|
| 25 |
+
|
| 26 |
+
firebase = pyrebase.initialize_app(config)
|
| 27 |
+
db = firebase.database()
|
| 28 |
+
|
| 29 |
+
print("-> Loading the predictor and detector...")
|
| 30 |
+
detector = cv2.CascadeClassifier("./haarcascade_frontalface_default.xml") #Faster but less accurate
|
| 31 |
+
predictor = dlib.shape_predictor('./shape_predictor_68_face_landmarks.dat')
|
| 32 |
+
|
| 33 |
+
def get_mediapipe_app(
|
| 34 |
+
max_num_faces=1,
|
| 35 |
+
refine_landmarks=True,
|
| 36 |
+
min_detection_confidence=0.5,
|
| 37 |
+
min_tracking_confidence=0.5,
|
| 38 |
+
):
|
| 39 |
+
"""Initialize and return Mediapipe FaceMesh Solution Graph object"""
|
| 40 |
+
face_mesh = mp.solutions.face_mesh.FaceMesh(
|
| 41 |
+
max_num_faces=max_num_faces,
|
| 42 |
+
refine_landmarks=refine_landmarks,
|
| 43 |
+
min_detection_confidence=min_detection_confidence,
|
| 44 |
+
min_tracking_confidence=min_tracking_confidence,
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
return face_mesh
|
| 48 |
+
|
| 49 |
+
def distance(point_1, point_2):
|
| 50 |
+
"""Calculate l2-norm between two points"""
|
| 51 |
+
dist = sum([(i - j) ** 2 for i, j in zip(point_1, point_2)]) ** 0.5
|
| 52 |
+
return dist
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def get_ear(landmarks, refer_idxs, frame_width, frame_height):
|
| 56 |
+
"""
|
| 57 |
+
Calculate Eye Aspect Ratio for one eye.
|
| 58 |
+
|
| 59 |
+
Args:
|
| 60 |
+
landmarks: (list) Detected landmarks list
|
| 61 |
+
refer_idxs: (list) Index positions of the chosen landmarks
|
| 62 |
+
in order P1, P2, P3, P4, P5, P6
|
| 63 |
+
frame_width: (int) Width of captured frame
|
| 64 |
+
frame_height: (int) Height of captured frame
|
| 65 |
+
|
| 66 |
+
Returns:
|
| 67 |
+
ear: (float) Eye aspect ratio
|
| 68 |
+
"""
|
| 69 |
+
try:
|
| 70 |
+
# Compute the euclidean distance between the horizontal
|
| 71 |
+
coords_points = []
|
| 72 |
+
for i in refer_idxs:
|
| 73 |
+
lm = landmarks[i]
|
| 74 |
+
coord = denormalize_coordinates(lm.x, lm.y, frame_width, frame_height)
|
| 75 |
+
coords_points.append(coord)
|
| 76 |
+
|
| 77 |
+
# Eye landmark (x, y)-coordinates
|
| 78 |
+
P1_P4 = dist.euclidean(coords_points[0], coords_points[3])
|
| 79 |
+
P2_P6 = dist.euclidean(coords_points[1], coords_points[5])
|
| 80 |
+
P3_P5 = dist.euclidean(coords_points[2], coords_points[4])
|
| 81 |
+
|
| 82 |
+
# Compute the eye aspect ratio
|
| 83 |
+
ear = (P2_P6 + P3_P5) / (2.0 * P1_P4)
|
| 84 |
+
|
| 85 |
+
except:
|
| 86 |
+
ear = 0.0
|
| 87 |
+
coords_points = None
|
| 88 |
+
|
| 89 |
+
return ear, coords_points
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def calculate_avg_ear(landmarks, left_eye_idxs, right_eye_idxs, image_w, image_h):
|
| 93 |
+
# Calculate Eye aspect ratio
|
| 94 |
+
|
| 95 |
+
left_ear, left_lm_coordinates = get_ear(landmarks, left_eye_idxs, image_w, image_h)
|
| 96 |
+
right_ear, right_lm_coordinates = get_ear(landmarks, right_eye_idxs, image_w, image_h)
|
| 97 |
+
Avg_EAR = (left_ear + right_ear) / 2.0
|
| 98 |
+
|
| 99 |
+
return Avg_EAR, (left_lm_coordinates, right_lm_coordinates)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def plot_eye_landmarks(frame, left_lm_coordinates, right_lm_coordinates, color):
|
| 103 |
+
for lm_coordinates in [left_lm_coordinates, right_lm_coordinates]:
|
| 104 |
+
if lm_coordinates:
|
| 105 |
+
for coord in lm_coordinates:
|
| 106 |
+
cv2.circle(frame, coord, 2, color, -1)
|
| 107 |
+
|
| 108 |
+
return frame
|
| 109 |
+
|
| 110 |
+
def lip_distance(shape):
|
| 111 |
+
top_lip = shape[50:53]
|
| 112 |
+
top_lip = np.concatenate((top_lip, shape[61:64]))
|
| 113 |
+
|
| 114 |
+
low_lip = shape[56:59]
|
| 115 |
+
low_lip = np.concatenate((low_lip, shape[65:68]))
|
| 116 |
+
|
| 117 |
+
top_mean = np.mean(top_lip, axis=0)
|
| 118 |
+
low_mean = np.mean(low_lip, axis=0)
|
| 119 |
+
|
| 120 |
+
distance = abs(top_mean[1] - low_mean[1])
|
| 121 |
+
return distance
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def plot_text(image, text, origin, color, font=cv2.FONT_HERSHEY_SIMPLEX, fntScale=0.8, thickness=2):
|
| 125 |
+
image = cv2.putText(image, text, origin, font, fntScale, color, thickness)
|
| 126 |
+
return image
|
| 127 |
+
|
| 128 |
+
class VideoFrameHandler:
|
| 129 |
+
def __init__(self):
|
| 130 |
+
"""
|
| 131 |
+
Initialize the necessary constants, mediapipe app
|
| 132 |
+
and tracker variables
|
| 133 |
+
"""
|
| 134 |
+
# Left and right eye chosen landmarks.
|
| 135 |
+
self.count_drowsy = 0
|
| 136 |
+
self.count_yawn = 0
|
| 137 |
+
self.eye_idxs = {
|
| 138 |
+
"left": [362, 385, 387, 263, 373, 380],
|
| 139 |
+
"right": [33, 160, 158, 133, 153, 144],
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
# Used for coloring landmark points.
|
| 143 |
+
# Its value depends on the current EAR value.
|
| 144 |
+
self.RED = (0, 0, 255) # BGR
|
| 145 |
+
self.GREEN = (0, 255, 0) # BGR
|
| 146 |
+
|
| 147 |
+
# Initializing Mediapipe FaceMesh solution pipeline
|
| 148 |
+
self.facemesh_model = get_mediapipe_app()
|
| 149 |
+
|
| 150 |
+
# For tracking counters and sharing states in and out of callbacks.
|
| 151 |
+
self.state_tracker = {
|
| 152 |
+
"start_time": time.perf_counter(),
|
| 153 |
+
"DROWSY_TIME": 0.0, # Holds the amount of time passed with EAR < EAR_THRESH
|
| 154 |
+
"COLOR": self.GREEN,
|
| 155 |
+
"play_alarm": False,
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
self.EAR_txt_pos = (10, 30)
|
| 159 |
+
|
| 160 |
+
def process(self, frame: np.array, thresholds: dict):
|
| 161 |
+
"""
|
| 162 |
+
This function is used to implement our Drowsy detection algorithm
|
| 163 |
+
|
| 164 |
+
Args:
|
| 165 |
+
frame: (np.array) Input frame matrix.
|
| 166 |
+
thresholds: (dict) Contains the two threshold values
|
| 167 |
+
WAIT_TIME and EAR_THRESH.
|
| 168 |
+
|
| 169 |
+
Returns:
|
| 170 |
+
The processed frame and a boolean flag to
|
| 171 |
+
indicate if the alarm should be played or not.
|
| 172 |
+
"""
|
| 173 |
+
|
| 174 |
+
# To improve performance,
|
| 175 |
+
# mark the frame as not writeable to pass by reference.
|
| 176 |
+
frame = cv2.flip(frame,1)
|
| 177 |
+
frame.flags.writeable = False
|
| 178 |
+
frame_h, frame_w, _ = frame.shape
|
| 179 |
+
|
| 180 |
+
DROWSY_TIME_txt_pos = (10, int(frame_h // 2 * 1.7))
|
| 181 |
+
ALM_txt_pos = (10, int(frame_h // 2 * 1.85))
|
| 182 |
+
|
| 183 |
+
#frame = cv2.flip(frame, 1)
|
| 184 |
+
results = self.facemesh_model.process(frame)
|
| 185 |
+
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
| 186 |
+
rects = detector.detectMultiScale(gray, scaleFactor=1.1,
|
| 187 |
+
minNeighbors=5, minSize=(30, 30),
|
| 188 |
+
flags=cv2.CASCADE_SCALE_IMAGE)
|
| 189 |
+
for (x, y, w, h) in rects:
|
| 190 |
+
rect = dlib.rectangle(int(x), int(y), int(x + w),int(y + h))
|
| 191 |
+
|
| 192 |
+
shape = predictor(gray, rect)
|
| 193 |
+
shape = face_utils.shape_to_np(shape)
|
| 194 |
+
|
| 195 |
+
distance = lip_distance(shape)
|
| 196 |
+
lip = shape[48:60]
|
| 197 |
+
cv2.drawContours(frame, [lip], -1, (0, 255, 0), 1)
|
| 198 |
+
if (distance > thresholds["LIP_THRESH"]):
|
| 199 |
+
plot_text(frame, "Yawn Alert", (460, 440), (0, 0, 255))
|
| 200 |
+
time.sleep(1)
|
| 201 |
+
self.count_yawn += 1
|
| 202 |
+
if os.environ.get("logged_in") == "True":
|
| 203 |
+
user_id = os.environ.get("user_id")
|
| 204 |
+
email = os.environ.get("email")
|
| 205 |
+
client = pymongo.MongoClient("mongodb+srv://admin:Admin123@aps.agcjjww.mongodb.net/?retryWrites=true&w=majority")
|
| 206 |
+
db = client["aps-db"]
|
| 207 |
+
users = db["count"]
|
| 208 |
+
user = users.find_one({"_id": ObjectId(user_id)})
|
| 209 |
+
if user:
|
| 210 |
+
users.update_one({"_id": ObjectId(user_id)}, {"$set": {"count_yawn": self.count_yawn, "email": email}})
|
| 211 |
+
else:
|
| 212 |
+
users.insert_one({"_id": ObjectId(user_id), "count_yawn": self.count_yawn, "email": email})
|
| 213 |
+
else:
|
| 214 |
+
st.error("Not logged in")
|
| 215 |
+
frame = plot_text(frame, f"Yawn count: {self.count_yawn}",(420,410), color=(0, 255, 0), thickness=2)
|
| 216 |
+
|
| 217 |
+
if results.multi_face_landmarks:
|
| 218 |
+
landmarks = results.multi_face_landmarks[0].landmark
|
| 219 |
+
EAR, coordinates = calculate_avg_ear(landmarks, self.eye_idxs["left"], self.eye_idxs["right"], frame_w, frame_h)
|
| 220 |
+
frame = plot_eye_landmarks(frame, coordinates[0], coordinates[1], self.state_tracker["COLOR"])
|
| 221 |
+
|
| 222 |
+
if EAR < thresholds["EAR_THRESH"]:
|
| 223 |
+
|
| 224 |
+
# Increase DROWSY_TIME to track the time period with EAR less than the threshold
|
| 225 |
+
# and reset the start_time for the next iteration.
|
| 226 |
+
end_time = time.perf_counter()
|
| 227 |
+
|
| 228 |
+
self.state_tracker["DROWSY_TIME"] += end_time - self.state_tracker["start_time"]
|
| 229 |
+
self.state_tracker["start_time"] = end_time
|
| 230 |
+
self.state_tracker["COLOR"] = self.RED
|
| 231 |
+
|
| 232 |
+
if self.state_tracker["DROWSY_TIME"] >= thresholds["WAIT_TIME"]:
|
| 233 |
+
self.state_tracker["play_alarm"] = True
|
| 234 |
+
plot_text(frame, "WAKE UP! WAKE UP", ALM_txt_pos, self.state_tracker["COLOR"])
|
| 235 |
+
time.sleep(1)
|
| 236 |
+
self.count_drowsy += 1
|
| 237 |
+
if os.environ.get("logged_in") == "True":
|
| 238 |
+
user_id = os.environ.get("user_id")
|
| 239 |
+
email = os.environ.get("email")
|
| 240 |
+
client = pymongo.MongoClient("mongodb+srv://admin:Admin123@aps.agcjjww.mongodb.net/?retryWrites=true&w=majority")
|
| 241 |
+
db = client["aps-db"]
|
| 242 |
+
users = db["count"]
|
| 243 |
+
user = users.find_one({"_id": ObjectId(user_id)})
|
| 244 |
+
if user:
|
| 245 |
+
users.update_one({"_id": ObjectId(user_id)}, {"$set": {"count_drowsy": self.count_drowsy, "email": email}})
|
| 246 |
+
else:
|
| 247 |
+
users.insert_one({"_id": ObjectId(user_id), "count_drowsy": self.count_drowsy, "email": email})
|
| 248 |
+
else:
|
| 249 |
+
self.state_tracker["start_time"] = time.perf_counter()
|
| 250 |
+
self.state_tracker["DROWSY_TIME"] = 0.0
|
| 251 |
+
self.state_tracker["COLOR"] = self.GREEN
|
| 252 |
+
self.state_tracker["play_alarm"] = False
|
| 253 |
+
|
| 254 |
+
EAR_txt = f"EAR: {round(EAR, 2)}"
|
| 255 |
+
DROWSY_TIME_txt = f"DROWSY: {round(self.state_tracker['DROWSY_TIME'], 3)} Secs"
|
| 256 |
+
plot_text(frame, EAR_txt, self.EAR_txt_pos, self.state_tracker["COLOR"])
|
| 257 |
+
plot_text(frame, DROWSY_TIME_txt, DROWSY_TIME_txt_pos, self.state_tracker["COLOR"])
|
| 258 |
+
frame = plot_text(frame, f"Drowsy count: {self.count_drowsy}",(400,30), color=(0, 255, 0), thickness=2)
|
| 259 |
+
|
| 260 |
+
else:
|
| 261 |
+
self.state_tracker["start_time"] = time.perf_counter()
|
| 262 |
+
self.state_tracker["DROWSY_TIME"] = 0.0
|
| 263 |
+
self.state_tracker["COLOR"] = self.GREEN
|
| 264 |
+
self.state_tracker["play_alarm"] = False
|
| 265 |
+
|
| 266 |
+
return frame, self.state_tracker["play_alarm"]
|
environment.yml
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: CSIA_APS
|
| 2 |
+
channels:
|
| 3 |
+
- anaconda
|
| 4 |
+
- conda-forge
|
| 5 |
+
- defaults
|
| 6 |
+
dependencies:
|
| 7 |
+
- bzip2=1.0.8=he774522_0
|
| 8 |
+
- ca-certificates=2022.12.7=h5b45459_0
|
| 9 |
+
- certifi=2022.12.7=pyhd8ed1ab_0
|
| 10 |
+
- cmake=3.22.1=h9ad04ae_0
|
| 11 |
+
- console_shortcut=0.1.1=4
|
| 12 |
+
- dlib=19.24.0=py310he5227f5_0
|
| 13 |
+
- intel-openmp=2023.0.0=h57928b3_25922
|
| 14 |
+
- jpeg=9e=h8ffe710_2
|
| 15 |
+
- libblas=3.9.0=8_mkl
|
| 16 |
+
- libcblas=3.9.0=8_mkl
|
| 17 |
+
- libffi=3.4.2=hd77b12b_6
|
| 18 |
+
- liblapack=3.9.0=8_mkl
|
| 19 |
+
- libpng=1.6.37=h2a8f88b_0
|
| 20 |
+
- libuv=1.40.0=he774522_0
|
| 21 |
+
- lz4-c=1.9.3=h2bbff1b_1
|
| 22 |
+
- mkl=2020.4=hb70f87d_311
|
| 23 |
+
- openssl=1.1.1s=h2bbff1b_0
|
| 24 |
+
- pip=22.3.1=py310haa95532_0
|
| 25 |
+
- python=3.10.9=h966fe2a_0
|
| 26 |
+
- python_abi=3.10=2_cp310
|
| 27 |
+
- setuptools=65.6.3=py310haa95532_0
|
| 28 |
+
- sqlite=3.40.1=h2bbff1b_0
|
| 29 |
+
- tk=8.6.12=h2bbff1b_0
|
| 30 |
+
- vc=14.2=h21ff451_1
|
| 31 |
+
- vs2015_runtime=14.27.29016=h5e58377_2
|
| 32 |
+
- wheel=0.37.1=pyhd3eb1b0_0
|
| 33 |
+
- wincertstore=0.2=py310haa95532_2
|
| 34 |
+
- xz=5.2.10=h8cc25b3_1
|
| 35 |
+
- zlib=1.2.13=h8cc25b3_0
|
| 36 |
+
- zstd=1.5.2=h19a0ad4_0
|
| 37 |
+
- pip:
|
| 38 |
+
- absl-py==1.4.0
|
| 39 |
+
- aioice==0.7.6
|
| 40 |
+
- aiortc==1.4.0
|
| 41 |
+
- altair==4.2.2
|
| 42 |
+
- attrs==22.2.0
|
| 43 |
+
- av==10.0.0
|
| 44 |
+
- blinker==1.5
|
| 45 |
+
- cachetools==5.3.0
|
| 46 |
+
- cffi==1.15.1
|
| 47 |
+
- charset-normalizer==3.0.1
|
| 48 |
+
- click==8.1.3
|
| 49 |
+
- colorama==0.4.6
|
| 50 |
+
- contourpy==1.0.7
|
| 51 |
+
- cryptography==38.0.4
|
| 52 |
+
- cycler==0.11.0
|
| 53 |
+
- decorator==5.1.1
|
| 54 |
+
- deprecated==1.2.13
|
| 55 |
+
- dnspython==2.3.0
|
| 56 |
+
- entrypoints==0.4
|
| 57 |
+
- flatbuffers==23.1.21
|
| 58 |
+
- fonttools==4.38.0
|
| 59 |
+
- gcloud==0.18.3
|
| 60 |
+
- gitdb==4.0.10
|
| 61 |
+
- gitpython==3.1.30
|
| 62 |
+
- google-crc32c==1.5.0
|
| 63 |
+
- googleapis-common-protos==1.58.0
|
| 64 |
+
- httplib2==0.21.0
|
| 65 |
+
- idna==3.4
|
| 66 |
+
- importlib-metadata==6.0.0
|
| 67 |
+
- imutils==0.5.4
|
| 68 |
+
- jinja2==3.1.2
|
| 69 |
+
- jsonschema==4.17.3
|
| 70 |
+
- jwcrypto==1.4.2
|
| 71 |
+
- kiwisolver==1.4.4
|
| 72 |
+
- markdown-it-py==2.1.0
|
| 73 |
+
- markupsafe==2.1.2
|
| 74 |
+
- matplotlib==3.6.3
|
| 75 |
+
- mdurl==0.1.2
|
| 76 |
+
- mediapipe==0.9.1.0
|
| 77 |
+
- netifaces==0.11.0
|
| 78 |
+
- numpy==1.24.1
|
| 79 |
+
- oauth2client==4.1.3
|
| 80 |
+
- opencv-contrib-python==4.7.0.68
|
| 81 |
+
- opencv-python==4.7.0.68
|
| 82 |
+
- packaging==23.0
|
| 83 |
+
- pandas==1.5.3
|
| 84 |
+
- pillow==9.4.0
|
| 85 |
+
- protobuf==3.20.3
|
| 86 |
+
- pyarrow==11.0.0
|
| 87 |
+
- pyasn1==0.4.8
|
| 88 |
+
- pyasn1-modules==0.2.8
|
| 89 |
+
- pycparser==2.21
|
| 90 |
+
- pycryptodome==3.17
|
| 91 |
+
- pydeck==0.8.0
|
| 92 |
+
- pydub==0.25.1
|
| 93 |
+
- pyee==9.0.4
|
| 94 |
+
- pygments==2.14.0
|
| 95 |
+
- pylibsrtp==0.8.0
|
| 96 |
+
- pymongo==4.3.3
|
| 97 |
+
- pympler==1.0.1
|
| 98 |
+
- pyopenssl==23.0.0
|
| 99 |
+
- pyparsing==3.0.9
|
| 100 |
+
- pyrebase4==4.6.0
|
| 101 |
+
- pyrsistent==0.19.3
|
| 102 |
+
- python-dateutil==2.8.2
|
| 103 |
+
- python-jwt==4.0.0
|
| 104 |
+
- pytz==2022.7.1
|
| 105 |
+
- pytz-deprecation-shim==0.1.0.post0
|
| 106 |
+
- requests==2.28.2
|
| 107 |
+
- requests-toolbelt==0.10.1
|
| 108 |
+
- rich==13.3.1
|
| 109 |
+
- rsa==4.9
|
| 110 |
+
- scipy==1.10.0
|
| 111 |
+
- semver==2.13.0
|
| 112 |
+
- six==1.16.0
|
| 113 |
+
- smmap==5.0.0
|
| 114 |
+
- streamlit==1.17.0
|
| 115 |
+
- streamlit-nested-layout==0.1.1
|
| 116 |
+
- streamlit-option-menu==0.3.2
|
| 117 |
+
- streamlit-webrtc==0.44.2
|
| 118 |
+
- toml==0.10.2
|
| 119 |
+
- toolz==0.12.0
|
| 120 |
+
- tornado==6.2
|
| 121 |
+
- typing-extensions==4.4.0
|
| 122 |
+
- tzdata==2022.7
|
| 123 |
+
- tzlocal==4.2
|
| 124 |
+
- urllib3==1.26.14
|
| 125 |
+
- validators==0.20.0
|
| 126 |
+
- watchdog==2.2.1
|
| 127 |
+
- wrapt==1.14.1
|
| 128 |
+
- zipp==3.12.0
|
| 129 |
+
prefix: C:\ProgramData\Anaconda3\envs\CSIA_APS
|
haarcascade_frontalface_default.xml
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
packages.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
cmake
|
requirements.txt
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
absl-py==1.4.0
|
| 2 |
+
aioice==0.7.6
|
| 3 |
+
aiortc==1.4.0
|
| 4 |
+
altair==4.2.2
|
| 5 |
+
attrs==22.2.0
|
| 6 |
+
av==10.0.0
|
| 7 |
+
blinker==1.5
|
| 8 |
+
cachetools==5.3.0
|
| 9 |
+
certifi==2022.12.7
|
| 10 |
+
cffi==1.15.1
|
| 11 |
+
charset-normalizer==3.0.1
|
| 12 |
+
click==8.1.3
|
| 13 |
+
colorama==0.4.6
|
| 14 |
+
contourpy==1.0.7
|
| 15 |
+
cryptography==38.0.4
|
| 16 |
+
cycler==0.11.0
|
| 17 |
+
decorator==5.1.1
|
| 18 |
+
Deprecated==1.2.13
|
| 19 |
+
dlib
|
| 20 |
+
dnspython==2.3.0
|
| 21 |
+
entrypoints==0.4
|
| 22 |
+
flatbuffers==23.1.21
|
| 23 |
+
fonttools==4.38.0
|
| 24 |
+
gcloud==0.18.3
|
| 25 |
+
gitdb==4.0.10
|
| 26 |
+
GitPython==3.1.30
|
| 27 |
+
google-crc32c==1.5.0
|
| 28 |
+
googleapis-common-protos==1.58.0
|
| 29 |
+
httplib2==0.21.0
|
| 30 |
+
idna==3.4
|
| 31 |
+
importlib-metadata==6.0.0
|
| 32 |
+
imutils==0.5.4
|
| 33 |
+
Jinja2==3.1.2
|
| 34 |
+
jsonschema==4.17.3
|
| 35 |
+
jwcrypto==1.4.2
|
| 36 |
+
kiwisolver==1.4.4
|
| 37 |
+
markdown-it-py==2.1.0
|
| 38 |
+
MarkupSafe==2.1.2
|
| 39 |
+
matplotlib==3.6.3
|
| 40 |
+
mdurl==0.1.2
|
| 41 |
+
mediapipe==0.9.1.0
|
| 42 |
+
netifaces==0.11.0
|
| 43 |
+
numpy==1.24.1
|
| 44 |
+
oauth2client==4.1.3
|
| 45 |
+
opencv-contrib-python==4.7.0.68
|
| 46 |
+
opencv-python==4.7.0.68
|
| 47 |
+
packaging==23.0
|
| 48 |
+
pandas==1.5.3
|
| 49 |
+
Pillow==9.4.0
|
| 50 |
+
protobuf==3.20.3
|
| 51 |
+
pyarrow==11.0.0
|
| 52 |
+
pyasn1==0.4.8
|
| 53 |
+
pyasn1-modules==0.2.8
|
| 54 |
+
pycparser==2.21
|
| 55 |
+
pycryptodome==3.17
|
| 56 |
+
pydeck==0.8.0
|
| 57 |
+
pydub==0.25.1
|
| 58 |
+
pyee==9.0.4
|
| 59 |
+
Pygments==2.14.0
|
| 60 |
+
pylibsrtp==0.8.0
|
| 61 |
+
pymongo==4.3.3
|
| 62 |
+
Pympler==1.0.1
|
| 63 |
+
pyOpenSSL==23.0.0
|
| 64 |
+
pyparsing==3.0.9
|
| 65 |
+
Pyrebase4==4.6.0
|
| 66 |
+
pyrsistent==0.19.3
|
| 67 |
+
python-dateutil==2.8.2
|
| 68 |
+
python-jwt==4.0.0
|
| 69 |
+
pytz==2022.7.1
|
| 70 |
+
pytz-deprecation-shim==0.1.0.post0
|
| 71 |
+
requests==2.28.2
|
| 72 |
+
requests-toolbelt==0.10.1
|
| 73 |
+
rich==13.3.1
|
| 74 |
+
rsa==4.9
|
| 75 |
+
scipy==1.10.0
|
| 76 |
+
semver==2.13.0
|
| 77 |
+
six==1.16.0
|
| 78 |
+
smmap==5.0.0
|
| 79 |
+
streamlit==1.17.0
|
| 80 |
+
streamlit-nested-layout==0.1.1
|
| 81 |
+
streamlit-option-menu==0.3.2
|
| 82 |
+
streamlit-webrtc==0.44.2
|
| 83 |
+
toml==0.10.2
|
| 84 |
+
toolz==0.12.0
|
| 85 |
+
tornado==6.2
|
| 86 |
+
typing_extensions==4.4.0
|
| 87 |
+
tzdata==2022.7
|
| 88 |
+
tzlocal==4.2
|
| 89 |
+
urllib3==1.26.14
|
| 90 |
+
validators==0.20.0
|
| 91 |
+
watchdog==2.2.1
|
| 92 |
+
wincertstore==0.2
|
| 93 |
+
wrapt==1.14.1
|
| 94 |
+
zipp==3.12.0
|