2013-05-11 18 views
8

Ja próbuje wykrywać położenie na podobieństwo obu czerwonych ścianach i białych kwadratów na obrazku poniżej dwóch białej ścianie z czerwonych wierzchołków i białych „słupków”:Multiple wykrywania obiektów kolor za pomocą OpenCV

enter image description here

Moje podejście było zrobić progowanie znaleźć czerwone ściany, które mogę teraz łatwo wykryć z tego wyjścia:

enter image description here

teraz mój problem jest wykrywanie lokalizacji na zielone świątki e kwadraty, ale jest to trudniejsze, biorąc pod uwagę białe ściany. Jeżeli mój próg oparty jest na bieli, nadal zachowuję niepożądane białe ściany pomiędzy słupkami białego kwadratu.

Każda pomoc zostanie bardzo doceniona.

+0

cóż, biali są w środku czerwonych, prawda? Idź po to. Szukaj bieli między czerwieniami. Lub szukaj luki między czerwonymi i sprawdź, czy jest biały. –

+0

@AnderBiguri To brzmi nieźle, nadal rysuję pustkę, jak to zaimplementować w OpenCV – salgarcia

+0

Udostępniony obraz progowy nie jest wynikiem przetwarzania tego obrazu wejściowego. Nie pasują :) – karlphillip

Odpowiedz

15

Jedno podejście polega Progowanie obrazu wejściowego z cv::inRange():

cv::Mat image = cv::imread(argv[1]); 
if (image.empty()) 
{ 
    std::cout << "!!! Failed imread()" << std::endl; 
    return -1; 
} 

cv::Mat red_image; 
cv::inRange(image, cv::Scalar(40, 0, 180), cv::Scalar(135, 110, 255), red_image); 
//cv::imwrite("out1.png", red_image); 

Wyjścia:

enter image description here

Możemy użyć cv::findContours pobrać kontury progowaniu obraz, aby móc tworzyć e ograniczające pola dla nich which is a technique described here:

std::vector<std::vector<cv::Point> > contours; 
std::vector<cv::Vec4i> hierarchy; 
cv::findContours(red_image, 
        contours, 
        hierarchy, 
        CV_RETR_TREE, 
        CV_CHAIN_APPROX_SIMPLE, 
        cv::Point(0, 0)); 

std::vector<std::vector<cv::Point> > contours_poly(contours.size()); 
std::vector<cv::Rect> boundRect(contours.size()); 
for(int i = 0; i < contours.size(); i++) 
    { 
     cv::approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true); 
     boundRect[i] = cv::boundingRect(cv::Mat(contours_poly[i])); 
    } 


// Debug purposes: draw bonding rects 
//cv::Mat tmp = cv::Mat::zeros(red_image.size(), CV_8UC3); 
//for(int i = 0; i< contours.size(); i++) 
// rectangle(tmp, boundRect[i].tl(), boundRect[i].br(), cv::Scalar(0, 255, 0), 2, 8, 0); 
//cv::imwrite("out2.png", tmp); 

Wyjście:

enter image description here

Wszystkie prostokąty wyświetlane na obrazie powyżej są przechowywane jako cv::Rect obiektu wewnątrz boundRect wektorze.Każdy rectangle składa się z 2 przeciwległych cv::Point obiektów, więc iteracyjne na tym wektorze, aby utworzyć nowy wektor składa się z zaledwie cv::Point obiektów:

// Two opposite cv::Point can be used to draw a rectangle. 
// Iterate on the cv::Rect vector and retrieve all cv::Point 
// and store them in a cv::Point vector. 
std::vector<cv::Point> rect_points; 
for(int i = 0; i < contours.size(); i++) 
{ 
    rect_points.push_back(boundRect[i].tl()); 
    rect_points.push_back(boundRect[i].br()); 
} 

//cv::Mat drawing = cv::Mat::zeros(red_image.size(), CV_8UC3); 
cv::Mat drawing = image.clone(); 

logika znaleźć białych kwadratów jest: Zakładamy, że 2 pikseli w 25x25 odległość od siebie zdefiniować biały kwadrat:

// Draw a rectangle when 2 points are less than 25x25 pixels of 
// distance from each other 
for(int i = 0; i < rect_points.size(); i++) 
{ 
    for(int j = 0; j < rect_points.size(); j++) 
    { 
     if (i == j) 
      continue; 

     int x_distance = (rect_points[i].x - rect_points[j].x); 
     if (x_distance < 0) 
      x_distance *= -1; 

     int y_distance = (rect_points[i].y - rect_points[j].y); 
     if (y_distance < 0) 
      y_distance *= -1; 

     if ((x_distance < 25) && (y_distance < 25)) 
     { 
      std::cout << "Drawing rectangle " << i << " from " 
         << rect_points[i] << " to " << rect_points[j] 
         << " distance: " << x_distance << "x" << y_distance << std::endl; 

      cv::rectangle(drawing, 
          rect_points[i], 
          rect_points[j], 
          cv::Scalar(255, 50, 0), 
          2); 
      break; 
     } 
    } 

} 

    //cv::imwrite("out3.png", drawing); 
cv::imshow("white rectangles", drawing);  
cv::waitKey(); 

Output:

enter image description here

Algorytm ten jest dość surowy i pomija dwa białe kwadraty na dole, ponieważ pod nimi nie ma czerwonych ścian.

Więc zostawiam to do ciebie, aby poprawić to podejście :)

powodzenia.

1

Wszystkie ważne informacje zawarte w scenie wydają się znajdować się w zeskanowanym zdjęciu wyodrębnionych czerwonych pasków. Próbowałbym zignorować oryginalny obraz tego etapu i użyć tylko geometrii prostokątów, aby znaleźć obszar między nimi.

Na przykład można zadzwonić pod numer findContours, aby uzyskać 8 obiektów typu blob na przykładowym obrazie. Jeśli zaznaczysz punkty na linii między ich środkami masy, punkt, który zwraca minimalną wartość do pointPolygonTest, jest punktem centralnym jednej z białych plamek (lub przynajmniej blisko).

Możesz użyć znanych informacji o scenie i jej zdjęciach, które napotkasz. Na przykład, możesz pogrupować kontury na "lewo" i "prawo" słupki i wykonywać tylko wyszukiwanie liniowe pomiędzy niektórymi konturami. Jednakże, jeśli chcesz być bardziej agnostyczny. twoje wejście, czerpiące mniej więcej wszystko (orientacja sceny, liczba ścian, grubość prostokątów ...) z progowanego obrazu powinno być całkiem możliwe.

Powiązane problemy