Donnez vie à votre application grâce à une enquête sur les défis rencontrés
En 2002 Steven Spielberg a réalisé un film sur des êtres capables de voir dans le futur — un sujet qui dépasse un peu cet article, même si j’aimerais m’attarder sur l’une de ses égéries — des caméras avec des scanners à iris permettant aux autorités et à la police de vous suivre partout.
Le balayage de l’iris est une technologie qu’Apple a commencé à intégrer dans ses iPhones avec le modèle X. Tech qu’ils appellent face-ID. Une fonctionnalité que vous pouvez utiliser bien plus que la simple reconnaissance des visages.
Vous pouvez, par exemple, l’utiliser pour suivre le regard de quelqu’un, le point sur un écran qu’il regarde. Rejoignez-moi dans cet article pour voir comment je peux faire passer l’accessibilité au niveau supérieur, en utilisant la puce de reconnaissance faciale de l’iPhone X pour créer une application contrôlée uniquement avec vos yeux.
Comme je l’ai déjà dit, pour utiliser cette technologie, vous aurez besoin d’un téléphone haut de gamme avec reconnaissance faciale – l’un des téléphones de ce liste. Bien sûr, je veux que vous continuiez à lire même si vous n’en avez pas, mais gardez cela à l’esprit si vous décidez d’essayer des choses.
Comme d’habitude, je voulais le faire avec une application basée sur SwiftUI ; J’aime les capacités de mise en page supérieures que vous obtenez avec le framework. J’ai donc commencé par un UIViewRepresentable
pour une instance SceneKit ARKit.
J’ai choisi SceneKit plutôt que RealityKit parce que je voulais un cadre AR défini à une distance spécifique ; Je ne voulais pas du tout que l’utilisateur ait à toucher le téléphone.
struct CustomARView: UIViewRepresentable {
typealias UIViewType = ARSCNViewvar view:ARSCNView
var options: [Any] = []
func makeUIView(context: Context) -> ARSCNView {
view.session.delegate = context.coordinator
return view
}
func updateUIView(_ view: ARSCNView, context: Context) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self.view)
}
}
Bon – alors vous l’avez deviné – j’ai ajouté la part du lion du code au coordinateur vu ici, bien qu’avant de montrer ledit code ici, voici un GIF de moi qui l’exécute.
Mon plus grand défi était de garder la tête droite vers la caméra pendant que j’essayais de suivre mon regard. Le problème, c’est un réflexe activé inconsciemment pour suivre votre regard avec votre tête. Un mouvement que vous remarquez à peine car vos yeux compensent.
Mais attendez — parce que si vous essayez d’utiliser l’appareil photo pour suivre votre regard et que vous bougez la tête, votre regard change — changeant les résultats que vous obtenez en retour.
Quoi qu’il en soit, pour coder – et voici le premier brouillon.
La clé ici est un tableau de formes de visage qui indiquent dans quelle direction vous regardez ; plus la valeur renvoyée par rapport à une forme est élevée, plus il est probable en théorie qu’elle corresponde.
Plus le nombre est bas, moins il est probable. J’ai donc utilisé 0,3 pour les gestes faciles, regarder à gauche, regarder en haut etc, et 0,2 pour ceux un peu plus difficiles, les coins. Quant aux formes, il y en a 52 en tout, bien plus que ce que je montre ici – des gestes que vous trouverez documentés ici.
Mais – comme je l’ai déjà mentionné, si vous bougez la tête, votre regard changera aussi puisque vos yeux suivront ce que vous regardez.
Bien sûr, tout a du sens; en regardant la réalisation de la vidéo Avatar 2, vous voyez les casques avec les caméras montées devant leurs visages. Une configuration que je comprends maintenant est là pour maintenir le suivi de mouvement stable et cohérent. C’était un luxe que je n’avais pas avec mon iPhone.
J’ai revu la documentation et essayé une syntaxe différente qui ressemblait à ceci. Le code était beaucoup plus court mais tout aussi décevant à mes yeux.
var newX = Float(faceAnchor.lookAtPoint.x) * 8
let newY = Float(faceAnchor.lookAtPoint.y) * 4let newXR = (newX * 100).rounded() / 100
let newYR = (newY * 100).rounded() / 100
print("sat \(satelliteNode.position)")
SCNTransaction.begin()
SCNTransaction.animationDuration = 1
sphereNode.simdPosition = SIMD3(x: newX, y: newY, z: -6)
SCNTransaction.commit()
Le principal problème était que je devais détourner le regard de l’écran pour faire bouger le marqueur; c’était déconcertant et cela ne semblait pas être un moyen raisonnable de contrôler quoi que ce soit.
J’ai réessayé, en utilisant la même idée que j’avais faite avec le papier de mon cube Rubik, en ajoutant un nœud enfant au cube et en mesurant la distance qu’il parcourait lorsque je changeais l’orientation de mon cube.
J’ai également ajouté quelques étiquettes indiquant les coordonnées X et Y du nœud enfant. Dans l’ensemble, un code qui ressemblait à ceci.
J’ai continué à jouer avec les variables, mais il était impossible d’imaginer que cela fonctionne dans un scénario réaliste. J’avais besoin de tenir compte du mouvement de la tête lorsque je cherchais le regard – j’avais l’impression d’avoir fait des progrès, avec cela une seconde me semblant à nouveau mortellement sérieux.
J’ai continué à jouer avec les variables, mais je ne pouvais pas imaginer que cela fonctionne dans un scénario réaliste.
J’ai codé par couleur les positions cette fois, donc le rouge est le centre, le bleu est à gauche et à droite et le vert est en haut et en bas. Mais c’était trop sensible à ce stade. Je n’ai pas essayé d’implémenter le corner focus avec ceci; J’avais besoin de trouver un meilleur plan.
J’étais sûr qu’Apple avait abordé et résolu ce problème ; J’avais juste besoin de mieux comprendre. je suis retourné à la blendedShapes
J’avais utilisé dans la première manche.
En lisant la documentation et en examinant de près l’ensemble du shebang, j’ai décidé d’apporter des modifications critiques.
La première était la méthode déléguée. Je suis passé à l’utilisation de la version updateAtTime du rendu et j’ai ajouté du code pour réduire le nombre de mises à jour à seulement quatre par seconde. Deuxièmement, j’ai ajouté une référence à l’angle du visage lui-même – de sorte que s’il dépassait huit degrés dans n’importe quelle direction, je désactiverais les commandes du regard. Enfin, j’ai utilisé les variables de regard comme valeurs à rechercher et valeurs pour discriminer les regards. Donc, si vous regardez vers le haut, il est clair que vous ne regardez pas vers le bas et si vous regardez vers la gauche, il est clair que vous ne regardez pas vers la droite.
Cela avait l’air mieux – l’angle de contrôle nécessitait un peu plus de travail, mais tant que vous étiez au bon endroit au démarrage en utilisant plus de variables de regard pour obtenir la direction, cela produisait moins de faux positifs.
Mais alors que j’essayais de l’accorder un peu plus, je me suis retrouvé face à un effet dont j’avais entendu parler en mécanique quantique mais que je n’avais jamais entièrement compris. Un problème connu sous le nom d’effet d’observateur, en fait, tout cela a commencé à ressembler un peu à du codage en robotique. Le défi avec le codage robotique est que lorsque vous dites à votre robot de tourner de 90 degrés, il peut y avoir une marge d’erreur. Donc les roues patinent et elles gèrent 89 degrés, ou il y a un dépassement et elles font 91 degrés.
Et bien, pour être honnête, obtenir des valeurs pour obtenir des résultats cohérents dans le monde de la RA semblait être la même chose. Le codage en dur de l’action à entreprendre avec les différents doubles renvoyés pour les formes mélangées n’allait jamais fonctionner efficacement à moins que j’ajoute beaucoup plus de cas – j’ai réfléchi au problème pendant quelques jours quand il m’est apparu que je pourrais peut-être utiliser le CreateML pour construire un modèle que je pourrais interroger. J’utiliserais le modèle pour décider dans quelle direction je regarde, en tenant compte de mes 9 variables.