c++ - Halide:如何处理(重叠) block 中的图像?

标签 c++ halide

我发现了 Halide,并通过管道做各种事情取得了一些成功 转换。其中大部分基于源代码中的示例(颜色转换、各种过滤器、hist-eq)。

我的下一步需要分块处理图像。在更一般的形式中, 部分重叠 block 。

例子

输入:

      [  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]
非重叠 block :

大小: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]
重叠 block :

尺寸: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]

       ...

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

我检查了什么

我试图从教程和示例应用程序中收集想法并发现以下内容, 这似乎与我想要实现的东西有些联系:

目标

所以一般来说,我问的是如何实现一个基于 block 的 View ,然后可以由 其他步骤。

  • 如果该方法足够通用以实现重叠和不重叠,那就太好了

    • 以某种方式先生成左上角的索引?
  • 在我的例子中,图像维度在编译时已知,这简化了这一点

    • 但我仍然想要一些紧凑的形式,从 Halide 的角度来看它很适合使用(没有像那些带有小过滤器框的示例那样的手动编码的东西)
  • 使用的方法可能取决于每个 block 的输出,在我的例子中是标量

也许有人可以给我一些想法和/或一些例子(这会很有帮助)。

很抱歉没有提供代码,因为我认为我无法产生任何有用的东西。

编辑:解决方案

在 dsharlet 的回答和一些微小的调试/讨论之后 here , 以下非常简化的自包含代码有效(假设 1 channel 64x128 输入,如 this one i created )。

#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 分成任意步长和大小的 block 的示例:

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

要计算每个 block 的一些减少(如统计数据),您可以执行以下操作:

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);

将图 block 展平成结果有点棘手。这可能取决于您在重叠区域组合结果的方法。如果您想添加重叠的图 block ,最简单的方法可能是使用 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 大小和重叠。

在您的两个示例中,tile_size_x = 4tile_size_y = 2。要获得不重叠的图 block ,请将图 block 步幅设置为等于图 block 大小。要获得 50% 的重叠图 block ,请设置 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);

还有其他选项,例如使用纯 func(无更新/RDom),它使用 mod 运算符计算出图 block 的内部和外部索引。但是,这种方法可能难以有效地安排重叠的图 block (取决于您在每个图 block 上进行的处理)。当出现这个问题时,我使用 RDom 方法。

请注意,使用 RDom 方法时,您必须提供要计算的图 block 索引的边界(min_tile_xoextent_tile_xo ...),这可以是对于重叠的图 block 很棘手。

关于c++ - Halide:如何处理(重叠) block 中的图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43455570/

相关文章:

c++ - 如何在 C++ win32 API 中使用 pwdlastset 值和 maxpwdage 值获取 pwdexpirydate?

c++ - 对宽度不匹配的输出缓冲区进行矢量化

halide - 在 Halide 中表达时间步长循环

c++ - avformat_find_stream_info 未填写 nb_streams 和流

c++ - 从标准输入 C++ 读取数百万整数的最快方法?

c++ - 有没有办法在 Halide Generator 中将两个输入图像堆叠到一个 4 维缓冲区中?

visual-studio-2015 - Visual Studio 无法识别已安装 NuGet 包的头文件

c++ - 如何在 Halide 中使用 C++ 随机函数?

c++ - 多行数学结果不同于单行

c++ - 在重新声明时添加默认参数使此构造函数成为默认构造函数