Po moim poprzednim pytaniu dotyczącym znalezienia palców u każdej łapy , zacząłem ładować inne pomiary, aby zobaczyć, jak by to wytrzymało. Niestety szybko napotkałem problem z jednym z poprzednich kroków: rozpoznaniem łap.
Widzisz, mój dowód koncepcji w zasadzie wziął maksymalne ciśnienie każdego czujnika w czasie i zaczął szukać sumy każdego rzędu, dopóki się nie dowie! = 0,0. Następnie robi to samo dla kolumn i gdy tylko znajdzie więcej niż 2 wiersze, które są ponownie zerowe. Przechowuje minimalne i maksymalne wartości wierszy i kolumn w jakimś indeksie.
Jak widać na rysunku, w większości przypadków działa to całkiem dobrze. Istnieje jednak wiele wad tego podejścia (poza byciem bardzo prymitywnym):
Ludzie mogą mieć „puste stopy”, co oznacza, że w samym śladzie jest kilka pustych rzędów. Ponieważ obawiałem się, że to może się zdarzyć także w przypadku (dużych) psów, odciąłem łapę co najmniej 2 lub 3 puste rzędy.
Stwarza to problem, jeśli inny kontakt zostanie nawiązany w innej kolumnie, zanim osiągnie kilka pustych wierszy, rozszerzając w ten sposób obszar. Myślę, że mógłbym porównać kolumny i sprawdzić, czy przekraczają pewną wartość, muszą to być osobne łapy.
Problem pogarsza się, gdy pies jest bardzo mały lub chodzi w wyższym tempie. To, co się dzieje, polega na tym, że palce przednich łap wciąż się stykają, podczas gdy palce tylnych łap zaczynają się stykać w tym samym obszarze co przednia łapa!
Za pomocą mojego prostego skryptu nie będzie w stanie podzielić tych dwóch, ponieważ musiałby określić, które klatki tego obszaru należą do której łapy, podczas gdy obecnie musiałbym jedynie patrzeć na maksymalne wartości we wszystkich klatkach.
Przykłady sytuacji, w których zaczyna się źle:
Więc teraz szukam lepszego sposobu rozpoznawania i rozdzielania łap (po czym przejdę do problemu decydowania, która to łapa!).
Aktualizacja:
Majstrowałem, żeby zaimplementować odpowiedź Joe (niesamowite!), Ale mam trudności z wyodrębnieniem rzeczywistych danych łap z moich plików.
Coded_paws pokazuje mi wszystkie różne łapy po zastosowaniu do obrazu maksymalnego nacisku (patrz wyżej). Jednak rozwiązanie obejmuje każdą ramkę (aby oddzielić nakładające się łapy) i ustawia cztery atrybuty prostokąta, takie jak współrzędne lub wysokość / szerokość.
Nie mogę wymyślić, jak wziąć te atrybuty i zapisać je w jakiejś zmiennej, którą mogę zastosować do danych pomiarowych. Ponieważ muszę wiedzieć dla każdej łapy, jakie jest jej położenie, podczas których ramek i połączyć ją z tą łapą (przednia / tylna, lewa / prawa).
Jak więc użyć atrybutów Prostokąty, aby wyodrębnić te wartości dla każdej łapy?
Pomiary, których użyłem w konfiguracji pytania, mam w moim publicznym folderze Dropbox ( przykład 1 , przykład 2 , przykład 3 ). Dla wszystkich zainteresowanych założyłem również blog, aby informować Cię na bieżąco :-)
źródło
Odpowiedzi:
Jeśli jesteś po prostu chcąc (pół) regiony sąsiadujące, nie ma już łatwa implementacja w Pythonie: scipy „s ndimage.morphology moduł. Jest to dość powszechna operacja morfologii obrazu .
Zasadniczo masz 5 kroków:
Rozmyj nieco dane wejściowe, aby upewnić się, że łapy mają ciągły ślad. (Bardziej wydajne byłoby po prostu użycie większego jądra (
structure
kwarg do różnychscipy.ndimage.morphology
funkcji), ale z jakiegoś powodu to nie działa poprawnie ...)Przekrocz próg tablicy, aby uzyskać boolowską tablicę miejsc, w których ciśnienie przekracza pewną wartość progową (tj.
thresh = data > value
)Wypełnij wszelkie wewnętrzne otwory, aby uzyskać czystsze regiony (
filled = sp.ndimage.morphology.binary_fill_holes(thresh)
)Znajdź oddzielne sąsiadujące regiony (
coded_paws, num_paws = sp.ndimage.label(filled)
). Zwraca tablicę z regionami kodowanymi przez liczbę (każdy region jest ciągłym obszarem unikalnej liczby całkowitej (1 do liczby łap) z zerami wszędzie indziej).Wyizoluj sąsiednie regiony za pomocą
data_slices = sp.ndimage.find_objects(coded_paws)
. Zwraca listę krotekslice
obiektów, dzięki czemu można uzyskać region danych dla każdej łapy[data[x] for x in data_slices]
. Zamiast tego narysujemy prostokąt na podstawie tych plasterków, co wymaga nieco więcej pracy.Dwie poniższe animacje pokazują przykładowe dane „Nakładające się łapy” i „Zgrupowane łapy”. Ta metoda wydaje się działać idealnie. (I niezależnie od tego, co jest warte, działa to znacznie płynniej niż poniższe obrazy GIF na mojej maszynie, więc algorytm wykrywania łap jest dość szybki ...)
Oto pełny przykład (teraz ze znacznie bardziej szczegółowymi wyjaśnieniami). Zdecydowana większość z nich czyta dane wejściowe i tworzy animację. Rzeczywiste wykrywanie łap to tylko 5 linii kodu.
Aktualizacja: Jeśli chodzi o określenie, która łapa ma kontakt z czujnikiem w danym momencie, najprostszym rozwiązaniem jest po prostu wykonanie tej samej analizy, ale wykorzystanie wszystkich danych jednocześnie. (tj. ułóż dane wejściowe w tablicy 3D i pracuj z nimi zamiast z pojedynczymi ramami czasowymi.) Ponieważ funkcje ndimage SciPy są przeznaczone do pracy z tablicami n-wymiarowymi, nie musimy modyfikować oryginalnej funkcji wyszukiwania łap w ogóle.
źródło
convert *.png output.gif
. Na pewno wyobrażałem sobie, że wyobraźnia już wcześniej rzuciła moją maszynę na kolana, choć w tym przykładzie działała dobrze. W przeszłości używałem tego skryptu: svn.effbot.python-hosting.com/pil/Scripts/gifmaker.py, aby bezpośrednio napisać animowany gif z pythona bez zapisywania poszczególnych ramek. Mam nadzieję, że to pomaga! Podam przykład na wspomniane pytanie @unutbu.bbox_inches='tight'
wplt.savefig
, druga była niecierpliwość :)Nie jestem ekspertem w wykrywaniu obrazów i nie znam Pythona, ale dam mu to ...
Aby wykryć pojedyncze łapy, należy najpierw wybrać wszystko z naciskiem większym niż jakiś niewielki próg, bardzo zbliżonym do braku nacisku. Każdy piksel / punkt powyżej tego powinien być „oznaczony”. Następnie każdy piksel sąsiadujący ze wszystkimi „zaznaczonymi” pikselami zostaje zaznaczony, a proces ten powtarza się kilka razy. Tworzą się całkowicie połączone masy, więc masz wyraźne obiekty. Następnie każdy „obiekt” ma minimalną i maksymalną wartość xiy, dzięki czemu obwiednia może być starannie zapakowana wokół nich.
Pseudo kod:
(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.
To powinno zrobić.
źródło
Uwaga: mówię piksel, ale mogą to być regiony wykorzystujące średnią liczbę pikseli. Optymalizacja to kolejny problem ...
Wygląda na to, że musisz przeanalizować funkcję (ciśnienie w czasie) dla każdego piksela i określić, gdzie funkcja się obraca (kiedy zmienia się> X w innym kierunku, uważa się, że zwrot jest przeciwny błędom).
Jeśli wiesz, w których klatkach się obraca, poznasz klatkę, w której nacisk był najcięższy, i będziesz wiedział, gdzie była najmniej twarda między dwiema łapami. Teoretycznie znałbyś wtedy dwie klatki, w których łapy naciskały najmocniej, i mógłbyś obliczyć średnią z tych przedziałów.
To ta sama trasa, co wcześniej, wiedząc, kiedy każda łapa wywiera największy nacisk, pomaga podjąć decyzję.
źródło