Ich helfe einer Tierklinik, den Druck unter einer Hundepfote zu messen. Ich benutze Python für meine Datenanalyse und versuche jetzt nicht mehr, die Pfoten in (anatomische) Unterregionen zu unterteilen.
Ich habe aus jeder Pfote ein 2D-Array erstellt, das aus den Maximalwerten für jeden Sensor besteht, der im Laufe der Zeit von der Pfote geladen wurde. Hier ist ein Beispiel für eine Pfote, bei der ich Excel verwendet habe, um die Bereiche zu zeichnen, die ich "erkennen" möchte. Dies sind 2 mal 2 Kästchen um den Sensor mit lokalen Maxima, die zusammen die größte Summe haben.
Also habe ich ein bisschen experimentiert und mich entschlossen, einfach nach den Maxima jeder Spalte und Zeile zu suchen (kann aufgrund der Form der Pfote nicht in eine Richtung schauen). Dies scheint die Position der einzelnen Zehen ziemlich gut zu "erkennen", markiert aber auch benachbarte Sensoren.
Was wäre der beste Weg, um Python zu sagen, welche dieser Maxima ich möchte?
Hinweis: Die 2x2 Quadrate können sich nicht überlappen, da es sich um separate Zehen handeln muss!
Ich habe auch 2x2 als Annehmlichkeit genommen, jede fortgeschrittenere Lösung ist willkommen, aber ich bin einfach ein Wissenschaftler für menschliche Bewegung, also bin ich weder ein richtiger Programmierer noch ein Mathematiker, also halte es bitte 'einfach'.
Hier ist eine Version, die mit geladen werden kannnp.loadtxt
Ergebnisse
Also habe ich die Lösung von @ jextee ausprobiert (siehe die Ergebnisse unten). Wie Sie sehen können, funktioniert es sehr gut an den Vorderpfoten, aber weniger gut an den Hinterbeinen.
Insbesondere kann es den kleinen Gipfel, der der vierte Zeh ist, nicht erkennen. Dies hängt offensichtlich damit zusammen, dass die Schleife von oben nach unten zum niedrigsten Wert schaut, ohne zu berücksichtigen, wo sich dieser befindet.
Würde jemand wissen, wie man den Algorithmus von @ jextee optimiert, damit er möglicherweise auch den 4. Zeh findet?
Da ich noch keine anderen Versuche bearbeitet habe, kann ich keine weiteren Proben liefern. Aber die Daten, die ich zuvor gegeben habe, waren die Durchschnittswerte jeder Pfote. Diese Datei ist ein Array mit den maximalen Daten von 9 Pfoten in der Reihenfolge, in der sie mit der Platte in Kontakt gekommen sind.
Dieses Bild zeigt, wie sie räumlich über die Platte verteilt waren.
Aktualisieren:
Ich habe ein Blog für alle Interessierten eingerichtet und ein SkyDrive mit allen Rohmessungen eingerichtet. Also an alle, die mehr Daten anfordern: mehr Leistung für Sie!
Neues Update:
Nach der Hilfe bekam ich meine Fragen zur Pfotenerkennung und zum Sortieren der Pfoten , konnte ich endlich die Zehenerkennung für jede Pfote überprüfen! Es stellt sich heraus, dass es nur bei Pfoten funktioniert, die so groß sind wie in meinem Beispiel. Natürlich im Nachhinein ist es meine eigene Schuld, dass ich den 2x2 so willkürlich gewählt habe.
Hier ist ein schönes Beispiel dafür, wo es schief geht: Ein Nagel wird als Zeh erkannt und die 'Ferse' ist so breit, dass sie zweimal erkannt wird!
Die Pfote ist zu groß, sodass bei einer Größe von 2 x 2 ohne Überlappung einige Zehen zweimal erkannt werden. Umgekehrt findet man bei kleinen Hunden oft keinen fünften Zeh, was vermutlich darauf zurückzuführen ist, dass der 2x2-Bereich zu groß ist.
Nachdem ich die aktuelle Lösung für alle meine Messungen ausprobiert habe ich kam ich zu dem erstaunlichen Schluss, dass für fast alle meine kleinen Hunde kein fünfter Zeh gefunden wurde und dass in über 50% der Auswirkungen für die großen Hunde mehr gefunden werden würde!
Also klar, ich muss es ändern. Meine eigene Vermutung war, die Größe des neighborhood
zu etwas kleiner für kleine Hunde und größer für große Hunde zu ändern . Aber generate_binary_structure
ich würde nicht die Größe des Arrays ändern lassen.
Daher hoffe ich, dass jemand anderes einen besseren Vorschlag zum Lokalisieren der Zehen hat, vielleicht mit der Zehenbereichsskala mit der Pfotengröße?
quelle
Antworten:
Ich habe die Peaks mit einem lokalen Maximalfilter erkannt . Hier ist das Ergebnis Ihres ersten Datensatzes mit 4 Pfoten:
Ich habe es auch auf dem zweiten Datensatz von 9 Pfoten ausgeführt und es hat auch funktioniert .
So geht's:
Alles, was Sie danach tun müssen, ist die Verwendung
scipy.ndimage.measurements.label
der Maske, um alle unterschiedlichen Objekte zu beschriften. Dann können Sie individuell mit ihnen spielen.Beachten Sie, dass die Methode gut funktioniert, da der Hintergrund nicht verrauscht ist. Wenn dies der Fall wäre, würden Sie eine Reihe anderer unerwünschter Spitzen im Hintergrund erkennen. Ein weiterer wichtiger Faktor ist die Größe der Nachbarschaft . Sie müssen es anpassen, wenn sich die Peakgröße ändert (die sollte ungefähr proportional bleiben).
quelle
Lösung
Datendatei : paw.txt . Quellcode:
Ausgabe ohne überlappende Quadrate. Es scheint, dass die gleichen Bereiche wie in Ihrem Beispiel ausgewählt sind.
Einige Kommentare
Der schwierige Teil besteht darin, die Summen aller 2x2 Quadrate zu berechnen. Ich nahm an, dass Sie alle brauchen, daher kann es zu Überschneidungen kommen. Ich habe Slices verwendet, um die ersten / letzten Spalten und Zeilen aus dem ursprünglichen 2D-Array auszuschneiden, sie dann alle miteinander zu überlappen und Summen zu berechnen.
Um es besser zu verstehen, stellen Sie sich ein 3x3-Array vor:
Dann können Sie seine Scheiben nehmen:
Stellen Sie sich nun vor, Sie stapeln sie übereinander und summieren Elemente an denselben Positionen. Diese Summen sind genau die gleichen Summen über den 2x2 Quadraten, wobei sich die obere linke Ecke an derselben Position befindet:
Wenn Sie die Summen über 2x2 Quadrate haben, können
max
Sie das Maximum odersort
odersorted
die Spitzen ermitteln.Um mich an die Positionen der Peaks zu erinnern, kopple ich jeden Wert (die Summe) mit seiner Ordnungsposition in einem abgeflachten Array (siehe
zip
). Dann berechne ich die Zeilen- / Spaltenposition erneut, wenn ich die Ergebnisse drucke.Anmerkungen
Ich habe zugelassen, dass sich die 2x2-Quadrate überlappen. Die bearbeitete Version filtert einige davon heraus, sodass in den Ergebnissen nur nicht überlappende Quadrate angezeigt werden.
Finger wählen (eine Idee)
Ein weiteres Problem ist die Auswahl der Finger aus allen Spitzen. Ich habe eine Idee, die funktionieren kann oder nicht. Ich habe momentan keine Zeit, es zu implementieren, also nur Pseudocode.
Mir ist aufgefallen, dass sich der hintere Finger innerhalb dieses Kreises befinden sollte, wenn die vorderen Finger auf einem fast perfekten Kreis bleiben. Auch die Vorderfinger sind mehr oder weniger gleichmäßig beabstandet. Wir können versuchen, diese heuristischen Eigenschaften zu verwenden, um die Finger zu erkennen.
Pseudocode:
Dies ist ein Brute-Force-Ansatz. Wenn N relativ klein ist, denke ich, dass es machbar ist. Für N = 12 gibt es C_12 ^ 5 = 792 Kombinationen, mal 5 Möglichkeiten, einen hinteren Finger auszuwählen, also 3960 Fälle, die für jede Pfote ausgewertet werden müssen.
quelle
Dies ist ein Problem bei der Bildregistrierung . Die allgemeine Strategie lautet:
Hier ist ein grober und vorgefertigter Ansatz , "das Dümmste, was möglicherweise funktionieren könnte":
Um dem Orientierungsproblem entgegenzuwirken, können Sie ungefähr 8 Grundeinstellungen für die Grundeinstellungen (Nord, Nordost usw.) vornehmen. Führen Sie jedes einzeln aus und werfen Sie alle Ergebnisse weg, bei denen zwei oder mehr Zehen am selben Pixel landen. Ich werde noch etwas darüber nachdenken, aber so etwas wird in der Bildverarbeitung noch erforscht - es gibt keine richtigen Antworten!
Etwas komplexere Idee: (gewichtet) K-bedeutet Clustering. Ist doch nicht so schlimm.
Dann iterieren bis zur Konvergenz:
Diese Methode liefert mit ziemlicher Sicherheit viel bessere Ergebnisse, und Sie erhalten die Masse jedes Clusters, die bei der Identifizierung der Zehen hilfreich sein kann.
(Auch hier haben Sie die Anzahl der Cluster im Voraus angegeben. Beim Clustering müssen Sie die Dichte auf die eine oder andere Weise angeben: Wählen Sie entweder die Anzahl der in diesem Fall geeigneten Cluster aus oder wählen Sie einen Clusterradius und sehen Sie, wie viele Sie beenden Ein Beispiel für Letzteres ist die Mittelwertverschiebung .)
Entschuldigung für das Fehlen von Implementierungsdetails oder anderen Besonderheiten. Ich würde das verschlüsseln, aber ich habe eine Frist. Wenn bis nächste Woche nichts anderes funktioniert hat, lass es mich wissen und ich werde es versuchen.
quelle
Bei Verwendung einer persistenten Homologie zur Analyse Ihres Datensatzes erhalte ich das folgende Ergebnis (zum Vergrößern anklicken):
Dies ist die 2D-Version der in dieser SO-Antwort beschriebenen Peakerkennungsmethode . Die obige Abbildung zeigt einfach 0-dimensionale persistente Homologieklassen, sortiert nach Persistenz.
Ich habe den Originaldatensatz mit scipy.misc.imresize () um den Faktor 2 hochskaliert. Beachten Sie jedoch, dass ich die vier Pfoten als einen Datensatz betrachtet habe. Eine Aufteilung in vier Teile würde das Problem erleichtern.
Methodik. Die Idee dahinter ist ganz einfach: Betrachten Sie den Funktionsgraphen der Funktion, die jedem Pixel seinen Pegel zuweist. Es sieht aus wie das:
Betrachten Sie nun einen Wasserstand in Höhe 255, der kontinuierlich auf niedrigere Niveaus abfällt. Bei lokalen Maxima tauchen Inseln auf (Geburt). An Sattelpunkten verschmelzen zwei Inseln; Wir betrachten die untere Insel als mit der höheren Insel verschmolzen (Tod). Das sogenannte Persistenzdiagramm (der 0-dimensionalen Homologieklassen, unserer Inseln) zeigt die Todesfälle über den Geburtswerten aller Inseln:
Die Beharrlichkeit einer Insel ist dann der Unterschied zwischen dem Geburts- und dem Todesniveau; der vertikale Abstand eines Punktes zur grauen Hauptdiagonale. Die Abbildung kennzeichnet die Inseln durch Verringern der Persistenz.
Das allererste Bild zeigt die Geburtsorte der Inseln. Diese Methode gibt nicht nur die lokalen Maxima an, sondern quantifiziert auch ihre "Bedeutung" durch die oben erwähnte Persistenz. Man würde dann alle Inseln mit einer zu geringen Persistenz herausfiltern. In Ihrem Beispiel ist jedoch jede Insel (dh jedes lokale Maximum) ein Gipfel, nach dem Sie suchen.
Python-Code finden Sie hier .
quelle
Dieses Problem wurde von Physikern eingehend untersucht. Es gibt eine gute Implementierung in ROOT . Schauen Sie sich die TSpectrum- Klassen an (insbesondere TSpectrum2 für Ihren Fall) und die Dokumentation dazu an.
Verweise:
... und für diejenigen, die keinen Zugang zu einem NIM-Abonnement haben:
quelle
Hier ist eine Idee: Sie berechnen den (diskreten) Laplace-Wert des Bildes. Ich würde erwarten, dass es bei Maxima (negativ und) groß ist, auf eine Weise, die dramatischer ist als in den Originalbildern. Somit könnten Maxima leichter zu finden sein.
Hier ist eine andere Idee: Wenn Sie die typische Größe der Hochdruckpunkte kennen, können Sie Ihr Bild zuerst glätten, indem Sie es mit einem Gaußschen derselben Größe falten. Dadurch können Sie möglicherweise einfachere Bilder verarbeiten.
quelle
Nur ein paar Ideen aus meinem Kopf:
Vielleicht möchten Sie auch einen Blick auf OpenCV werfen , es hat eine ziemlich anständige Python-API und einige Funktionen, die Sie nützlich finden würden.
quelle
Ich bin mir sicher, dass Sie jetzt genug haben, um fortzufahren, aber ich kann nicht anders, als die Verwendung der k-means-Clustering-Methode vorzuschlagen. k-means ist ein unbeaufsichtigter Clustering-Algorithmus, mit dem Sie Daten (in einer beliebigen Anzahl von Dimensionen - ich mache dies zufällig in 3D) in k Cluster mit unterschiedlichen Grenzen anordnen können. Es ist schön hier, weil Sie genau wissen, wie viele Zehen diese Eckzähne haben (sollten).
Außerdem ist es in Scipy implementiert, was wirklich nett ist ( http://docs.scipy.org/doc/scipy/reference/cluster.vq.html) ).
Hier ist ein Beispiel dafür, wie 3D-Cluster räumlich aufgelöst werden können:
Was Sie tun möchten, ist etwas anders (2D und enthält Druckwerte), aber ich denke immer noch, dass Sie es versuchen könnten.
quelle
danke für die rohdaten. Ich bin im Zug und das ist so weit wie ich gekommen bin (meine Haltestelle kommt). Ich habe Ihre txt-Datei mit regulären Ausdrücken massiert und sie zur Visualisierung in eine HTML-Seite mit etwas Javascript eingefügt. Ich teile es hier, weil einige, wie ich, es leichter hacken können als Python.
Ich denke, ein guter Ansatz wird skalierungs- und rotationsinvariant sein, und mein nächster Schritt wird darin bestehen, Gemische von Gaußschen zu untersuchen. (Jedes Pfotenpolster ist das Zentrum eines Gaußschen).
quelle
Physikerlösung:
Definieren Sie 5 Pfotenmarker, die durch ihre Positionen identifiziert werden,
X_i
und initiieren Sie sie mit zufälligen Positionen. Definieren Sie eine Energiefunktion, indem Sie eine Auszeichnung für die Position von Markern in Pfotenpositionen mit einer Bestrafung für die Überlappung von Markern kombinieren. sagen wir:(
S(X_i)
ist die mittlere Kraft in 2x2 Quadrat umX_i
,alfa
ist ein Parameter, der experimentell erreicht werden soll)Jetzt ist es Zeit, etwas Metropolis-Hastings-Magie zu üben:
1. Wählen Sie einen zufälligen Marker und verschieben Sie ihn um ein Pixel in zufällige Richtung.
2. Berechnen Sie dE, die Energiedifferenz, die diese Bewegung verursacht hat.
3. Erhalten Sie eine einheitliche Zufallszahl von 0-1 und nennen Sie sie r.
4. Wenn
dE<0
oderexp(-beta*dE)>r
, akzeptieren Sie den Zug und gehen Sie zu 1; Wenn nicht, machen Sie die Bewegung rückgängig und gehen Sie zu 1.Dies sollte wiederholt werden, bis die Markierungen zu Pfoten konvergieren. Beta steuert das Scannen, um den Kompromiss zu optimieren. Daher sollte es auch experimentell optimiert werden. Sie kann auch mit der Zeit der Simulation ständig erhöht werden (simuliertes Tempern).
quelle
Hier ist ein anderer Ansatz, den ich verwendet habe, als ich etwas Ähnliches für ein großes Teleskop gemacht habe:
1) Suchen Sie nach dem höchsten Pixel. Sobald Sie das haben, suchen Sie danach nach der besten Anpassung für 2x2 (möglicherweise Maximierung der 2x2-Summe) oder führen Sie eine 2D-Gauß-Anpassung innerhalb des Unterbereichs von beispielsweise 4x4 durch, der auf dem höchsten Pixel zentriert ist.
Setzen Sie dann die gefundenen 2x2 Pixel um die Spitzenmitte auf Null (oder vielleicht 3x3)
Gehen Sie zurück zu 1) und wiederholen Sie den Vorgang, bis der höchste Peak eine Geräuschschwelle unterschreitet oder Sie alle Zehen haben, die Sie benötigen
quelle
Es lohnt sich wahrscheinlich, es mit neuronalen Netzen zu versuchen, wenn Sie in der Lage sind, einige Trainingsdaten zu erstellen. Dafür sind jedoch viele von Hand kommentierte Beispiele erforderlich.
quelle
ein grober Umriss ...
Sie möchten wahrscheinlich einen Algorithmus für verbundene Komponenten verwenden, um jede Pfotenregion zu isolieren. Wiki hat eine anständige Beschreibung davon (mit etwas Code) hier: http://en.wikipedia.org/wiki/Connected_Component_Labeling
Sie müssen sich entscheiden, ob Sie 4 oder 8 Verbindungen verwenden möchten. persönlich bevorzuge ich für die meisten probleme 6-vernetzung. Sobald Sie jeden "Pfotenabdruck" als verbundene Region getrennt haben, sollte es einfach genug sein, durch die Region zu iterieren und die Maxima zu finden. Sobald Sie die Maxima gefunden haben, können Sie die Region iterativ vergrößern, bis Sie einen vorgegebenen Schwellenwert erreichen, um ihn als einen bestimmten "Zeh" zu identifizieren.
Ein subtiles Problem hierbei ist, dass Sie Rotationen, Schrägstellungen und Übersetzungen berücksichtigen müssen, sobald Sie anfangen, mithilfe von Computer-Vision-Techniken etwas als rechte / linke / vordere / hintere Pfote zu identifizieren und einzelne Zehen zu betrachten. Dies wird durch die Analyse sogenannter "Momente" erreicht. Bei Vision-Anwendungen sind einige verschiedene Momente zu berücksichtigen:
zentrale Momente: Translationsinvariante normalisierte Momente: Skalierung und Translationsinvariante Hu-Momente: Translations-, Skalierungs- und Rotationsinvariante
Weitere Informationen zu Momenten finden Sie, indem Sie im Wiki nach "Bildmomenten" suchen.
quelle
Vielleicht können Sie so etwas wie Gaußsche Mischungsmodelle verwenden. Hier ist ein Python-Paket für GMMs (habe gerade eine Google-Suche durchgeführt): http://www.ar.media.kyoto-u.ac.jp/members/david/softwares/em/
quelle
Es scheint, dass Sie mit dem Jetxee-Algorithmus ein bisschen schummeln können. Er findet die ersten drei Zehen in Ordnung, und Sie sollten erraten können, wo die vierten darauf basieren.
quelle
Interessantes Problem. Die Lösung, die ich versuchen würde, ist die folgende.
Wenden Sie ein Tiefpassfilter an, z. B. eine Faltung mit einer 2D-Gauß-Maske. Dies gibt Ihnen eine Reihe von (wahrscheinlich, aber nicht unbedingt Gleitkomma) Werten.
Führen Sie eine nicht maximale 2D-Unterdrückung mit dem bekannten ungefähren Radius jedes Pfotenpolsters (oder Zehs) durch.
Dies sollte Ihnen die maximalen Positionen geben, ohne dass mehrere Kandidaten nahe beieinander liegen. Zur Verdeutlichung sollte der Radius der Maske in Schritt 1 auch dem in Schritt 2 verwendeten Radius ähnlich sein. Dieser Radius kann wählbar sein oder der Tierarzt kann ihn vorher explizit messen (er variiert je nach Alter / Rasse / usw.).
Einige der vorgeschlagenen Lösungen (mittlere Verschiebung, neuronale Netze usw.) funktionieren wahrscheinlich bis zu einem gewissen Grad, sind jedoch zu kompliziert und wahrscheinlich nicht ideal.
quelle
Nun, hier ist ein einfacher und nicht besonders effizienter Code, aber für diese Größe eines Datensatzes ist er in Ordnung.
Ich mache einfach ein Array mit der Position oben links und der Summe jedes 2x2-Quadrats und sortiere es nach der Summe. Ich nehme dann das 2x2-Quadrat mit der höchsten Summe aus dem Wettbewerb und setze es in die
best
Array und entferne alle anderen 2x2-Quadrate, die einen Teil dieses gerade entfernten 2x2-Quadrats verwendet haben.Es scheint gut zu funktionieren, außer mit der letzten Pfote (die mit der kleinsten Summe ganz rechts in Ihrem ersten Bild). Es stellt sich heraus, dass es zwei andere geeignete 2x2-Quadrate mit einer größeren Summe gibt (und sie haben die gleiche Summe zu gegenseitig). Einer von ihnen wählt immer noch ein Quadrat aus Ihrem 2x2-Quadrat aus, der andere befindet sich links. Glücklicherweise wählen wir zum Glück mehr von dem, was Sie möchten, aber dies erfordert möglicherweise einige andere Ideen, um die ganze Zeit das zu bekommen, was Sie tatsächlich wollen.
quelle
Ich möchte euch nur sagen, dass es eine gute Möglichkeit gibt, lokale
maxima
Bilder in Bildern mit Python zu finden:oder zum Überfliegen
0.8.0
:http://scikit-image.org/docs/0.8.0/api/skimage.feature.peak.html
quelle
Vielleicht reicht hier ein naiver Ansatz aus: Erstellen Sie eine Liste aller 2x2 Quadrate in Ihrem Flugzeug und ordnen Sie sie nach ihrer Summe (in absteigender Reihenfolge).
Wählen Sie zuerst das am höchsten bewertete Quadrat in Ihrer "Pfotenliste" aus. Wählen Sie dann iterativ 4 der nächstbesten Quadrate aus, die sich mit keinem der zuvor gefundenen Quadrate schneiden.
quelle
Es gibt mehrere und umfangreiche Softwarekomponenten aus der Astronomie- und Kosmologie-Community - dies ist sowohl historisch als auch aktuell ein bedeutendes Forschungsgebiet.
Seien Sie nicht beunruhigt, wenn Sie kein Astronom sind - einige sind außerhalb des Feldes einfach zu bedienen. Zum Beispiel könnten Sie Astropie / Photutils verwenden:
https://photutils.readthedocs.io/en/stable/detection.html#local-peak-detection
[Es scheint ein bisschen unhöflich, ihren kurzen Beispielcode hier zu wiederholen.]
Eine unvollständige und leicht voreingenommene Liste von Techniken / Paketen / Links, die von Interesse sein könnten, ist unten angegeben. Fügen Sie in den Kommentaren weitere hinzu, und ich werde diese Antwort nach Bedarf aktualisieren. Natürlich gibt es einen Kompromiss zwischen Genauigkeit und Rechenressourcen. [Ehrlich gesagt gibt es zu viele, um Codebeispiele in einer einzigen Antwort wie dieser anzugeben, daher bin ich mir nicht sicher, ob diese Antwort fliegen wird oder nicht.]
Source Extractor https://www.astromatic.net/software/sextractor
MultiNest https://github.com/farhanferoz/MultiNest [+ pyMultiNest]
Herausforderung bei der Suche nach ASKAP / EMU-Quellen: https://arxiv.org/abs/1509.03931
Sie können auch nach Planck- und / oder WMAP-Quellenextraktionsproblemen suchen.
...
quelle
Was ist, wenn Sie Schritt für Schritt vorgehen: Sie suchen zuerst das globale Maximum, verarbeiten bei Bedarf die umgebenden Punkte anhand ihres Werts, setzen dann den gefundenen Bereich auf Null und wiederholen ihn für den nächsten.
quelle
Ich bin nicht sicher, ob dies die Frage beantwortet, aber es scheint, als könnten Sie nur nach den n höchsten Gipfeln suchen, die keine Nachbarn haben.
Hier ist das Wesentliche. Beachten Sie, dass es in Ruby ist, aber die Idee sollte klar sein.
quelle