I came up with this solution because I just need a bounding box around the whole object:
[... some processing ...]
std::vector<std::vector<cv::Point> > contours;
findContours(input, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
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 );
}
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]);
}
}
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 noises 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;
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) {
*(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;
pThis += 2;
pUp1 += 2;
pUp2 += 2;
pDown1 += 2;
pDown2 += 2;
}
}
pThis++;
pUp1++;
pUp2++;
pDown1++;
pDown2++;
}
}
}
source
share