【问题标题】:Efficiently calculating distance of pixels to their corresponding epipolar lines有效计算像素与其对应的极线的距离
【发布时间】:2019-11-18 10:53:32
【问题描述】:

我正在尝试计算立体相机设置中两个对应像素到它们各自的极线的距离。我为此目的实现的代码如下:

#include <iostream>
#include <vector>
#include <opencv2/calib3d/calib3d.hpp>

float calculateDistanceToEpiLineSum(const cv::Mat2f& left_candidate, const cv::Mat2f& right_candidate, const cv::Matx33f& fundamental_mat) {

  // Calculate epipolar lines
  cv::Mat epiLineRight=cv::Mat(1,3,CV_32FC1);
  cv::Mat epiLineLeft=cv::Mat(1,3,CV_32FC1);
  cv::computeCorrespondEpilines(left_candidate,2,fundamental_mat,epiLineRight);
  cv::computeCorrespondEpilines(right_candidate,1,fundamental_mat,epiLineLeft);

  // Calculate distances of the image points to their corresponding epipolar line
  float distance_left_im=std::abs(epiLineLeft.at<float>(0)*left_candidate[0][0][0]+
                                   epiLineLeft.at<float>(1)*left_candidate[0][0][1]+
                                   epiLineLeft.at<float>(2))/
      std::sqrt(std::pow(epiLineLeft.at<float>(0),2.f)+std::pow(epiLineLeft.at<float>(1),2.f));

  float distance_right_im=std::abs(epiLineRight.at<float>(0)*right_candidate[0][0][0]+
                                   epiLineRight.at<float>(1)*right_candidate[0][0][1]+
                                   epiLineRight.at<float>(2))/
      std::sqrt(std::pow(epiLineRight.at<float>(0),2.f)+std::pow(epiLineRight.at<float>(1),2.f));

  return distance_left_im+distance_right_im;
}

int main()
{
  cv::Matx33f fundamental_mat=cv::Matx33f{-0.000000234008931f,-0.000013193232976f, 0.010025275471910f,
                                          -0.000017896532640f, 0.000009948056751f, 0.414125924093639f,
                                           0.006296743991557f,-0.411007947095269f,-4.695511356888332f};

  cv::Vec2f left_candidate_vec(135.,289.);
  cv::Vec2f right_candidate_vec(205.,311.);
  cv::Mat2f left_candidate(left_candidate_vec);
  cv::Mat2f right_candidate(right_candidate_vec);

  float distance_sum=calculateDistanceToEpiLineSum(left_candidate,right_candidate,fundamental_mat);

  std::cout<<"The sum of the distances equals "<<distance_sum<<" pixels\n";

  return 0;
}

我面临的问题是我每秒可能必须执行此操作数千次。我知道cv::computeCorrespondEpiliness 的第一个输入可以是一个像素向量,它允许一种更加向量化的方法,并且可能会加快一点速度。问题是,我无法使用它,因为我没有使用传统相机,而是使用event-based sensors,因此我将异步接收像素(而不是接收帧)。
现在我想知道以下内容:

  1. calculateDistanceToEpiLineSum 中是否存在任何重大缺陷? 以不好的方式影响功能的性能?在这里不使用 OpenCV 函数,而是自己实现 computeCorrespondEpilines 可能是个好主意吗?
  2. 我之前考虑过“离线”计算极线 节省处理时间。问题是,我不知道我会怎么做 有效地计算和保护极线。我想过 计算每个图像的每个像素的核线和 根据ax+by+c=0将行参数存储在三元组中, 但假设每个相机的分辨率为 480x360,这将给出 我有两个相当大的 480x360x3 矩阵。是否可行 还是这样,还是有更好的方法?

【问题讨论】:

    标签: c++ performance opencv computer-vision


    【解决方案1】:

    如果不知道您的计算限制是什么,就无法回答时间性能问题,因此以下是一个非常粗略的估计。

    在底部,计算候选匹配像素对的一个点与其关联的极线的距离大致成本:

    • 一个矩阵乘法 = 9 次乘法,6 次加法 = 15 次翻转
    • 归一化 = 2 次乘法,1 次加法,1 次平方根 =~ 10 次失败
    • 带线系数的点积:3 mult, 2 add = 5 flops
    • 除法 =~ 4 次失败

    所以这对大约有 70 次翻牌。

    这一切以秒为单位的含义至少取决于您的处理器时钟周期。 Skylake IA64 可以执行 16 DP 矢量化触发器/周期,因此将其称为 5 个周期。在 3 GHz 时,所需时间不到 2 ns。在这方面留有很大的余地,我们称之为总共 10 ns。

    您说您必须每秒执行“数千次”计算。在每对 10ns 的情况下,您每秒可以处理 1 亿 个。

    鉴于上述情况,您确定这个特定操作将成为瓶颈,而不是例如来自相机的 I/O(包括图像解码)?

    忠告:学习使用良好的微基准测试框架来获取硬件的实际性能数据。我推荐好老Google Benchmark

    【讨论】:

    • 感谢您的回答。我肯定会研究谷歌基准。如果我可以根据它优化任何东西,我会告诉你的。
    猜你喜欢
    • 2014-06-08
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多