Je travaille comme enseignant au parc technologique pour enfants Quantorium. Pendant la période d'auto-isolement, nous sommes, comme tout le monde, passés à l'enseignement à distance. Et en raison du fait que les enfants ont commencé à passer encore plus de temps devant l'ordinateur, l'administration a décidé de raccourcir l'heure académique et de faire des pauses entre le travail - pour préserver leur vue. Nous avons écrit une application qui calcule le temps passé devant l’ordinateur, conserve les statistiques dans Excel - utile pour les parents, et donne une alerte sonore quand il est temps de faire une pause.
L'application sera utile pour ceux qui sont perdus dans le temps à travailler sur le PC et veulent se plonger dans le laps de temps ou garder une trace de la partie de la vie perdue dans l'espace numérique.
Lien vers le référentiel
Sous la coupe, une analyse détaillée.
Pour créer un programme, vous devez résoudre les tâches suivantes:
- web ( mtcnn);
- ( time)
- excel ( openpyxl);
- ;
- .
web
Nous avons envisagé la possibilité de suivre la présence à l'ordinateur par le mouvement de la souris de l'ordinateur, c'est peut-être plus facile et la webcam restera gratuite, mais alors nous ne pourrons pas prendre en compte le visionnage d'émissions de télévision ou de vidéos youtube, de plus, l'utilisation de la reconnaissance faciale est beaucoup plus intéressante.
Pour la détection de visage, nous utilisons l'architecture mtcnn. Une tête positionnée à n'importe quel angle, portant des lunettes, dans de mauvaises conditions d'éclairage, même si le visage ne tombe pas complètement dans le cadre ou est couvert par une main, le réseau neuronal fonctionne correctement. Nous ne le construirons pas nous-mêmes, nous connecterons la bibliothèque du même nom, ce qui résoudra notre problème en utilisant quelques lignes de code.
Au départ, la méthode Viola-Jones a été utilisée. La précision est bien pire que celle de mtcnn, le processeur se charge de la même manière.
Nous allons déplacer la sortie du résultat dans une fonction séparée, il suffit de voir comment fonctionne la reconnaissance.
import cv2
import os
from mtcnn.mtcnn import MTCNN
def show_face_frame():
if faces:
bounding_box = faces[0]['box']
keypoints = faces[0]['keypoints']
cv2.rectangle(img,
(bounding_box[0], bounding_box[1]),
(bounding_box[0] + bounding_box[2],
bounding_box[1] + bounding_box[3]),
(0, 0, 255),
2)
cv2.circle(img, (keypoints['left_eye']), 3, (0, 0, 255), 2)
cv2.circle(img, (keypoints['right_eye']), 2, (0, 0, 255), 2)
cv2.circle(img, (keypoints['nose']), 3, (0, 0, 255), 2)
cv2.circle(img, (keypoints['mouth_left']), 3, (0, 0, 255), 2)
cv2.circle(img, (keypoints['mouth_right']), 3, (0, 0, 255), 2)
cv2.imshow('frame', img)
cap = cv2.VideoCapture(0)
detector = MTCNN()
while cap.isOpened():
_, img = cap.read()
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
faces = detector.detect_faces(img)
show_face_frame()
cv2.waitKey(300)
cap.release()
cv2.destroyAllWindows()
Gros délai cv2.waitKey (300) pour ne pas charger le processeur. Le traitement de 3 à 4 images par seconde charge le i3-8145U en moyenne de 15%.
Compter le temps
Le programme ne doit pas écrire dans le journal dans les cas suivants:
- s'assit à l'ordinateur pendant 5 secondes pour faire quelque chose de byrik;
- est sorti pour me servir du café ou me dégourdir les jambes.
Pour résoudre ces problèmes, le programme utilise deux chronomètres time_here (décompte le temps où le visage est dans le cadre) et time_not_here (lorsqu'il n'y a pas de visage). Les deux chronomètres sont réinitialisés lorsqu'une entrée de journal est effectuée. De plus, time_not_here est réinitialisé chaque fois qu'un visage apparaît dans le cadre.
La variable min_time_here indique le temps minimum passé sur l'ordinateur, après quoi il vaut la peine d'écrire dans le journal. L'enregistrement sera effectué après que la personne soit distraite de l'ordinateur pendant une durée plus longue que celle spécifiée dans min_time_not_here .
Dans le code ci-dessous, une entrée est effectuée si vous avez passé au moins 5 minutes devant l'ordinateur. Le programme ne tiendra pas compte du fait que je suis distrait pendant moins de 2 minutes.
import cv2
import time
import os
from mtcnn.mtcnn import MTCNN
cap = cv2.VideoCapture(0)
path = os.path.abspath(__file__)[:-11] #
here, not_here = 0, 0 #
time_here, time_not_here = 0, 0 #
switch = True #
min_time_here = 300 # , ( )
min_time_not_here = 120 # ( )
detector = MTCNN()
try:
while cap.isOpened():
_, img = cap.read()
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
faces = detector.detect_faces(img)
show_face_frame()
audio_message(path, here)
if faces and switch:
not_here = 0
switch = False
if here == 0:
here = time.time()
print(' ' + time.strftime("%H:%M:%S", time.localtime(here)))
elif not faces and not switch:
not_here = time.time()
switch = True
if not_here != 0:
time_not_here = time.time() - not_here
if here != 0 and not switch:
time_here = time.time() - here
if time_here > min_time_here and time_not_here > min_time_not_here: # min_time_here
write_excel(path, here)
print(' ' + time.strftime('%H:%M:%S', time.gmtime(time.time() - here)))
time_here, time_not_here = 0, 0
here, not_here = 0, 0
elif time_not_here > min_time_not_here and time_here < min_time_here: # min_time_here,
print(' ')
time_here, time_not_here = 0, 0
here, not_here = 0, 0
cv2.waitKey(300)
except KeyboardInterrupt:
if time_here > min_time_here: # min_time_here
write_excel(path, here)
cap.release()
cv2.destroyAllWindows()
Si l'utilisateur souhaite éteindre l'ordinateur, vous devez d'abord interrompre le programme (ctrl + c) et l'heure du travail en cours sera enregistrée. Pour cela, un gestionnaire d'exceptions est utilisé.
Écrire des données dans un document Excel
Pour travailler avec Excel, la merveilleuse bibliothèque openpyxl vous aidera, qui lit et écrit simultanément des données.
Chaque jour, le programme crée une nouvelle feuille avec la date actuelle.
Sur 1 feuille, les informations quotidiennes sont enregistrées, sur quel jour combien de temps a été passé à l'ordinateur.
La fonction write_excel ouvre le document, écrit les données et le ferme immédiatement.
Vous ne pouvez pas modifier un document via openpyxl s'il est déjà ouvert par l'utilisateur. Une exception a été ajoutée pour ce cas.
def write_excel(path_excel, time_start):
wb = openpyxl.load_workbook(path_excel + r'\dnevnik.xlsx')
today = time.strftime("%d.%m.%Y", time.localtime(time.time()))
if today not in wb.sheetnames: # ,
wb.create_sheet(title=today)
sheet = wb[today]
sheet.column_dimensions['A'].width = 20
sheet.column_dimensions['B'].width = 20
sheet.column_dimensions['C'].width = 20
sheet.column_dimensions['D'].width = 31
sheet['A1'] = ' '
sheet['B1'] = ' '
sheet['C1'] = ' '
sheet['D1'] = ' :'
sheet['D2'] = ' :'
sheet = wb[today]
row = 2
all_time = 0
else: #
sheet = wb[today]
row = sheet['E1'].value # excel
all_time = sheet['E2'].value #
all_time = all_time.split(':')
all_time = int(all_time[0]) * 3600 + int(all_time[1]) * 60 + int(all_time[2]) #
row = row + 2 #
sheet['A' + str(row)] = time.strftime("%H:%M:%S", time.localtime(time_start)) #
sheet['C' + str(row)] = time.strftime("%H:%M:%S", time.localtime(time.time())) # -
seconds = time.time() - time_start #
sheet['B' + str(row)] = time.strftime('%H:%M:%S', time.gmtime(seconds))
sheet['E1'] = row - 1 #
all_time = all_time + seconds
all_time = time.strftime('%H:%M:%S', time.gmtime(all_time))
sheet['E2'] = all_time
#
sheet_0 = wb.worksheets[0]
sheet_0['A' + str(len(wb.sheetnames))] = today
sheet_0['B' + str(len(wb.sheetnames))] = all_time
while True: #
try:
wb.save(path_excel + r'\dnevnik.xlsx')
except PermissionError:
input(' excel enter')
else:
break
Alerte sonore
Pour changer, nous avons généré 8 fichiers audio à l'aide d' un synthétiseur vocal , qui s'exécutent au hasard après une heure de travail. Tant que vous ne faites pas de pause, il n'y aura pas d'alertes audio répétées.
def audio_message(path, here):
if here == 0:
pass
elif time.strftime('%H:%M:%S', time.gmtime(time.time()-here)) == "01:00:00":
wav = random.choice(os.listdir(path + r'\audio'))
winsound.PlaySound(path + r'\audio\\' + wav, winsound.SND_FILENAME)
Script de démarrage lors de la mise sous tension du PC
Pour que le programme se charge avec Windows, vous pouvez créer un fichier de commandes qui exécutera le script python. Le fichier batch doit se trouver dans le répertoire:
C: \ Users \% username% \ AppData \ Roaming \ Microsoft \ Windows \ Start Menu \ Programs \ Startup Le
fichier batch et le fichier source étant stockés dans des répertoires différents, vous ne pouvez pas utiliser os.getcwd ( ) car il renverra le chemin vers le fichier de commandes. Nous utilisons os.path.abspath (__ fichier __) [: - 11]
UPD: ak545a suggéré une meilleure option os.path.dirname (os.path.abspath (__ file__))
Dans le futur
Je voulais que le programme suive mon visage, et non tout le monde assis devant l'ordinateur. Pour cela, FaceNet sera utilisé, qui est capable de reconnaissance faciale.
Il est également prévu de développer un beau widget au lieu d'une vilaine console noire, et de sorte que lorsque l'ordinateur est éteint, l'enregistrement se fasse automatiquement, sans utiliser d'interruption.
Merci de votre attention. Si vous avez des questions, écrivez dans les commentaires ou sur https://www.linkedin.com/in/evg-voronov/