Przetwarzanie obrazu: Ulepszenie algorytmu rozpoznawania „Coca-Coli Can”


1657

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.

Dopasowywanie wzorców

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):

Całkowity błąd

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:

  1. 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ć. Obraz binarny
  2. 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.
  3. Użycie Canny Edge Detection Filter do uzyskania konturów wszystkich elementów po 2 poprzednich krokach. Wykrywanie konturu

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:

GHT

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ć. :)


45
Można powiedzieć, że to pytanie jest bardziej odpowiednie na dsp.stackexchange.com lub stats.stackexchange.com, i na pewno powinieneś rozważyć ponowne pytanie również na tych stronach.
ely

49
Pierwszą rzeczą do zrobienia jest przeanalizowanie, dlaczego zdarzają się różne przypadki awarii. Np. Wyizoluj przykłady miejsc, w których wygrywają butelki, gdzie obrazy są rozmyte itp., I wykonaj analizę statystyczną, aby poznać różnicę między ich reprezentacjami Hougha a tymi, które chciałbyś wykryć. Niektóre wspaniałe miejsca, aby dowiedzieć się o alternatywnych podejść tutaj i tutaj
Ely

7
@stacker ma rację. Aby uzyskać szybkość, chcesz uzyskać tanie funkcje obliczeniowe, takie jak histogramy zorientowanych gradientów. Naprawdę naiwnym pierwszym podejściem byłoby ręczne oznaczenie kilku prostokątów puszek na niektórych obrazach szkoleniowych i użycie tych plus losowych negatywnych przykładów do wyszkolenia SVM lub klasyfikatora drzewa decyzyjnego. Szkolenie potrwa dłużej, ale wykonanie nowych powieści będzie znacznie szybsze. Planuję napisać tę metodę, kiedy będę mieć więcej wolnego czasu na zamieszczenie odpowiednich referencji.
ely

9
Co powiesz na podejście podobne do reCAPTCHA ? ;)
George Duckett

39
Dlaczego przeniesiono to z dsp.stackexchange.com ? Wygląda na to, że ta strona byłaby jeszcze lepsza niż stackoverflow o_O
BlueRaja - Danny Pflughoeft

Odpowiedzi:


672

Alternatywnym podejściem byłoby wyodrębnienie elementów (punktów kluczowych) przy użyciu niezmiennej w skali transformacji funkcji (SIFT) lub przyspieszonej niezawodnej funkcji (SURF).

Jest zaimplementowany w OpenCV 2.3.1.

Możesz znaleźć dobry przykład kodu, używając funkcji w Feature2D + Homography, aby znaleźć znany obiekt

Oba algorytmy są niezmienne dla skalowania i rotacji. Ponieważ działają one z funkcjami, możesz także obsługiwać okluzję (o ile widoczna jest wystarczająca liczba punktów kluczowych).

Wpisz opis zdjęcia tutaj

Źródło obrazu: przykład samouczka

Przetwarzanie zajmuje kilkaset ms dla SIFT, SURF jest nieco szybszy, ale nie nadaje się do aplikacji w czasie rzeczywistym. ORB używa FAST, który jest słabszy pod względem niezmienności rotacji.

Oryginalne dokumenty


6
Zgadzam się z @stacker - SIFT to doskonały wybór. Jest bardzo odporny na operacje skalowania i obrotu. Jest dość odporny na deformację perspektywy (można to poprawić zgodnie z sugestią układacza: baza danych szablonów z różnymi widokami perspektywicznymi pożądanego obiektu). Z mojego doświadczenia wynika, że ​​piętą achillesową byłyby silne warianty oświetlenia i bardzo kosztowne obliczenia. Nie znam żadnych implementacji Java. Jestem świadomy implementacji OpenCV i użyłem implementacji GPU c ++ / Windows ( SiftGPU ) odpowiedniej do wydajności w czasie rzeczywistym.

31
Uwaga: tak jak kocham SIFT / SURF i to, co mi zrobili, są obciążeni patentem. Może to stanowić problem, w zależności od wielu warunków, w tym położenia geograficznego AFAIK.
Agos,

12
Wypróbuj ORC lub FREAK OpenCV, które nie mają problemów patentowych. ORB jest znacznie szybszy niż SIFT. Kula jest trochę uboga ze skalą i lekkimi zmianami w moim doświadczeniu, ale sprawdź to sam.
Rui Marques

66
Jak możesz zaakceptować to jako odpowiedź ... Żaden z deskryptorów funkcji nie odróżnia butelek od puszek. Wszystkie po prostu wyświetlają niezmienne lokalne deskryptory wzorców. Zgadzam się, że SIFT, SURF, ORB, FREAK itp. Mogą pomóc w dopasowaniu funkcji, ale .. Co z pozostałymi częściami pytania, takimi jak okluzje, Butelka kontra puszka itp. Mam nadzieję, że nie jest to kompletne rozwiązanie, gdybyś chciał POSTĄPIŁO od problemu, prawdopodobnie pierwszym rezultatem będzie tylko ta odpowiedź.
G453,

11
@ G453 masz absolutną rację! Prawdopodobnie był zafascynowany występem SHIFT i zapomniał, że wyodrębnianie i dopasowywanie funkcji NIE JEST
PROBLEMEM

383

Aby przyspieszyć, skorzystam z faktu, że nie jesteś proszony o znalezienie dowolnego obrazu / obiektu, a konkretnie takiego z logo Coca-Coli. Jest to znaczące, ponieważ to logo jest bardzo charakterystyczne i powinno mieć charakterystyczną, niezmienną w skali sygnaturę w dziedzinie częstotliwości, szczególnie w czerwonym kanale RGB. Innymi słowy, naprzemienny wzór koloru czerwonego do białego do czerwonego napotykany przez poziomą linię skanowania (wytrenowaną na poziomo wyrównanym logo) będzie miał charakterystyczny „rytm”, gdy przechodzi przez środkową oś logo. Rytm ten „przyspieszy” lub „zwolni” w różnych skalach i orientacjach, ale pozostanie proporcjonalnie równoważny. Można zidentyfikować / zdefiniować kilkadziesiąt takich linii skanowania, zarówno poziomo, jak i pionowo, poprzez logo i kilka innych po przekątnej, we wzór gwiazdy. Nazwij je „liniami skanowania podpisów”.

Linia skanowania podpisu

Wyszukiwanie tego podpisu na obrazie docelowym to prosta kwestia zeskanowania obrazu poziomymi paskami. Poszukaj wysokiej częstotliwości w czerwonym kanale (wskazującym przejście z czerwonego obszaru do białego), a po znalezieniu sprawdź, czy następuje po nim jeden z rytmów częstotliwości określonych podczas sesji treningowej. Po znalezieniu dopasowania natychmiast poznasz orientację i położenie linii skanowania w logo (jeśli śledzisz te rzeczy podczas treningu), więc identyfikowanie granic logo jest stamtąd banalne.

Byłbym zaskoczony, gdyby nie był to algorytm wydajny liniowo lub prawie tak. Oczywiście nie odnosi się to do dyskryminacji butelek, ale przynajmniej będziesz mieć swoje logo.

(Aktualizacja: do rozpoznawania butelek szukałbym koksu (brązowej cieczy) sąsiadującego z logo - to znaczy wewnątrz butelki. Lub, w przypadku pustej butelki, szukałem zakrętki, która zawsze będzie miała ten sam podstawowy kształt, rozmiar i odległość od logo i zazwyczaj będą białe lub czerwone. Szukaj eliptycznego kształtu w jednolitym kolorze, w którym powinna znajdować się czapka , w stosunku do logo. Oczywiście nie jest to niezawodne, ale Twoim celem powinno być tutaj znaleźć łatwe te szybko ).

