Jednym z najciekawszych projektów, nad którymi pracowałem w ciągu ostatnich kilku lat, był projekt dotyczący przetwarzania obrazu . Celem było opracowanie systemu umożliwiającego rozpoznawanie „puszek” Coca-Coli (zauważ, że podkreślam słowo „puszki”, za chwilę zrozumiesz dlaczego). Poniżej możesz zobaczyć próbkę z puszką rozpoznaną w zielonym prostokącie ze skalą i obrotem.
Niektóre ograniczenia dotyczące projektu:
- Tło może być bardzo głośne.
- Puszki może mieć jakąkolwiek skalę lub obrót lub orientacji nawet (w rozsądnych granicach).
- Obraz może mieć pewien stopień rozmycia (kontury mogą nie być całkowicie proste).
- Na obrazie mogą znajdować się butelki Coca-Coli, a algorytm powinien wykrywać tylko puszkę !
- Jasność obrazu może się bardzo różnić (więc nie można polegać „zbytnio” na wykrywaniu kolorów).
- Puszka może być częściowo ukryte po bokach i na środku i ewentualnie częściowo ukryty za butelkę.
- Na obrazie nie może być żadnej puszki , w którym to przypadku nie musisz nic znaleźć i napisać taką wiadomość.
Możesz więc skończyć z takimi trudnymi rzeczami (które w tym przypadku całkowicie zawiodły mój algorytm):
Zrobiłem ten projekt jakiś czas temu i miałem dużo zabawy, robiąc to, i miałem przyzwoitą implementację. Oto kilka szczegółów na temat mojej implementacji:
Język : Wykonano w C ++ przy użyciu biblioteki OpenCV .
Wstępne przetwarzanie : Do wstępnego przetwarzania obrazu, tj. Przekształcenia obrazu w bardziej surową formę w celu nadania algorytmowi, zastosowałem 2 metody:
- Zmiana domeny kolorów z RGB na HSV i filtrowanie w oparciu o „czerwony” odcień, nasycenie powyżej pewnego progu, aby uniknąć kolorów podobnych do pomarańczowego, oraz filtrowanie o niskiej wartości, aby uniknąć ciemnych tonów. Efektem końcowym był binarny czarno-biały obraz, w którym wszystkie białe piksele reprezentowałyby piksele pasujące do tego progu. Oczywiście na obrazie wciąż jest dużo badziewia, ale zmniejsza to liczbę wymiarów, z którymi musisz pracować.
- Filtrowanie szumów za pomocą filtrowania medianowego (pobieranie wartości mediany pikseli wszystkich sąsiadów i zastępowanie piksela tą wartością) w celu zmniejszenia szumu.
- Użycie Canny Edge Detection Filter do uzyskania konturów wszystkich elementów po 2 poprzednich krokach.
Algorytm : sam algorytm, który wybrałem do tego zadania, został zaczerpnięty z tej niesamowitej książki na temat ekstrakcji funkcji i nazywał się Uogólnioną transformatą Hougha (całkiem inną niż zwykła transformacja Hougha). Mówi w zasadzie kilka rzeczy:
- Możesz opisać obiekt w przestrzeni, nie znając jego równania analitycznego (co ma miejsce tutaj).
- Jest odporny na deformacje obrazu, takie jak skalowanie i obrót, ponieważ w zasadzie przetestuje obraz pod kątem każdej kombinacji współczynnika skali i współczynnika obrotu.
- Wykorzystuje model podstawowy (szablon), którego algorytm „się nauczy”.
- Każdy piksel pozostały na obrazie konturowym będzie głosował na inny piksel, który prawdopodobnie będzie środkiem (pod względem grawitacji) obiektu, na podstawie tego, czego nauczył się z modelu.
W końcu otrzymujesz mapę cieplną głosów, na przykład tutaj wszystkie piksele konturu puszki będą głosować za jej środkiem grawitacyjnym, więc będziesz mieć dużo głosów w tym samym pikselu odpowiadającym centrum i zobaczy szczyt na mapie ciepła, jak poniżej:
Gdy to osiągniesz, prosta heurystyka oparta na progach może podać lokalizację środkowego piksela, z którego możesz uzyskać skalę i obrót, a następnie narysować wokół niej swój mały prostokąt (ostateczna skala i współczynnik obrotu będą oczywiście zależne od twojego oryginalny szablon). Teoretycznie przynajmniej ...
Wyniki : Mimo że podejście to działało w podstawowych przypadkach, w niektórych obszarach bardzo go brakowało:
- To jest bardzo wolne ! Nie podkreślam tego wystarczająco. Potrzebny był prawie cały dzień na przetworzenie 30 zdjęć testowych, oczywiście ponieważ miałem bardzo wysoki współczynnik skalowania dla rotacji i translacji, ponieważ niektóre puszki były bardzo małe.
- Został całkowicie utracony, gdy butelki były na zdjęciu, i z jakiegoś powodu prawie zawsze znajdował butelkę zamiast puszki (być może dlatego, że butelki były większe, więc miały więcej pikseli, a więc więcej głosów)
- Rozmyte obrazy również nie były dobre, ponieważ głosy kończyły się w pikselach w losowych lokalizacjach w centrum, co zakończyło się bardzo głośną mapą ciepła.
- Osiągnięto różnice w translacji i rotacji, ale nie w orientacji, co oznacza, że puszka, która nie była skierowana bezpośrednio w stronę obiektywu aparatu, nie została rozpoznana.
Czy możesz mi pomóc ulepszyć mój specyficzny algorytm, używając wyłącznie funkcji OpenCV , aby rozwiązać cztery wymienione problemy?
Mam nadzieję, że niektórzy również się z tego czegoś nauczą, w końcu uważam, że nie tylko ludzie, którzy zadają pytania, powinni się uczyć. :)