Ben Chaaben Assil
Ben Chaaben Assil

Reputation: 125

Extract object by it centroid

I have developed an application using OpenCV that detects circularity form and get there centroid from a binary image. I want now to delete object that has not been detected from my original image. So I want to know if there is a solution to extract an object from an image by its centroid.

Here is what I have got so far:

enter image description here

The result of the for segmentation : enter image description here

// Read image
    cv::Mat im = cv::imread( "11002847.bmp", cv::IMREAD_GRAYSCALE );
    bitwise_not(im, im);
    cv::Mat im2;
    im.copyTo(im2);


    //Detec the contour to get all the obeject centroid
    std::vector<std::vector<cv::Point> > contours;
    vector<cv::Vec4i> hierarchy;
    findContours( im2, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
    vector<cv::Moments> mu(contours.size() );
    for( int i = 0; i < contours.size(); i++ )
    { 
        mu[i] = moments( contours[i], false ); 
    }
    ofstream file;
    file.open("log.txt");
    ///  Get the mass centers:
    vector<cv::Point2f> mc( contours.size() );
    for( int i = 0; i < contours.size(); i++ )
    { 
        mc[i] = cv::Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); 
        file << mc[i].x << "   "<< mc[i].y << endl;
    } 
    file.close();


    //Dtect the circular objects and get there centroid
    // Setup SimpleBlobDetector parameters.
    cv::SimpleBlobDetector::Params params;
    // Change thresholds
    //params.minThreshold = 10;
    //params.maxThreshold = 200;
    // Filter by Area.
    params.filterByArea = true;
    params.minArea = 1;
    // Filter by Circularity
    params.filterByCircularity = true;
    params.minCircularity = 0.5;
    // Filter by Convexity
    params.filterByConvexity = true;
    params.minConvexity = 0.1;
    // Filter by Inertia
    params.filterByInertia = true;
    params.minInertiaRatio = 0.0;
    // Storage for blobs
    vector<cv::KeyPoint> keypoints;
    // Set up detector with params
    cv::SimpleBlobDetector detector(params);
    // Detect blobs
    detector.detect( im, keypoints);


    ofstream file2;
    file2.open("log2.txt");

    for(vector<cv::KeyPoint>::iterator it = keypoints.begin(); it != keypoints.end(); ++it) 
    {
        cv::KeyPoint k =  *it;
        file2 << k.pt.x << "      "<<  k.pt.y << endl;
    }

    file2.close();
    // Draw detected blobs as red circles.
    // DrawMatchesFlags::DRAW_RICH_KEYPOINTS flag ensures
    // the size of the circle corresponds to the size of blob
    cv::Mat im_with_keypoints;
    drawKeypoints( im, keypoints, im_with_keypoints, cv::Scalar(0,0,255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS );
    // Show blobs
    cv::imwrite("keypoints.bmp", im_with_keypoints );

Upvotes: 1

Views: 333

Answers (1)

mirosval
mirosval

Reputation: 6822

I hope I understood your problem, but just in case, I will rephrase it. You want to remove the contours from your top image, which have not been detected as keypoints (i.e. don't have red circles in/around them) in the bottom image.

In order to do this, iterate over all your contours and check each contour for presence of KeyPoints using pointPolygonTest

auto end = contours.end();
for (auto contour_itr = contours.begin(); contour_itr != end; ++contour_itr) {
    auto keypoint_end = keypoints.end();
    for (auto keypoint_itr = keypoints.begin(); keypoint_itr != keypoint_end; ++ keypoint_itr) {
        auto contour = *contour_itr;
        auto keypoint = *keypoint_itr;

        if (cv::pointPolygonTest(contour, keypoint.pt, false) > 0) {
            // do your thing here (e.g. store contour into an array or paint it into a new image
        }
    }
}

Hope that helps

Upvotes: 1

Related Questions