(Minęło kilka lat od moich dni przetwarzania obrazów, więc utrzymałem tę sugestię na wysokim poziomie i konceptualnie. Myślę, że może nieco przybliżać sposób działania ludzkiego oka - a przynajmniej mój mózg!)


24
To świetna sugestia, szczególnie podoba mi się fakt, że ten algorytm powinien być dość szybki, nawet jeśli prawdopodobnie będzie miał wiele fałszywych negatywów. Jednym z moich ukrytych celów jest wykorzystanie tego wykrywania w czasie rzeczywistym do robotyki, aby był to dobry kompromis!
Charles Menguy,

42
Tak, często zapomina się (w dziedzinie charakteryzującej się precyzją), że algorytmy aproksymacji są niezbędne dla większości zadań modelowania w czasie rzeczywistym. (Oparłem moją tezę na tej koncepcji.) Oszczędzaj czasochłonne algorytmy dla ograniczonych regionów (aby przycinać fałszywe alarmy). I pamiętaj: w robotyce zwykle nie jesteś ograniczony do jednego obrazu. Zakładając, że robot mobilny, szybki alg może wyszukiwać dziesiątki zdjęć pod różnymi kątami w krótszym czasie niż wyrafinowane glony spędzają na jednym, znacznie zmniejszając liczbę fałszywych negatywów.
kmote

29
Podoba mi się pomysł użycia skanera kodów kreskowych do bardzo szybkiego wykrywania logo Coca-Coli. +1!
Li-aung Yip

8
Problem ze znalezieniem podpisów w tym przypadku polega na tym, że jeśli odwrócimy puszkę na drugą stronę, tj. Ukrywając podpis, algorytm nie wykryje puszki.
karlphillip

34
@karlphillip: Jeśli ukryjesz podpis, tj. logo, każda metoda polegająca na szukaniu logo zawiedzie.
Li-aung Yip

162

Zabawny problem: kiedy spojrzałem na twoje zdjęcie butelki, pomyślałem, że to też może być puszka. Ale jako człowiek zrobiłam różnicę, że zauważyłam, że to także butelka…

Tak więc, aby odróżnić puszki i butelki od siebie, może po prostu najpierw przejrzysz butelki? Jeśli znajdziesz, zamaskuj etykietę, zanim zaczniesz szukać puszek.

Nie za trudne do wdrożenia, jeśli już robisz puszki. Prawdziwym minusem jest to, że podwaja Twój czas przetwarzania. (Ale myśląc o aplikacjach rzeczywistych, i tak będziesz chciał robić butelki ;-)


5
Tak, też o tym myślałem, ale nie miałem dużo czasu, aby to zrobić. Jak rozpoznałbyś butelkę, skoro jej główna część będzie wyglądać jak wyskalowana puszka? Zastanawiałem się również, czy nie mogę znaleźć czerwonej wtyczki i sprawdzić, czy jest ona wyrównana z butelkowanym środkiem, ale to nie wydaje się zbyt solidne.
Charles Menguy,

42
Jeśli równolegle do „Coca coli” jest czerwona czapka (lub pierścień), najprawdopodobniej jest to butelka.
Łukasz Madon

@linker Jak wytrenowałeś swój algorytm dla puszek? Czy masz przykłady puszek? Co powiesz na trening z przykładami butelek?
siamii

1
Siłą tego algorytmu jest to, że potrzebujesz tylko jednego szablonu, aby trenować, a następnie stosuje on wszystkie transformacje, aby dopasować go do innych potencjalnych puszek. Użyłem binarnej i opartej na konturach wersji tego szablonu, aby trenować, więc jedyną różnicą między puszką a butelką byłaby korek, ale obawiam się, że przyniosłoby to więcej fałszywych trafień, ponieważ środek ciężkości znajdowałby się gdzieś na krawędzi lub na zewnątrz butelki. Chyba warto spróbować. Ale to podwoi mój czas przetwarzania i zamierzam płakać;)
Charles Menguy

7
Zasadniczo jest to rozsądny kierunek. Wyraziłbym to nieco inaczej: najpierw znajdź wszystkich kandydatów, a następnie dla każdego kandydata ustal, czy jest to butelka, puszka czy coś innego.
MSalters

131

Czy nie jest trudno nawet ludziom odróżnić butelkę od puszki na drugim zdjęciu (pod warunkiem, że przezroczysty obszar butelki jest ukryty)?

Są prawie takie same, z wyjątkiem bardzo małego regionu (to znaczy szerokość na górze puszki jest trochę mała, podczas gdy opakowanie butelki ma taką samą szerokość na całej długości, ale niewielka zmiana, prawda?)

Pierwszą rzeczą, jaka przyszła mi do głowy, było sprawdzenie czerwonego wieczka butelki. Ale nadal jest problem, jeśli nie ma góry na butelkę lub jeśli jest częściowo ukryta (jak wspomniano powyżej).

Drugą rzeczą, o której myślałem, była przezroczystość butelki. OpenCV pracuje nad znalezieniem przezroczystych obiektów na obrazie. Sprawdź poniższe linki.

W szczególności spójrz na to, aby zobaczyć, jak dokładnie wykrywają szkło:

Zobacz wynik ich wdrożenia:

Wpisz opis zdjęcia tutaj

Mówią, że jest to realizacja dokumentu „Geodezyjny aktywny kontur konturowy do znalezienia szkła” autorstwa K. McHenry i J. Ponce, CVPR 2006 .

W twoim przypadku może to być trochę pomocne, ale problem pojawia się ponownie, jeśli butelka jest napełniona.

Myślę więc, że możesz najpierw poszukać przezroczystego korpusu butelek lub czerwonego obszaru połączonego z dwoma przezroczystymi obiektami z boku, którym jest oczywiście butelka. (Idealnie działa obraz w następujący sposób.)

Wpisz opis zdjęcia tutaj

Teraz możesz usunąć żółty region, czyli etykietę butelki i uruchomić algorytm, aby znaleźć puszkę.

W każdym razie to rozwiązanie ma również inne problemy, jak w innych rozwiązaniach.

  1. Działa tylko wtedy, gdy twoja butelka jest pusta. W takim przypadku będziesz musiał poszukać czerwonego regionu pomiędzy dwoma czarnymi kolorami (jeśli płyn Coca Coli jest czarny).
  2. Kolejny problem, jeśli część przezroczysta jest zakryta.

Ale w każdym razie, jeśli na zdjęciach nie ma żadnego z powyższych problemów, wydaje się, że jest to lepszy sposób.


+1 Myślałem o tym i byłem w stanie wdrożyć to podejście. Jednak @linker powinien udostępnić swój zestaw zdjęć, abyśmy mogli spróbować zgadnąć.
karlphillip

tak .. zbyt uważam, że byłoby dobrze, gdyby było więcej zdjęć.
Abid Rahman K

Biorąc pod uwagę, czy mamy tylko etykiety na butelki / puszki i żaden z innych wyróżniających czynników zakrętki lub przezroczystości puszki lub góry / dołu puszki - Szerokość butelki jest inna niż szerokość puszki.
Ken

Co jeśli puszka zostanie umieszczona przed logo butelki?
AlgoRythm

51

Bardzo podoba mi się odpowiedź Darrena Cooka i układacza na ten problem. Właśnie zastanawiałem się nad tymi komentarzami, ale wierzę, że moje podejście jest zbyt ukierunkowane na odpowiedź, aby nie opuścić tutaj.

