Pomagam klinice weterynaryjnej mierzącej ciśnienie pod łapą psa. Używam Pythona do analizy danych i teraz utknąłem próbując podzielić łapy na (anatomiczne) podregiony.
Zrobiłem tablicę 2D każdej łapy, która składa się z maksymalnych wartości dla każdego czujnika, który został obciążony przez łapę w czasie. Oto przykład jednej łapy, w której użyłem programu Excel do narysowania obszarów, które chcę „wykryć”. Są to 2 na 2 pola wokół czujnika z lokalnymi maksimami, które razem mają największą sumę.
Więc spróbowałem trochę eksperymentować i postanowiłem po prostu poszukać maksimów każdej kolumny i rzędu (nie mogę patrzeć w jednym kierunku z powodu kształtu łapy). Wydaje się, że dość dobrze „wykrywa” to położenie oddzielnych palców, ale oznacza także sąsiednie czujniki.
Więc jaki byłby najlepszy sposób, aby powiedzieć Pythonowi, które z tych maksimów są tymi, których chcę?
Uwaga: kwadraty 2x2 nie mogą się pokrywać, ponieważ muszą być oddzielnymi palcami!
Również wziąłem 2x2 jako wygodę, każde bardziej zaawansowane rozwiązanie jest mile widziane, ale jestem po prostu naukowcem zajmującym się ludzkim ruchem, więc nie jestem ani prawdziwym programistą, ani matematykiem, więc proszę, zachowaj prostotę.
Oto wersja, którą można załadowaćnp.loadtxt
Wyniki
Wypróbowałem więc rozwiązanie @ jextee (zobacz wyniki poniżej). Jak widać, działa bardzo na przednich łapach, ale działa gorzej na tylne nogi.
Mówiąc dokładniej, nie rozpoznaje małego piku, który jest czwartym palcem. Jest to oczywiście nieodłączne od faktu, że pętla wygląda od góry w dół w kierunku najniższej wartości, bez względu na to, gdzie to jest.
Czy ktokolwiek wiedziałby, jak dostosować algorytm @ jextee, aby mógł znaleźć również czwarty palec u nogi?
Ponieważ nie przetworzyłem jeszcze żadnych prób, nie mogę dostarczyć żadnych innych próbek. Ale dane, które podałem wcześniej, były średnimi dla każdej łapy. Ten plik to tablica z maksymalnymi danymi 9 łap w kolejności, w której zetknęły się z płytką.
Ten obraz pokazuje, jak zostały one rozmieszczone przestrzennie na talerzu.
Aktualizacja:
Założyłem blog dla wszystkich zainteresowanych i skonfigurowałem SkyDrive ze wszystkimi nieprzetworzonymi pomiarami. Tak więc każdemu, kto prosi o więcej danych: więcej mocy dla Ciebie!
Nowa aktualizacja:
Więc po otrzymaniu pomocy z pytaniami dotyczącymi wykrywania i sortowania łap , w końcu mogłem sprawdzić wykrywanie palców u każdej łapy! Okazuje się, że nie działa tak dobrze w niczym innym, jak łapy wielkości podobne do tej z mojego przykładu. Oczywiście z perspektywy czasu to moja wina, że wybrałem 2x2 tak arbitralnie.
Oto dobry przykład, w którym idzie źle: paznokieć jest rozpoznawany jako palec u nogi, a „pięta” jest tak szeroka, że zostaje rozpoznana dwukrotnie!
Łapa jest zbyt duża, więc przyjęcie rozmiaru 2x2 bez zachodzenia na siebie powoduje dwukrotne wykrycie niektórych palców. Odwrotnie, u małych psów często nie znajduje się 5. palec u nogi, co, jak podejrzewam, jest spowodowane zbyt dużym obszarem 2x2.
Po wypróbowaniu obecnego rozwiązania we wszystkich moich pomiarach doszedłem do oszałamiającego wniosku, że dla prawie wszystkich moich małych psów nie znalazł piątego palca u nogi i że w ponad 50% uderzeń dużych psów znalazłby więcej!
Tak wyraźnie muszę to zmienić. Domyślam się, że zmieniłem rozmiar neighborhood
na coś mniejszego dla małych psów i większego dla dużych psów. Ale generate_binary_structure
nie pozwoliłbym zmienić rozmiaru tablicy.
Dlatego mam nadzieję, że ktokolwiek ma lepszą propozycję lokalizacji palców, być może mając skalę obszaru palców wraz z rozmiarem łapy?
źródło
Odpowiedzi:
Wykryłem piki za pomocą lokalnego filtru maksymalnego . Oto wynik pierwszego zestawu danych 4 łap:
Uruchomiłem go również na drugim zestawie danych 9 łap i również zadziałało .
Oto jak to zrobić:
Wszystko, co musisz zrobić po, to użyć
scipy.ndimage.measurements.label
maski do oznaczenia wszystkich różnych obiektów. Wtedy będziesz mógł grać z nimi indywidualnie.Należy pamiętać, że metoda działa dobrze, ponieważ tło nie jest głośne. Gdyby tak było, wykryłbyś w tle kilka innych niepożądanych szczytów. Innym ważnym czynnikiem jest wielkość dzielnicy . Będziesz musiał go dostosować, jeśli zmieni się rozmiar piku (powinien pozostać w przybliżeniu proporcjonalny).
źródło
Rozwiązanie
Plik danych: paw.txt . Kod źródłowy:
Wyjście bez nakładających się kwadratów. Wygląda na to, że wybrane są te same obszary, co w twoim przykładzie.
Niektóre komentarze
Trudną częścią jest obliczenie sumy wszystkich kwadratów 2x2. Zakładałem, że potrzebujesz ich wszystkich, więc mogą się nakładać. Użyłem wycinków, aby wyciąć pierwsze / ostatnie kolumny i wiersze z oryginalnej tablicy 2D, a następnie nałożyć je wszystkie na siebie i obliczyć sumy.
Aby to lepiej zrozumieć, zobrazuj tablicę 3x3:
Następnie możesz wziąć jego plasterki:
Teraz wyobraź sobie, że układasz je jeden na drugim i sumujesz elementy w tych samych pozycjach. Te sumy będą dokładnie takie same sumy na kwadratach 2x2 z lewym górnym rogiem w tej samej pozycji:
Kiedy masz sumy powyżej 2x2 kwadratów, możesz użyć,
max
aby znaleźć maksimum lubsort
, lubsorted
znaleźć szczyty.Aby zapamiętać pozycje pików, łączę każdą wartość (sumę) z jej porządkową pozycją w spłaszczonej tablicy (patrz
zip
). Następnie ponownie drukuję pozycję wiersza / kolumny podczas drukowania wyników.Notatki
Pozwoliłem, aby kwadraty 2x2 zachodziły na siebie. Edytowana wersja odfiltrowuje niektóre z nich, tak że w wynikach pojawiają się tylko nie nakładające się kwadraty.
Wybór palców (pomysł)
Kolejnym problemem jest to, jak wybrać palce, które prawdopodobnie będą palcami ze wszystkich szczytów. Mam pomysł, który może, ale nie musi, działać. Nie mam teraz czasu na jego wdrożenie, więc po prostu pseudo-kod.
Zauważyłem, że jeśli przednie palce pozostaną na prawie idealnym okręgu, tylny palec powinien znajdować się wewnątrz tego koła. Ponadto przednie palce są mniej więcej równomiernie rozmieszczone. Możemy próbować wykorzystać te właściwości heurystyczne do wykrycia palców.
Pseudo kod:
To podejście oparte na brutalnej sile. Jeśli N jest stosunkowo mały, to myślę, że jest to wykonalne. Dla N = 12 istnieją kombinacje C_12 ^ 5 = 792 razy 5 razy, aby wybrać tylny palec, więc 3960 przypadków do oceny dla każdej łapy.
źródło
Jest to problem z rejestracją obrazu . Ogólna strategia to:
Oto szorstkie i gotowe podejście , „najgłupsza rzecz, która mogłaby ewentualnie zadziałać”:
Aby przeciwdziałać problemowi z orientacją, możesz mieć około 8 ustawień początkowych dla podstawowych kierunków (północ, północ wschód itp.). Uruchom każdy z osobna i wyrzuć wszystkie wyniki, w których dwa lub więcej palców kończy się na tym samym pikselu. Zastanowię się nad tym jeszcze trochę, ale tego rodzaju rzeczy są wciąż badane w przetwarzaniu obrazu - nie ma prawidłowych odpowiedzi!
Nieco bardziej złożony pomysł: (ważony) K-oznacza grupowanie. Nie jest tak źle.
Następnie iteruj aż do konwergencji:
Ta metoda prawie na pewno da znacznie lepsze wyniki, a otrzymasz masę każdego skupienia, co może pomóc w identyfikacji palców.
(Ponownie podałeś liczbę klastrów z góry. W przypadku klastrowania musisz określić gęstość w ten czy inny sposób: albo wybierz liczbę klastrów, odpowiednią w tym przypadku, albo wybierz promień klastra i zobacz, ile zakończymy w górę. Przykładem tego drugiego jest zmiana średniej ).
Przepraszamy za brak szczegółów implementacyjnych lub innych szczegółów. Kodowałbym to, ale mam termin. Jeśli nic nie zadziała do następnego tygodnia, daj mi znać, a dam ci szansę.
źródło
Używając trwałej homologii do analizy zestawu danych, otrzymuję następujący wynik (kliknij, aby powiększyć):
Jest to wersja 2D metody wykrywania pików opisanej w tej odpowiedzi SO . Powyższy rysunek pokazuje po prostu 0-wymiarowe klasy homologii trwałej posortowane według trwałości.
Zrobiłem przeskalować oryginalny zestaw danych o współczynnik 2 używając scipy.misc.imresize (). Zauważ jednak, że cztery łapy uznałem za jeden zestaw danych; podzielenie go na cztery ułatwiłoby problem.
Metodologia. Idea tego dość prosta: rozważ wykres funkcji, która przypisuje poziom każdemu pikselowi. To wygląda tak:
Teraz rozważ poziom wody na wysokości 255, który stale schodzi do niższych poziomów. Na lokalnych wyspach maksymalnych pojawiają się (narodziny). W punktach siodłowych łączą się dwie wyspy; uważamy dolną wyspę za połączoną z wyższą wyspą (śmierć). Tak zwany diagram trwałości (klas homologii 0-wymiarowej, nasze wyspy) przedstawia wartości śmiertelne z powodu narodzin wszystkich wysp:
Trwałość z wysp jest to różnica pomiędzy narodzenie- i śmierci poziomie; pionowa odległość kropki od szarej głównej przekątnej. Liczba ta określa wyspy, zmniejszając ich wytrzymałość.
Pierwsze zdjęcie pokazuje miejsca narodzin wysp. Ta metoda nie tylko podaje lokalne maksima, ale także określa ich „znaczenie” na podstawie wyżej wspomnianej trwałości. Następnie odfiltrowano by wszystkie wyspy o zbyt niskiej trwałości. Jednak w twoim przykładzie każda wyspa (tj. Każde lokalne maksimum) jest szczytem, którego szukasz.
Kod Pythona można znaleźć tutaj .
źródło
Problem ten został dogłębnie zbadany przez fizyków. Istnieje dobra implementacja w ROOT . Spójrz na klasy TSpectrum (szczególnie TSpectrum2 dla twojego przypadku) i dokumentację dla nich.
Bibliografia:
... a dla tych, którzy nie mają dostępu do subskrypcji NIM:
źródło
Oto pomysł: obliczasz (dyskretny) Laplaciana obrazu. Spodziewałbym się, że będzie on (ujemny i) duży przy maksimach, w sposób bardziej dramatyczny niż na oryginalnych obrazach. Tak więc maksima mogłyby być łatwiejsze do znalezienia.
Oto kolejny pomysł: jeśli znasz typowy rozmiar plam wysokociśnieniowych, możesz najpierw wygładzić obraz, zwijając go gaussianem tego samego rozmiaru. Może to ułatwić przetwarzanie obrazów.
źródło
Kilka pomysłów z mojej głowy:
Możesz także rzucić okiem na OpenCV , ma dość przyzwoity interfejs API Pythona i może mieć pewne funkcje, które mogą ci się przydać.
źródło
Jestem pewien, że masz już wystarczająco dużo czasu, ale nie mogę nie poradzić, ale sugeruję użycie metody klastrowania k-średnich. K-średnich jest nie nadzorowanym algorytmem grupowania, który zabierze cię danych (w dowolnej liczbie wymiarów - robię to w 3D) i uporządkuje je w klastry z wyraźnymi granicami. Jest tu miło, ponieważ dokładnie wiesz, ile palców mają te kły (powinny) mieć.
Dodatkowo jest zaimplementowany w Scipy, co jest naprawdę miłe ( http://docs.scipy.org/doc/scipy/reference/cluster.vq.html ).
Oto przykład tego, co może zrobić, aby przestrzennie rozwiązać klastry 3D:
To, co chcesz zrobić, jest nieco inne (2D i zawiera wartości ciśnienia), ale nadal myślę, że możesz spróbować.
źródło
dzięki za surowe dane. Jestem w pociągu i to jest tak daleko, jak to możliwe (zbliża się mój przystanek). Zmasowałem twój plik txt za pomocą regexps i umieściłem go na stronie HTML z javascript do wizualizacji. Udostępniam go tutaj, ponieważ niektórzy, podobnie jak ja, mogą łatwiej go zhakować niż python.
Myślę, że dobrym podejściem będzie niezmienność skali i rotacji, a moim następnym krokiem będzie zbadanie mieszanin gaussów. (każda podkładka łapy jest środkiem gaussa).
źródło
Rozwiązanie fizyka:
Zdefiniuj 5 znaczników łap zidentyfikowanych według ich pozycji
X_i
i zainicjuj je losowymi pozycjami. Zdefiniuj jakąś funkcję energetyczną, łącząc pewną nagrodę za lokalizację znaczników w pozycjach łap z pewną karą za nakładanie się znaczników; powiedzmy:(
S(X_i)
to średnia siła w kwadracie 2x2 wokółX_i
,alfa
jest parametrem, który należy eksperymentalnie zwiększyć)Teraz czas na magię Metropolis-Hastings:
1. Wybierz losowy znacznik i przesuń go o jeden piksel w losowym kierunku.
2. Oblicz dE, różnicę energii spowodowaną tym ruchem.
3. Uzyskaj jednolity losowy numer od 0-1 i nazwij go r.
4. Jeśli
dE<0
lubexp(-beta*dE)>r
, zaakceptuj ruch i przejdź do 1; jeśli nie, cofnij ruch i przejdź do 1. Powtórztę czynność, aż znaczniki zbiegną się w łapy. Beta kontroluje skanowanie w celu optymalizacji kompromisu, dlatego należy go również zoptymalizować eksperymentalnie; można go również stale zwiększać wraz z czasem symulacji (symulowane wyżarzanie).
źródło
Oto inne podejście, które zastosowałem, robiąc coś podobnego dla dużego teleskopu:
1) Wyszukaj najwyższy piksel. Gdy już to zrobisz, poszukaj tego, aby uzyskać najlepsze dopasowanie dla 2x2 (być może maksymalizując sumę 2x2), lub wykonaj dopasowanie 2d gaussa w podregionie powiedzmy 4x4 wyśrodkowanym na najwyższym pikselu.
Następnie ustaw znalezione 2x2 piksele na zero (a może 3x3) wokół środka piku
wróć do 1) i powtarzaj, aż najwyższy szczyt spadnie poniżej progu hałasu lub będziesz mieć wszystkie palce, których potrzebujesz
źródło
Prawdopodobnie warto wypróbować sieci neuronowe, jeśli jesteś w stanie stworzyć dane treningowe ... ale to wymaga wielu próbek opatrzonych adnotacjami ręcznie.
źródło
przybliżony zarys ...
prawdopodobnie chcesz użyć algorytmu połączonych komponentów do izolacji każdego regionu łapy. wiki ma porządny opis tego (z pewnym kodem) tutaj: http://en.wikipedia.org/wiki/Connected_Component_Labeling
musisz podjąć decyzję, czy użyć połączenia 4 czy 8. osobiście, dla większości problemów wolę połączenie 6. tak czy inaczej, po oddzieleniu każdego „odcisku łapy” jako połączonego regionu, powinno być łatwo przejść przez ten region i znaleźć maksima. po znalezieniu maksimów możesz iteracyjnie powiększać region, aż osiągniesz z góry określony próg, aby zidentyfikować go jako dany „palec u nogi”.
jednym subtelnym problemem jest to, że jak tylko zaczniesz korzystać z komputerowych technik wizyjnych, aby zidentyfikować coś jako prawą / lewą / przednią / tylną łapę i zaczniesz patrzeć na poszczególne palce u stóp, musisz zacząć brać pod uwagę obroty, pochylenia i tłumaczenia. osiąga się to poprzez analizę tak zwanych „momentów”. w aplikacjach wizyjnych należy rozważyć kilka różnych momentów:
momenty centralne: niezmienne tłumaczenie znormalizowane momenty: skalowanie i tłumaczenie niezmienne momenty hu: niezmienne tłumaczenie, skala i rotacja
więcej informacji o chwilach można znaleźć, przeszukując „momenty obrazów” na wiki.
źródło
Być może możesz użyć czegoś takiego jak Gaussian Mixture Models. Oto pakiet Pythona do wykonywania GMM (właśnie przeprowadziłem wyszukiwanie w Google) http://www.ar.media.kyoto-u.ac.jp/members/david/softwares/em/
źródło
Wygląda na to, że możesz trochę oszukiwać za pomocą algorytmu jetxee. Uważa, że pierwsze trzy palce są w porządku i powinieneś być w stanie zgadnąć, gdzie opiera się czwarty.
źródło
Ciekawy problem. Rozwiązanie, które chciałbym wypróbować, jest następujące.
Zastosuj filtr dolnoprzepustowy, taki jak splot z maską gaussowską 2D. To da ci garść (prawdopodobnie, ale niekoniecznie zmiennoprzecinkowych) wartości.
Wykonaj nie-maksymalne tłumienie 2D, używając znanego przybliżonego promienia każdej poduszki (lub palca).
To powinno dać ci maksymalną liczbę pozycji bez posiadania wielu kandydatów, którzy są blisko siebie. Aby to wyjaśnić, promień maski w kroku 1 powinien być również podobny do promienia zastosowanego w kroku 2. Promień ten można wybrać, lub weterynarz może go wyraźnie zmierzyć wcześniej (zmienia się w zależności od wieku / rasy / itp.).
Niektóre z sugerowanych rozwiązań (średnia zmiana, sieci neuronowe itp.) Prawdopodobnie będą do pewnego stopnia działały, ale są zbyt skomplikowane i prawdopodobnie nie są idealne.
źródło
Oto prosty i niezbyt wydajny kod, ale dla tego rozmiaru zestawu danych jest w porządku.
Zasadniczo po prostu tworzę tablicę z pozycją lewego górnego rogu i sumą każdego kwadratu 2x2 i sortuję według sumy. Następnie biorę kwadrat 2x2 z najwyższą sumą ze sporu, umieszczam go w
best
tablicy i usuwam wszystkie pozostałe kwadraty 2x2, które wykorzystały dowolną część tego właśnie usuniętego kwadratu 2x2.Wygląda na to, że działa dobrze, z wyjątkiem ostatniej łapy (tej z najmniejszą sumą po prawej stronie na pierwszym zdjęciu), okazuje się, że istnieją dwa inne kwalifikujące się kwadraty 2x2 z większą sumą (i mają one taką samą kwotę jak wzajemnie). Jeden z nich nadal wybiera jeden kwadrat z twojego kwadratu 2x2, ale drugi znajduje się po lewej stronie. Na szczęście na szczęście widzimy, że wybieramy więcej tego, czego chcesz, ale może to wymagać innych pomysłów, aby uzyskać to, czego naprawdę chcesz przez cały czas.
źródło
Chcę wam tylko powiedzieć, że istnieje fajna opcja znalezienia lokalnego
maxima
obrazu na Pythonie:lub do skimage
0.8.0
:http://scikit-image.org/docs/0.8.0/api/skimage.feature.peak.html
źródło
Może wystarczające jest naiwne podejście: Zbuduj listę wszystkich kwadratów 2x2 na swoim samolocie, uporządkuj je według ich sumy (w kolejności malejącej).
Najpierw wybierz kwadrat o najwyższej wartości z „listy łap”. Następnie, iteracyjnie wybierz 4 z następnych najlepszych kwadratów, które nie przecinają się z żadnym z wcześniej znalezionych kwadratów.
źródło
Istnieje wiele obszernych programów dostępnych w społeczności astronomii i kosmologii - jest to znaczący obszar badań zarówno historycznych, jak i obecnie.
Nie przejmuj się, jeśli nie jesteś astronomem - niektóre są łatwe w użyciu poza polem. Na przykład możesz użyć astropy / photutils:
https://photutils.readthedocs.io/en/stable/detection.html#local-peak-detection
[Powtarzanie krótkiego przykładowego kodu tutaj jest trochę niegrzeczne.]
Niekompletna i nieco stronnicza lista technik / pakietów / linków, które mogą być interesujące, znajduje się poniżej - dodaj więcej w komentarzach, a ja w razie potrzeby zaktualizuję tę odpowiedź. Oczywiście istnieje kompromis między dokładnością a zasobami obliczeniowymi. [Szczerze mówiąc, jest zbyt wielu, aby podać przykłady kodu w jednej odpowiedzi, takiej jak ta, więc nie jestem pewien, czy ta odpowiedź będzie latać, czy nie.]
Ekstraktor źródłowy https://www.astromatic.net/software/sextractor
MultiNest https://github.com/farhanferoz/MultiNest [+ pyMultiNest]
Wyzwanie w poszukiwaniu źródła ASKAP / EMU: https://arxiv.org/abs/1509.03931
Możesz także wyszukać wyzwania związane z wydobyciem źródła przez Planck i / lub WMAP.
...
źródło
Co się stanie, jeśli wykonasz krok po kroku: najpierw zlokalizujesz globalne maksimum, w razie potrzeby przetworzysz otaczające punkty na podstawie ich wartości, następnie ustaw znaleziony region na zero i powtórz dla następnego.
źródło
Nie jestem pewien, czy to odpowiada na pytanie, ale wygląda na to, że możesz po prostu wyszukać n najwyższych szczytów, które nie mają sąsiadów.
Oto sedno. Zauważ, że jest w Ruby, ale pomysł powinien być jasny.
źródło