【问题标题】:What's the fastest way to compare point elements with each other?I have used Nested for loop to do that, but it's very slow比较点元素最快的方法是什么?我用嵌套的for循环来做,但是很慢
【发布时间】:2015-09-06 22:53:48
【问题描述】:

我想找到点之间的距离小于3的点。例如,一些点如下, (220,221)(220,119)(220,220)(20,90)(220,222)。 我用 (220,221) 来找点。然后我可以得到 (220,221)(220,119)(220,220)(220,222) 我使用 (220,119) 来查找点。然后我可以得到 (220,221)(220,119)(220,220) 我已经使用嵌套的for循环来做到这一点,但它很慢。它工作效率低下。代码如下,

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;

int main()
{

    vector<Point>  p;
    vector<Point> temp;
    vector<vector<Point> > centerbox;

    p.push_back(Point(110, 110));
    p.push_back(Point(110, 111));
    p.push_back(Point(110, 110));
    p.push_back(Point(110, 112));
    p.push_back(Point(111, 112));
    p.push_back(Point(150, 111));


    for (vector<Point> ::iterator iter1 = p.begin(); iter1 != p.end(); ++iter1) {


        for (vector<Point> ::iterator iter2 = p.begin(); iter2 != p.end();) {



            if (abs((*iter1).x - (*iter2).x) + abs((*iter1).y - (*iter2).y) < 3) {

                temp.push_back((*iter2));
                ++iter2;
            }
            else {
                ++iter2;
            }
        }


        centerbox.push_back(temp);

        temp.clear();

    }

        return 0;
}

我怎样做才能比使用嵌套 for 循环更快?

【问题讨论】:

  • 您可以使用空间分区/散列技术将您的点“分类”到垃圾箱中。之后,对于固定的最大距离,您只需将每个点与几个相邻 bin 中的点进行比较。
  • 使其更快的最简单方法是使用对称性。如果 p1 的 dist
  • 使用简单的索引而不是迭代器,如果你知道点数的上限,那么使用数组而不是向量。
  • 使用 std::vector::reservestd::vector::emplace 应该会给你一些性能提升。
  • 谢谢大家!我之前也想用sort,但是sort很费时间,不是吗?

标签: c++ opencv for-loop dictionary vector


【解决方案1】:

对于 20000 个随机点,每个点大约有 27 个邻居,这个函数给了我一个加速。与原来的方法相比,它所需的时间减少了大约 33%。

std::vector<std::vector<cv::Point> > findNeighborsOptimized(std::vector<cv::Point> p, float maxDistance = 3.0f)
{

    std::vector<std::vector<cv::Point> > centerbox(p.size()); // already create a output vector for each input point

    /*
    // if you  have enough memory, you can reserve enough space for each point. If not, just remove this part, which will result in a lot of reallocations later.
    //unsigned int reserveSize = p.size(); // definitely enough space so no reallocations will happen but probably too much space reserved...
    //unsigned int reserveSize = p.size()/2; 
    //unsigned int reserveSize = p.size()/3;
    //unsigned int reserveSize = p.size()/10;
    unsigned int reserveSize = 1;

    for(unsigned int i=0; i<centerbox.size(); ++i)
    {
        centerbox[i].reserve(reserveSize);
    }
    */
    // for me it turned out to be slower to reserve a lot of memory... maybe because of caching?!?
    // will depend on the average number of neighbors for each point...


    for(unsigned int j=0; j<p.size(); ++j)
    {
        std::vector<cv::Point> & p1Neighbors = centerbox[j];

        // create a reference to the point so that we dont need to GET it several times
         cv::Point & p1 = p[j];
         //p1Neighbors.push_back(p1); // uncomment this if you want to show the point be a neighbor of itself (dist to itself is alway == 0).
         // for p2 ignore p1 and start at the next point

         for(unsigned int i=j+1; i<p.size(); ++i)
         {
             cv::Point & p2 = p[i];

             // instead you might want to use cv::norm(p1-p2) or something, but I'll stay at your original logic
            if(abs(diff.x) + abs(diff.y) < maxDistance)
             {
                 p1Neighbors.push_back(p2);
                 // add p1 to neighbors of p2 too
                 centerbox[j].push_back(p1);
             }
         }
    }


    return centerbox;
}

取决于您在应用程序中拥有的点数以及它们的分布,空间分区或空间散列可能会给您带来更好的改进。

【讨论】:

  • 感谢您的 cmets。您说“空间散列可能会给您带来更好的改进”。我曾使用 unordered_mulitmap 来做到这一点,但我不知道如何比较这些点。不同的点有不同的哈希码,所以我不能把点放在一个桶里来比较点。所以我写了一个哈希函数,使所有点都有相同的哈希码,将被放入同一个桶中。然后使用哈希比较函数相互比较。但是我感谢所有点都有一个哈希码不是一个好主意。你有什么想法吗?你能展示一下在我的案例中使用哈希来查找点的代码吗?提前致谢!
  • 从未使用过空间散列,只在讲座中看到过。但试试zufallsgenerator.github.io/2014/01/26/…gamedev.net/page/resources/_/technical/game-programming/…
【解决方案2】:

push_back 创建您发送的对象的副本,因此存储指向 Point 的指针而不是整个 Point 对象可能会更快。

您也可以使用std::vector&lt;T&gt;::reserve 提前在临时向量中预留空间。这将减少push_back 重新分配内存的机会(这很慢!)。

【讨论】:

  • 感谢您的评论1
猜你喜欢
  • 2017-08-19
  • 2017-06-28
  • 1970-01-01
  • 1970-01-01
  • 2016-06-01
  • 1970-01-01
  • 2016-12-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多