目前,我试图让Open Image Denoise与Bazel一起工作,因此,我实现了rules_oidn。
要试用它,您可以执行
git clone https://github.com/Vertexwahn/rules_oidn.git
cd rules_oidn
cd tests
使用Ubuntu 22.04运行示例:
bazel run --config=gcc11 //:example
使用Visual Studio 2022运行示例:
bazel run --config=vs2022 //:example
该示例获取一个有噪图像并对其进行去噪。
...
int main() {
cout << "Simple denoising example" << endl;
Image3f color = load_image_openexr("data/cornel_box.naive_diffuse.box_filter.spp128.embree.exr");
...
Image3f out{color.width(), color.height()};
...
float* colorPtr = color.data();
...
float* outputPtr = out.data();
int width = out.width();
int height = out.height();
oidn::DeviceRef device = oidn::newDevice();
device.set("verbose", 1);
device.commit();
// Create a filter for denoising a beauty (color) image using optional auxiliary images too
oidn::FilterRef filter = device.newFilter("RT"); // generic ray tracing filter
filter.setImage("color", colorPtr, oidn::Format::Float3, width, height); // beauty
...
filter.setImage("output", outputPtr, oidn::Format::Float3, width, height); // denoised beauty
filter.set("hdr", true); // beauty image is HDR
filter.commit();
// Filter the image
filter.execute();
// Check for errors
const char* errorMessage;
if (device.getError(errorMessage) != oidn::Error::None) {
std::cout << "Error: " << errorMessage << std::endl;
}
store_open_exr("denoised.exr", out);
return 0;
}
不幸的是,去噪图像包含黑色条纹:
我用https://github.com/DeclanRussell/IntelOIDenoiser测试了相同的输入,得到了预期的结果(没有黑色条纹),因此,问题一定是在OIDN的bazalization或周围的支持中。
如果我选择一个恒定颜色的图像,例如
// for debug reasons the color image can be initialized with a const color
if(true) {
for (int x = 0; x < color.width(); ++x) {
for (int y = 0; y < color.height(); ++y) {
color.set_pixel(x,y,.5f, .5f, .5f);
}
}
}
我也有黑色条纹。
目前,我缺少一个很好的策略来找到这个问题。欢迎任何提示或解决方案来解决这个问题。
我还创建了一个oidn分支,它包含了一个"直接"的oidn bazelization,它几乎与rules_oidn相似:https://github.com/Vertexwahn/oidn/tree/add-bazel-support。在这个分支中,我bazelize了oidnTest
,其中包含一些测试用例,这些测试用例都成功通过。我还bazelize了oidnDenoiser
。您可以通过以下方式运行它:
# the_cornell_box.pfm is in data folder in the oidn repo
bazel run --config=gcc11 //:oidnDenoise -- --hdr /home/vertexwahn/Desktop/the_cornell_box.pfm -o /home/vertexwahn/Desktop/denoised.pfm
生成的文件denoised.pfm
显示相同的黑色条纹。似乎黑色条纹总是5像素宽,后面跟着3个看起来正确的彩色条纹。
不确定将内存移交给ISPC或执行过滤操作等是否有任何问题。由于我测试了不同的图像格式(OpenEXR、PFM),我认为错误不在我存储图像的方式范围内。
我开始调试并比较CMake/Windows版本和Bazel/Ubuntu版本,但直到现在我还没有发现明显的区别:
Image3f
类如下所示:
class Image3f {
public:
Image3f(const int width, const int height) : width_(width), height_(height) {
data_ = new float[width_ * height_ * 3];
for (int x = 0; x < width_; ++x) {
for (int y = 0; y < height_; ++y) {
auto r = 0.f;
auto g = 0.f;
auto b = 0.f;
data_[(width_ * y + x) * 3] = r;
data_[(width_ * y + x) * 3 + 1] = g;
data_[(width_ * y + x) * 3 + 2] = b;
}
}
}
void set_pixel(int x, int y, float red, float green, float blue) {
assert(x >= 0);
assert(y >= 0);
assert(x < width_);
assert(y < height_);
data_[(width_ * y + x) * 3] = red;
data_[(width_ * y + x) * 3 + 1] = green;
data_[(width_ * y + x) * 3 + 2] = blue;
}
float *data() const {
return data_;
}
float *data() {
return data_;
}
int width() const {
return width_;
}
int height() const {
return height_;
}
private:
int width_ = 0;
int height_ = 0;
float *data_;
};
- 有关Bazelization的更多详细信息**
Open Image Denoise v1.4.3有一些依赖项。它依赖于oneTBB、oneDNN,利用ISPC和英特尔隐式SPMD程序编译器,并使用Python根据训练权重生成C代码。所有这些都需要通过Bazel获得支持,才能使Open Image Denoise Bazel构建版正常工作。
我在2021年年中就已经将oneTBB bazelize化了。我有一个CI构建工作,它拉取最新的oneTBB master并使用它进行Bazel测试构建。在撰写本文时,这仍然有效。测试构建使用了oneTBB和Embree的组合。我还有一个独立的演示,展示了如何单独使用oneTBB和Bazel。
为了支持带Bazel的ISPC,我创建了rules_ispc。要在C中使用ISPC,您需要编写ISPC程序,然后由ISPC编译器翻译。ISPC编译的程序可以通过C调用。所有用于下载正确ISPC编译器版本、翻译ISPC程序以及将其链接到C可执行文件的搭建都是rules_ispc的一部分。
整个依赖关系的概述可以在这里看到:
生成途径:
bazel query --noimplicit_deps 'deps(//:example) - @com_openexr//...:* - @Imath//...:* - @net_zlib_zlib//...:*' --output graph > simplified_graph.in
dot -Tpng < simplified_graph.in > simple_graph.png
- Bazel Build的失败测试用例(但在CMake端工作)**
如果我加上
// -----------------------------------------------------------------------------
TEST_CASE("denoise constant image", "[sanitization]")
{
DeviceRef device = newDevice();
REQUIRE(bool(device));
device.commit();
REQUIRE(device.getError() == Error::None);
const int W = 1024;
const int H = 1024;
FilterRef filter = device.newFilter("RT");
REQUIRE(bool(filter));
std::shared_ptr<ImageBuffer> input = makeConstImage(device, W, H, 3, 0.5f);
ImageBuffer output(device, W, H, 3);
setFilterImage(filter, "color", *input);
setFilterImage(filter, "output", output);
filter.set("hdr", true);
filter.commit();
REQUIRE(device.getError() == Error::None);
filter.execute();
REQUIRE(device.getError() == Error::None);
REQUIRE_THAT(((float*)output.bufferPtr)[0], Catch::Matchers::WithinAbs(0.4787f, 1e-4));
REQUIRE(((float*)output.bufferPtr)[9] != 0.f); // This is violated on Bazel build but not CMake build
for (int i = 0; i < output.size(); ++i) {
REQUIRE(((float*)output.bufferPtr)[i] != 0.f); // This is violated on Bazel build but not CMake build
}
}
到oidnTest
,在基于CMake的构建环境中所有测试都成功。同时,使用Bazel时相同的代码失败。
- 注意:**我也愿意接受将问题缩小到更小代码"占用空间"的答案,如所示的单元测试(更像是高级验收测试)
1条答案
按热度按时间yc0p9oo01#
一个可能的原因是调用
filter.setImage()
时没有正确设置跨距参数。需要为每个图像缓冲区指定每行像素的字节大小。例如,如果图像有3个通道,每个通道4个字节,则步幅应为width * 3 * 4。
您可以尝试在
filter.commit()
之前添加以下行: