Question

Is there a function to connect two (or more) nearby contours? Take a look at my in-/output and you'll see what I mean …

My code:

[... 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

Was it helpful?

Solution

I came up with this solution, because I just need the bounding box around the whole object:

[... 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);

Sometimes removing pepper noise can lead to better results:

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++;
        }
    }
}

OTHER TIPS

Simply go through points and find the closest startpoints or endpoints and then connect them. It's hard to decide in your case if contours should be connected or not. If morfology as Adrian Popovici said doesn't help you must specify some max distance which decide if points are to be connected.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top