Krótko mówiąc, zidentyfikowałeś algorytm, który określa, że ​​logo Coca-Coli jest obecne w określonym miejscu w kosmosie. Teraz próbujesz określić, dla dowolnych orientacji i dowolnych czynników skalowania, heurystykę odpowiednią do odróżnienia puszek Coca-Coli od innych przedmiotów, w tym: butelek , billboardów , reklam i akcesoriów Coca-Coli, wszystkie związane z tym kultowym logo. Nie wskazałeś wielu z tych dodatkowych przypadków w opisie problemu, ale uważam, że są one niezbędne dla powodzenia twojego algorytmu.

Sekret polega na tym, aby określić, jakie cechy wizualne może zawierać puszka lub, poprzez negatywną przestrzeń, jakie cechy są obecne dla innych produktów Coke, które nie są obecne dla puszek. W tym celu bieżąca odpowiedź naszkicuje podstawowe podejście do wybierania „może” wtedy i tylko wtedy, gdy „butelka” nie zostanie zidentyfikowana, czy to przez obecność zakrętki, płynu, czy innej podobnej heurystyki wizualnej.

Problem polega na tym, że się psuje. Butelka może na przykład być pusta i pozbawiona nakrętki, co prowadzi do fałszywie dodatniego wyniku. Lub może to być częściowa butelka z popsutymi dodatkowymi funkcjami, co ponownie prowadzi do fałszywego wykrywania. Nie trzeba dodawać, że nie jest to eleganckie i nie jest skuteczne dla naszych celów.

W tym celu najbardziej poprawne kryteria wyboru puszek wydają się następujące:

  • Czy kształt sylwetki obiektu, naszkicowany w pytaniu , jest prawidłowy? Jeśli tak, +1.
  • Jeśli założymy obecność światła naturalnego lub sztucznego, czy wykrywamy chromowany kontur na butelce, który wskazuje, czy jest on wykonany z aluminium? Jeśli tak, +1.
  • Czy stwierdzamy, że właściwości lustrzane obiektu są prawidłowe w stosunku do naszych źródeł światła ( ilustracyjny link wideo na temat wykrywania źródła światła )? Jeśli tak, +1.
  • Czy możemy określić inne właściwości dotyczące obiektu, które identyfikują go jako puszkę, w tym, ale nie wyłącznie, pochylenie obrazu topologicznego logo, orientację obiektu, zestawienie obiektu (na przykład na płaskiej powierzchni jak stół lub w kontekście innych puszek), a obecność zaczepu? Jeśli tak, dla każdego +1.

Twoja klasyfikacja może wyglądać następująco:

  • Jeśli dla każdego dopasowania kandydata zostanie wykryte logo Coca Coli, narysuj szarą ramkę.
  • Dla każdego meczu powyżej +2 narysuj czerwoną ramkę.

To wizualnie podkreśla użytkownikowi to, co zostało wykryte, podkreślając słabe pozytywy, które można poprawnie wykryć jako zniekształcone puszki.

Wykrywanie każdej właściwości niesie ze sobą bardzo różną złożoność czasową i przestrzenną, a dla każdego podejścia szybkie przejście przez http://dsp.stackexchange.com jest więcej niż rozsądne dla ustalenia najbardziej poprawnego i najbardziej wydajnego algorytmu dla twoich celów. Moim celem tutaj jest, czysto i prosto, podkreślenie, że wykrycie, czy coś jest puszką poprzez unieważnienie niewielkiej części przestrzeni wykrywania kandydatów, nie jest najbardziej niezawodnym ani skutecznym rozwiązaniem tego problemu, a najlepiej, abyś podjął odpowiednie działania odpowiednio.

I cześć, gratuluję opublikowania Hacker News! Ogólnie rzecz biorąc, jest to dość przerażające pytanie godne rozgłosu, który otrzymał. :)


2
To interesujące podejście, które warto przynajmniej spróbować, naprawdę podoba mi się twoje rozumowanie problemu
Charles Menguy

To właśnie tak myślałem: nie wykluczaj konkretnych rodzajów fałszywych trafień. Rządz więcej funkcji tego, co czyni puszkę colą. Ale zastanawiam się: co robisz ze ściśniętą puszką? Chodzi mi o to, że jeśli nadepniesz na puszkę coli, nadal będzie puszka coli. Ale nie będzie już miał tego samego kształtu. Czy jest to problem AI-Complete?
Ian

41

Patrząc na kształt

Weź podglądacz w kształcie czerwonej części puszki / butelki. Zauważ, jak puszka zwęża się nieznacznie u samej góry, podczas gdy etykieta na butelce jest prosta. Możesz je rozróżnić, porównując szerokość czerwonej części na całej jej długości.

Patrząc na najważniejsze wydarzenia

Jednym ze sposobów odróżnienia butelek od puszek jest materiał. Butelka wykonana jest z plastiku, a puszka z aluminium. W wystarczająco dobrze oświetlonych sytuacjach patrzenie na lusterko byłoby jednym ze sposobów odróżnienia etykiety butelki od etykiety puszki.

O ile mi wiadomo, w ten sposób człowiek odróżniałby dwa typy etykiet. Jeśli warunki oświetleniowe są złe, rozróżnienie tych dwóch elementów może być niepewne. W takim przypadku musisz być w stanie wykryć obecność samej przezroczystej / półprzezroczystej butelki.


Podoba mi się ten pomysł, ale wydaje się, że potrzebujesz naprawdę dobrych warunków oświetleniowych. Na przykładowym zdjęciu, na którym jest zarówno puszka, jak i butelka, wydaje się to nieco trudne do rozróżnienia.
Charles Menguy,

W swoim przykładzie zwróć uwagę, w jaki sposób odblask na plastikowej etykiecie jest znacznie bardziej rozproszony niż bardzo jasne plamy na puszce? Tak możesz powiedzieć.
tskuzzy

Rozumiem, jakiego rodzaju reprezentacji przestrzeni kolorów użyłbyś w tym przypadku do uchwycenia specularity w twoim algorytmie? Wydaje się to dość trudne do uzyskania w RGB lub HSV
Charles Menguy

2
Co jeśli źródło światła było za puszką? Myślę, że nie zobaczysz najważniejszego wydarzenia.
Rui Marques

37

Proszę spojrzeć na tracker Predator Zdenka Kalala . Wymaga to szkolenia, ale może aktywnie nauczyć się, jak śledzony obiekt wygląda w różnych orientacjach i skalach, i robi to w czasie rzeczywistym!

Kod źródłowy jest dostępny na jego stronie. Jest w MATLAB , ale być może jest już implementacja Java wykonana przez członka społeczności. Udało mi się ponownie wdrożyć część TLD z funkcją śledzenia w języku C #. O ile dobrze pamiętam, TLD używa paproci jako detektora punktów kluczowych. Zamiast tego używam SURF lub SIFT (już sugerowane przez @stacker), aby odzyskać obiekt, jeśli został on utracony przez moduł śledzący. Informacje zwrotne od trackera ułatwiają budowanie z czasem dynamicznej listy szablonów przesiewania / surfowania, które z czasem umożliwiają ponowne uzyskanie obiektu z bardzo wysoką precyzją.

Jeśli jesteś zainteresowany moją implementacją modułu śledzącego w języku C #, możesz zapytać.


Dzięki za link, który wygląda interesująco. Jeśli chodzi o szkolenie, jaki jest rozmiar zestawu treningów, który byłby rozsądny do osiągnięcia rozsądnych wyników? Jeśli masz implementację nawet w języku c #, byłoby to również bardzo pomocne!
Charles Menguy,

