2013-10-01 3 views
2

У меня есть двоичное изображение (черно-белые пиксели), и я хотел бы сгруппировать белые пиксели в группы (объекты) в зависимости от расстояния друг к другу и получить центроида каждого кластера.C++ и OpenCV: алгоритм кластеризации белых пикселей

Это пример изображения, в котором я должен работать на:

Image

(рамка на фиолетовый)

Я хотел бы проверить, если кластерный подход обеспечит результаты I я ищу, что означает, что я пытаюсь избежать реализации алгоритма самостоятельно, прежде чем знать, что это того стоит.
Есть ли у OpenCV метод, который мне нужен?

ответ

0

Если вы знаете количество кластеров на изображении, вы можете использовать K-Means algorithm, который реализован в OpenCV.

Кроме того, я не знаю другого простого решения этой задачи. Если вы хотите реализовать эту кластеризацию самостоятельно, вам может помочь this paper, это касается адаптации k-средств, которые не должны иметь фиксированного количества кластеров.

+0

Число кластеров может меняться, и нет никакого способа узнать заранее, сколько они. Да, я думаю, мне придется что-то реализовать –

2

Я знаю, что это довольно старый, но, возможно, этот ответ может быть полезным.


Вы можете использовать partition, который разделит элемент установлен на классы эквивалентности.

Вы можете определить класс эквивалентности как все точки в пределах данного евклидова расстояния. Это может быть либо лямбда-функция (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; 
} 
Смежные вопросы