【问题标题】:How to Generate Halide Function with float argument如何使用浮点参数生成卤化物函数
【发布时间】:2018-07-26 17:41:02
【问题描述】:

我正在尝试创建一个 (C++) 辅助函数,它将在我的 C++ 代码中计算的查找表转换为 Halide Func,该函数将浮点数作为参数并在 LUT 中的样本之间进行 lerps。

这里的用例是用户使用带有一堆控制点的样条曲线生成了色调曲线,我们希望将这些控制点应用于 Halide。所以我在一堆点上采样这个样条,我想写一个卤化物函数,让我在这些样本之间进行线性插值。这是我目前的尝试:

#include <Halide.h>

using namespace Halide;
using namespace std;

static Func LutFunc(const vector<float> &lut) {
    Func result;
    Var val;

    // Copy the LUT into a Halide Buffer.
    int lutSize = (int) lut.size();
    Buffer<float> lutbuf(lutSize);
    for(int i = 0; i < lut.size(); i++) {
        lutbuf(i) = lut[i];
    }

    // Compute the offset into the LUT along with the blending factor
    // for the 2 samples we'll take.
    auto y = val * ((float) lutSize - 1);
    auto index = clamp(cast<int>(y), 0, lutSize - 2);
    auto fract = y - cast<float>(index);

    // interpolate between the 2 nearest samples
    result(val) = (lutbuf(index) * (1.0f - fract)) + (lutbuf(index + 1) * fract);

    return result;
}

问题是,如果我尝试将此函数包含到我的卤化物管道中,我会收到以下错误:

Implicit cast from float32 to int in argument 1 in call to "f" is not allowed. Use an explicit cast.

我如何向 Halide 解释这个函数的参数应该是浮点数,而不是整数?

这里有一个简短的测试程序,以防它有帮助:

int main(int argc, char *argv[]) {
    vector<float> lut = { 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 };
    auto f = LutFunc(lut);

    Buffer<float> testData(4);
    testData(0) = 0.05;
    testData(1) = 0.15;
    testData(2) = 0.25;
    testData(3) = 0.35;

    Func testFn;
    Var x;

    testFn(x) = f(testData(x));

    Buffer<float> resultBuf(4);
    testFn.realize(resultBuf);

    for(int i = 0; i < 4; i++) {
        cout << i << " = " << resultBuf(i) << endl;
    }

    return 0;
}

(如果有更简单的方法来生成这些 lerping LUT 函数(尤其是如果它能够利用 GPU 上的采样器硬件),我也很想知道这一点)

【问题讨论】:

    标签: c++ halide


    【解决方案1】:

    如您所见,Halide::Func 的参数总是 整数类型(默认为 int32);这是 Halide 所固有的。

    Re:更好的 lerping 方法,Halide 有一个内置的 lerp() 助手:见 http://halide-lang.org/docs/namespace_halide.html#a55158f5f229510194c425dfae256d530

    【讨论】:

      【解决方案2】:

      好的,所以似乎不可能用 Func() 来做到这一点: Func 似乎它们的预期用例是封装源数据的转换——它们有一个约束,即它们的参数是整数,并且预期的用例是指定输入的像素坐标。

      我认为实现这一点的方法是将其分为两部分:将我的 LUT 转换为 Halide Buffer 的方法,以及将 Expr 作为参数并返回 Expr 的第二个方法,实现内联计算,我们将生成的缓冲区传递给它。

      这是我想要的功能的修订版本:

      #include <Halide.h>
      
      using namespace Halide;
      using namespace std;
      
      static Expr LutInterp(const Buffer<float> &lutbuf, Expr val) {
          // Interpolate the two values nearest the specified input.
          int lutSize = lutbuf.dim(0).extent();
          auto y = val * ((float) lutSize - 1);
          auto index = clamp(cast<int>(y), 0, lutSize - 2);
          auto fract = y - cast<float>(index);
          return (lutbuf(index) * (1.0f - fract)) + (lutbuf(index + 1) * fract);
      }
      
      static Buffer<float> LutToBuff(const vector<float> &lut) {
          int lutSize = (int) lut.size();
          Buffer<float> lutbuf(lutSize);
          for(int i = 0; i < lut.size(); i++) {
              lutbuf(i) = lut[i];
          }
          return lutbuf;
      }
      
      
      int main(int argc, char *argv[]) {
          vector<float> lut = { 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 };
          auto lutbuf = LutToBuff(lut);
      
          Buffer<float> testData(4);
          testData(0) = 0.05;
          testData(1) = 0.15;
          testData(2) = 0.25;
          testData(3) = 0.35;
      
          Func testFn;
          Var x;
      
          testFn(x) = LutInterp(lutbuf, testData(x));
      
          Buffer<float> resultBuf(4);
          testFn.realize(resultBuf);
      
          for(int i = 0; i < 4; i++) {
              cout << i << " = " << resultBuf(i) << endl;
          }
      
          return 0;
      }
      

      我会暂时继续这个,如果我将来有更好的解决方案,我会换掉它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-17
        • 2015-09-03
        • 2016-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多