Podczas badania TLD znalazłem innego użytkownika szukającego implementacji w C # --- czy jest jakiś powód, aby nie umieszczać swojej pracy w Github? stackoverflow.com/questions/29436719/…
spillner

2
NB Lata później link już nie działa
J Evans

33

Jeśli nie jesteś ograniczony tylko do aparatu, który nie był objęty jednym z twoich ograniczeń, być może możesz przejść do korzystania z czujnika zasięgu, takiego jak Xbox Kinect . Dzięki temu można przeprowadzić dopasowaną segmentację obrazu w oparciu o głębię i kolor. Pozwala to na szybszą separację obiektów na obrazie. Następnie możesz użyć dopasowania ICP lub podobnych technik, aby nawet dopasować kształt puszki, a nie tylko jej obrysu lub koloru, a biorąc pod uwagę, że jest cylindryczny, może to być poprawna opcja dla dowolnej orientacji, jeśli masz poprzedni skan 3D celu. Techniki te są często dość szybkie, szczególnie gdy są używane do tak konkretnego celu, który powinien rozwiązać problem prędkości.

Mógłbym również zasugerować, niekoniecznie ze względu na dokładność lub szybkość, ale dla zabawy możesz użyć wyszkolonej sieci neuronowej na obrazie podzielonym na odcień, aby zidentyfikować kształt puszki. Są one bardzo szybkie i często mogą być do 80/90% dokładne. Trening byłby trochę długim procesem, ponieważ musiałbyś ręcznie zidentyfikować puszkę na każdym obrazie.


3
Właściwie nie wyjaśniłem tego w poście, ale do tego zadania dostałem zestaw około 30 obrazów i musiałem wykonać algorytm, który dopasowałby je wszystkie w różnych sytuacjach, zgodnie z opisem. Oczywiście niektóre obrazy zostały ostatecznie przetestowane, aby przetestować algorytm. Ale podoba mi się pomysł czujników Kinect i chciałbym przeczytać więcej na ten temat!
Charles Menguy,

Jaki byłby w przybliżeniu rozmiar zestawu treningowego z siecią neuronową, aby uzyskać satysfakcjonujące wyniki? Zaletą tej metody jest również to, że potrzebuję tylko jednego szablonu, aby dopasować prawie wszystko.
Charles Menguy

2
Jeśli twój zestaw obrazów jest predefiniowany i ograniczony, po prostu hardcorowo doskonałe wyniki w twoim
progu

Tak, jeśli trenuję na zbiorze danych, na którym mam zamiar uruchomić algorytm, na pewno uzyskam doskonałe wyniki :) Ale na przykład dla tego zadania program został ostatecznie przetestowany przez nauczyciela na zestawie przetrzymywanych obrazów . Chciałbym zrobić coś, co byłoby solidne i nie pasowało do danych treningowych.
Charles Menguy

Liczba zestawów treningowych jest różna, musisz jednak uważać na kilka rzeczy: Nie przestawaj, prawdopodobnie chcesz, aby zestaw testowy pokazał, jak idzie twoja dokładność. Również liczba zestawów treningowych będzie zależeć od liczby używanych warstw.
Fantastyczny Pan Lis,

24

Wykrywałbym czerwone prostokąty: RGB -> HSV, filtruj czerwony -> obraz binarny, zamykaj (rozszerzaj, a następnie eroduj, znany jak imclosew Matlabie)

Następnie spójrz przez prostokąty od największego do najmniejszego. Prostokąty, które mają mniejsze prostokąty w znanej pozycji / skali, mogą zostać usunięte (zakładając, że proporcje butelek są stałe, mniejszy prostokąt byłby zakrętką do butelki).

To zostawiłoby ci czerwone prostokąty, wtedy musisz jakoś wykryć logo, aby stwierdzić, czy jest to czerwony prostokąt czy puszka coli. Jak OCR, ale ze znanym logo?


2
Tak jak omawiano to na DSP w krótkim czasie, gdy został przeniesiony, niektóre butelki mogą nie mieć zatyczek;) lub korek może być częściowo ukryty.
Charles Menguy,

22

To może być bardzo naiwny pomysł (lub może w ogóle nie działać), ale wymiary wszystkich puszek coli są ustalone. Może się tak zdarzyć, jeśli ten sam obraz zawiera zarówno puszkę, jak i butelkę, możesz je rozróżnić pod względem wielkości (butelki będą większe). Teraz z powodu braku głębokości (tj. Mapowania 3D do mapowania 2D) możliwe jest, że butelka może wydawać się skurczona i nie ma różnicy wielkości. Możesz odzyskać niektóre informacje o głębokości za pomocą obrazowania stereo, a następnie odzyskać oryginalny rozmiar.


3
Właściwie nie: nie ma ograniczenia wielkości ani orientacji (lub orientacji, ale tak naprawdę nie poradziłem sobie z tym), więc możesz mieć butelkę bardzo daleko w tle i puszkę na pierwszym planie, a puszka byłaby znacznie większa niż butelka.
Charles Menguy,

Sprawdziłem również, że stosunek szerokości do wysokości jest dość podobny w przypadku butelki i może, więc tak naprawdę nie jest to również opcja.
Charles Menguy,

Współczynnik etykiet (będący znakiem towarowym) jest taki sam. Jeśli więc (większa) butelka znajduje się nieco dalej na zdjęciu, jej rozmiar będzie dokładnie taki sam jak puszki.
littleadv

3
Aby wyjaśnić nieco więcej. Załóżmy, że puszka ma wartość z = 0, a butelka ma wartość z = -100. Ponieważ butelka jest daleko w tyle, będzie wyglądać na mniejszą. Ale jeśli wiem, że butelka ma wartość z = -100 i może mieć wartość z = 0, to mogę obliczyć oczekiwany rozmiar puszki / butelki, jeśli oba są tłumaczone na z = 0. Więc teraz są na tej samej głębokości i dlatego mogę podejmować decyzje na podstawie wielkości.
Sharad

2
To jest tylko komentarz, a nie odpowiedź, ale znacznie bliżej jest być odpowiedzią niż powyższy komentarz jako odpowiedź z 120 głosami.
Fattie,

22

Hmm, właściwie myślę, że coś mi się podoba (to najbardziej interesujące pytanie w historii - szkoda byłoby nie kontynuować próby znalezienia „idealnej” odpowiedzi, nawet jeśli znaleziono akceptowalną). .

Gdy znajdziesz logo, twoje problemy są w połowie skończone. Potem trzeba tylko, aby dowiedzieć się różnic co wokół logo. Ponadto chcemy zrobić jak najmniej dodatkowych korzyści. Myślę, że to właściwie ta łatwa część ...

Co jest wokół logo? W przypadku puszki możemy zobaczyć metal, który pomimo działania oświetlenia nie zmienia się w swoim podstawowym kolorze. Tak długo, jak znamy kąt etykiety, możemy powiedzieć, co jest bezpośrednio nad nią, więc patrzymy na różnicę między nimi:

To, co powyżej i poniżej logo jest całkowicie ciemne, ma jednolity kolor. Stosunkowo łatwe pod tym względem.

Tutaj to, co powyżej i poniżej, jest jasne, ale nadal ma jednolity kolor. Jest całkowicie srebrny, a całkowicie srebrny metal wydaje się dość rzadki, podobnie jak srebrne kolory w ogóle. Dodatkowo jest w cienkim poślizgu i wystarczająco blisko czerwonego, który został już zidentyfikowany, dzięki czemu można prześledzić jego kształt na całej długości, aby obliczyć procent tego, co można uznać za metalowy pierścień puszki. Naprawdę potrzebujesz tylko niewielkiej części tego miejsca w dowolnym miejscu na puszce, aby stwierdzić, że jest częścią tego, ale nadal musisz znaleźć równowagę, która zapewni, że nie będzie to tylko pusta butelka z czymś metalowym za nią.

