C ++ - 最快的双线性插值?

时间:2015-07-15 20:20:09

标签: performance c++11 profiling eigen

我想加快我的c ++双线性插值代码。

设置如下:从灰度图像 img 我想在 cent 位置提取矩形补丁 pat 单位间距,没有上/下采样。<​​/ strong>

由于 cent 通常不是整数,我必须双线插值提取的补丁。

图像 img ,提取的补丁 pat 和位置 cent 存储为浮点数。 补丁的大小为[2 * pad + 1], pad 是位置 cent 的左右填充。

目前的解决方案如下:

void function(Eigen::Matrix<float, Eigen::Dynamic, 1>* pat, 
              const float* img, 
              const Eigen::Vector2f* cent)
{

  Eigen::Vector4f we; // bilinear weight vector
  // ... [CROPPED: compute bilinear weights]

  float *pat_it = pat->data();
  for (y=cent[1]-pad; y <= cent[1]+pad; ++y)    
  {
    int postmp_a = y        * image_width;
    int postmp_b = (y-1)    * image_width;

    for (x=cent[0]-pad; x <= cent[0]+pad; ++x, ++pat_it)    
    {

          (*pat_it)     = we[0] * img[ x    +  postmp_a] +  
                          we[1] * img[x-1   +  postmp_a] +
                          we[2] * img[ x    +  postmp_b] +
                          we[3] * img[x-1   +  postmp_b]; 
    }
  }
}
  1. 是否可以进一步提高速度?此功能将在实时信号处理管道中被调用数百万次。 没有内存限制。

  2. 是否可能有特定的特征函数?

  3. 由于这是我的代码最关键的瓶颈,我也愿意考虑将代码移动到不同的编程语言/架构(汇编程序,CUDA等......)。有关于此的任何想法/提示吗?

  4. 更一般地说,您如何系统地对此进行分析?

  5. 更多细节:代码使用'-Ofast -std = c ++ 11'编译,并且已经使用OpenMP并行运行。图像大小约为~1000x1200像素, pad 在5-10像素之间。

    修改

    通过直接使用指向4个相应图像位置的指针,我已经设法提高了约6%的速度。

    ...
    for (x=cent[0]-pad; x <= cent[0]+pad; ++x,++pat_it,
         ++img_a,++img_b,++img_c,++img_d)    
    {
    
          (*pat_it)   = we[0] * (*img_a) +  
                        we[1] * (*img_b) +
                        we[2] * (*img_c) +
                        we[3] * (*img_d); 
    }
    ...
    

1 个答案:

答案 0 :(得分:1)

您可以尝试让Eigen简化其中的一些内容,例如:

void function(Eigen::VectorXf* pat, 
              const float* img, 
              const Eigen::Vector2f* cent)
{
...
  for (y=cent[1]-pad; y <= cent[1]+pad; ++y)    
  {
    ...
    Eigen::Map<Eigen::Array4f, 0, Eigen::OuterStride<>> mp(img + cent[0]-pad -1 +  postmp_b, 4, Eigen::OuterStride<>(image_width));
    for (x=cent[0]-pad; x <= cent[0]+pad; ++x, ++pat_it)    
    {
      new (&mp) Eigen::Map<Eigen::Array4f>(img + x-1 +  postmp_b, 4, Eigen::OuterStride<>(image_width));
      (*pat_it) = (mp * we.array()).sum();
...

注意:您可能需要重新排列we以匹配img元素的新顺序。

你可以通过不创建一堆地图来尝试做得更好,而是创建一个大的地图:

void function(Eigen::VectorXf* pat, 
              const float* img, 
              const Eigen::Vector2f* cent)
{
  ...
  Eigen::Map<Eigen::ArrayXXf, 0, Eigen::OuterStride<>> mp(img, image_width, image_height, Eigen::OuterStride<>(image_width));
  for (y=cent[1]-pad; y <= cent[1]+pad; ++y)    
  {
    ...
    for (x=cent[0]-pad; x <= cent[0]+pad; ++x, ++pat_it)    
    {
      (*pat_it) = (mp.block<2,2>(x,y) * we.array()).sum();
...

你可能会做得更好,我还没有测试过这些。这导致我发出以下免责声明。我还没有测试过这个。这意味着,您可能需要更改InnerStrideOuterStride以及image_widthimage_height等。

如果这对你有所帮助,我很想知道它给了多少加速。