Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ opencv欧几里德聚类与findContours_C++_Opencv_Cluster Analysis - Fatal编程技术网

C++ opencv欧几里德聚类与findContours

C++ opencv欧几里德聚类与findContours,c++,opencv,cluster-analysis,C++,Opencv,Cluster Analysis,我有以下图像掩码: 我想应用类似于cv::findContours,但该算法只连接相同组中的连接点。我想用一些容差来实现这一点,也就是说,我想在给定的半径容差内添加彼此相邻的像素:这类似于欧几里德距离层次聚类 这是在OpenCV中实现的吗?或者有没有快速的方法来实现这一点 我想要的是类似的东西 应用于此遮罩的白色像素 谢谢。我建议使用算法。这正是你要找的。使用简单的欧几里德距离甚至曼哈顿距离可能会更好。 输入为所有白点(阈值ed)。输出是一组点(连接的组件) 这是一个 编辑: 我试过自己,结

我有以下图像掩码:

我想应用类似于
cv::findContours
,但该算法只连接相同组中的连接点。我想用一些容差来实现这一点,也就是说,我想在给定的半径容差内添加彼此相邻的像素:这类似于欧几里德距离层次聚类

这是在OpenCV中实现的吗?或者有没有快速的方法来实现这一点

我想要的是类似的东西

应用于此遮罩的白色像素

谢谢。

我建议使用算法。这正是你要找的。使用简单的欧几里德距离甚至曼哈顿距离可能会更好。 输入为所有白点(阈值ed)。输出是一组点(连接的组件)

这是一个

编辑: 我试过自己,结果如下:

如您所见,仅将真正连接的点视为一个簇

该结果是使用标准DBSCAN算法获得的,EPS=3(静态无需调整)MinPoints=1(也可静态)和曼哈顿距离可用于:

partition
将元素集拆分为等价类。可以将等价类定义为给定欧几里德距离(半径公差)内的所有点

如果您有C++11,则只需使用lambda函数即可:

int th_distance = 18; // radius tolerance

int th2 = th_distance * th_distance; // squared radius tolerance
vector<int> labels;

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; 
});
int th_距离=18;//半径公差
int th2=th_距离*th_距离;//平方半径公差
矢量标签;
int n_labels=分区(pts、标签[th2](常量点和左侧、常量点和右侧){
返回((lhs.x-rhs.x)*(lhs.x-rhs.x)+(lhs.y-rhs.y)*(lhs.y-rhs.y))
否则,您可以只构建一个函子(请参阅下面代码中的详细信息)

通过适当的半径距离(我发现这张图片上有18个作品很好),我得到:

完整代码:

#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 radius tolerance
    int th_distance = 18; // radius tolerance

    // Apply partition 
    // All pixels within the radius tolerance distance will belong to the same class (same label)
    vector<int> labels;

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

    // With lambda function (require C++11)
    int th2 = th_distance * th_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;
    });

    // You can save all points in the same class in a vector (one for each class), just like findContours
    vector<vector<Point>> contours(n_labels);
    for (int i = 0; i < pts.size(); ++i)
    {
        contours[labels[i]].push_back(pts[i]);
    }

    // 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 labels
    Mat3b lbl(img.rows, img.cols, Vec3b(0, 0, 0));
    for (int i = 0; i < pts.size(); ++i)
    {
        lbl(pts[i]) = colors[labels[i]];
    }

    imshow("Labels", lbl);
    waitKey();

    return 0;
}
#包括
#包括
#包括
使用名称空间std;
使用名称空间cv;
结构欧几里德常数函数
{
国际区2;
欧几里德常数函数(int dist):_dist2(dist*dist){
布尔运算符()(常量点和左侧、常量点和右侧)常量
{
返回((左S.x-右S.x)*(左S.x-右S.x)+(左S.y-右S.y)*(左S.y-右S.y))<\u dist2;
}
};
int main()
{
//加载图像(灰度)
Mat1b img=imread(“路径到图像”,imread\U灰度);
//获得所有非黑点
向量pts;
findNonZero(img、pts);
//定义半径公差
int th_距离=18;//半径公差
//应用分区
//半径公差距离内的所有像素将属于同一类别(同一标签)
矢量标签;
//带函子
//int n_labels=分区(pts,labels,euclideandstancefunctor(th_距离));
//使用lambda函数(需要C++11)
int th2=th_距离*th_距离;
int n_labels=分区(pts、标签[th2](常量点和左侧、常量点和右侧){
返回((lhs.x-rhs.x)*(lhs.x-rhs.x)+(lhs.y-rhs.y)*(lhs.y-rhs.y))
不清楚您希望算法做什么。你能用预期的结果显示另一幅图像吗?在某种程度上,形态学算子似乎能满足你的所有需要,所以我确信情况并非如此。我们需要看看你想要达到的效果。@RogerRowland No形态学操作符不是一个选项,因为它们会扭曲我的边缘。我要做的是根据蒙版图像中的边缘之间的欧几里德距离对它们进行分组。我认为@Humam的建议是一个很好的建议,尽管没有OpenCV实现。对于OpenCV中的集群任务,除了k-means或meanshift之外,您不会得到更多。然而,由于您已经链接了一个示例算法,将其移植到OpenCV可能更为简单(而且您可能不需要3D)。@Rogerowland非常适合此任务。@Miki Good stuff,这对我来说是一个新的算法,+1用于您的评论和回答。+1用于OpenCV方法-1对于非基于密度的方法。距离的门槛将是一场噩梦。如果您能分享您对调整此问题阈值的通用方法的想法,我将非常高兴;)@很好,感谢+1;关于-1,让我回答一下:1)DBSCAN(至少在原始公式中)需要2个参数,其中一个参数正好是距离阈值(如下所示)。2) 问题在于半径公差范围内的聚类,而不是基于密度的方法。3) 问题没有提到对异常值的鲁棒性。这就是为什么有人提出了这个解决方案。@HumamHelfawi关于调整阈值,这实际上取决于OP的最终目标。他可能需要将属于同一圆的所有点放在同一个类中。在这种图像(基本上没有噪声)中,这可以通过随机hough变换的一些变体轻松实现(但仍然需要设置一些参数)。让我考虑一下其他一些方法:D@Miki我没有说我的答案是好的。我刚刚批评了你的回答:D.只是开玩笑。。DBSCAN需要距离参数,是,这是真的。然而,DBS的工作方式可以是