简体   繁体   English

C++ 和 OpenCV:聚类白像素算法

[英]C++ and OpenCV: clustering white pixels algorithm

I have a binary image (black and white pixels), and I'd like to cluster the white pixels into groups (objects), depending on the distance to each other, and retrieve the centroid of each cluster.我有一个二进制图像(黑色和白色像素),我想根据彼此的距离将白色像素聚类成组(对象),并检索每个聚类的质心。

This is an example image in which I have to work on:这是我必须处理的示例图像:

图片

(frame on purple) (紫色边框)

I'd like to check if a clustering approach would provide the results I am looking for, which means that I'm trying to avoid implementing an algorithm myself before knowing it will be worth it.我想检查聚类方法是否会提供我正在寻找的结果,这意味着我试图避免自己实现算法,然后才知道它是否值得。
Does OpenCV have a method to do what I need? OpenCV 有什么方法可以做我需要的吗?

I know this is quite old, but maybe this answer could be helpful.我知道这已经很老了,但也许这个答案可能会有所帮助。


You can use partition , which will split an element set into equivalency classes.您可以使用partition ,它将元素集拆分为等价类。

You can define an equivalence class as all points within a given euclidean distance .您可以将等价类定义为给定欧几里得距离内的所有点 This can be either a lambda function (C++11) or a functor (see both examples in the code).这可以是 lambda 函数 (C++11) 或函子(参见代码中的两个示例)。

Starting from this image (I removed purple border manually):从这张图片开始(我手动删除了紫色边框):

在此处输入图片说明

using an euclidean distance of 20 I got:使用欧氏距离 20 我得到:

在此处输入图片说明

You can see that all white pixels that are within the euclidean distance are assigned to the same cluster (same color).您可以看到欧几里得距离内的所有白色像素都被分配到同一个集群(相同颜色)。 The circles denotes the centroids for each cluster.圆圈表示每个集群的质心。

Code:代码:

#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;
}

If you know the number of clusters in the image, you could use the K-Means algorithm , which is implemented in OpenCV.如果您知道图像中的簇数,则可以使用在 OpenCV 中实现的K-Means 算法

Besides that, i do not know any other easy solution for this task.除此之外,我不知道此任务的任何其他简单解决方案。 If you like to implement this clustering yourself, this paper could help you, it is about an adaption of the k-means which must not have a fixed number of clusters.如果你想自己实现这种聚类,这篇论文可以帮助你,它是关于 k-means 的一种适应,它不能有固定数量的聚类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM