C++ 最近点算法|如何改进?

C++ 最近点算法|如何改进?,c++,algorithm,performance,optimization,graphics,C++,Algorithm,Performance,Optimization,Graphics,我写了一个k均值聚类算法和一个颜色量化算法。就结果而言,它们的工作与预期的一样,但我想让它们更快。在这两种实现中,我都需要解决一个问题:在三维空间中有两个点阵列,然后对于第一个阵列的每个点,您需要找到与第二个阵列最近的点。我是这样做的: size_t closest_cluster_index; double x_dif, y_dif, z_dif; double old_distance; double new_distance; for (auto point = points.begin

我写了一个k均值聚类算法和一个颜色量化算法。就结果而言,它们的工作与预期的一样,但我想让它们更快。在这两种实现中,我都需要解决一个问题:在三维空间中有两个点阵列,然后对于第一个阵列的每个点,您需要找到与第二个阵列最近的点。我是这样做的:

size_t closest_cluster_index;
double x_dif, y_dif, z_dif;
double old_distance;
double new_distance;

for (auto point = points.begin(); point != points.end(); point++)
{
    //FIX
    //as suggested by juvian
    //K = 1
    if (point != points.begin())
    {
        auto cluster = &(clusters[closest_cluster_index]);

        r_dif = cluster->r - point->r;
        g_dif = cluster->g - point->g;
        b_dif = cluster->b - point->b;

        new_distance = r_dif * r_dif + g_dif * g_dif + b_dif * b_dif;

        if (new_distance <= std::sqrt(old_distance) - ColorU8::differenceRGB(*(point - 1), *point))
        {
            old_distance = new_distance;
            //do sth with closest_cluster_index;
            continue;
        }
    }
    //END OF FIX

    old_distance = std::numeric_limits<double>::infinity();

    for (auto cluster = clusters.begin(); cluster != clusters.end(); cluster++)
    {
        x_dif = cluster->x - point->x;
        y_dif = cluster->y - point->y;
        z_dif = cluster->z - point->z;

        new_distance = x_dif * x_dif + y_dif * y_dif + z_dif * z_dif;

        if (new_distance < old_distance)
        {
            old_distance = new_distance;
            closest_cluster_index = cluster - clusters.begin();
        }
    }
    //do sth with: closest_cluster_index
}
size\t最近的聚类索引;
双x_dif,y_dif,z_dif;
双倍老_距离;
双倍的新距离;
对于(自动点=点。开始();点!=点。结束();点++)
{
//修理
//正如朱维安所建议的那样
//K=1
if(point!=points.begin())
{
自动聚类=&(聚类[最近的聚类索引]);
r_dif=簇->r点->r;
g_dif=簇->g点->g;
b_dif=集群->b点->b;
新距离=r_dif*r_dif+g_dif*g_dif+b_dif*b_dif;
如果(新距离x-点->x;
y_dif=簇->y点->y;
z_dif=簇->z点->z;
新距离=x_dif*x_dif+y_dif*y_dif+z_dif*z_dif;
if(新距离<旧距离)
{
旧的_距离=新的_距离;
最近的_cluster_index=cluster-clusters.begin();
}
}
//用最近的聚类索引做某事
}
我怎样才能改进它?
(我不想让它成为多线程的或由GPU计算的)

有多种数据结构可用于高效的最近邻查询。对于3d,a工作得非常好,平均每个查询的复杂性为O(logn),这将改善当前的O(n)

因此,使用此结构,您可以将集群中的所有点添加到其中,然后对于点中的每个点,您可以使用此结构查询最近的点。对于您的特定情况,静态kdtree就足够了,因为您不需要更新点

另一种方法

我们可以尝试冒险在某些点上进行额外计算,以换取在其他点上进行更少的计算。此方法应在以下假设下运行良好:

  • 一个簇与另一个簇之间的距离很远
  • 点与相邻点之间的距离较低
我认为这些适用于你的情况,因为你的簇很少有颜色,你的点来自真实的图像,相邻像素之间往往有相似的颜色

对于每个点,创建一个堆。不是存储最近的群集,而是存储在最近的k个群集中。当您移动到下一个点时,我们可以使用此信息。我们将此点称为p和其第k个最近的群集C


现在,对于一个新的点P2,在比较所有集群之前,我们将检查距离P2最近的集群是否在我们的堆中。只有当任何集群与堆之间的距离为P2时,这才可能是真的。使用适当的数据结构(如kdtree)从集群获取所有点,然后针对第一个数组中的每个点,询问该结构的最近点@朱维安:你的评论看起来真像是一个答案;)dup?:@YSC不习惯简短的回答,但试了一下^^@ArneVogel是的,我知道。将此算法拆分为多个线程非常简单。然而,这是我学习工作的一部分。我将测量它的执行时间,评估结果,并与其他算法(如中值切割)进行比较。为了做出公正的判断,我在一个线程中完成所有任务,只使用CPU。@John Smith你的问题的大小是多少?另外,您可以检查问题是树的构造还是它的使用。@JohnSmith好的,所以在您的例子中,N远大于簇的数量,所以这对您没有帮助。如果你有很多集群,你会注意到一个不同,但是它们太少了,这是不值得的。目前需要多长时间?@JohnSmith您也可以尝试使用八叉树。主要的问题是,即使一个结构提供了O(日志集群)步骤中的最近邻,这些步骤的常数也比简单for循环高,因此执行其中的8个步骤实际上可能比只执行256个简单步骤更昂贵operations@JohnSmith您可能希望将当前性能与其他颜色量化工具进行比较,如果他们更好,试着搜索他们是如何做到的。是一个已知的工具,对它们的方法有很好的解释。@JohnSmith 16迭代看起来不错。一个关键点是为第一次迭代选择集群。我想你已经尝试过优化它了。第一次尝试时,可以使用次优但更快的算法。例如,首先使用较少的点运行算法,然后增加点数。它不知道这对你来说是否有意义。