2012-08-28 34 views
10

Pracuję nad aplikacją rozpoznawania kształtów. W tym momencie zestaw punktów (x, y) jest określany przez detektor narożny (czerwone punkty, img 2.). Cztery z tych punktów (w czerwonych ramkach, imam. 2.) Są wierzchołkami prostokąta (czasami trochę zniekształconego prostokąta). Jaki byłby najlepszy sposób na znalezienie ich między innymi?Jak sprawdzić, czy cztery punkty tworzą prostokąt?

Oto przykładem obrazu wejściowego: Input image

A wygląda to tak po wykryciu róg:

Image with detected corners

Odpowiedz

11

To nie jest odpowiedź na twoje pytanie - to tylko sugestia.

Moim zdaniem wykrywacz naroży jest złym sposobem na wykrycie prostokątów - zajmie to dużo czasu, aby obliczyć wszystkie odległości w punktach, sugerowane przez mathematician1975. W tej sytuacji musisz zastosować inną technikę:

  1. Ten znaczek ma kolor fioletowy, więc pierwszą rzeczą, którą powinieneś zrobić, jest segmentacja kolorów.
  2. Po wykonaniu czynności z krok 1 można użyć do wykrywania linii na obrazie binarnym. Lub znajdź wszystkie kontury na obrazie.
  3. Ostatnim krokiem jest wykrycie prostokąta.

Aktualizacja:

Oto kolejne rozwiązanie, które powinny również działać w szarych obrazów.

  1. Czy próg do konwersji obrazu do 1bit (użyłem od 255 za progiem).
  2. Znajdź wszystkie kontury w nowym obrazku, które mają większy obszar niż pewna stała (wzięłam).
  3. Znajdź obwiedni prostokąt dla każdego konturu i zrobić test:

ContourArea/BoundingReactangleArea> stała

zażyciem constant jak 0,9.

I to algorytm dał mi następny wynik: enter image description here

Oto kod OpenCV:

Mat src = imread("input.jpg"), gray, result; 
vector<vector<Point> > contours; 
vector<Vec4i> hierarchy; 

result = Mat(src.size(), CV_8UC1); 

