如何通过另一个具有位置的垫子访问opencv中的矩阵数据(索引)

How to access matrix data in opencv by another mat with locations (indexing)

假设我有一个名为 B 的索引(位置)矩阵,我们可以说这个矩阵具有 1 x 100 的维度并且我们假设有另一个矩阵,称为 A,充满相同维度的数据B的。 现在,我将使用 B 访问 A 的数据。通常我会创建一个 for 循环,我会为 B 的每个元素获取 A 的正确元素。对于最挑剔的网站,这是我的代码会写:

for(int i=0; i < B.cols; i++){
    int index = B.at<int>(0, i);
    std::cout<<A.at<int>(0, index)<<std:endl;
}

好的,既然我已经向您展示了我可以做什么,我想问您是否有一种方法可以更智能、更快速地访问矩阵 A,始终使用 B 索引。由于 numpy.take() 功能,有人可以在 python 中做到这一点。

为此目的,此操作被称为 remapping. In OpenCV, you can use function cv::remap

下面我展示了重映射算法如何工作的非常基本的例子;请注意,在这个例子中我不处理边界条件,但 cv::remap 处理 - 它允许您使用镜像、夹紧等来指定如果索引超过图像的尺寸会发生什么。我也没有说明插值是如何完成的;查看我上面链接的 cv::remap 文档。

如果您要使用重新映射,您可能必须将索引转换为浮点数;如果您的图像是 one-dimensional,您还必须引入另一个索引数组,这些索引应该是微不足道的(全部等于 0)。如果这开始代表性能问题,我建议您自己实现等效的 1-D 重映射。当然,在优化之前先进行基准测试。

有关所有详细信息,请查看文档,其中涵盖了使用算法所需了解的所有内容。

cv::Mat<float> remap_example(cv::Mat<float> image, 
                             cv::Mat<float> positions_x, 
                             cv::Mat<float> positions_y)
{
   // sizes of positions arrays must be the same
   int size_x = positions_x.cols;
   int size_y = positions_x.rows;
   auto out = cv::Mat<float>(size_y, size_x);

   for(int y = 0; y < size_y; ++y)
     for(int x = 0; x < size_x; ++x)
     {
       float ps_x = positions_x(x, y);
       float ps_y = positions_y(x, y);

       // use interpolation to determine intensity at image(ps_x, ps_y),
       // at this point also handle border conditions 
       // float interpolated = bilinear_interpolation(image, ps_x, ps_y);

       out(x, y) = interpolated;
      }

return out;
}

一种快速的方法是对 A(数据)和 B(索引)都使用指针。

const int* pA = A.ptr<int>(0);
const int* pIndexB = B.ptr<int>(0);
int sum = 0;
for(int i = 0; i < Bi.cols; ++i)
{
    sum += pA[*pIndexB++];
}

注意:请注意像素类型,在本例中(如您在代码中所写)为 int!

注意 2:对每个点访问使用 cout 使优化无用!

注3:在这篇文章中,Satya 比较了四种像素访问方法,最快的似乎是"foreach":https://www.learnopencv.com/parallel-pixel-access-in-opencv-using-foreach/