使用 OpenCV 丢弃细胞图像中的异常 SIFT 关键点

Posted

技术标签:

【中文标题】使用 OpenCV 丢弃细胞图像中的异常 SIFT 关键点【英文标题】:Discard outlier SIFT Key Points in Cell Image with OpenCV 【发布时间】:2012-06-07 09:46:51 【问题描述】:

我正在处理一项生物信息学的任务,需要从一些细胞图像中提取一些特征。

我使用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);

但我想从vector 中丢弃所有那些关键点,例如,在图像中以它们为中心的某个感兴趣区域 (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

我有三个问题:

    是否有任何现有功能可以做类似的事情? 如果不能,您能否帮我理解如何自己实现它? 对于此任务,您会使用圆形还是矩形 ROI?您将如何在输入中指定它?

注意:

我忘了指定我想要一个有效的函数实现,即检查每个关键点的所有其他关键点相对于它的相对位置不是一个好的解决方案(如果存在另一种方法)。

【问题讨论】:

可以发一下原图吗?我想尝试一下,如果成功了再把结果发回来:) @mevatron - s18.postimage.org/jayhj4q3d/phase1_image1.jpg 给你,我上传了 RGB 版本,如果你愿意,只需将其转换为灰度......让我知道你在做什么 ;) 如果您可以定义模型,您可以使用 RANSAC。 RANSAC 将决定哪些点是内点(适合模型)和异常点(不适合模型)。也许您的模型可以是定义小于 X 的区域的 3 点(这意味着它们足够接近)。这是一个想法。 @Matteo 嘿,谢谢! @mevatron - 完美!我会等待消息,无论如何请告诉我!谢谢 ;D 【参考方案1】:

我决定采用统计路线,但如果您看到多个单元格,这可能行不通。

我的解决方案相当简单:

    计算关键点位置 找到关键点空间位置的质心 计算所有点到质心的欧几里得距离 按distance &lt; 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;

希望有帮助!

【讨论】:

其实你提出的解决方案真的很简洁明了!!但是,正如您所注意到的,当图像中包含多个单元格时,这可能会出现问题。在我的数据集中有一些不好的图像,但我试图通过丢弃这些样本来清理它。我现在会坚持这个解决方案,以防万一寻求进一步的帮助! ;) 太想了…… 太棒了!很高兴你发现它有用;顺便说一句很酷的问题 :) 我在想如果你有多个单元格,你可以做某种类型的聚类操作(K-Nearest Neighbors 或类似的东西)作为预处理步骤,并以这种方式分别处理它们。 这是一个生物信息学的项目,我需要通过分析细胞的形态来对细胞的进化进行分类!而这仅仅是个开始 ;) k-means 的想法似乎也很聪明,我会尝试一下,如果你有兴趣,想办法让你了解项目的演变。 非常酷 :) 期待看到进展,也许还有更多关于它的问题! @mevatron:很好的解决方案。但是你为什么不试试ransac呢?我相信它可能会更快,例如:***.com/questions/8855020/…

以上是关于使用 OpenCV 丢弃细胞图像中的异常 SIFT 关键点的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 OpenCV 和 SIFT 查找我的训练图像的多个实例

SIFT openCV 的关键点数?

OpenCV SIFT特征算法详解与使用

OpenCV+Python特征提取算法与图像描述符之SIFT / SURF / ORB

OpenCV中的特征匹配(Feature Matching)

OpenCV实现SIFT图像拼接源代码