# Seperate touching Objects

What is the best way to quickly seperate two close objects?

For example those two rectangles are so close, their shadows overlap and get very dark. Using my initial approach to binarize the image and then do an CCA does not work, because the binarized image is completely connected.

I think using convex defects may also not work properly, because the difference here is not very big.

What might be a better solution to this problem?

edit retag close merge delete

Sort by » oldest newest most voted

Hello,

I don't know if there are any universal methods for such problems. But for the example above you can try this method. The output from each stage of the algorithm is given below This is the output of adaptive thresholding stage Output of cca Final output showing bounding boxes overlapped over the original image

The algorithm code is given below

   Mat image;

// convert to gray
Mat gray;
cvtColor(image, gray, CV_BGR2GRAY);

// pre processing
Mat preproc;
imshow("preproc", preproc);

// blur the image two times to remove noise with 3x3 kernel
Mat blurred;
blur(preproc, blurred, Size(3,3));
blur(blurred, blurred, Size(3,3));
imshow("blurred", blurred);
waitKey();

// apply and adaptive threshold with a block size of 5x5 and c = 1
Mat thresh;

// negative of the threshold output
thresh = 255 - thresh;
imshow("Threshold", thresh);

// apply a connected component analysis with statistics
// (from opencv 3.0 onwards)
//cca
Mat labels, stats, centroids;
Mat cca = thresh;
int numObjects = connectedComponentsWithStats(thresh, labels, stats, centroids);

// go through the whole image and remove all pixels which are part
// of objects whose area is less than MIN_OBJECT_AREA
const int MIN_OBJECT_AREA = 150;
int i,j;
int* p;
for( i = 0; i < cca.rows; ++i)
{
p = labels.ptr<int>(i);
for ( j = 0; j < cca.cols; ++j)
{
// area < MIN_OBJECT_AREA
if(stats.at<int>(p[j],CC_STAT_AREA ) < MIN_OBJECT_AREA )
cca.at<uchar>(i,j) = 0;
}
}
imshow("cca", cca);

// Draw bounding boxes for objects in the original image
// exclude background = 0
for(i=1; i<numObjects; i++)
{
if(stats.at<int>(i, CC_STAT_AREA) >= MIN_OBJECT_AREA)
{
int left = stats.at<int>(i, CC_STAT_LEFT);
int top = stats.at<int>(i, CC_STAT_TOP);
int width = stats.at<int>(i, CC_STAT_WIDTH);
int height = stats.at<int>(i, CC_STAT_HEIGHT);
// draw rectangle
rectangle(image, Rect(left, top, width, height), Scalar(0,255,0), 2);
}
}

imshow("BoundingBoxes", image);


As per @sturkmen suggestion, here is the output using minAreaRect(). It shows the rotated bounding boxes in green. The changed code is given below

   // Draw bounding boxes for objects in the original image
const int MIN_CONTOUR_LENGTH = 50;
vector<vector<Point> > contours;
// find contours
findContours(thresh, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
for( int i = 0; i < contours.size(); i++ )
{
if(contours[i].size() > MIN_CONTOUR_LENGTH )
{

RotatedRect minRect = minAreaRect( Mat(contours[i]) );

// rotated rectangle
Point2f rect_points;
minRect.points( rect_points );
for( int j = 0; j < 4; j++ )
line( image, rect_points[j], rect_points[(j+1)%4], Scalar(0,255,0), 2, 8 );
}
}


Feel free to ask in case of any doubt

Thanks Amal

more

2

+1 you can improve your solution by using minAreaRect()

Official site

GitHub

Wiki

Documentation