Bonjour, citoyens Habrovsk! EastBanc Technologies a un grand nombre de projets liés au développement mobile. À cet égard, tout un zoo d'appareils est nécessaire pour les tests à toutes les étapes. Et, de manière caractéristique, chaque appareil est constamment nécessaire à une variété de personnes, et le trouver même dans un département de développement mobile de plusieurs dizaines de personnes est toute une histoire. Sans oublier qu'il y a finalement des testeurs, des designers, des PM!
Et pour ne pas perdre le téléphone, mais pour savoir clairement où il se trouve et avec qui, nous utilisons une base de données en ligne qui reconnaît les employés à leurs visages. Maintenant, nous allons dire comment nous en sommes arrivés à cela et l'avons mis en œuvre.

Contexte historique
Nous avions un tableau avec des «cartes» d'appareils avec des informations de base et une place pour un aimant indiquant un employé. Tout le monde a noté la prise de l'appareil.

Ce système a ses inconvénients - pas critique, mais généralement inconfortable:
- Les aimants ne sont pas si faciles à déplacer d'un endroit à un autre.
- Pour regarder un tel tableau, vous devrez certainement vous rendre dans un autre bureau.
- Et pourtant, quelqu'un peut avoir besoin de plusieurs appareils à la fois ... Ce qui signifie que vous avez besoin de plusieurs aimants par employé.
- Oh oui, même les employés arrêtent parfois et de nouveaux viennent, sur lesquels des aimants doivent également être fabriqués.
Application mobile
Dans une entreprise engagée dans l'automatisation des processus métier, l'utilisation de la solution «analogique» décrite ci-dessus n'est pas très saine. Naturellement, nous avons décidé d'automatiser la tâche de trouver le bon appareil. La première étape a été d'écrire une application mobile qui peut déterminer et signaler son emplacement dans les chambres via des points d'accès Wi-Fi. En cours de route, pour plus de commodité, ils ont donné à l'appareil la possibilité d'informer le serveur de la version du système d'exploitation, et montrent également une caractéristique aussi importante que la charge de la batterie.
Il semblerait que le problème soit résolu. Vous regardez la liste dans la base de données où la dernière fois que l'appareil a vu le Wi-Fi, vous y allez et ...
En fonctionnement, il s'est avéré que tout n'est pas si simple. Nous avons installé l'application sur des appareils de test et l'avons utilisée pendant plusieurs mois. Il s'est avéré que cette option est pratique, mais pas idéale non plus.
Les appareils sont déchargés, ils s'éteignent simplement, les points d'accès Wi-Fi sont réorganisés d'un endroit à un autre, et la géolocalisation à elle seule indique seulement que l'appareil est au bureau. Merci capitaine!
Vous pouvez bien sûr essayer d'optimiser le système existant, mais pourquoi ne pas le réinventer à partir des technologies du 21e siècle? Aussitôt dit, aussitôt fait.
Comment nous voulions que ce soit
Nous avons trouvé un concept pour un système qui reconnaîtrait les employés par leurs visages, testerait les appareils par des étiquettes spéciales, demanderait la confirmation d'un changement d'état de l'appareil, puis apporterait des modifications à la base de données en ligne, que tout employé peut voir sans se lever de sa chaise.
Reconnaissance faciale
La reconnaissance faciale dans son ensemble a résolu le problème en 2018. Par conséquent, nous n'avons pas réinventé la roue et essayé de former nos propres modèles, mais avons profité d'une solution toute faite. Le module
FaceRecognition semblait être l'option la plus pratique, car il ne nécessite pas de formation supplémentaire et fonctionne très rapidement même sans accélération sur le GPU.
À l'aide de la fonction
face_locations , des
visages ont été détectés sur les photos des employés et à l'aide de
face_encodings, les traits du visage d'un employé particulier en ont été extraits.
Les données reçues ont été collectées dans la base de données. Pour déterminer un employé spécifique à l'aide de la fonction
face_distance , la «différence» entre l'encodage de l'employé détecté et les encodages de la base de données a été prise en compte.
En général, à ce stade, on pourrait aller plus loin et créer un classifieur, par exemple, basé sur
KNN , afin que le système soit moins sensible à la dynamique des visages des salariés. Cependant, en pratique, cela nécessite beaucoup plus de temps. Et la moyenne banale de l'encodage du visage d'une personne entre celui qui est maintenant dans la base de données et celui que le système a trouvé pour changer le statut de l'appareil s'est avéré suffisant pour éviter d'accumuler des erreurs dans la pratique.
Code de reconnaissance facialeface_locations = face_recognition.face_locations(rgb_small_frame) face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations) face_names = [] for face_encoding in face_encodings: matches = face_recognition.face_distance( known_face_encodings, face_encoding) name = "Unknown" if np.min(matches) <= 0.45: best_match_index = np.argmin(matches) name = known_face_info[str(best_match_index)]['name'] else: best_match_index = None
Reconnaissance de l'appareil
Initialement, l'idée est venue d'utiliser
des codes QR pour la reconnaissance de l'appareil, dans lesquels entrer en même temps des informations sur l'appareil. Cependant, pour une reconnaissance stable du code QR, il fallait le rapprocher très près de la caméra, ce qui n'est pas pratique.
En conséquence, l'idée est venue d'utiliser des marqueurs de réalité augmentée. Ils portent moins d'informations, mais sont beaucoup plus stables. Au cours des expériences, un marqueur de 30 millimètres a été reconnu par la caméra avec de petits écarts par rapport à la verticale (3 à 5 degrés) à une distance pouvant atteindre deux mètres et demi.
Cette option était déjà bien meilleure.
ARuco a été choisi parmi l'ensemble des
marqueurs de réalité augmentée, comme tous les outils nécessaires pour travailler avec eux sont présents dans la
distribution opencv-contrib-python .
Code de reconnaissance de jeton ARuco self.video_capture = cv2.VideoCapture(0) ret, frame = self.video_capture.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) markers = cv2.aruco.detectMarkers(gray, self.dictionary)
En conséquence, chaque appareil s'est vu attribuer un index numérique, auquel un marqueur était associé à cet index.
C'est un truc de chapeau?
Il semblerait que nous ayons appris à reconnaître les appareils et les visages, le travail est fait. Fanfare, applaudissements! Quoi d'autre pourrait être nécessaire?
En fait, le travail ne fait que commencer. Désormais, tous les composants du système doivent fonctionner de manière stable et rapide «au combat».
Il est nécessaire d'optimiser le coût des ressources du serveur en veille, de réfléchir aux cas d'utilisateurs et de comprendre à quoi cela devrait ressembler graphiquement.
Interface
L'interface est peut-être le point le plus important dans le développement de tels systèmes. Quelqu'un peut argumenter, mais l'utilisateur est l'élément central de cette situation.
Le plus rapidement possible, vous pouvez implémenter la partie frontale à l'aide de
Tkinter .
Quelques notes sur Tkinter L'interface se compose de cartes avec des informations sur l'appareil et l'utilisateur qui utilise actuellement cet appareil. La majeure partie de l'écran est occupée par le catalogue de cartes - le principal outil de comptabilité. En haut, il y a un filtre avec lequel vous pouvez filtrer le répertoire par plate-forme ou version du système d'exploitation.

