我发现了Halide,并且通过执行各种操作的管道获得了一些成功
转变。其中大多数是基于源中的示例(颜色转换,各种过滤器,hist-eq)。

我的下一步需要按块处理图像。以更一般的形式
部分重叠的块。

例子

输入:

      [  1,  2,  3,  4,  5,  6,  7,  8,
         9, 10, 11, 12, 13, 14, 15, 16,
        17, 18, 19, 20, 21, 22, 23, 24,
        25, 26, 27, 28, 29, 30, 31, 32]

不重叠的块:

尺寸:2x4
      [ 1,  2,  3,  4,
        9, 10, 11, 12]

      [  5,  6,  7,  8,
        13, 14, 15, 16]

      [ 17, 18, 19, 20,
        25, 26, 27, 28]

      [ 21, 22, 23, 24,
        29, 30, 31, 32]

重叠块:

大小:2x4,重叠50%(两个轴)
      [ 1,  2,  3,  4,
        9, 10, 11, 12]

      [ 3,  4, 5, 6,
        11, 12, 13, 14]

      [ 5,  6, 7, 8,
       13, 14, 15, 16]

       -

      [ 9, 10, 11, 12,
       17, 18, 19, 20]

      [11, 12, 13, 14,
       19, 20, 21, 22]

       ...

我怀疑应该有表达它们的好方法,因为它们也很常见
在许多算法中(例如宏块)。

我检查了什么

我尝试从教程和示例应用程序中收集想法,并发现以下内容:
这似乎与我要实现的目标有关:
  • Halide tutorial lesson 6: Realizing Funcs over arbitrary domains
  • // We start by creating an image that represents that rectangle
  • Image<int> shifted(5, 7); // In the constructor we tell it the size
  • shifted.set_min(100, 50); // Then we tell it the top-left corner
  • 我的问题是:如何在不循环的情况下将其推广到多个移位域?
  • Halide tutorial lesson 9: Multi-pass Funcs, update definitions, and reductions
  • 这里介绍了RDom,它看起来很适合创建块 View
  • 大多数使用RDom的示例似乎都是像滑动窗口一样没有跳转的方法

  • 目标

    所以通常我问的是如何实现基于块的 View ,然后可以通过
    其他步骤。
  • 如果该方法足够通用以实现重叠和不重叠两者,那就太好了
  • 以某种方式首先生成左上角的索引?
  • 在我的情况下,图像尺寸在编译时是已知的,从而简化了此操作
  • 但是我仍然想要一种紧凑的形式,从Halide的 Angular 来看,它很适合工作(没有像那些带有小型过滤器框的示例这样的手工编码的东西)
  • 使用的方法可能取决于每个块的输出,在我的情况下,它是一个标量

  • 也许有人可以给我一些想法和/或一些例子(这将非常有帮助)。

    很抱歉没有提供代码,因为我认为我无法提供任何帮助。

    编辑:解决方案

    在dsharlet的回答和一些小的调试/讨论here之后,下面的非常简化的自包含代码就可以工作了(假设像this one i created这样的1通道64x128输入)。
    #include "Halide.h"
    #include "Halide/tools/halide_image_io.h"
    #include <iostream>
    
    int main(int argc, char **argv) {
      Halide::Buffer<uint8_t> input = Halide::Tools::load_image("TestImages/block_example.png");
    
      // This is a simple example assuming an input of 64x128
      std::cout << "dim 0: " << input.width() << std::endl;
      std::cout << "dim 1: " << input.height() << std::endl;
    
      // The "outer" (block) and "inner" (pixel) indices that describe a pixel in a tile.
      Halide::Var xo, yo, xi, yi, x, y;
    
      // The distance between the start of each tile in the input.
      int tile_stride_x = 32;
      int tile_stride_y = 64;
      int tile_size_x = 32;
      int tile_size_y = 64;
    
      Halide::Func tiled_f;
      tiled_f(xi, yi, xo, yo) = input(xo * tile_stride_x + xi, yo * tile_stride_y + yi);
    
      Halide::RDom tile_dom(0, tile_size_x, 0, tile_size_y);
      Halide::Func tile_means;
      tile_means(xo, yo) = sum(Halide::cast<uint32_t>(tiled_f(tile_dom.x, tile_dom.y, xo, yo))) / (tile_size_x * tile_size_y);
    
      Halide::Func output;
      output(xo, yo) = Halide::cast<uint8_t>(tile_means(xo, yo));
    
      Halide::Buffer<uint8_t> output_(2, 2);
      output.realize(output_);
    
      Halide::Tools::save_image(output_, "block_based_stuff.png");
    }
    

    最佳答案

    这是将Func分成任意步长和大小的示例:

    Func f = ... // The thing being blocked
    
    // The "outer" (block) and "inner" (pixel) indices that describe a pixel in a tile.
    Var xo, yo, xi, yi;
    // The distance between the start of each tile in the input.
    int tile_stride_x, tile_stride_y;
    
    Func tiled_f;
    tiled_f(xi, yi, xo, yo) = f(xo * tile_stride_x + xi, yo * tile_stride_y + yi);
    
    Func tiled_output;
    tiled_output(xi, yi, xo, yo) = ... // Your tiled processing here
    

    要计算每个块的某种减少量(如统计量),您可以执行以下操作:
    RDom tile_dom(0, tile_size_x, 0, tile_size_y);
    Func tile_means;
    tile_means(xo, yo) = sum(tiled_output(tile_dom.x, tile_dom.y, xo, yo)) / (tile_size_x * tile_size_y);
    

    将图块弄平以得到结果有点棘手。这可能取决于您在重叠区域组合结果的方法。如果要累加重叠的图块,最简单的方法可能是使用RDom:
    RDom tiles_dom(
        0, tile_size_x,
        0, tile_size_y,
        min_tile_xo, extent_tile_xo,
        min_tile_yo, extent_tile_yo);
    
    Func output;
    Expr output_x = tiles_dom[2] * tile_stride_x + tiles_dom[0];
    Expr output_y = tiles_dom[3] * tile_stride_y + tiles_dom[1];
    output(x, y) = 0;
    output(output_x, output_y) += tiled_output(tiles_dom[0], tiles_dom[1], tiles_dom[2], tiles_dom[3]);
    

    请注意,在以上两个代码块中,tile_stride_x和tile_size_x是独立的参数,允许任何图块大小和重叠。

    在您的两个示例tile_size_x = 4tile_size_y = 2中。要获得不重叠的图块,请将图块步幅设置为等于图块大小。要获得50%的重叠图块,请设置tile_stride_x = 2tile_stride_y = 1

    像这样的算法的有用时间表是:
    // Compute tiles as needed by the output.
    tiled_output.compute_at(output, tile_dom[2]);
    // or
    tiled_output.compute_at(tile_means, xo);
    

    还有其他选项,例如使用纯函数(无更新/ RDom),该函数使用mod运算符来计算图块的内部和外部索引。但是,使用重叠的图块可能很难有效地调度此方法(取决于您对每个图块进行的处理)。出现此问题时,我使用RDom方法。

    请注意,使用RDom方法时,必须提供要计算的图块索引的范围(min_tile_xoextent_tile_xo,...),这对于重叠的图块可能会很棘手。

    09-09 23:40
    查看更多