I w końcu podstępna. Ale nie takie trudne, gdy przechodzimy tylko przez to, co widzimy bezpośrednio nad (i poniżej) czerwonym opakowaniem. Jest przezroczysty, co oznacza, że ​​pokaże wszystko, co się za nim kryje. To dobrze, ponieważ rzeczy, które stoją za nim, prawdopodobnie nie będą tak spójne w kolorze, jak srebrny okrągły metal puszki. Może być za nim wiele różnych rzeczy, które mogłyby nam powiedzieć, że jest to pusta (lub wypełniona przezroczystą cieczą) butelka lub jednolity kolor, co może oznaczać, że jest wypełniona cieczą lub że butelka jest po prostu przed jednolity kolor. Pracujemy z tym, co najbliżej góry i dołu, a szanse na właściwe kolory we właściwym miejscu są stosunkowo niewielkie. Wiemy, że to butelka, ponieważ nie ma tego kluczowego elementu wizualnego puszki,

(ten ostatni był najlepszy, jaki mogłem znaleźć z pustej dużej butelki Coca Coli - co ciekawe, nakrętka ORAZ pierścień są żółte, co wskazuje, że nie należy polegać na zaczerwienieniu nakrętki)

W rzadkich przypadkach, gdy podobny odcień srebra znajduje się za butelką, nawet po pobraniu plastiku lub butelka jest w jakiś sposób wypełniona tym samym odcieniem srebrnej cieczy, możemy powrócić do tego, co możemy z grubsza oszacować jako kształt srebra - który, jak wspomniałem, jest okrągły i podąża za kształtem puszki. Ale choć brakuje mi pewnej wiedzy na temat przetwarzania obrazu, brzmi to wolno. Co więcej, dlaczego nie wywnioskować tego, sprawdzając po bokach logo, aby upewnić się, że nie ma w nim nic w tym samym srebrnym kolorze? Ach, ale co, jeśli za puszką jest ten sam odcień srebra? Następnie rzeczywiście musimy zwracać większą uwagę na kształty, ponownie patrząc na górę i dół puszki.

W zależności od tego, jak bezbłędnie to wszystko musi być, może być bardzo powolne, ale myślę, że moją podstawową koncepcją jest sprawdzenie najpierw najłatwiejszych i najbliższych rzeczy. Przejdź przez różnice kolorów wokół już dopasowanego kształtu (co i tak wydaje się najbardziej trywialną częścią), zanim przystąpisz do opracowywania kształtu pozostałych elementów. Aby to wymienić, idzie:

  • Znajdź główną atrakcję (czerwone tło logo i być może samo logo orientacyjne, choć w przypadku, gdy puszka zostanie odwrócona, musisz skoncentrować się na samym czerwonym)
  • Sprawdź kształt i orientację, jeszcze raz dzięki bardzo charakterystycznemu zaczerwienieniu
  • Sprawdź kolory wokół kształtu (ponieważ jest szybki i bezbolesny)
  • Na koniec, jeśli to konieczne, sprawdź kształt tych kolorów wokół głównej atrakcji dla właściwej okrągłości.

W przypadku, gdy nie możesz tego zrobić, prawdopodobnie oznacza to, że górna i dolna część puszki są zakryte, a jedynymi możliwymi rzeczami, których człowiek mógł użyć do niezawodnego rozróżnienia puszki i butelki, jest okluzja i odbicie puszki, która byłaby o wiele trudniejsza do przetworzenia. Jednak, aby pójść jeszcze dalej, możesz śledzić kąt puszki / butelki, aby sprawdzić cechy podobne do butelek, używając półprzezroczystych technik skanowania wymienionych w innych odpowiedziach.

Ciekawe dodatkowe koszmary mogą obejmować puszkę wygodnie siedzącą za butelką w takiej odległości, że metal tak się pokazuje powyżej i poniżej etykiety, co nadal zawodzi, dopóki skanujesz wzdłuż całej długości czerwonego etykieta - co w rzeczywistości jest większym problemem, ponieważ nie wykrywasz puszki tam, gdzie możesz ją mieć, w przeciwieństwie do tego, że faktycznie wykrywasz butelkę, w tym puszkę przez przypadek. W takim razie szklanka jest w połowie pusta!


Jako zrzeczenie się, nie mam doświadczenia ani nigdy nie myślałem o przetwarzaniu obrazów poza tym pytaniem, ale jest to tak interesujące, że zastanowiłem się nad tym głęboko, a po przeczytaniu wszystkich innych odpowiedzi uważam, że może to być najłatwiejszy i najskuteczniejszy sposób, aby to zrobić. Osobiście cieszę się, że tak naprawdę nie muszę myśleć o programowaniu tego!

EDYTOWAĆ

zły rysunek puszki w farbie stwardnienia rozsianego Dodatkowo spójrz na ten rysunek, który zrobiłem w MS Paint ... Jest absolutnie okropny i dość niekompletny, ale na podstawie samego kształtu i kolorów możesz zgadnąć, co prawdopodobnie będzie. W gruncie rzeczy są to jedyne rzeczy, które trzeba zawracać sobie głowy skanowaniem. Kiedy spojrzysz na tak bardzo charakterystyczny kształt i kombinację kolorów tak blisko, co jeszcze może być? Kawałek, którego nie malowałem, białe tło, należy uznać za „coś niespójnego”. Gdyby miał przezroczyste tło, mógłby przejść na prawie każdy inny obraz i nadal można go zobaczyć.


10
Szczególny odcień czerwieni jest głównie subiektywny i silnie wpływają na to względy oświetlenia i balans bieli. Możesz być zaskoczony, jak wiele mogą się zmienić. Rozważmy na przykład iluzję szachownicy .
Octopus,

1
Aktualizacja linku opublikowanego przez @Octopus
Hat

Złudzenie postrzegania nie wpływa na to, co widzi kamera internetowa - tj. Na kod, tylko na to, jak ludzkie oko pomaga (?) Oszukać mózg.
barny

17

Nie znam OpenCV, ale logicznie patrzę na problem. Myślę, że możesz rozróżnić butelkę i zmieniając obraz, którego szukasz, np. Coca Cola. Powinieneś dołączyć do górnej części puszki, ponieważ w przypadku puszki znajduje się srebrna podszewka u góry coca coli, aw przypadku butelki nie będzie takiej srebrnej podszewki.

Ale oczywiście ten algorytm zawiedzie w przypadkach, gdy górna część puszki jest ukryta, ale w takim przypadku nawet człowiek nie będzie w stanie rozróżnić tych dwóch (jeśli widoczna jest tylko część butelki / puszki coca cola)


1
Myślałem tak samo, ale myślę, że srebrna podszewka na górze puszki zmienia się dramatycznie w zależności od kąta puszki na zdjęciu. Może to być linia prosta lub okrąg. Może mógłby użyć obu jako odniesienia?
Alexis Dufrenoy

15

Lubię wyzwanie i chciałem udzielić odpowiedzi, która, jak sądzę, rozwiązuje problem.

  1. Wyodrębnij cechy (punkty kluczowe, deskryptory, takie jak SIFT, SURF) logo
  2. Dopasuj punkty do obrazu modelu logo (używając Matchera, takiego jak Brute Force)
  3. Oszacuj współrzędne ciała sztywnego (problem PnP - SolvePnP)
  4. Oszacuj pozycję nasadki zgodnie ze sztywnym korpusem
  5. Wykonaj projekcję wsteczną i oblicz pozycję piksela obrazu (ROI) na zakrętce butelki (zakładam, że masz wewnętrzne parametry aparatu)
  6. Sprawdź za pomocą metody, czy czapka jest na miejscu, czy nie. Jeśli tak, to jest to butelka

