这是我在这里的第一篇文章,如果我做错了,那就很抱歉:)。我会努力做到最好。
我目前正在研究我的HDR图像处理程序,我想使用Halide实现一些基础TMO。问题是我的所有图像都表示为浮点数组(顺序如:b1,g1,r1,a1,b2,g2,r2,a2,...)。使用Halide处理图像需要Halide :: Image类。问题是我不知道如何在那里传递这些数据。
任何人都可以提供帮助,或者有同样的问题并知道答案?
编辑:
终于搞定了!我需要在生成器中设置输入和输出缓冲区的步幅。谢谢所有人的帮助: - )
编辑:
我尝试了两种不同的方式:
int halideOperations( float data[] , int size, int width,int heighy )
{
buffer_t input_buf = { 0 };
input_buf.host = &data[0];
}
或:
int halideOperations( float data[] , int size, int width,int heighy )
{
Halide::Image(Halide::Type::Float, x, y, 0, 0, data);
}
我正在考虑编辑Halide.h文件并将uint8_t * host更改为float_t * host但我不认为这是个好主意。
编辑:
我尝试使用下面的代码和我的浮动图像(RGBA):
AOT函数生成:
int main(int arg, char ** argv)
{
Halide::ImageParam img(Halide::type_of<float>(), 3);
Halide::Func f;
Halide::Var x, y, c;
f(x, y, c) = Halide::pow(img(x,y,c), 2.f);
std::vector<Halide::Argument> arguments = { img };
f.compile_to_file("function", arguments);
return 0;
}
正确的代码呼叫:
int halideOperations(float data[], int size, int width, int height)
{
buffer_t output_buf = { 0 };
buffer_t buf = { 0 };
buf.host = (uint8_t *)data;
float * output = new float[width * height * 4];
output_buf.host = (uint8_t*)(output);
output_buf.extent[0] = buf.extent[0] = width;
output_buf.extent[1] = buf.extent[1] = height;
output_buf.extent[2] = buf.extent[2] = 4;
output_buf.stride[0] = buf.stride[0] = 4;
output_buf.stride[1] = buf.stride[1] = width * 4;
output_buf.elem_size = buf.elem_size = sizeof(float);
function(&buf, &output_buf);
delete output;
return 1;
}
不幸的是我遇到了msg的崩溃:
Error: Constraint violated: f0.stride.0 (4) == 1 (1)
我认为这一行有问题:output_buf.stride [0] = buf.stride [0] = 4,但我不确定应该改变什么。有什么提示吗?
答案 0 :(得分:1)
如果直接使用buffer_t,则必须将分配给主机的指针强制转换为uint8_t *:
buf.host = (uint8_t *)&data[0]; // Often, can be just "(uint8_t *)data"
如果您正在使用Ahead-Of-Time(AOT)编译,并且未将数据作为直接调用Halide的代码的一部分进行分配,那么这就是您要执行的操作。 (下面讨论的其他方法控制存储分配,因此它们不能获取传递给它们的指针。)
如果您使用的是Halide :: Image或Halide :: Tools :: Image,则会在内部处理类型转换。上面用于Halide :: Image的构造函数不存在,因为Halide :: Image是一个模板类,其中底层数据类型是模板参数:
Halide::Image<float> image_storage(width, height, channels);
请注意,这将以平面布局存储数据。 Halide :: Tools :: Image类似,但可以选择进行交错布局。 (就个人而言,我尽量不在小型测试程序之外使用其中任何一个。有一个长期计划合理化所有这些将在任意维度buffer_t分支合并之后继续。注意Halide :: Image需要libHalide.a在Halide :: Tools :: Image不能链接的地方,只有通过包含common / halide_image.h才是头文件。)
还有Halide :: Buffer类,它是buffer_t的包装器,在即时(JIT)编译中很有用。它可以引用存储中的传递而不是模板化的。但是我的猜测是你想直接使用buffer_t而只需要使用类型转换来分配主机。还要确保将buffer_t的elem_size字段设置为“sizeof(float)”。
对于交错的浮点缓冲区,最终会得到类似的结果:
buffer_t buf = {0};
buf.host = (uint8_t *)float_data; // Might also need const_cast
// If the buffer doesn't start at (0, 0), then assign mins
buf.extent[0] = width; // In elements, not bytes
buf.extent[1] = height; // In elements, not bytes
buf.extent[2] = 3; // Assuming RGB
// No need to assign additional extents as they were init'ed to zero above
buf.stride[0] = 3; // RGB interleaved
buf.stride[1] = width * 3; // Assuming no line padding
buf.stride[2] = 1; // Channel interleaved
buf.elem_size = sizeof(float);
您还需要注意Halide代码本身的界限。可能最好查看tutorial / lesson_16_rgb_generate.cpp中的set_stride和bound调用,以获取相关信息。
答案 1 :(得分:0)
除了Zalman上面的回答,你还必须在定义你的Halide函数时指定输入和输出的步幅,如下所示:
int main(int arg, char ** argv)
{
Halide::ImageParam img(Halide::type_of<float>(), 3);
Halide::Func f;
Halide::Var x, y, c;
f(x, y, c) = Halide::pow(img(x,y,c), 2.f);
// You need the following
f.set_stride(0, f.output_buffer().extent(2));
f.set_stride(1, f.output_buffer().extent(0) * f.output_buffer().extent(2));
img.set_stride(0, img.extent(2));
img.set_stride(1, img.extent(2) *img.extent(0));
// <- up to here
std::vector<Halide::Argument> arguments = { img };
f.compile_to_file("function", arguments);
return 0;
}
然后你的代码应该运行。