J'aide une clinique vétérinaire à mesurer la pression sous la patte d'un chien. J'utilise Python pour l'analyse de mes données et maintenant je suis coincé à essayer de diviser les pattes en sous-régions (anatomiques).
J'ai fait un tableau 2D de chaque patte, qui se compose des valeurs maximales pour chaque capteur qui a été chargé par la patte au fil du temps. Voici un exemple d'une patte, où j'ai utilisé Excel pour dessiner les zones que je veux «détecter». Ce sont des cases 2 par 2 autour du capteur avec des maxima locaux, qui ont ensemble la plus grande somme.
J'ai donc essayé quelques expériences et j'ai décidé de simplement chercher les maximums de chaque colonne et ligne (je ne peux pas regarder dans une direction à cause de la forme de la patte). Cela semble assez bien «détecter» l'emplacement des orteils séparés, mais cela marque également les capteurs voisins.
Alors, quelle serait la meilleure façon de dire à Python quels sont ces maximums que je veux?
Remarque: Les carrés 2x2 ne peuvent pas se chevaucher, car ils doivent être des orteils séparés!
J'ai également pris 2x2 pour plus de commodité, toute solution plus avancée est la bienvenue, mais je suis simplement un scientifique du mouvement humain, donc je ne suis ni un vrai programmeur ni un mathématicien, alors s'il vous plaît restez simple.
Voici une version qui peut être chargée avecnp.loadtxt
Résultats
J'ai donc essayé la solution de @ jextee (voir les résultats ci-dessous). Comme vous pouvez le voir, cela fonctionne très bien sur les pattes avant, mais cela fonctionne moins bien pour les pattes arrière.
Plus précisément, il ne peut pas reconnaître le petit pic qui est le quatrième orteil. Ceci est évidemment inhérent au fait que la boucle regarde de haut en bas vers la valeur la plus basse, sans tenir compte de son emplacement.
Quelqu'un sait-il comment modifier l'algorithme de @ jextee, afin qu'il puisse également trouver le 4e orteil?
Comme je n'ai pas encore traité d'autres essais, je ne peux pas fournir d'autres échantillons. Mais les données que j'ai données auparavant étaient les moyennes de chaque patte. Ce fichier est un tableau avec les données maximales de 9 pattes dans l'ordre où elles ont pris contact avec la plaque.
Cette image montre comment ils ont été répartis dans l'espace sur la plaque.
Mise à jour:
J'ai créé un blog pour toute personne intéressée et j'ai configuré un SkyDrive avec toutes les mesures brutes. Donc à tous ceux qui demandent plus de données: plus de pouvoir pour vous!
Nouvelle mise à jour:
Donc, après l'aide que j'ai reçue avec mes questions concernant la détection et le tri des pattes , j'ai finalement pu vérifier la détection des orteils pour chaque patte! Il s'avère que cela ne fonctionne pas si bien que les pattes de la taille de celle de mon propre exemple. Bien sûr, avec le recul, c'est ma faute si j'ai choisi arbitrairement le 2x2.
Voici un bel exemple de problème: un ongle est reconnu comme un orteil et le «talon» est si large qu'il est reconnu deux fois!
La patte est trop grande, donc en prenant une taille 2x2 sans chevauchement, certains orteils sont détectés deux fois. Dans l'autre sens, chez les petits chiens, il ne parvient souvent pas à trouver un 5e orteil, ce qui, je le soupçonne, est dû à une zone 2x2 trop grande.
Après avoir essayé la solution actuelle sur toutes mes mesures, je suis arrivé à la conclusion stupéfiante que pour presque tous mes petits chiens, il n'a pas trouvé de 5e orteil et que dans plus de 50% des impacts pour les grands chiens, il en trouverait plus!
Donc, clairement, je dois le changer. Ma propre supposition changeait la taille de la neighborhood
pour quelque chose de plus petit pour les petits chiens et plus grand pour les gros chiens. Mais generate_binary_structure
ne me laisse pas changer la taille du tableau.
Par conséquent, j'espère que quelqu'un d'autre aura une meilleure suggestion pour localiser les orteils, peut-être avoir l'échelle de la zone des orteils avec la taille de la patte?
la source
Réponses:
J'ai détecté les pics en utilisant un filtre maximum local . Voici le résultat sur votre premier jeu de données de 4 pattes:
Je l'ai également exécuté sur le deuxième ensemble de données de 9 pattes et cela a également fonctionné .
Voici comment procéder:
Il vous suffit ensuite d'utiliser
scipy.ndimage.measurements.label
le masque pour étiqueter tous les objets distincts. Ensuite, vous pourrez jouer avec eux individuellement.Notez que la méthode fonctionne bien car le fond n'est pas bruyant. Si c'était le cas, vous détecteriez un tas d'autres pics indésirables en arrière-plan. Un autre facteur important est la taille du quartier . Vous devrez l'ajuster si la taille du pic change (la devrait rester à peu près proportionnelle).
la source
Solution
Fichier de données: paw.txt . Code source:
Sortie sans carrés qui se chevauchent. Il semble que les mêmes zones soient sélectionnées comme dans votre exemple.
Certains commentaires
La partie délicate consiste à calculer les sommes de tous les carrés 2x2. J'ai supposé que vous en aviez besoin, donc il pourrait y avoir des chevauchements. J'ai utilisé des tranches pour couper les premières / dernières colonnes et lignes du tableau 2D d'origine, puis les recouvrir toutes ensemble et calculer des sommes.
Pour mieux le comprendre, imaginez une matrice 3x3:
Ensuite, vous pouvez prendre ses tranches:
Imaginez maintenant que vous les empilez les uns au-dessus des autres et que vous additionnez les éléments aux mêmes positions. Ces sommes seront exactement les mêmes sur les carrés 2x2 avec le coin supérieur gauche dans la même position:
Lorsque vous avez les sommes sur 2x2 carrés, vous pouvez utiliser
max
pour trouver le maximum, ousort
, ousorted
pour trouver les pics.Pour me souvenir des positions des pics, je couple chaque valeur (la somme) avec sa position ordinale dans un tableau aplati (voir
zip
). Ensuite, je calcule à nouveau la position de la ligne / colonne lorsque j'imprime les résultats.Remarques
J'ai permis aux carrés 2x2 de se chevaucher. La version modifiée en filtre certains, de sorte que seuls les carrés qui ne se chevauchent pas apparaissent dans les résultats.
Choisir les doigts (une idée)
Un autre problème est de savoir comment choisir ce qui est susceptible d'être des doigts parmi tous les pics. J'ai une idée qui peut ou non fonctionner. Je n'ai pas le temps de l'implémenter en ce moment, donc juste un pseudo-code.
J'ai remarqué que si les doigts avant restent sur un cercle presque parfait, le doigt arrière devrait être à l'intérieur de ce cercle. De plus, les doigts avant sont plus ou moins également espacés. Nous pouvons essayer d'utiliser ces propriétés heuristiques pour détecter les doigts.
Pseudo code:
Il s'agit d'une approche par force brute. Si N est relativement petit, je pense que c'est faisable. Pour N = 12, il existe C_12 ^ 5 = 792 combinaisons, fois 5 façons de sélectionner un doigt arrière, donc 3960 cas à évaluer pour chaque patte.
la source
Il s'agit d'un problème d'enregistrement d'image . La stratégie générale est la suivante:
Voici une approche approximative et prête , "la chose la plus stupide qui pourrait éventuellement fonctionner":
Pour contrer le problème d'orientation, vous pouvez avoir environ 8 réglages initiaux pour les directions de base (Nord, Nord-Est, etc.). Exécutez chacun individuellement et jetez tous les résultats où deux ou plusieurs orteils se retrouvent au même pixel. J'y penserai un peu plus, mais ce genre de chose est toujours à l'étude dans le traitement d'image - il n'y a pas de bonnes réponses!
Idée un peu plus complexe: (pondéré) clustering K-means. C'est pas si mal.
Itérer ensuite jusqu'à convergence:
Cette méthode donnera presque certainement de bien meilleurs résultats et vous obtiendrez la masse de chaque grappe, ce qui peut aider à identifier les orteils.
(Encore une fois, vous avez spécifié le nombre de clusters à l'avance. Avec le clustering, vous devez spécifier la densité d'une manière ou d'une autre: choisissez le nombre de clusters, approprié dans ce cas, ou choisissez un rayon de cluster et voyez combien vous finissez Un exemple de ce dernier est le décalage moyen .)
Désolé pour le manque de détails d'implémentation ou d'autres détails. Je coderais cela, mais j'ai un délai. Si rien d'autre n'a fonctionné la semaine prochaine, faites le moi savoir et je vais essayer.
la source
En utilisant l'homologie persistante pour analyser votre ensemble de données, j'obtiens le résultat suivant (cliquez pour agrandir):
Il s'agit de la version 2D de la méthode de détection des pics décrite dans cette réponse SO . La figure ci-dessus montre simplement les classes d'homologie persistante à 0 dimension triées par persistance.
J'ai mis à l'échelle l'ensemble de données d'origine par un facteur de 2 en utilisant scipy.misc.imresize (). Cependant, notez que j'ai considéré les quatre pattes comme un ensemble de données; le diviser en quatre faciliterait le problème.
Méthodologie. L'idée derrière cela est assez simple: considérons le graphique de fonction de la fonction qui attribue à chaque pixel son niveau. Cela ressemble à ceci:
Considérons maintenant un niveau d'eau à la hauteur 255 qui descend en continu vers des niveaux inférieurs. Aux îles maxima locales apparaissent (naissance). Aux points de selle, deux îles fusionnent; nous considérons l'île inférieure comme fusionnant avec l'île supérieure (mort). Le soi-disant diagramme de persistance (des classes d'homologie de dimension 0, nos îles) représente les valeurs de mortalité par rapport à la naissance de toutes les îles:
La persistance d'une île est alors la différence entre les niveaux de naissance et de mort; la distance verticale d'un point à la diagonale grise principale. La figure marque les îles en diminuant la persistance.
La toute première photo montre les lieux de naissance des îles. Cette méthode donne non seulement les maxima locaux mais quantifie également leur «signification» par la persistance mentionnée ci-dessus. On filtrerait alors toutes les îles avec une persistance trop faible. Cependant, dans votre exemple, chaque île (c'est-à-dire chaque maximum local) est un pic que vous recherchez.
Le code Python peut être trouvé ici .
la source
Ce problème a été étudié en profondeur par les physiciens. Il y a une bonne implémentation dans ROOT . Regardez les classes TSpectrum (en particulier TSpectrum2 pour votre cas) et leur documentation.
Références:
... et pour ceux qui n'ont pas accès à un abonnement à NIM:
la source
Voici une idée: vous calculez le laplacien (discret) de l'image. Je m'attendrais à ce qu'il soit (négatif et) grand au maximum, d'une manière plus dramatique que dans les images originales. Ainsi, les maxima pourraient être plus faciles à trouver.
Voici une autre idée: si vous connaissez la taille typique des taches à haute pression, vous pouvez d'abord lisser votre image en la convoluant avec un gaussien de la même taille. Cela peut vous donner des images plus simples à traiter.
la source
Juste quelques idées du haut de ma tête:
Vous voudrez peut-être également jeter un œil à OpenCV , il dispose d'une API Python assez décente et pourrait avoir certaines fonctions que vous trouveriez utiles.
la source
Je suis sûr que vous en avez assez pour continuer, mais je ne peux m'empêcher de suggérer d'utiliser la méthode de clustering k-means. k-means est un algorithme de clustering non supervisé qui vous prendra des données (dans n'importe quel nombre de dimensions - il se trouve que je le fais en 3D) et les organisera en k clusters avec des limites distinctes. C'est bien ici parce que vous savez exactement combien d'orteils ces canines (devraient) avoir.
De plus, il est implémenté dans Scipy, ce qui est vraiment sympa ( http://docs.scipy.org/doc/scipy/reference/cluster.vq.html ).
Voici un exemple de ce qu'il peut faire pour résoudre spatialement les clusters 3D:
Ce que vous voulez faire est un peu différent (2D et inclut des valeurs de pression), mais je pense toujours que vous pourriez essayer.
la source
merci pour les données brutes. Je suis dans le train et c'est aussi loin que je suis arrivé (mon arrêt arrive). J'ai massé votre fichier txt avec des expressions rationnelles et l'ai déposé dans une page html avec du javascript pour la visualisation. Je le partage ici parce que certains, comme moi, pourraient le trouver plus facilement piratable que python.
Je pense qu'une bonne approche sera l'échelle et la rotation invariantes, et ma prochaine étape sera d'étudier les mélanges de gaussiens. (chaque patte étant le centre d'un gaussien).
la source
Solution du physicien:
Définissez 5 marqueurs de patte identifiés par leur position
X_i
et initiez-les avec des positions aléatoires. Définir une fonction énergétique combinant une récompense pour l'emplacement des marqueurs dans la position des pattes avec une punition pour le chevauchement des marqueurs; Disons:(
S(X_i)
est la force moyenne en carré de 2x2 environX_i
,alfa
est un paramètre à atteindre expérimentalement)Il est maintenant temps de faire de la magie Metropolis-Hastings:
1. Sélectionnez un marqueur aléatoire et déplacez-le d'un pixel dans une direction aléatoire.
2. Calculez dE, la différence d'énergie provoquée par ce mouvement.
3. Obtenez un nombre aléatoire uniforme de 0 à 1 et appelez-le r.
4. Si
dE<0
ouexp(-beta*dE)>r
, acceptez le mouvement et passez à 1; sinon, annulez le mouvement et passez à 1.Cela devrait être répété jusqu'à ce que les marqueurs convergent vers les pattes. La bêta contrôle l'analyse pour optimiser le compromis, elle doit donc également être optimisée expérimentalement; il peut également être constamment augmenté avec le temps de simulation (recuit simulé).
la source
Voici une autre approche que j'ai utilisée en faisant quelque chose de similaire pour un grand télescope:
1) Recherchez le pixel le plus élevé. Une fois que vous avez cela, recherchez autour de lui le meilleur ajustement pour 2x2 (peut-être en maximisant la somme 2x2), ou faites un ajustement gaussien 2d à l'intérieur de la sous-région de 4x4 centrée sur le pixel le plus élevé.
Ensuite, définissez ces pixels 2x2 que vous avez trouvés à zéro (ou peut-être 3x3) autour du centre du pic
revenir à 1) et répéter jusqu'à ce que le pic le plus élevé tombe en dessous d'un seuil de bruit, ou que vous ayez tous les orteils dont vous avez besoin
la source
Cela vaut probablement la peine d'essayer avec les réseaux de neurones si vous êtes capable de créer des données d'entraînement ... mais cela nécessite de nombreux échantillons annotés à la main.
la source
un aperçu approximatif ...
vous voudrez probablement utiliser un algorithme de composants connectés pour isoler chaque région de patte. wiki a une description décente de cela (avec du code) ici: http://en.wikipedia.org/wiki/Connected_Component_Labeling
vous devrez décider si vous souhaitez utiliser la connectivité 4 ou 8. personnellement, pour la plupart des problèmes, je préfère la connectivité 6. de toute façon, une fois que vous avez séparé chaque "empreinte de patte" en tant que région connectée, il devrait être assez facile de parcourir la région et de trouver les maxima. une fois que vous avez trouvé les maxima, vous pouvez agrandir la région de manière itérative jusqu'à ce que vous atteigniez un seuil prédéterminé afin de l'identifier comme un "orteil" donné.
un problème subtil ici est que dès que vous commencez à utiliser des techniques de vision par ordinateur pour identifier quelque chose comme une patte droite / gauche / avant / arrière et que vous commencez à regarder les orteils individuels, vous devez commencer à prendre en compte les rotations, les asymétries et les traductions. ceci est accompli grâce à l'analyse des soi-disant «moments». il y a quelques moments différents à considérer dans les applications de vision:
moments centraux: invariant de translation moments normalisés: invariant de mise à l'échelle et de translation moments hu: invariant de translation, d'échelle et de rotation
plus d'informations sur les moments peuvent être trouvées en recherchant "moments image" sur wiki.
la source
Vous pouvez peut-être utiliser quelque chose comme des modèles de mélange gaussiens. Voici un package Python pour faire des GMM (vient de faire une recherche Google) http://www.ar.media.kyoto-u.ac.jp/members/david/softwares/em/
la source
Il semble que vous puissiez tricher un peu en utilisant l'algorithme de jetxee. Il trouve que les trois premiers orteils vont bien, et vous devriez pouvoir deviner où le quatrième est basé.
la source
Problème intéressant. La solution que j'essaierais est la suivante.
Appliquez un filtre passe-bas, tel que la convolution avec un masque gaussien 2D. Cela vous donnera un tas de valeurs (probablement, mais pas nécessairement en virgule flottante).
Effectuez une suppression 2D non maximale en utilisant le rayon approximatif connu de chaque patte (ou orteil).
Cela devrait vous donner les positions maximales sans avoir plusieurs candidats qui sont proches les uns des autres. Juste pour clarifier, le rayon du masque à l'étape 1 devrait également être similaire au rayon utilisé à l'étape 2. Ce rayon pourrait être sélectionnable, ou le vétérinaire pourrait le mesurer explicitement à l'avance (cela variera avec l'âge / la race / etc.).
Certaines des solutions suggérées (décalage moyen, réseaux neuronaux, etc.) fonctionneront probablement dans une certaine mesure, mais sont trop compliquées et probablement pas idéales.
la source
Eh bien, voici un code simple et pas terriblement efficace, mais pour cette taille d'un ensemble de données, c'est très bien.
Je fais simplement un tableau avec la position du coin supérieur gauche et la somme de chaque carré 2x2 et je le trie par la somme. Je prends ensuite le carré 2x2 avec la somme la plus élevée hors de contention, le place dans le
best
tableau et supprime tous les autres carrés 2x2 qui ont utilisé n'importe quelle partie de ce carré 2x2 juste supprimé.Cela semble bien fonctionner sauf avec la dernière patte (celle avec la plus petite somme à l'extrême droite dans votre première photo), il s'avère qu'il y a deux autres carrés 2x2 éligibles avec une somme plus grande (et ils ont une somme égale à L'une et l'autre). L'un d'eux sélectionne toujours un carré de votre carré 2x2, mais l'autre est à gauche. Heureusement, par chance, nous pensons choisir plus de celui que vous voudriez, mais cela peut nécessiter d'autres idées pour obtenir tout le temps ce que vous voulez réellement.
la source
Je veux juste vous dire qu'il y a une bonne option pour trouver du local
maxima
dans des images avec python:ou pour skimage
0.8.0
:http://scikit-image.org/docs/0.8.0/api/skimage.feature.peak.html
la source
Peut-être qu'une approche naïve est suffisante ici: Construisez une liste de tous les carrés 2x2 sur votre avion, triez-les par leur somme (en ordre décroissant).
Tout d'abord, sélectionnez le carré le plus apprécié dans votre "liste de pattes". Ensuite, choisissez de manière itérative 4 des meilleurs carrés suivants qui ne se croisent avec aucun des carrés trouvés précédemment.
la source
Il existe plusieurs et vastes logiciels disponibles auprès de la communauté de l'astronomie et de la cosmologie - il s'agit d'un domaine de recherche important à la fois historique et actuel.
Ne vous inquiétez pas si vous n'êtes pas astronome - certains sont faciles à utiliser en dehors du terrain. Par exemple, vous pouvez utiliser l'astropie / photutils:
https://photutils.readthedocs.io/en/stable/detection.html#local-peak-detection
[Il semble un peu grossier de répéter leur court exemple de code ici.]
Une liste incomplète et légèrement biaisée des techniques / packages / liens qui pourraient être intéressants est donnée ci-dessous - ajoutez-en plus dans les commentaires et je mettrai à jour cette réponse si nécessaire. Bien sûr, il existe un compromis entre la précision et les ressources de calcul. [Honnêtement, il y en a trop pour donner des exemples de code dans une seule réponse comme celle-ci, donc je ne sais pas si cette réponse volera ou non.]
Extracteur de source https://www.astromatic.net/software/sextractor
MultiNest https://github.com/farhanferoz/MultiNest [+ pyMultiNest]
Défi de recherche de source ASKAP / EMU: https://arxiv.org/abs/1509.03931
Vous pouvez également rechercher des défis d'extraction de source Planck et / ou WMAP.
...
la source
Que faire si vous procédez étape par étape: vous localisez d'abord le maximum global, traitez si nécessaire les points environnants en fonction de leur valeur, puis définissez la région trouvée sur zéro et répétez pour la suivante.
la source
Je ne suis pas sûr que cela réponde à la question, mais il semble que vous pouvez simplement rechercher les n plus hauts sommets qui n'ont pas de voisins.
Voici l'essentiel. Notez que c'est en Ruby, mais l'idée doit être claire.
la source