我有一个二进制图像(黑白像素),并且我想根据彼此的距离将白色像素聚类成组(对象),并检索每个群集的质心。C++和OpenCV:聚类白色像素算法
这是在其中我必须工作在一个示例图像:
(上紫色帧)
我想检查一个聚类方法将提供结果我我正在寻找,这意味着我在尝试避免自己实现算法之前知道它是值得的。
OpenCV有办法做我需要的吗?
我有一个二进制图像(黑白像素),并且我想根据彼此的距离将白色像素聚类成组(对象),并检索每个群集的质心。C++和OpenCV:聚类白色像素算法
这是在其中我必须工作在一个示例图像:
(上紫色帧)
我想检查一个聚类方法将提供结果我我正在寻找,这意味着我在尝试避免自己实现算法之前知道它是值得的。
OpenCV有办法做我需要的吗?
如果知道图像中的簇数,可以使用在OpenCV中实现的K-Means algorithm。
除此之外,我不知道这个任务的任何其他简单的解决方案。如果你想自己实现这个集群,this paper可以帮助你,它是关于k-means的适应,它必须不具有固定数量的集群。
我知道这是相当古老的,但也许这个答案可能会有所帮助。
您可以使用partition,这将分裂成集等效类的元素。
您可以在给定的欧几里德距离内定义一个等价类为。这可以是一个lambda函数(C++ 11)或一个仿函数(参见代码中的两个示例)。
从这个图像开始(我删除手动紫色边框):
使用20的欧氏距离我:
你可以看到,所有白色像素在欧氏距离范围内的颜色被分配到相同的颜色组(相同的颜色)。圆圈表示每个群集的质心。
代码:
#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;
}
集群的数量可能会有所不同,也没有办法知道他们事先有多少。 是的,我想我必须自己实现一些东西 –