【问题标题】:C++ efficient way to find matches between two std::mapC++ 查找两个 std::map 之间匹配的有效方法
【发布时间】:2016-09-13 09:46:34
【问题描述】:

我有一个使用 RGB-D 相机获取的数据集和一个文本文件,其中存储了数据集的每个图像的时间戳和文件名。我要做的是解析这个文件并填充两个std::map,一个用于rgb图像,另一个用于深度图像。现在,由于时间戳不相交,我必须编写一个基于时间戳查找匹配图像的例程。这是我到目前为止写的:

typedef map<double,string> StampImageMap;

...

vector<string> &vstrImageFilenamesRGB;
vector<string> &vstrImageFilenamesD;
vector<double> &vTimestampsRGB;
vector<double> &vTimestampsDPT;

double tolerance = 0.02;

for(StampImageMap::iterator it=rgb_images.begin(); it != rgb_images.end(); it++) {
        bool found = false;
        StampImageMap::iterator jt=depth_images.begin();
        while(found == false && jt!=depth_images.end()) {
            if(fabs(it->first - jt->first) < tolerance) {
                found = true;
                vstrImageFilenamesRGB.push_back(it->second);
                vstrImageFilenamesD.push_back(jt->second);
                vTimestampsRGB.push_back(it->first);
                vTimestampsDPT.push_back(jt->first);
            }
            jt++;
        }
    }

我想知道是否有更有效的方法来执行此任务!

【问题讨论】:

  • RGB 和 D 时间戳有一对一的关系吗?他们是否遵循固定规则,例如同一张图片的 RGB 时间戳总是小于 D 时间戳?
  • 是的,相机的帧率是30Hz,所以对应的RGB和DEPTH图像不能有相同的时间戳(原因很明显)但是它们之间的差异不能大于1/33s,这就是我设置变量容差的原因。
  • @FedericoNardi 如果序列是“完整的”(两者都没有间隙)并且是一对一的,你不能只找到最早的匹配然后按顺序配对吗? (即第一个 rgb 图像与第一个深度图像,第二个与第二个图像,依此类推。)
  • @molbdnilo 不幸的是,事实并非如此。一些 DEPTH 图像没有对应的 RGB 图像 :(
  • @FedericoNardi 太糟糕了。不过,您无需从头开始搜索深度图像,因为您找不到比上一个更早的匹配项。

标签: c++ algorithm dataset matching stdmap


【解决方案1】:

现在编写代码时,复杂度为 Θ(n m),其中 nm 是序列的大小。至少有两种方法可以改善这一点(第二种更有效,但更难编码)。

  • 在外部循环的主体中,不要通过while(found == false &amp;&amp; jt!=depth_images.end()) 遍历第二个映射中的所有元素。相反,使用std::map::lower_boundstd::map::upper_bound 分别搜索it-&gt;first - toleranceit-&gt;first + tolerance。仅在这两个调用的结果之间循环。

    所以,代码变成了这样:

    for(StampImageMap::iterator it=rgb_images.begin(); it != rgb_images.end(); it++) {
        StampImageMap::const_iterator lower = depth_images.lower_bound(it->first - tolerance);
        StampImageMap::const_iterator upper = depth_images.lower_bound(it->first + tolerance);
    
        // Now just search between lower and upper.
    }
    

    这会将每次迭代减少到 Θ(log(m)) + p,其中 p 是这个范围的大小。

  • 由于地图的键已排序,您可以将standard technique of finding the intersection of two sorted arrays 修改为这种情况。这会将运行时间减少到Θ(m + n)。请注意,修改有点棘手,因为您不是试图找到确切元素的交集,而是“足够接近”元素的交集。

    这是本案例的伪代码

     it = rgb_image.begin();
     jt = depth_image.begin();
    
     while(it != rgb_image.end() && jt != depth_image.end()) {
         if(fabs(it->first - jt->first) < tolerance) {
             // Match found!
             ++it;
             ++jt;
             continue;
         }
    
         if(it.first > jt.first + tolerance) {
             ++jt;
             continue;
         }
    
         ++it;
     }
    

【讨论】:

  • 您将需要创建特殊的比较器来处理容差范围内的比较(微不足道。已经在 OP 代码中完成)——它不是传递性的,但它适用于地图中的所有值,这是有什么重要的——也许是特殊的输出迭代器,它可以完成你在分配时需要的东西,然后你就可以轻松地使用标准库了。
  • @Revolver_Ocelot 对,这是个好主意。但是,如果一个人对细节有耐心,那么第二个的复杂性较低,我不确定是否有一个标准的库算法来解决这个问题(不过,你关于比较函子的正确观点也是如此)。
  • 哦,我注意到您不能使用 set_intersection,因为您需要来自两个地图的值。您可以稍后再循环通过第二张地图,但它会更慢(但在算法上仍然比 O(nm) 好),所以您的解决方案基本上是 set_intersection,但同时处理两个值。
  • @Revolver_Ocelot 没错。我完全同意您的评论,尽管使用“公差”比较功能,这两个选项都会更具可读性 - 谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多