我正在尝试创建一个(C ++)辅助函数,该函数将在C ++代码中计算出的查找表转换为Halide Func,该函数将浮点数作为参数并在LUT中的样本之间保留。
这里的用例是用户使用样条生成了一条色调曲线,该样条带有我们要在Halide上应用的一堆控制点。因此,我在许多点上对该样条进行采样,并且我想编写一个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;
}
问题是,如果我随后尝试将此函数包含到我的Halide管道中,则会出现此错误:
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;
}
(如果有一种更简便的方法来生成这些出色的LUT函数(特别是如果它能够利用GPU上的采样器硬件),我也想知道这一点)
答案 0 :(得分:0)
好吧,所以似乎不可能用Func()来做到这一点:Funcs似乎其预期的用例是封装对源数据的转换-它们具有一个约束,即其参数必须是整数,并且预期的用例是指定输入的像素坐标。
我认为实现此目的的方法是将其分为两部分:将我的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;
}
我暂时将继续进行此操作,如果将来遇到更好的解决方案,请换掉它。
答案 1 :(得分:0)
您已经发现,Halide::Func
的参数总是 整数类型(默认为int32);这是卤化物所固有的。
关于:一种更好的方法,Halide具有内置的lerp()
助手:请参见http://halide-lang.org/docs/namespace_halide.html#a55158f5f229510194c425dfae256d530