cvtColor(src, src, CV_BGR2GRAY); 
threshold(src, gray, 200, 255, THRESH_BINARY_INV); 
findContours(gray, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 

result = Scalar::all(0); 
for (size_t i=0; i<contours.size(); i++) 
{ 
    Rect rect = boundingRect(contours[i]); 
    if (rect.area() > 1000) 
    { 
     double area = contourArea(contours[i]); 
     if (area/rect.area() > 0.9) 
     { 
      drawContours(result, contours, i, Scalar(255), -1); 
     } 
    } 
} 
+0

Tak, jak zauważyłeś, obliczenie wszystkich odległości zajmuje dużo czasu, nawet dla _small_ obrazu wejściowego. Sprawdziłem już to rozwiązanie. Segmentacja kolorów nie byłaby przydatna w przypadku obrazów w skali szarości (przykłady są nieco mylące, przepraszam), ale użyłem ich do renderowania RGB. Jeśli chodzi o transformację Hougha, zrobiłem kilka testów i działa całkiem dobrze, ale wykryte linie ** nie ** krzyżują się ze sobą, jak pokazano tutaj: [hough] (http://i.imgur.com/NP8HT .jpg). – sowizz

+0

@sowizz spójrz na aktualizację. – ArtemStorozhuk

+0

W większości przypadków działa to całkiem dobrze, więc zamierzam oznaczyć je jako odpowiedź. Jednak w niektórych sytuacjach zawiedzie, ponieważ nie ma zamkniętego obszaru. Przydają się wówczas operacje morfologiczne, ale prawie w każdym przypadku wymagają innych parametrów, co czyni je mniej przydatnymi. Wszelkie pomysły, jak rozwiązać ten problem? Oto przykład takiej sytuacji: [kliknij] (http://i.imgur.com/mY27w.jpg) – sowizz

9

Oblicz zestaw 6 długościach, że trzeba będzie między każdą parą 4 różnych punktów. W ramach tego zestawu 6 długości, jeśli istnieją więcej niż 3 różne wartości, nie ma prostokąta (2 równe długości boków plus równe długości przekątnej)

+3

z pewnymi tolerancjami lub oczywiście –

+0

@RodyOldenhuis oczywiście. – mathematician1975

+0

Dobre rozwiązanie, ale niezbyt użyteczne w tym konkretnym problemie. Obliczanie wszystkich odległości zajmuje dużo czasu, nawet jeśli jest 100 punktów, a ja zwykle dostaję około 2500. – sowizz

0

Rozważyć należy masz numer 8 ale masz numer 7, następnie masz zamiar dodać numer 1 (zwane delta lub korekcja błędów), aby to poprawić.

W podobny sposób mają współrzędne w trójkąt delta, aby skorygować prostokąt. Sprawdź, czy punkt (współrzędna) wypada wewnątrz prostokąta delty.

The współrzędnych prostokątnych są wymienione poniżej:

x+delta,y+delta 
x-delta,y+delta 
x+delta,y-delta 
x-delta,y-delta 

Daj mi znać, jeśli to działa dobrze dla ciebie lub jeśli okaże się lepsze rozwiązanie

2

Jesteś świadomy, że wizualnie kontroli temperatury mętnienia ty czy potrafisz już rozróżnić wiele prostokątów? Innymi słowy, najprawdopodobniej znajdziesz wiele prostokątów, jeśli nie wykonujesz jakiejś procedury wstępnej selekcji ...

W każdym razie, oprócz metody już podanej przez @ mathematician1975, możesz również po prostu sprawdzić, czy strony są (mniej więcej) równoległe. Metoda

nazwijmy @ mathematician1975 za method 1 i równoległe sprawdzić method 2. Następnie:

%# method 1: 
n1 = |u1-u2| %# 3 sub., 3 mult, 2 add. per distance 
n2 = |u3-u2| %# total of 6 distances to compute. 
n3 = |u4-u3| %# then max 5+4+3+2+1 = 15 comp. to find unique distances 
n4 = |u1-u4|  
n5 = |u4-u2| %# Total: 
n6 = |u3-u1| %# 12 sub., 18 mult., 12 add, 15 comp 



%# method 2: 
w1 = u1-u2  %# 3 subtractions per vector 
w2 = u3-u2  %# total of 4 vectors to compute 
w3 = u3-u2 
w4 = u1-u4     
         %# 12 sub. 
abs(w1-w3) == [0 0 0] %# 3 sub., 3 comp., 1 sign. 
abs(w2-w4) == [0 0 0] %# 3 sub., 3 comp., 1 sign. 

         %# Total: 18 sub., 6 comp. 2 sign. 

Należy pamiętać, że są to zarówno najgorszy przypadek; przy odrobinie księgowości można drastycznie obniżyć koszty obu.

Należy również pamiętać, że method 2 musi wcześniej wiedzieć, że wierzchołki są już we właściwej kolejności. Jeśli tak nie jest, zwiększy to koszt o współczynnik 4, czyli o więcej niż method 1..

Czy mogę zapytać, jak obliczasz odległości?

+0

Tak, wiem, że posiadanie tej liczby punktów utworzy wiele prostokątów, ale nie jestem pewien, czy na tym etapie mogę coś na to poradzić (później obliczę pewne statystyki, które pozwolą mi wybrać tylko właściwe prostokąty). Odległość między dwoma punktami jest obliczana jako odległość euklidesowa: 'odległość = sqrt ((x2-x1)^2 + (y2-y1)^2);' i nie jestem pewien, czy jest to 2500x4, ponieważ musicie wybrać jeden punkt, a następnie kolejne 3, obliczać odległości, a następnie dla tego samego punktu pięści wybieramy kolejne 3 punkty (różne od poprzednich), które są poza kombinacjami 2500x4. – sowizz

+1

@sowizz Wypróbuj 'normę' - powinno być o wiele szybciej. Lub, jeśli chcesz, po prostu pomiń pierwiastek kwadratowy - porównywanie odległości do kwadratu lub odległości nie ma znaczenia. Lub użyj dystansów miejskich: 'abs (x2-x1) + abs (y2-y1)'. Da to bardzo przybliżony, ale * znacznie szybszy * przybliżenie do odległości, która w przypadku prostokąta będzie musiała być równa. –