Wykrywanie czapki to kolejny problem. Może to być skomplikowane lub proste. Gdybym był tobą, po prostu sprawdziłbym histogram kolorów w ROI, aby podjąć prostą decyzję.

Proszę o informację zwrotną, jeśli się mylę. Dzięki.


13

Kilka lat spóźniłem się z odpowiedzią na to pytanie. Biorąc pod uwagę najnowocześniejszy stan wiedzy, który został przekroczony przez CNN w ciągu ostatnich 5 lat, nie użyłbym teraz OpenCV do wykonania tego zadania! ( Wiem, że szczególnie chciałeś funkcji OpenCv w pytaniu ). Wydaje mi się, że algorytmy wykrywania obiektów, takie jak Faster-RCNN, YOLO, SSD itp., Pokonałyby ten problem ze znacznym marginesem w porównaniu z funkcjami OpenCV. Gdybym miał teraz rozwiązać ten problem (po 6 latach !!), zdecydowanie użyłbym Faster-RCNN .


5
OP powiedział, że jest 30 obrazów w wysokiej rozdzielczości, co prawdopodobnie nie jest najlepszym scenariuszem do szkolenia ConvNets. Nie tylko jest ich za mało (a nawet rozszerzone), ale także część o wysokiej rozdzielczości zniszczy ConvNets.
Kostas Mouratidis

11

Podoba mi się twoje pytanie, niezależnie od tego, czy jest nie na temat, czy nie: P

Ciekawe na bok; Właśnie ukończyłem przedmiot, który obejmował robotykę i wizję komputerową. Nasz projekt na semestr był niesamowicie podobny do tego, który opisujesz.

Musieliśmy opracować robota, który używał Xbox Kinect do wykrywania butelek i puszek z koksem w dowolnej orientacji w różnych warunkach oświetleniowych i środowiskowych. Nasze rozwiązanie polegało na zastosowaniu filtru pasmowo-przepustowego na kanale Barwa w połączeniu z transformacją koła Hougha. Byliśmy w stanie nieco ograniczyć środowisko (mogliśmy wybrać, gdzie i jak ustawić robota i czujnik Kinect), w przeciwnym razie użyjemy transformacji SIFT lub SURF.

O naszym podejściu możesz przeczytać na moim blogu na ten temat :)


2
Ciekawy projekt, ale dotyczy tylko bardzo specyficznej konfiguracji.
Rui Marques

10

Istnieje wiele deskryptorów kolorów używanych do rozpoznawania obiektów, poniższy papier porównuje wiele z nich. Są szczególnie wydajne w połączeniu z SIFT lub SURF. Same SURF lub SIFT nie są zbyt przydatne w obrazie coca coli, ponieważ nie rozpoznają wielu punktów zainteresowania, potrzebujesz informacji o kolorze, aby pomóc. Używam BIC (Border / Interior Pixel Classi fi kation) z SURF w projekcie i świetnie sprawdzało się rozpoznawanie obiektów.

Deskryptory kolorów dla pobierania obrazów z Internetu: badanie porównawcze


10

Głęboka nauka

Zbierz co najmniej kilkaset zdjęć zawierających puszki coli, oznacz obwiednię wokół nich jako klasy pozytywne, w tym butelki z colą i inne produkty coli oznaczaj je jako klasy negatywne, a także losowe obiekty.

Jeśli nie zbierzesz bardzo dużego zestawu danych, wykonaj sztuczkę polegającą na korzystaniu z funkcji głębokiego uczenia się w przypadku małego zestawu danych. Idealnie przy użyciu kombinacji maszyn wektorów wsparcia (SVM) z głębokimi sieciami neuronowymi.

Po wprowadzeniu obrazów do wcześniej wyszkolonego modelu dogłębnego uczenia się (np. GoogleNet), zamiast wykorzystywać warstwę decyzyjną (ostatnią) sieci neuronowej do klasyfikacji, użyj danych z poprzednich warstw jako funkcji do szkolenia klasyfikatora.

OpenCV i Google Net: http://docs.opencv.org/trunk/d5/de7/tutorial_dnn_googlenet.html

OpenCV i SVM: http://docs.opencv.org/2.4/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html


9

Potrzebujesz programu, który uczy się i poprawia dokładność klasyfikacji na podstawie własnego doświadczenia.

Zasugeruję głębokie uczenie się, przy głębokim uczeniu się staje się to trywialny problem.

Możesz przekwalifikować model początkowy v3 na Tensorflow:

Jak przekwalifikować końcową warstwę Incepcji dla nowych kategorii .

W takim przypadku będziesz trenował splotową sieć neuronową, aby sklasyfikować obiekt jako coca-cola, czy nie.


2
Hot dog czy nie hot dog?
YellowPillow

6

Alternatywą dla wszystkich tych fajnych rozwiązań jest wyszkolenie własnego klasyfikatora i zwiększenie odporności aplikacji na błędy. Jako przykład możesz użyć treningu Haar , zapewniającego dużą liczbę pozytywnych i negatywnych obrazów twojego celu.

Przydatne może być wyciąganie tylko puszek i można je łączyć z wykrywaniem przezroczystych obiektów.


3

Istnieje pakiet wizji komputerowej o nazwie HALCON firmy MVTec, którego dema mogą dostarczyć dobrych pomysłów na algorytm. Istnieje wiele przykładów podobnych do problemu, które można uruchomić w trybie demonstracyjnym, a następnie spojrzeć na operatorów w kodzie i zobaczyć, jak je zaimplementować z istniejących operatorów OpenCV.

Użyłem tego pakietu, aby szybko prototypować złożone algorytmy dla takich problemów, a następnie znaleźć sposób ich implementacji przy użyciu istniejących funkcji OpenCV. W szczególności w twoim przypadku możesz spróbować zaimplementować w OpenCV funkcjonalność osadzoną w operatorze find_scaled_shape_model . Niektórzy operatorzy wskazują na artykuł naukowy dotyczący implementacji algorytmów, który może pomóc dowiedzieć się, jak zrobić coś podobnego w OpenCV. Mam nadzieję że to pomoże...


0

Jeśli interesuje Cię to, aby działało w czasie rzeczywistym, musisz dodać filtr wstępnego przetwarzania, aby określić, co zostanie zeskanowane za pomocą ciężkich urządzeń. Dobry szybki filtr wstępnego przetwarzania w czasie rzeczywistym, który pozwala skanować rzeczy, które mogą być coca-colą, zanim przejdzie do bardziej niepewnych rzeczy, jest mniej więcej taki: wyszukaj obraz w poszukiwaniu największych łat koloru, który jest pewną tolerancją z dala od sqrt(pow(red,2) + pow(blue,2) + pow(green,2))puszki coca-coli. Zacznij od bardzo ścisłej tolerancji kolorów i przejdź do łagodniejszych tolerancji kolorów. Następnie, gdy robotowi zabraknie przydzielonego czasu na przetworzenie bieżącej ramki, wykorzystuje aktualnie znalezione butelki do twoich celów. Pamiętaj, że będziesz musiał dostosować kolory RGB, sqrt(pow(red,2) + pow(blue,2) + pow(green,2))aby uzyskać je dokładnie.

