2012-01-23 12 views
5

Czy istnieje funkcja łączenia dwóch (lub więcej) kont znajdujących się w pobliżu? Spójrz na moją wejść/wyjść, a zobaczysz co mam na myśli ...OpenCV C++/Obj-C: Łączenie konturów w pobliżu

Mój kod:

[... some processing ...] 

// getting contours 
std::vector<std::vector<cv::Point> > contours; 
findContours(input, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 

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

// debugging 
cv::Scalar colors[3]; 
colors[0] = cv::Scalar(255, 0, 0); 
colors[1] = cv::Scalar(0, 255, 0); 
colors[2] = cv::Scalar(0, 0, 255); 
for (int idx = 0; idx < contours_poly.size(); idx++) { 
    cv::drawContours(output, contours_poly, idx, colors[idx % 3]); 
} 

output output

+2

Mógłbyś rozszerzać obraz, aby połączyć krzywe, jeśli są wystarczająco blisko. – Adrian

+0

Jak to zrobiłeś z iOS? –

+0

Działa na iOS. Po prostu weź kopię tego OpenCV dla wersji iOS tutaj: https://github.com/aptogo/OpenCVForiPhone i otul się wokół niego ... – dom

Odpowiedz

8

wpadłem na to rozwiązanie, bo wystarczy obwiedni wokół całego obiektu:

[... some processing ...] 

// getting contours 
std::vector<std::vector<cv::Point> > contours; 
findContours(input, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 

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

// merge all contours into one vector 
std::vector<cv::Point> merged_contour_points; 
for (int i = 0; i < contours_poly.size(); i++) { 
    for (int j = 0; j < contours_poly[i].size(); j++) { 
    merged_contour_points.push_back(contours_poly[i][j]); 
    } 
} 

// get rotated bounding box 
std::vector<cv::Point> hull; 
cv::convexHull(cv::Mat(merged_contour_points),hull); 
cv::Mat hull_points(hull); 
cv::RotatedRect rotated_bounding_rect = minAreaRect(hull_points); 

Czasami usunięcie pieprz hałasu może prowadzić do lepszych wyników:

void removePepperNoise(cv::Mat &mask) 
{ 
    for (int y=2; y<mask.rows-2; y++) { 
     uchar *pUp2 = mask.ptr(y-2); 
     uchar *pUp1 = mask.ptr(y-1); 
     uchar *pThis = mask.ptr(y); 
     uchar *pDown1 = mask.ptr(y+1); 
     uchar *pDown2 = mask.ptr(y+2); 
     pThis += 2; 
     pUp1 += 2; 
     pUp2 += 2; 
     pDown1 += 2; 
     pDown2 += 2; 

     for (int x=2; x<mask.cols-2; x++) { 
      uchar value = *pThis; // Get this pixel value (0 or 255). // Check if this is a black pixel that is surrounded by white pixels 
      if (value == 0) { 
       bool above, left, below, right, surroundings; 
       above = *(pUp2 - 2) && *(pUp2 - 1) && *(pUp2) && *(pUp2 + 1) && *(pUp2 + 2); 
       left = *(pUp1 - 2) && *(pThis - 2) && *(pDown1 - 2); 
       below = *(pDown2 - 2) && *(pDown2 - 1) && *(pDown2) && *(pDown2 + 1) && *(pDown2 + 2); 
       right = *(pUp1 + 2) && *(pThis + 2) && *(pDown1 + 2); 
       surroundings = above && left && below && right; 
       if (surroundings == true) { 
        // Fill the whole 5x5 block as white. Since we know 
        // the 5x5 borders are already white, we just need to 
        // fill the 3x3 inner region. 
        *(pUp1 - 1) = 255; 
        *(pUp1 + 0) = 255; 
        *(pUp1 + 1) = 255; 
        *(pThis - 1) = 255; 
        *(pThis + 0) = 255; 
        *(pThis + 1) = 255; 
        *(pDown1 - 1) = 255; 
        *(pDown1 + 0) = 255; 
        *(pDown1 + 1) = 255; 
        // Since we just covered the whole 5x5 block with 
        // white, we know the next 2 pixels won't be black, 
        // so skip the next 2 pixels on the right. 
        pThis += 2; 
        pUp1 += 2; 
        pUp2 += 2; 
        pDown1 += 2; 
        pDown2 += 2; 
       } 
      } 
      // Move to the next pixel on the right. 
      pThis++; 
      pUp1++; 
      pUp2++; 
      pDown1++; 
      pDown2++; 
     } 
    } 
} 
+0

Awesome. Zaakceptuj tę odpowiedź, kiedy tylko możesz. Kliknij pole wyboru obok, aby wybrać ją jako oficjalną odpowiedź. – karlphillip

+0

@karlphillip Tak, zrobię to! – dom

+0

Kto głosował: Wyjaśnij, dlaczego! – dom

2

Wystarczy przejść przez punkty i znaleźć najbliższy startpoints lub punkty końcowe a następnie je połączyć. W twoim przypadku trudno zdecydować, czy kontury powinny być połączone, czy nie. Jeśli morfologia, jak powiedział Adrian Popovici, nie pomaga, musisz określić maksymalną odległość, która decyduje, czy punkty mają być połączone.

Powiązane problemy