Voici les composants clés de l'interface:
- Périphérique
Les cartes d'appareil sont affichées à l'écran avec la version du système d'exploitation, le nom et l'ID de l'appareil, ainsi que l'utilisateur sur lequel cet appareil est actuellement enregistré. - Photofixing
Sur la droite se trouve l'unité de contrôle, où l'image de la webcam est affichée, ainsi que des boutons pour enregistrer et modifier les informations personnelles.
Nous affichons l'image pour donner des commentaires à l'utilisateur - vous frappez certainement l'écran avec l'étiquette de l'appareil. - Sélection de la version du système d'exploitation
Nous avons fait une liste avec le choix de la version du système d'exploitation qui vous intéresse, car souvent pour les tests, vous n'avez pas besoin d'un appareil spécifique, mais d'une certaine version d'Android ou iOS. Le filtre de version est rendu horizontal pour économiser de l'espace et rendre la liste des versions accessible sans défilement, sur un seul écran.
Optimisation
Un passage de n'importe quel composant du système ne prend pas trop de temps. Cependant, si vous démarrez la reconnaissance des marqueurs et des visages en même temps, une tentative de reconnaître les 30 images par seconde fournies par la caméra entraînera un épuisement complet des ressources informatiques sans GPU.
Il est clair que 99% du temps, le système fera ce travail au ralenti.
Pour éviter cela, les décisions d'optimisation suivantes ont été prises:
- Seule une huitième image est introduite dans le traitement.
Code if self.lastseen + self.rec_threshold > time.time() or self.frame_number != 8: ret, frame = self.video_capture.read() self.frame_number += 1 if self.frame_number > 8: self.frame_number = 8 return frame, None, None, None
Le délai de réponse du système s'élève à environ 8/30 secondes, tandis que le temps de réaction humain est d'environ une seconde. En conséquence, un tel retard ne sera toujours pas perceptible par l'utilisateur. Et nous avons déjà réduit huit fois la charge du système. - Tout d'abord, le marqueur de l'appareil est recherché dans le cadre, et uniquement lorsqu'il est détecté, la reconnaissance faciale est lancée. Étant donné que la recherche de marqueurs dans le cadre est environ 300 fois moins coûteuse que la recherche de visages, nous avons décidé qu'en mode veille, nous ne vérifierons que la présence d'un marqueur.
- Pour réduire les «freins» lors de la recherche de visages lorsqu'il n'y a aucun visage dans l'image, le paramètre number_of_time_to_upsample a été désactivé dans la fonction face_locations.
face_locations = face_recognition.face_locations (rgb_small_frame, number_of_times_to_upsample = 0)
De ce fait, le temps de traitement d'une image sur laquelle il n'y a pas de visages est égal au temps de traitement d'une image où les visages sont facilement détectés.
Quel est le résultat?
À l'heure actuelle, le système a été déployé avec succès sur le MacMini fin 2009, qui est venu à portée de main, sur deux cœurs Core 2 Duo. Dans le cadre des tests, il a fonctionné avec succès, même sur un cœur virtuel avec 1024 mégaoctets de RAM et 4 gigaoctets de mémoire morte dans le conteneur Docker. MacMini a connecté un écran tactile pour rendre le look minimaliste.
Maintenant, même les utilisateurs qui n'ont pas utilisé l'ancienne carte avec enthousiasme et sourient à l'enregistrement des appareils sur eux-mêmes, et il y a eu beaucoup moins de cas de recherches infructueuses!
Et ensuite?
Il y a sans aucun doute beaucoup plus de points dans le système actuel que nous pouvons et voudrions améliorer:
- Assurez-vous que les contrôles du système d'exploitation n'apparaissent pas lorsque des boîtes de dialogue apparaissent (il s'agit maintenant d'une boîte de message du package Tkinter).
- Séparez les calculs et les demandes de serveur dans différents threads avec le traitement de l'interface (maintenant ils sont effectués dans le thread principal, mainloop Tkinter, qui fige l'interface lors de l'envoi de requêtes à la base de données en ligne).
- Apportez l'interface à la même conception avec d'autres ressources d'entreprise.
- Créez une interface Web complète pour la visualisation à distance des données.
- Utilisez la reconnaissance vocale pour confirmer / annuler les actions et remplir les champs de texte.
- Implémentez l'enregistrement de plusieurs appareils simultanément.
PS Et voici comment cela fonctionne.Vidéo enregistrée en version bêta de l'interface graphique