J'ai ce projet pratique qui permet à l'utilisateur de dessiner sur l'écran en se touchant avec ses doigts. Application très simple que j'ai faite comme exercice. Mon petit cousin a pris la liberté de dessiner des choses avec son doigt avec mon iPad sur cette appli (dessins d'enfants: cercle, lignes, etc., tout ce qui lui venait à l'esprit). Puis il a commencé à dessiner des cercles, puis il m'a demandé de faire un "bon cercle" (d'après ce que j'ai compris: faites le cercle dessiné parfaitement rond, car nous savons quelle que soit la stabilité que nous essayons de dessiner avec notre doigt sur l'écran, un un cercle n'est jamais vraiment aussi arrondi qu'un cercle devrait l'être).
Ma question ici est donc la suivante: y a-t-il un moyen dans le code où nous pouvons d'abord détecter une ligne dessinée par l'utilisateur qui forme un cercle et générer approximativement la même taille du cercle en le rendant parfaitement rond sur l'écran. Faire une ligne droite pas si droite est quelque chose que je saurais faire, mais en ce qui concerne le cercle, je ne sais pas trop comment le faire avec Quartz ou d'autres méthodes.
Mon raisonnement est que le point de départ et le point final de la ligne doivent se toucher ou se croiser après que l'utilisateur lève son doigt pour justifier le fait qu'il essayait réellement de dessiner un cercle.
Réponses:
Parfois, il est vraiment utile de passer du temps à réinventer la roue. Comme vous l'avez peut-être déjà remarqué, il existe de nombreux frameworks, mais il n'est pas si difficile d'implémenter une solution simple mais utile sans introduire toute cette complexité. (S'il vous plaît ne vous méprenez pas, pour tout objectif sérieux, il est préférable d'utiliser un cadre mature et éprouvé pour être stable).
Je vais d'abord présenter mes résultats, puis expliquer l'idée simple et directe qui les sous-tend.
Vous verrez dans mon implémentation qu'il n'est pas nécessaire d'analyser chaque point et de faire des calculs complexes. L'idée est de repérer des méta-informations précieuses. J'utiliserai la tangente comme exemple:
Identifions un motif simple et direct, typique de la forme sélectionnée:
Il n'est donc pas si difficile de mettre en œuvre un mécanisme de détection de cercle basé sur cette idée. Voir la démo de travail ci-dessous (Désolé, j'utilise Java comme le moyen le plus rapide de fournir cet exemple rapide et un peu sale):
L'implémentation d'un comportement similaire sur iOS ne devrait pas poser de problème, car vous n'avez besoin que de plusieurs événements et coordonnées. Quelque chose comme ce qui suit (voir exemple ):
Il existe plusieurs améliorations possibles.
Commencez à tout moment
L'exigence actuelle est de commencer à dessiner un cercle à partir du point central supérieur en raison de la simplification suivante:
Veuillez noter que la valeur par défaut de
index
est utilisée. Une simple recherche dans les «parties» disponibles de la forme supprimera cette limitation. Veuillez noter que vous devrez utiliser un tampon circulaire pour détecter une forme complète:Dans le sens horaire et antihoraire
Afin de prendre en charge les deux modes, vous devrez utiliser le tampon circulaire de l'amélioration précédente et rechercher dans les deux sens:
Dessinez une ellipse
Vous avez déjà tout ce dont vous avez besoin dans le
bounds
tableau.Utilisez simplement ces données:
Autres gestes (facultatifs)
Enfin, il vous suffit de gérer correctement une situation où
dx
(oudy
) est égal à zéro afin de prendre en charge d'autres gestes:Mettre à jour
Ce petit PoC a attiré une grande attention, j'ai donc mis à jour un peu le code afin de le faire fonctionner correctement et de fournir des conseils de dessin, mettre en évidence les points de support, etc.:
Voici le code:
la source
Une technique classique de vision par ordinateur pour détecter une forme est la transformation de Hough. L'un des avantages de la transformation de Hough est qu'elle tolère très bien les données partielles, les données imparfaites et le bruit. Utilisation de Hough pour un cercle: http://en.wikipedia.org/wiki/Hough_transform#Circle_detection_process
Étant donné que votre cercle est dessiné à la main, je pense que la transformation de Hough peut vous convenir.
Voici une explication "simplifiée", je m'excuse de ne pas vraiment être aussi simple. Une grande partie provient d'un projet scolaire que j'ai réalisé il y a de nombreuses années.
La transformation de Hough est un système de vote. Un tableau à deux dimensions d'entiers est alloué et tous les éléments sont mis à zéro. Chaque élément correspond à un seul pixel de l'image en cours d'analyse. Ce tableau est appelé tableau accumulateur puisque chaque élément va accumuler des informations, des votes, indiquant la possibilité qu'un pixel puisse être à l'origine d'un cercle ou d'un arc.
Un détecteur de bord d'opérateur de gradient est appliqué à l'image et les pixels de bord, ou bords, sont enregistrés. Un edgel est un pixel qui a une intensité ou une couleur différente par rapport à ses voisins. Le degré de différence est appelé la magnitude du gradient. Pour chaque edgel d'une amplitude suffisante, un schéma de vote est appliqué qui incrémentera les éléments du tableau d'accumulateurs. Les éléments incrémentés (votés pour) correspondent aux origines possibles des cercles qui traversent l'edgel considéré. Le résultat souhaité est que si un arc existe, la véritable origine recevra plus de votes que les fausses origines.
Notez que les éléments du tableau d'accumulateurs visités pour voter forment un cercle autour de l'edgel considéré. Le calcul des coordonnées x, y pour lesquelles voter est le même que celui des coordonnées x, y d'un cercle que vous dessinez.
Dans votre image dessinée à la main, vous pourrez peut-être utiliser directement les pixels (colorés) définis plutôt que de calculer les bords.
Désormais, avec des pixels imparfaits, vous n'obtiendrez pas nécessairement un seul élément de tableau accumulateur avec le plus grand nombre de votes. Vous pouvez obtenir une collection d'éléments de tableau voisins avec un tas de votes, un cluster. Le centre de gravité de cet amas peut offrir une bonne approximation de l'origine.
Notez que vous devrez peut-être exécuter la transformation de Hough pour différentes valeurs de rayon R. Celui qui produit le groupe de votes le plus dense est le «meilleur» ajustement.
Il existe différentes techniques à utiliser pour réduire les votes pour les fausses origines. Par exemple, un avantage de l'utilisation des bordures est qu'ils ont non seulement une grandeur mais aussi une direction. Lors du vote, il suffit de voter pour les origines possibles dans la direction appropriée. Les lieux recevant des votes formeraient un arc plutôt qu'un cercle complet.
Voici un exemple. Nous commençons par un cercle de rayon un et un tableau d'accumulateurs initialisé. Comme chaque pixel est considéré, les origines potentielles sont votées. La véritable origine reçoit le plus de voix, ce qui dans ce cas est de quatre.
la source
Voici une autre manière. Utilisation de UIView touchesBegan, touchesMoved, touchesEnded et ajout de points à un tableau. Vous divisez le tableau en deux et testez si chaque point d'un tableau a à peu près le même diamètre que son homologue de l'autre tableau que toutes les autres paires.
Ça vous va? :)
la source
Je ne suis pas un expert en reconnaissance de formes, mais voici comment je pourrais aborder le problème.
Tout d'abord, tout en affichant le chemin de l'utilisateur à main levée, accumulez secrètement une liste d'échantillons ponctuels (x, y) avec les temps. Vous pouvez obtenir les deux faits à partir de vos événements de glissement, les envelopper dans un objet modèle simple et les empiler dans un tableau mutable.
Vous voudrez probablement prélever les échantillons assez fréquemment, disons toutes les 0,1 seconde. Une autre possibilité serait de commencer vraiment fréquemment, peut-être toutes les 0,05 secondes, et de regarder combien de temps l'utilisateur traîne; s'ils traînent plus longtemps qu'un certain temps, abaissez la fréquence d'échantillonnage (et déposez tous les échantillons qui auraient été manqués) à quelque chose comme 0,2 seconde.
(Et ne prenez pas mes chiffres pour un évangile, parce que je les ai simplement sortis de mon chapeau. Expérimentez et trouvez de meilleures valeurs.)
Deuxièmement, analysez les échantillons.
Vous voudrez tirer deux faits. Tout d'abord, le centre de la forme, qui (IIRC) devrait être juste la moyenne de tous les points. Deuxièmement, le rayon moyen de chaque échantillon à partir de ce centre.
Si, comme @ user1118321 l'a deviné, vous souhaitez prendre en charge les polygones, le reste de l'analyse consiste à prendre cette décision: si l'utilisateur souhaite dessiner un cercle ou un polygone. Vous pouvez commencer par regarder les échantillons comme un polygone pour effectuer cette détermination.
Vous pouvez utiliser plusieurs critères:
La troisième et dernière étape consiste à créer la forme, centrée sur le point central précédemment déterminé, avec le rayon précédemment déterminé.
Rien ne garantit que tout ce que j'ai dit ci-dessus fonctionnera ou sera efficace, mais j'espère que cela vous mettra au moins sur la bonne voie - et s'il vous plaît, si quelqu'un qui en sait plus sur la reconnaissance de forme que moi (qui est une barre très basse) voit cela, n'hésitez pas à poster un commentaire ou votre propre réponse.
la source
J'ai eu assez de chance avec un module de reconnaissance à 1 $ correctement formé ( http://depts.washington.edu/aimgroup/proj/dollar/ ). Je l'ai utilisé pour les cercles, les lignes, les triangles et les carrés.
C'était il y a longtemps, avant UIGestureRecognizer, mais je pense qu'il devrait être facile de créer des sous-classes UIGestureRecognizer appropriées.
la source
Une fois que vous avez déterminé que l'utilisateur a fini de dessiner sa forme là où il a commencé, vous pouvez prendre un échantillon des coordonnées qu'il a dessinées et essayer de les ajuster à un cercle.
Il existe une solution MATLAB à ce problème ici: http://www.mathworks.com.au/matlabcentral/fileexchange/15060-fitcircle-m
Ce qui est basé sur l'article Ajustement des moindres carrés de cercles et d'ellipses par Walter Gander, Gene H. Golub et Rolf Strebel: http://www.emis.de/journals/BBMS/Bulletin/sup962/gander.pdf
Le Dr Ian Coope de l'Université de Canterbury, NZ a publié un article avec le résumé:
http://link.springer.com/article/10.1007%2FBF00939613
Le fichier MATLAB peut calculer à la fois le problème TLS non linéaire et LLS linéaire.
la source
Voici un moyen assez simple d'utiliser:
en supposant cette grille matricielle:
Placez quelques UIViews sur les emplacements "X" et testez-les pour devenir touchés (dans l'ordre). S'ils sont tous touchés dans l'ordre, je pense qu'il pourrait être juste de laisser l'utilisateur dire "Bravo, vous avez dessiné un cercle"
Ça vous va? (et simple)
la source