当前位置: 首页 > 知识库问答 >
问题:

C++与OpenCV:白色像素聚类算法

阳兴朝
2023-03-14

我有一个二值图像(黑色和白色像素),我想将白色像素聚类成组(对象),这取决于彼此的距离,并检索每个聚类的质心。

(紫色框架)

我想检查一下聚类方法是否能提供我想要的结果,这意味着在知道值得之前,我试图避免自己实现一个算法。
OpenCV有一个方法来做我需要的事情吗?

共有1个答案

桓高澹
2023-03-14

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

您可以使用partition,它将把一个元素集拆分为等效类。

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

您可以看到,在欧几里得距离内的所有白色像素都被分配到相同的集群(相同的颜色)。圆圈表示每个星团的中心。

代码:

#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;
}
 类似资料:
  • 我已经在网上搜索过了,我已经找到了一些方法来做我想做的事情,但是与我需要的相比,这些方法在效率上失败了。 我有一个kinect(使用Microsoft SDK),它当前正在获取一个删除背景的人,将结果保存在一个3通道的垫子中,并将该人从背景中删除。现在我需要裁剪图像以只适合那个人,忽略黑色区域。 这里是棘手的部分:我没有很多时间浪费在每个操作上(我还需要做其他几个操作,这应该是实时工作。我目前实现

  • 在OpenCV python中,假设我们用cv2.imread读取一个图像,并得到一个BGR numpy数组。接下来我们使用cv2.inrange命令生成一个掩码。掩模具有相同的宽度/高度,并且每个掩模像素要么是黑色的,要么是白色的。 我必须先将掩码转换成BGR图像吗?如果是,怎么做? 编辑:我不想像在将蒙版应用到彩色图像中那样将整个蒙版应用到图像上。另一种表达我所想要的方式:将面具视为一个黑白图

  • 本文向大家介绍C#图像颜色聚类高效方法实例,包括了C#图像颜色聚类高效方法实例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了C#图像颜色聚类高效方法。分享给大家供大家参考。具体分析如下: 图像颜色聚类的方法有很多,但是对于视频监控而言,现有方法很难满足实时性的要求,这里介绍一种位屏蔽压缩的方法实现颜色聚类,可以满足实时性的要求。 位屏蔽法就是在3D的RGB真彩空间中近似均匀采样的颜色压缩

  • 问题内容: 我在Python中具有以下测试代码以读取,设置阈值和显示图像: 我想计算带有特定标签(例如黑色)的图像内像素的数量。我怎样才能做到这一点 ?我看了OpenCV的教程,但没有找到任何帮助:-( 谢谢! 问题答案: 对于黑色图像,您将获得像素总数(行*列),然后从得出的结果中减去它。 对于其他值,您可以创建一个遮罩,该遮罩用于返回显示所需颜色/标签/值的所有位置的二进制遮罩,然后用于计算其

  • 我有两种不同格式的图像。一个是BGR,一个是黑白(只有黑白,没有灰色的彩色像素)。它是相同的精确图像(相同的大小和像素)。我想在黑白图像中找到所有的白色像素,标记下来然后在BGR图像中找到完全相同的像素(显然它们在BGR图像中是着色的),并将它们着色为黑色。我试过了,但问题是黑白图像有1个通道,而BGR图像有3个通道,所以我失败了...我正在使用C++中的opencv。谢谢你的帮助!:)

  • 使用k-means算法时需要指定分类的数量,这也是算法名称中“k”的由来。 k-means是Lloyd博士在1957年提出的,虽然这个算法已有50年的历史,但却是当前最流行的聚类算法! 下面让我们来了解一下k-means聚类过程: 我们想将图中的记录分成三个分类(即k=3),比如上文提到的犬种数据,坐标轴分别是身高和体重。 由于k=3,我们随机选取三个点来作为聚类的起始点(分类的中心点),并用红黄