2013-10-01 27 views
2

我有一个二进制图像(黑白像素),并且我想根据彼此的距离将白色像素聚类成组(对象),并检索每个群集的质心。C++和OpenCV:聚类白色像素算法

这是在其中我必须工作在一个示例图像:

Image

(上紫色帧)

我想检查一个聚类方法将提供结果我我正在寻找,这意味着我在尝试避免自己实现算法之前知道它是值得的。
OpenCV有办法做我需要的吗?

回答

0

如果知道图像中的簇数,可以使用在OpenCV中实现的K-Means algorithm

除此之外,我不知道这个任务的任何其他简单的解决方案。如果你想自己实现这个集群,this paper可以帮助你,它是关于k-means的适应,它必须不具有固定数量的集群。

+0

集群的数量可能会有所不同,也没有办法知道他们事先有多少。 是的,我想我必须自己实现一些东西 –

2

我知道这是相当古老的,但也许这个答案可能会有所帮助。


您可以使用partition,这将分裂成集等效类的元素。

您可以在给定的欧几里德距离内定义一个等价类为。这可以是一个lambda函数(C++ 11)或一个仿函数(参见代码中的两个示例)。

从这个图像开始(我删除手动紫色边框):

enter image description here

使用20的欧氏距离我:

enter image description here

你可以看到,所有白色像素在欧氏距离范围内的颜色被分配到相同的颜色组(相同的颜色)。圆圈表示每个群集的质心。

代码:

#include <opencv2\opencv.hpp> 
#include <vector> 
#include <algorithm> 

using namespace std; 
using namespace cv; 

struct EuclideanDistanceFunctor 
{ 
    int _dist2; 
    EuclideanDistanceFunctor(int dist) : _dist2(dist*dist) {} 

    bool operator()(const Point& lhs, const Point& rhs) const 
    { 
     return ((lhs.x - rhs.x)*(lhs.x - rhs.x) + (lhs.y - rhs.y)*(lhs.y - rhs.y)) < _dist2; 
    } 
}; 

int main() 
{ 
    // Load the image (grayscale) 
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE); 

    // Get all non black points 
    vector<Point> pts; 
    findNonZero(img, pts); 

    // Define the distance between clusters 
    int euclidean_distance = 20; 

    // Apply partition 
    // All pixels within the the given distance will belong to the same cluster 

    vector<int> labels; 

    // With functor 
    //int n_labels = partition(pts, labels, EuclideanDistanceFunctor(euclidean_distance)); 

    // With lambda function 
    int th2 = euclidean_distance * euclidean_distance; 
    int n_labels = partition(pts, labels, [th2](const Point& lhs, const Point& rhs) { 
     return ((lhs.x - rhs.x)*(lhs.x - rhs.x) + (lhs.y - rhs.y)*(lhs.y - rhs.y)) < th2; 
    }); 


    // Store all points in same cluster, and compute centroids 
    vector<vector<Point>> clusters(n_labels); 
    vector<Point> centroids(n_labels, Point(0,0)); 

    for (int i = 0; i < pts.size(); ++i) 
    { 
     clusters[labels[i]].push_back(pts[i]); 
     centroids[labels[i]] += pts[i]; 
    } 
    for (int i = 0; i < n_labels; ++i) 
    { 
     centroids[i].x /= clusters[i].size(); 
     centroids[i].y /= clusters[i].size(); 
    } 

    // Draw results 

    // Build a vector of random color, one for each class (label) 
    vector<Vec3b> colors; 
    for (int i = 0; i < n_labels; ++i) 
    { 
     colors.push_back(Vec3b(rand() & 255, rand() & 255, rand() & 255)); 
    } 

    // Draw the points 
    Mat3b res(img.rows, img.cols, Vec3b(0, 0, 0)); 
    for (int i = 0; i < pts.size(); ++i) 
    { 
     res(pts[i]) = colors[labels[i]]; 
    } 

    // Draw centroids 
    for (int i = 0; i < n_labels; ++i) 
    { 
     circle(res, centroids[i], 3, Scalar(colors[i][0], colors[i][1], colors[i][2]), CV_FILLED); 
     circle(res, centroids[i], 6, Scalar(255 - colors[i][0], 255 - colors[i][1], 255 - colors[i][2])); 
    } 


    imshow("Clusters", res); 
    waitKey(); 

    return 0; 
} 
相关问题