我的目标是能够在Halide中模拟依赖于信号的高斯噪声。我有一个用OpenCV构建的模型,我现在移植到Halide。挑战是Halide的随机数发生器不是正态分布的,所以我需要使用外部函数来产生噪声值。
实现尝试使用C ++随机数生成器生成正态分布式噪声,使用Halide Func生成每个像素处噪声的信号依赖标准偏差,然后将噪声添加到renoise中的像素。下面我展示了功能的布局。
// Note: This is an implementation of the noise model found in the paper below:
// "Noise measurement for raw-data of digital imaging sensors by
// automatic segmentation of non-uniform targets"
float get_normal_dist_rand( float mean, float std_dev ) {
std::default_random_engine generator;
std::normal_distribution<float> distribution(mean,std_dev);
float out = distribution(generator);
return out;
}
Func make_get_std_dev( Func *in_func ) {
Var x, y, c;
float q = 0.0060;
float p = 0.0500;
// std_dev = q * sqrt(unnoised_pixel - p)
Func get_std_dev("get_std_dev");
get_std_dev(x,y,c) = q * sqrt( (*in_func)(x,y,c) - p );
return get_std_dev;
}
Func make_renoise( Func *in_func, Func *std_dev ) {
Var x, y, c;
// Noise parameters
// noised_pixel = unnoised_pixel +
// gaussian_rand( std_dev = q * sqrt(unnoised_pixel - p) )
// q and p values do not vary between channels
Func renoise("renoise");
renoise(x,y,c) = (*in_func)(x,y,c) +
get_normal_dist_rand(0,(*std_dev)(x,y,c));
return renoise;
}
这对我来说很有意义,但不幸的是,当我尝试编译时,我收到以下错误:
../common/pipe_stages.cpp: In function 'Halide::Func make_renoise(Halide::Func*, Halide::Func*)':
../common/pipe_stages.cpp:223:64: error: cannot convert 'std::enable_if<true, Halide::FuncRef>::type {aka Halide::FuncRef}' to 'float' for argument '2' to 'float get_normal_dist_rand(float, float)'
get_normal_dist_rand(0,(*std_dev)(x,y,c));
^
因此似乎无法将Func的输出提供给C ++函数。我想这可以作为Halide的限制,但我并没有真正看到实现信号依赖的正态分布噪声的替代方案。还有另一种在Halide中使用外部C ++函数的方法吗?我见过人们谈论使用&#34; extern&#34;但不幸的是,关于该功能的文档似乎很轻,我无法找到我需要的东西。
答案 0 :(得分:2)
您需要使用我们的一个外部机制来绑定到C ++代码。 HalideExtern_ *是两者中较容易的,并且可以让您拨打电话,一次获得一个随机数。唉测试/正确性/ c_function.cpp是这方面的直接例子,这将有所帮助,但可能更清楚。
出于效率原因,我希望你能一次请求一个随机数的缓冲区。这可以通过define_extern机制完成。 C ++函数必须参与边界推理,因此它涉及更多。对此的测试是正确性/ extern_producer.cpp。
我希望将我们的随机数转换成适当的分布,或者在Halide中实现随机数生成算法是获得真正快速生产代码的正确方法,但这可能比你想做的更多工作这工作最初。
答案 1 :(得分:1)
你也可以使用Halide的RNG以及高斯的二项式近似:
Expr gaussian_random(Expr sigma) {
return (random_float() + random_float() + random_float() - 1.5f) * 2 * sigma;
}
添加更多randomFloat实例,以便越来越接近真正的正态分布。