Ask Your Question
1

Seperate touching Objects

asked 2016-05-18 07:39:23 -0600

lapayo gravatar image

updated 2016-05-25 07:01:45 -0600

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 flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
5

answered 2016-05-21 00:41:25 -0600

lama123 gravatar image

updated 2016-05-21 05:52:28 -0600

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

image description This is the output of adaptive thresholding stage

image description Output of cca

image description Final output showing bounding boxes overlapped over the original image

The algorithm code is given below

   Mat image;
    // read the input image
    image = imread("D:\\work\\Forums\\opencv\\14635747219571405.png");

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

    // pre processing
    // remove shadows first
    const int SHADOW_THRESHOLD = 30;
    Mat preproc;
    threshold(gray, preproc, SHADOW_THRESHOLD, 255, CV_THRESH_TOZERO);
    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;
    adaptiveThreshold(blurred, thresh, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 5, 1);

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

image description

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[4];
            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

edit flag offensive delete link more

Comments

2

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

sturkmen gravatar imagesturkmen ( 2016-05-21 04:54:35 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2016-05-18 07:39:07 -0600

Seen: 1,958 times

Last updated: May 25 '16