Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Discard outlier SIFT Key Points in Cell Image with OpenCV

I'm approaching a task of Bio Informatics, and need to extract some features from some cell images.

I used SIFT algorithm to extract Key Points inside of the image, as you can see in the picture.

enter image description here

As you can also see in the picture (circled in red), some key points are outliers and I don't want to calculate any feature on them.

I obtained the cv::KeyPoint vector with the following code:

const cv::Mat input = cv::imread("/tmp/image.jpg", 0); //Load as grayscale

cv::SiftFeatureDetector detector;
std::vector<cv::KeyPoint> keypoints;
detector.detect(input, keypoints);

but I would like to discard from the vector all those key points that, say for example, have less than 3 key points inside of a certain region of interest (ROI) centred on them in the image.

Therefore I need to implement a function returning the number of key points inside of a certain ROI given as input:

int function_returning_number_of_key_points_in_ROI( cv::KeyPoint, ROI );
   //I have not specified ROI on purpose...check question 3

I have three questions:

  1. Is there any existing function doing something similar?
  2. If not can you give me some help in understanding how to implement it by myself?
  3. Would you use a circular, or rectangular ROI for this task?And how would you specify it in input?

Note:

I forgot to specify that I would like an efficient implementation for the function, i.e. checking for each key point the relative position of all others with respect to it would not be a good solution (if there exists another way of doing).

like image 596
Matteo Avatar asked Jun 07 '12 09:06

Matteo


1 Answers

I decided to go with the statistical route, but this may not work if you have multiple cells in view.

My solution is fairly straightforward:

  1. Compute the keypoint locations
  2. Find the centroid of the keypoint spatial locations
  3. Compute the Euclidean distance of all points to the centroid
  4. Filter original keypoints by distance < mu + 2*sigma

Here is the image that I get using this algorithm (keypoints == green, centroid == red):

enter image description here

Finally, here is the code example of how I did it:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>

#include <iostream>
#include <vector>

using namespace cv;
using namespace std;

void distanceFromCentroid(const vector<Point2f>& points, Point2f centroid, vector<double>& distances)
{
    vector<Point2f>::const_iterator point;
    for(point = points.begin(); point != points.end(); ++point)
    {
        double distance = std::sqrt((point->x - centroid.x)*(point->x - centroid.x) + (point->y - centroid.y)*(point->y - centroid.y));
        distances.push_back(distance);
    }
}

int main(int argc, char* argv[])
{
    Mat input = imread("cell.jpg", 0); //Load as grayscale

    SiftFeatureDetector detector;
    vector<cv::KeyPoint> keypoints;
    detector.detect(input, keypoints);

    vector<Point2f> points;
    vector<KeyPoint>::iterator keypoint;
    for(keypoint = keypoints.begin(); keypoint != keypoints.end(); ++keypoint)
    {
        points.push_back(keypoint->pt);
    }

    Moments m = moments(points, true);
    Point2f centroid(m.m10 / m.m00, m.m01 / m.m00);

    vector<double> distances;
    distanceFromCentroid(points, centroid, distances);

    Scalar mu, sigma;
    meanStdDev(distances, mu, sigma);

    cout << mu.val[0] << ", " << sigma.val[0] << endl;

    vector<KeyPoint> filtered;
    vector<double>::iterator distance;
    for(size_t i = 0; i < distances.size(); ++i)
    {
        if(distances[i] < (mu.val[0] + 2.0*sigma.val[0]))
        {
            filtered.push_back(keypoints[i]);
        }
    }

    Mat out = input.clone();
    drawKeypoints(input, filtered, out, Scalar(0, 255, 0));

    circle(out, centroid, 7, Scalar(0, 0, 255), 1);

    imshow("kpts", out);
    waitKey();

    imwrite("statFilter.png", out);

    return 0;
}

Hope that helps!

like image 181
mevatron Avatar answered Sep 29 '22 20:09

mevatron