Ich habe dieses Übungsprojekt, mit dem der Benutzer auf dem Bildschirm zeichnen kann, wenn er mit den Fingern berührt. Sehr einfache App, die ich vor langer Zeit als Übung gemacht habe. Mein kleiner Cousin hat sich erlaubt, mit meinem iPad in dieser App Dinge mit dem Finger zu zeichnen (Kinderzeichnungen: Kreis, Linien usw., was auch immer ihm in den Sinn kam). Dann fing er an, Kreise zu zeichnen, und dann bat er mich, einen "guten Kreis" zu machen (nach meinem Verständnis: Machen Sie den gezeichneten Kreis perfekt rund, da wir wissen, egal wie stabil wir versuchen, etwas mit dem Finger auf dem Bildschirm zu zeichnen, a Kreis ist nie wirklich so gerundet wie ein Kreis sein sollte).
Meine Frage hier ist also, ob es im Code eine Möglichkeit gibt, zuerst eine vom Benutzer gezeichnete Linie zu erkennen, die einen Kreis bildet, und ungefähr die gleiche Größe des Kreises zu erzeugen, indem wir ihn auf dem Bildschirm perfekt rund machen. Ich würde wissen, wie man eine nicht so gerade Linie gerade macht, aber was den Kreis betrifft, weiß ich nicht genau, wie ich es mit Quarz oder anderen Methoden machen soll.
Meine Argumentation ist, dass sich Start- und Endpunkt der Linie berühren oder kreuzen müssen, nachdem der Benutzer seinen Finger gehoben hat, um die Tatsache zu rechtfertigen, dass er versucht hat, tatsächlich einen Kreis zu zeichnen.
Antworten:
Manchmal ist es wirklich nützlich, etwas Zeit damit zu verbringen, das Rad neu zu erfinden. Wie Sie vielleicht bereits bemerkt haben, gibt es viele Frameworks, aber es ist nicht so schwer, eine einfache, aber dennoch nützliche Lösung zu implementieren, ohne all diese Komplexität einzuführen. (Bitte verstehen Sie mich nicht falsch, für jeden ernsthaften Zweck ist es besser, ein ausgereiftes und nachweislich stabiles Framework zu verwenden.)
Ich werde zuerst meine Ergebnisse präsentieren und dann die einfache und unkomplizierte Idee dahinter erläutern.
Sie werden sehen, dass in meiner Implementierung nicht jeder einzelne Punkt analysiert und komplexe Berechnungen durchgeführt werden müssen. Die Idee ist, einige wertvolle Metainformationen zu finden. Ich werde Tangente als Beispiel verwenden:
Lassen Sie uns ein einfaches und einfaches Muster identifizieren, das für die ausgewählte Form typisch ist:
Es ist also nicht so schwer, einen Kreiserkennungsmechanismus zu implementieren, der auf dieser Idee basiert. Siehe Arbeitsdemo unten (Entschuldigung, ich verwende Java als schnellsten Weg, um dieses schnelle und etwas schmutzige Beispiel bereitzustellen):
Es sollte kein Problem sein, ein ähnliches Verhalten unter iOS zu implementieren, da Sie nur mehrere Ereignisse und Koordinaten benötigen. So etwas wie das Folgende (siehe Beispiel ):
Es sind mehrere Verbesserungen möglich.
Beginnen Sie an einem beliebigen Punkt
Derzeit ist es aufgrund der folgenden Vereinfachung erforderlich, einen Kreis vom oberen Mittelpunkt aus zu zeichnen:
Bitte beachten Sie, dass der Standardwert von
index
verwendet wird. Eine einfache Suche durch die verfügbaren "Teile" der Form hebt diese Einschränkung auf. Bitte beachten Sie, dass Sie einen kreisförmigen Puffer verwenden müssen, um eine vollständige Form zu erkennen:Im Uhrzeigersinn und gegen den Uhrzeigersinn
Um beide Modi zu unterstützen, müssen Sie den Ringpuffer aus der vorherigen Erweiterung verwenden und in beide Richtungen suchen:
Zeichne eine Ellipse
Sie haben alles, was Sie brauchen, bereits im
bounds
Array.Verwenden Sie einfach diese Daten:
Andere Gesten (optional)
Schließlich müssen Sie nur eine Situation richtig behandeln, in der
dx
(oderdy
) gleich Null ist, um andere Gesten zu unterstützen:Aktualisieren
Dieser kleine PoC hat eine ziemlich hohe Aufmerksamkeit erhalten, daher habe ich den Code ein wenig aktualisiert, damit er reibungslos funktioniert und einige Zeichenhinweise enthält, unterstützende Punkte hervorhebt usw.:
Hier ist der Code:
quelle
Eine klassische Computer Vision-Technik zum Erkennen einer Form ist die Hough-Transformation. Eines der schönen Dinge an der Hough-Transformation ist, dass sie sehr tolerant gegenüber Teildaten, unvollständigen Daten und Rauschen ist. Verwenden von Hough für einen Kreis: http://en.wikipedia.org/wiki/Hough_transform#Circle_detection_process
Angesichts der Tatsache, dass Ihr Kreis von Hand gezeichnet ist, denke ich, dass die Hough-Transformation gut zu Ihnen passt.
Hier ist eine "vereinfachte" Erklärung, ich entschuldige mich dafür, dass es nicht wirklich so einfach ist. Ein Großteil davon stammt aus einem Schulprojekt, das ich vor vielen Jahren durchgeführt habe.
Die Hough-Transformation ist ein Abstimmungsschema. Ein zweidimensionales Array von Ganzzahlen wird zugewiesen und alle Elemente werden auf Null gesetzt. Jedes Element entspricht einem einzelnen Pixel im zu analysierenden Bild. Dieses Array wird als Akkumulatorarray bezeichnet, da jedes Element Informationen und Stimmen akkumuliert, was auf die Möglichkeit hinweist, dass sich ein Pixel am Ursprung eines Kreises oder Bogens befindet.
Ein Gradientenoperator-Kantendetektor wird auf das Bild angewendet und Kantenpixel oder Kanten werden aufgezeichnet. Ein Rand ist ein Pixel, das in Bezug auf seine Nachbarn eine andere Intensität oder Farbe aufweist. Der Grad der Differenz wird als Gradientengröße bezeichnet. Für jede Kante mit ausreichender Größe wird ein Abstimmungsschema angewendet, das Elemente des Akkumulatorarrays inkrementiert. Die Elemente, die inkrementiert (gewählt) werden, entsprechen den möglichen Ursprüngen von Kreisen, die durch den betrachteten Rand verlaufen. Das gewünschte Ergebnis ist, dass wenn ein Bogen existiert, der wahre Ursprung mehr Stimmen erhält als der falsche Ursprung.
Es ist zu beachten, dass Elemente des Akkumulatorarrays, die zur Abstimmung besucht werden, einen Kreis um den betrachteten Rand bilden. Die Berechnung der zu stimmenden x, y-Koordinaten entspricht der Berechnung der x, y-Koordinaten eines Kreises, den Sie zeichnen.
In Ihrem handgezeichneten Bild können Sie möglicherweise die festgelegten (farbigen) Pixel direkt verwenden, anstatt Kanten zu berechnen.
Mit unvollständig angeordneten Pixeln erhalten Sie nicht unbedingt ein einzelnes Akkumulator-Array-Element mit der größten Anzahl von Stimmen. Möglicherweise erhalten Sie eine Sammlung benachbarter Array-Elemente mit einer Reihe von Stimmen, einen Cluster. Der Schwerpunkt dieses Clusters kann eine gute Annäherung für den Ursprung bieten.
Beachten Sie, dass Sie möglicherweise die Hough-Transformation für verschiedene Werte des Radius R ausführen müssen. Diejenige, die den dichteren Stimmencluster erzeugt, ist die "bessere" Anpassung.
Es gibt verschiedene Techniken, um Stimmen für falsche Ursprünge zu reduzieren. Ein Vorteil der Verwendung von Kanten ist beispielsweise, dass sie nicht nur eine Größe haben, sondern auch eine Richtung. Bei der Abstimmung müssen wir nur für mögliche Ursprünge in die entsprechende Richtung stimmen. Die Orte, die Stimmen erhalten, würden eher einen Bogen als einen vollständigen Kreis bilden.
Hier ist ein Beispiel. Wir beginnen mit einem Kreis mit dem Radius eins und einem initialisierten Akkumulatorarray. Da jedes Pixel als potenzielle Herkunft betrachtet wird, wird abgestimmt. Der wahre Ursprung erhält die meisten Stimmen, in diesem Fall vier.
quelle
Hier ist ein anderer Weg. Verwenden von UIView touchBegan, touchMoved, touchEnded und Hinzufügen von Punkten zu einem Array. Sie teilen das Array in zwei Hälften und testen, ob jeder Punkt in einem Array ungefähr den gleichen Durchmesser wie sein Gegenstück im anderen Array hat wie alle anderen Paare.
Das klingt okay? :) :)
quelle
Ich bin kein Experte für Formerkennung, aber hier ist, wie ich das Problem angehen könnte.
Während Sie den Pfad des Benutzers als Freihand anzeigen, sammeln Sie zunächst heimlich eine Liste von Punkt- (x, y) Abtastwerten zusammen mit den Zeiten. Sie können beide Fakten aus Ihren Drag-Ereignissen abrufen, sie in ein einfaches Modellobjekt einwickeln und diese in einem veränderlichen Array stapeln.
Sie möchten die Proben wahrscheinlich ziemlich häufig entnehmen - beispielsweise alle 0,1 Sekunden. Eine andere Möglichkeit wäre, wirklich anzufangen häufig , vielleicht alle 0,05 Sekunden, und zu beobachten, wie lange der Benutzer schleppt. Wenn sie länger als eine gewisse Zeit ziehen, senken Sie die Sample-Frequenz (und lassen Sie alle Samples fallen, die übersehen worden wären) auf etwa 0,2 Sekunden.
(Und nimm meine Zahlen nicht für das Evangelium, weil ich sie einfach aus meinem Hut gezogen habe. Experimentiere und finde bessere Werte.)
Zweitens analysieren Sie die Proben.
Sie möchten zwei Fakten ableiten. Erstens das Zentrum der Form, das (IIRC) nur der Durchschnitt aller Punkte sein sollte. Zweitens der durchschnittliche Radius jeder Probe von diesem Zentrum.
Wenn Sie, wie @ user1118321 vermutet, Polygone unterstützen möchten, besteht der Rest der Analyse darin, diese Entscheidung zu treffen: ob der Benutzer einen Kreis oder ein Polygon zeichnen möchte. Sie können die Beispiele zunächst als Polygon betrachten, um diese Bestimmung vorzunehmen.
Es gibt verschiedene Kriterien, die Sie verwenden können:
Der dritte und letzte Schritt besteht darin, die Form, die auf dem zuvor bestimmten Mittelpunkt zentriert ist, mit dem zuvor bestimmten Radius zu erstellen.
Keine Garantie, dass alles, was ich oben gesagt habe, funktioniert oder effizient ist, aber ich hoffe, es bringt Sie zumindest auf den richtigen Weg - und bitte, wenn jemand, der mehr über Formerkennung weiß als ich (was ein sehr niedriger Balken ist), sieht Fühlen Sie sich frei, einen Kommentar oder Ihre eigene Antwort zu posten.
quelle
Ich hatte ziemlich viel Glück mit einem gut ausgebildeten 1-Dollar-Erkenner ( http://depts.washington.edu/aimgroup/proj/dollar/ ). Ich habe es für Kreise, Linien, Dreiecke und Quadrate verwendet.
Es war lange her, bevor UIGestureRecognizer, aber ich denke, es sollte einfach sein, richtige UIGestureRecognizer-Unterklassen zu erstellen.
quelle
Sobald Sie festgestellt haben, dass der Benutzer seine Form dort gezeichnet hat, wo er begonnen hat, können Sie eine Stichprobe der Koordinaten nehmen, durch die er gezeichnet hat, und versuchen, sie an einen Kreis anzupassen.
Hier gibt es eine MATLAB-Lösung für dieses Problem: http://www.mathworks.com.au/matlabcentral/fileexchange/15060-fitcircle-m
Was auf der Arbeit Least-Squares Fitting of Circles and Ellipses von Walter Gander, Gene H. Golub und Rolf Strebel basiert : http://www.emis.de/journals/BBMS/Bulletin/sup962/gander.pdf
Dr. Ian Coope von der University of Canterbury, Neuseeland, veröffentlichte einen Artikel mit der Zusammenfassung:
http://link.springer.com/article/10.1007%2FBF00939613
Die MATLAB-Datei kann sowohl das nichtlineare TLS- als auch das lineare LLS-Problem berechnen.
quelle
Hier ist eine ziemlich einfache Möglichkeit:
unter der Annahme dieses Matrixgitters:
Platzieren Sie einige UIViews an den "X" -Positionen und testen Sie sie (nacheinander) auf Treffer. Wenn sie alle nacheinander getroffen werden, ist es meiner Meinung nach fair, den Benutzer sagen zu lassen: "Gut gemacht, Sie haben einen Kreis gezeichnet."
Klingt okay? (und einfach)
quelle