Poza tym wydaje się to głupie, ale czy upewniłeś się, że -oFastwłączyłeś optymalizacje kompilatora podczas kompilacji kodu C?


0

Może zbyt wiele lat spóźnienia, ale jednak teoria do wypróbowania.

Stosunek ograniczającego prostokąta obszaru czerwonego logo do ogólnego wymiaru butelki / puszki jest inny. W przypadku Can powinien wynosić 1: 1, natomiast będzie różny w butelce (z lub bez zakrętki). Powinno to ułatwić rozróżnienie między nimi.

Aktualizacja: Pozioma krzywizna regionu logo będzie różna dla puszki i butelki ze względu na ich różnicę wielkości. Może to być szczególnie przydatne, jeśli twój robot musi podnieść puszkę / butelkę i odpowiednio zdecydujesz o chwycie.


-1

Pierwszych rzeczy, których szukałem, to kolor - jak CZERWONY, podczas wykrywania czerwonych oczu na obrazie - istnieje pewien zakres kolorów do wykrycia, niektóre cechy dotyczące tego, biorąc pod uwagę otaczający obszar i takie jak odległość od drugiego oka, jeśli to jest rzeczywiście widoczny na obrazie.

1: Pierwszą cechą jest kolor, a czerwony dominuje. Po wykryciu Coca Coli Red jest kilka interesujących elementów 1A: Jak duży jest ten czerwony obszar (czy jest wystarczającej ilości, aby ustalić prawdziwą puszkę, czy nie - 10 pikseli to prawdopodobnie za mało), 1B: Czy zawiera kolor etykiety - „Coca-Cola” lub fala. 1B1: Czy jest wystarczająco dużo, aby rozważyć wysokie prawdopodobieństwo, że jest to etykieta.

Pozycja 1 jest rodzajem skrótu - proces wstępny, jeśli na obrazie nie ma smoka - przejdź dalej.

Więc jeśli tak jest, mogę wykorzystać ten fragment mojego obrazu i zacząć trochę bardziej oddalać dany obszar - w zasadzie spójrz na otaczający region / krawędzie ...

2: Biorąc pod uwagę powyższy obszar obrazu o numerze ID 1 - sprawdź otaczające punkty [krawędzie] danego elementu. Odp .: Czy istnieje coś, co wydaje się być górną lub dolną puszką - srebrne? B: Butelka może wydawać się przezroczysta, ale może też szklany stolik - podobnie jak szklany stolik / półka lub przezroczysty obszar - jeśli tak, istnieje wiele możliwych wyjść. Butelka MOŻE mieć czerwoną nasadkę, może nie, ale powinna mieć albo kształt górnej części butelki / śruby gwintowane, albo nasadkę. C: Nawet jeśli to się nie powiedzie A i B, to wciąż może to być puszka - częściowa. Jest to bardziej skomplikowane, gdy jest częściowe, ponieważ częściowa puszka / częściowa puszka może wyglądać tak samo, więc trochę więcej przetwarzania pomiaru krawędzi obszaru czerwonego do krawędzi .. mała butelka może mieć podobny rozmiar ..

3: Po powyższej analizie, kiedy spojrzałem na literę i logo fali - ponieważ mogę ukierunkować wyszukiwanie niektórych liter w słowach, ponieważ możesz nie mieć całego tekstu z powodu braku wszystkich może, fala wyrównałaby się w pewnych punktach do tekstu (pod względem odległości), więc mogłam wyszukać to prawdopodobieństwo i wiedzieć, które litery powinny istnieć w tym punkcie fali w odległości x.


-9

To jest stary projekt, nad którym pracowałem. Obrazy MAP są bardzo łatwe w użyciu z javascript. Oferuję ci przedmiot, czytasz go i wiesz, jak go używać. Nie potrzebujemy JQuery i innych systemów do korzystania z obrazów MAP.

    //Copyright Cherif yahiaoui, by ELEBAN.FR

//variables de flottement.
var myInstOne = null;
var globalize = null;

var eleban_preload_images = function (name, imgs, url){
try{
    var oThis = this;
    this.images = new Array();
    this.imageshover = new Array();
    this.imagesNames = new Array(imgs.split(";"));


        for(var i=0; i < this.imagesNames[0].length; i++){
            this.images[i] = new Image();
            this.imageshover[i] = new Image();
        }

    this.url = url;

    this.GetAbsoluteurl = function () {

    var img = new Image(); img.src = url;
    url = img.src; img = null; 
        this.url = url; 

    };

    this.Preload = function () {

        for(var i=0; i < this.imagesNames[0].length; i++){
            this.images[i].src = this.url+("btn-"+this.imagesNames[0][i]+".png");
            this.imageshover[i].src = this.url+("btn-"+this.imagesNames[0][i]+"-hover.png");
        }

    };
    this.GetAbsoluteurl();
    this.Preload();
}
finally {return;}
}

var g_preloaderhover = new eleban_preload_images("loaderhover","menu;malette;reservation;cabine;facebook;map;amis","./images/");


//variable arret flottement
var g_stopflo = false;

var myObjfloater = function(name, idname, itop, differ ) {
var oThis = this; // création d'une référence vers l'objet courant
this.name = name;
this.id =idname;
this.xstep= 0.3;
this.itime = 30;
this.obj = null;
this.y = itop;
this.yadd = 0;
this.up = true;
this.pause = false;
this.differ = differ;
this.coordsimage = null;
this.objimg = null;
this.initimages = false;
this.compteur = 0;
this.over = false;
this.timeoutstop = null;
try{
this.initimage = function(){
var img = this.obj.getElementsByTagName('img')[0];
this.coordsimage = new Array(img.width, img.height);
this.objimg = img;
this.initimages = true;
};


this.myMethod = function() {
if(!g_stopflo){
    if(this.differ != 0){ 
this.differ=this.differ-0.1; 
}else{

if(this.obj){
if(this.over == false){
    this.yadd=this.yadd+0.1; this.itime = this.itime + 10;
this.obj.style.visibility = "hidden";
this.y = ((this.up)? this.y - this.yadd : this.y + this.yadd);
this.obj.style.marginTop = this.y +"%" ;
this.obj.style.visibility = "visible";

if (this.yadd > this.xstep){ 
    this.up = (this.up)? false : true;
    this.yadd = -0.1; this.itime=180;
}
}
}else{
    if (document){
        if(document.getElementById) {
         this.obj = document.getElementById(this.id); 
        //this.y = this.obj.offsetTop;
        }else{
        if(document.getElementByTagName) { this.obj = document.getElementByTagName(this.id); this.y = this.obj.offsetTop;}
        }

    }
}
}
this.timeoutstop=setTimeout(function() { oThis.myMethod(); }, this.itime);
}    
};

this.callDelayed = function() {
    // utilisation de la référence vers l'objet
if(!g_stopflo){
    this.timeoutstop=setTimeout(function() { oThis.myMethod(); }, this.itime);
}
};
}
finally {return;}
};

