使用OpenCV在细胞图像中排除异常SIFT关键点

6
我正在处理一项生物信息学任务,需要从一些细胞图像中提取一些特征。
我使用SIFT算法提取图像内部的关键点,如您在图片中所见。
同时,正如您在图片中看到的(用红圈标出),有些关键点是异常值,我不想对它们进行任何特征计算。
我使用以下代码获取了cv::KeyPoint向量:
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);

但是我希望从向量中删除那些关键点,例如,在图像上特定感兴趣区域(ROI)周围少于3个关键点的关键点。

因此,我需要实现一个函数,该函数返回给定输入的某个ROI内的关键点数:

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

我有三个问题:
  1. 是否有任何现有的功能类似于此?
  2. 如果没有,你能帮我理解如何自己实现吗?
  3. 对于这个任务,你会使用圆形还是矩形ROI?如何在输入中指定它?
注意:
我忘了说明我想要一个高效的函数实现,即检查每个关键点相对于其他所有关键点的位置关系不是一个好的解决方案(如果存在另一种方法)。

1
你能发布原始图像吗?我想尝试一些东西,如果成功的话就会回帖结果 :) - mevatron
@mevatron - http://s18.postimage.org/jayhj4q3d/phase1_image1.jpg 这是你要的,我上传了RGB版本,如果你想的话可以将其转换为灰度...让我知道你在做什么 ;) - Matteo
如果您可以定义一个模型,那么您可以使用RANSAC。 RANSAC将决定哪些点是内点(适合模型)和离群值(不适合模型)。也许您的模型可以是像三个点定义一个小于X的区域(这意味着它们足够接近)之类的东西。这只是一个想法。 - Jav_Rock
@mevatron - 太好了!我会等待消息的,无论如何请告诉我!谢谢 ;D - Matteo
1个回答

8
我决定采用统计方法,但如果你的视图中有多个单元格,则此方法可能不起作用。
我的解决方案非常简单:
1. 计算关键点位置 2. 找到关键点空间位置的质心 3. 计算所有点到质心的欧几里德距离 4. 通过distance < mu + 2*sigma过滤原始关键点
使用此算法得到的图像如下(关键点=绿色,质心=红色):
最后,这是我如何做到的代码示例:
#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;
}

希望这有所帮助!

实际上,您提出的解决方案非常简洁明了!但是,正如您所注意到的那样,当图像中包含多个单元格时,可能会出现问题。在我的数据集中有一些糟糕的图像,但我正在尝试通过丢弃这些样本来清理它。我现在将坚持使用这个解决方案,并在需要时寻求进一步的帮助!;) 非常感谢... - Matteo
2
太棒了!很高兴你觉得它有用;顺便说一下,这是个很酷的问题 :) 我在想如果你有多个单元格,你可能可以进行某种类型的聚类操作(K-最近邻或类似的操作)作为预处理步骤,然后分别处理它们。 - mevatron
1
这是一个生物信息学项目,我需要通过分析细胞形态来分类细胞的进化!而且这只是个开始 ;) 另外,k-means 的想法似乎非常聪明,我会尝试一下,如果你有兴趣,我会找到一些方法让你知道项目的进展。 - Matteo
非常酷 :) 期待看到进展,也许会有更多关于它的问题! - mevatron
@yes123 谢谢!使用RANSAC时,您必须提供一个模型来用于异常值过滤。由于我没有定义细胞结构的模型,所以它不会非常有效 :-\ RANSAC 可能比我的线性扫描慢得多,但是如果有一个好的模型,它可能更加健壮。 - mevatron
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接