Nach meiner vorherigen Frage zum Finden von Zehen in jeder Pfote begann ich, andere Messungen zu laden, um zu sehen, wie es halten würde. Leider stieß ich schnell auf ein Problem mit einem der vorhergehenden Schritte: Erkennen der Pfoten.
Sie sehen, mein Proof of Concept hat im Grunde genommen den maximalen Druck jedes Sensors über die Zeit genommen und würde anfangen, nach der Summe jeder Zeile zu suchen, bis er darauf findet! = 0.0. Dann macht es dasselbe für die Spalten und sobald es mehr als 2 Zeilen findet, sind diese wieder Null. Es speichert die minimalen und maximalen Zeilen- und Spaltenwerte in einem Index.
Wie Sie in der Abbildung sehen können, funktioniert dies in den meisten Fällen recht gut. Dieser Ansatz hat jedoch viele Nachteile (abgesehen davon, dass er sehr primitiv ist):
Menschen können "hohle Füße" haben, was bedeutet, dass sich innerhalb des Fußabdrucks selbst mehrere leere Reihen befinden. Da ich befürchtete, dass dies auch bei (großen) Hunden passieren könnte, wartete ich auf mindestens 2 oder 3 leere Reihen, bevor ich die Pfote abschnitt.
Dies führt zu einem Problem, wenn ein anderer Kontakt in einer anderen Spalte hergestellt wird, bevor er mehrere leere Zeilen erreicht, wodurch der Bereich erweitert wird. Ich glaube, ich könnte die Spalten vergleichen und sehen, ob sie einen bestimmten Wert überschreiten. Es müssen separate Pfoten sein.
Das Problem wird schlimmer, wenn der Hund sehr klein ist oder schneller läuft. Was passiert ist, dass die Zehen der Vorderpfote immer noch Kontakt haben, während die Zehen der Hinterpfote gerade im gleichen Bereich wie die Vorderpfote Kontakt aufnehmen!
Mit meinem einfachen Skript kann es diese beiden nicht aufteilen, da es bestimmen müsste, welche Frames dieses Bereichs zu welcher Pfote gehören, während ich derzeit nur die Maximalwerte über alle Frames betrachten müsste.
Beispiele dafür, wo es schief geht:
Jetzt suche ich nach einer besseren Möglichkeit, die Pfoten zu erkennen und zu trennen (danach komme ich zum Problem, zu entscheiden, um welche Pfote es sich handelt!).
Aktualisieren:
Ich habe versucht, Joes (großartige!) Antwort umzusetzen, aber ich habe Schwierigkeiten, die tatsächlichen Pfoten-Daten aus meinen Dateien zu extrahieren.
Die coded_paws zeigen mir alle verschiedenen Pfoten, wenn sie auf das Bild mit maximalem Druck angewendet werden (siehe oben). Die Lösung geht jedoch über jeden Frame (um überlappende Pfoten zu trennen) und legt die vier Rechteckattribute fest, z. B. Koordinaten oder Höhe / Breite.
Ich kann nicht herausfinden, wie ich diese Attribute in einer Variablen speichern kann, die ich auf die Messdaten anwenden kann. Da ich für jede Pfote wissen muss, wo sie sich in welchen Frames befindet, und diese mit der Pfote koppeln muss (vorne / hinten, links / rechts).
Wie kann ich die Rechteck-Attribute verwenden, um diese Werte für jede Pfote zu extrahieren?
Ich habe die Messungen, die ich im Fragen-Setup verwendet habe, in meinem öffentlichen Dropbox-Ordner ( Beispiel 1 , Beispiel 2 , Beispiel 3 ). Für alle Interessierten habe ich auch einen Blog eingerichtet , um euch auf dem Laufenden zu halten :-)
quelle
Antworten:
Wenn Sie nur (halb) zusammenhängende Regionen möchten, gibt es in Python bereits eine einfache Implementierung: SciPy ‚s ndimage.morphology Modul. Dies ist eine ziemlich häufige Bildmorphologieoperation .
Grundsätzlich haben Sie 5 Schritte:
Verwischen Sie die Eingabedaten ein wenig, um sicherzustellen, dass die Pfoten einen kontinuierlichen Fußabdruck haben. (Es wäre effizienter, nur einen größeren Kernel zu verwenden (das
structure
Kwarg für die verschiedenenscipy.ndimage.morphology
Funktionen), aber dies funktioniert aus irgendeinem Grund nicht ganz richtig ...)Schwellenwert für das Array, sodass Sie ein boolesches Array von Stellen haben, an denen der Druck über einem bestimmten Schwellenwert liegt (dh
thresh = data > value
)Füllen Sie alle inneren Löcher, damit Sie sauberere Bereiche haben (
filled = sp.ndimage.morphology.binary_fill_holes(thresh)
)Finden Sie die einzelnen zusammenhängenden Regionen (
coded_paws, num_paws = sp.ndimage.label(filled)
). Dies gibt ein Array mit den durch die Nummer codierten Regionen zurück (jede Region ist ein zusammenhängender Bereich einer eindeutigen Ganzzahl (1 bis zur Anzahl der Pfoten) mit Nullen überall sonst)).Isolieren Sie die zusammenhängenden Bereiche mit
data_slices = sp.ndimage.find_objects(coded_paws)
. Dies gibt eine Liste von Tupeln vonslice
Objekten zurück, sodass Sie den Bereich der Daten für jede Pfote mit abrufen können[data[x] for x in data_slices]
. Stattdessen zeichnen wir ein Rechteck basierend auf diesen Slices, was etwas mehr Arbeit erfordert.Die beiden folgenden Animationen zeigen Ihre Beispieldaten "Überlappende Pfoten" und "Gruppierte Pfoten". Diese Methode scheint perfekt zu funktionieren. (Und was auch immer es wert ist, dies läuft viel reibungsloser als die GIF-Bilder unten auf meinem Computer, so dass der Pfotenerkennungsalgorithmus ziemlich schnell ist ...)
Hier ist ein vollständiges Beispiel (jetzt mit viel detaillierteren Erklärungen). Die überwiegende Mehrheit davon liest die Eingabe und erstellt eine Animation. Die eigentliche Pfotenerkennung besteht nur aus 5 Codezeilen.
Update: Um festzustellen, welche Pfote zu welchen Zeiten mit dem Sensor in Kontakt steht, besteht die einfachste Lösung darin, nur dieselbe Analyse durchzuführen, aber alle Daten gleichzeitig zu verwenden. (dh stapeln Sie die Eingabe in ein 3D-Array und arbeiten Sie damit anstelle der einzelnen Zeitrahmen.) Da die ndimage-Funktionen von SciPy für n-dimensionale Arrays vorgesehen sind, müssen wir die ursprüngliche Pfotenfindungsfunktion nicht ändern überhaupt.
quelle
convert *.png output.gif
. Ich hatte sicherlich schon einmal Imagemagick, der meine Maschine in die Knie zwang, obwohl es in diesem Beispiel gut funktioniert hat. In der Vergangenheit habe ich dieses Skript verwendet: svn.effbot.python-hosting.com/pil/Scripts/gifmaker.py , um ein animiertes GIF direkt aus Python zu schreiben, ohne die einzelnen Frames zu speichern. Hoffentlich hilft das! Ich werde ein Beispiel bei der genannten Frage @unutbu posten.bbox_inches='tight'
in derplt.savefig
, der andere war Ungeduld :)Ich bin kein Experte für Bilderkennung und kenne Python nicht, aber ich werde es versuchen ...
Um einzelne Pfoten zu erkennen, sollten Sie zunächst nur alles auswählen, dessen Druck über einem kleinen Schwellenwert liegt und der nahezu keinem Druck entspricht. Jedes Pixel / jeder Punkt darüber sollte "markiert" sein. Dann wird jedes Pixel neben allen "markierten" Pixeln markiert, und dieser Vorgang wird einige Male wiederholt. Es würden sich Massen bilden, die vollständig miteinander verbunden sind, sodass Sie unterschiedliche Objekte haben. Dann hat jedes "Objekt" einen minimalen und maximalen x- und y-Wert, so dass Begrenzungsrahmen ordentlich um sie herum gepackt werden können.
Pseudocode:
(MARK) ALL PIXELS ABOVE (0.5)
(MARK) ALL PIXELS (ADJACENT) TO (MARK) PIXELS
REPEAT (STEP 2) (5) TIMES
SEPARATE EACH TOTALLY CONNECTED MASS INTO A SINGLE OBJECT
MARK THE EDGES OF EACH OBJECT, AND CUT APART TO FORM SLICES.
Das sollte es ungefähr tun.
quelle
Hinweis: Ich sage Pixel, aber dies können Regionen sein, die einen Durchschnitt der Pixel verwenden. Optimierung ist ein weiteres Problem ...
Klingt so, als müssten Sie für jedes Pixel eine Funktion (Druck über die Zeit) analysieren und bestimmen, wohin sich die Funktion dreht (wenn sich> X in die andere Richtung ändert, wird dies als Drehung angesehen, um Fehlern entgegenzuwirken).
Wenn Sie wissen, an welchen Rahmen es sich dreht, kennen Sie den Rahmen, in dem der Druck am stärksten war, und Sie wissen, wo er zwischen den beiden Pfoten am wenigsten hart war. Theoretisch kennen Sie dann die beiden Frames, in denen die Pfoten am stärksten gedrückt haben, und können einen Durchschnitt dieser Intervalle berechnen.
Dies ist die gleiche Tour wie zuvor. Wenn Sie wissen, wann jede Pfote den größten Druck ausübt, können Sie sich entscheiden.
quelle