// special creation des zones AREA
function eleban_createallarea(){
try{
var measur = new Array("w", "h");
measur["w"] = new Array(330,570,185,300,115,390,225);
measur["h"] = new Array(460,570,295,450,100,190,115);
var ititle = new Array("Voir les menus  et nos suggestions","Repas &agrave; emporter","R&eacute;servation d&rsquo;une table","Nous contacter","Nous rejoindre sur FaceBook","Calculer votre trajet","liste des amis");
var ihref = new Array("menus.html","emporter.html","reservation.html","contact.html","likebox.html","google.html","amis.html");
var b_map = new Array(0,1,2,3,4,5,6);
b_map[0] = "71,32,240,32,249,43,289,352,280,366,102,385,90,371,51,38";
b_map[1] = "66,52,95,14,129,56,115,91,100,93,112,273,128,284,122,366,176,343,193,296,191,194,147,189,145,166,201,111,199,84,545,105,532,354,509,388,412,478,32,401,77,383,87,375,82,286,95,269,94,221,24,195,11,165,9,120,89,123,89,94,78,92,77,92,77,93,75,93,77,93,76,93,79,92";
b_map[2] = "19,25,169,38,173,112,161,113,105,103,90,125,91,262,121,269,124,281,96,293,62,289,49,281,56,268,83,264,84,121,71,98,16,90";
b_map[3] = "60,0,216,1,226,20,225,403,168,421,42,410,45,10";
b_map[4] = "31,7,72,10,82,18,88,45,88,71,76,81,29,80,17,68,16,18";
b_map[5] = "91,40,141,38,178,27,184,4,211,5,223,24,240,23,386,135,229,121,103,180,6,156,49,94";
b_map[6] = "6,32,69,18,79,6,118,7,141,2,149,10,211,17,202,28,209,30,189,62,195,70,178,74,180,90,164,90,154,107,68,101,34,104,34,98,18,97,28,84,15,84,30,65";

if (document.getElementById){
for (var i=0; i<b_map.length;i++){
var obj = document.getElementById("pc_menu"+i);
    if(obj){
    var ct = '<img class=\"pc_menu\" src=\"'+g_preloaderhover.images[i].src+'\" alt=\"\" width=\"'+measur["w"][i]+'\" height=\"'+measur["h"][i]+'\" usemap=\"#MAP_INDEX'+i+'\" \/>';
    ct+='<map name=\"MAP_INDEX'+i+'\">';
    ct+='<area shape=\"poly\" coords=\"'+b_map[i]+'\" title=\"'+ititle[i]+'\" href=\"'+ihref[i]+'\" \/>';
    ct+='<\/map>';
    obj.innerHTML = ct;
    }
}
}
}
finally {return;}
}

//preload, creation et gestion de tous les evenements


var image_resizer = function(g_layer){


    b_org_elm = new Array("w",  "h");
    b_org_elm["w"] = new Array(330,570,185,300,115,390,225);
    b_org_elm["h"] = new Array(460,570,295,450,100,190,115);

    b_map = new Array(0,1,2,3,4,5,6);
    b_map[0] = new Array(71,32,240,32,249,43,289,352,280,366,102,385,90,371,51,38);
    b_map[1] = new Array(66,52,95,14,129,56,115,91,100,93,112,273,128,284,122,366,176,343,193,296,191,194,147,189,145,166,201,111,199,84,545,105,532,354,509,388,412,478,32,401,77,383,87,375,82,286,95,269,94,221,24,195,11,165,9,120,89,123,89,94,78,92,77,92,77,93,75,93,77,93,76,93,79,92);
    b_map[2] = new Array(19,25,169,38,173,112,161,113,105,103,90,125,91,262,121,269,124,281,96,293,62,289,49,281,56,268,83,264,84,121,71,98,16,90);
    b_map[3] = new Array(60,0,216,1,226,20,225,403,168,421,42,410,45,10);
    b_map[4] = new Array(31,6,70,10,78,18,84,23,88,44,88,70,78,80,75,81,33,82,23,76,18,69,16,22,21,13);
    b_map[5] = new Array(91,40,141,38,178,27,184,4,211,5,223,24,240,23,386,135,229,121,103,180,6,156,49,94);
    b_map[6] = new Array(6,32,69,18,79,6,118,7,141,2,149,10,211,17,202,28,209,30,189,62,195,70,178,74,180,90,164,90,154,107,68,101,34,104,34,98,18,97,28,84,15,84,30,65);


    b_layer = g_layer;

//gere mouseover
    this.mouseover = function(e){
        if (!e) var e = window.event;
        var tg = (window.event) ? e.srcElement : e.target
            if (tg.nodeName){
                if(tg.nodeName == "AREA"){
                var divpar = (tg.parentNode)? tg.parentNode.parentNode : tg.parentElement.parentElement;
                    if (divpar){
                        if(divpar.nodeName == "DIV"){
                            var iiobjimg = divpar.getElementsByTagName('img');
                                if (iiobjimg){
                                    ii = parseInt(divpar.id.substring(divpar.id.length-1,divpar.id.length));
                                    iiobjimg[0].src = g_preloaderhover.imageshover[ii].src;
                                }
                        }
                    }
                }
            }
    };

//gere mouseout
    this.mouseout = function(e){
        if (!e) var e = window.event;
        tg = (window.event) ? e.srcElement : e.target
            if (tg.nodeName){
                if(tg.nodeName == "AREA"){
                divpar = (tg.parentNode)? tg.parentNode.parentNode : tg.parentElement.parentElement;
                    if (divpar){
                        if(divpar.nodeName == "DIV"){
                            var iiobjimg = divpar.getElementsByTagName('img');
                                if (iiobjimg){
                                    ii = parseInt(divpar.id.substring(divpar.id.length-1,divpar.id.length));
                                    iiobjimg[0].src = g_preloaderhover.images[ii].src;
                                }
                        }
                    }
                }
            }
    };

//ajout evenements entree sortie à la page web lors du chargement de la page
    this.init = function () {

        for(var i=0; i<b_org_elm["w"].length;i++){
            w = document.getElementById("pc_menu"+i).offsetWidth;
            h = document.getElementById("pc_menu"+i).offsetHeight;

            xa = w/parseFloat(b_org_elm["w"][i]);
            ya = h/parseFloat(b_org_elm["h"][i]);

            area = document.getElementById("pc_menu"+i).getElementsByTagName('area')[0];

            b_map2 = area.coords.split(",");
            yswitch = true;
                for(m=0; m<b_map2.length;m++){
                b_map2[m] = Math.round(parseFloat(b_map[i][m]) * ((yswitch)? xa: ya));
                yswitch = (yswitch)? false :  true;
                }
            area.coords = b_map2.join(',');
        }
    }; 


    this.resize = function () {
    clearTimeout(myInstOne.timeoutstop);
    g_stopflo=true;

    globalize.init();
    g_stopflo=false;
    myInstOne.obj = null;
    myInstOne.callDelayed();
    };


    nar = document.getElementsByTagName('area').length;

        for(var i=0; i<nar;i++){
            var elem = document.getElementsByTagName('area')[i];
            if (elem.addEventListener){
                    elem.addEventListener("onmouseover",this.mouseover,true);
                elem.addEventListener("onmouseout",this.mouseout,true);
            }else if (elem.attachEvent) {
                    elem.attachEvent("onmouseover", this.mouseover);
                    elem.attachEvent("onmouseout", this.mouseout);
            }else{
                    elem["onmouseover"] = this.mouseover;
                    elem["onmouseout"] = this.mouseout;
            }
        }

            window.onresize = this.resize;
        window.onmouseover = this.mouseover;
        window.onmouseout = this.mouseout;
}


//permet de temporiser et éviter les erreurs de chargement des objets
function temporise_Init(Lastdiv){
if(document.getElementById){
    if(document.getElementById(Lastdiv)){

    eleban_createallarea();

    myInstOne = new myObjfloater('b_menumap11', 'pc_menu1', 1, 0);

    globalize = new image_resizer(document.getElementById('pc_redim'));
    globalize.init();
        globalize.resize();



    }else{
    setTimeout(temporise_Init(Lastdiv), 30);
    }
}
}


window.onload = function () {
temporise_Init("pc_bandeau");
}

2
co to robi
user8408080
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.