c++ 尝试建立和获得开放图像降噪与Bazel工作

uelo1irk  于 2023-03-05  发布在  其他
关注(0)|答案(1)|浏览(132)

目前,我试图让Open Image DenoiseBazel一起工作,因此,我实现了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时相同的代码失败。

    • 注意:**我也愿意接受将问题缩小到更小代码"占用空间"的答案,如所示的单元测试(更像是高级验收测试)
yc0p9oo0

yc0p9oo01#

一个可能的原因是调用filter.setImage()时没有正确设置跨距参数。需要为每个图像缓冲区指定每行像素的字节大小。
例如,如果图像有3个通道,每个通道4个字节,则步幅应为width * 3 * 4。
您可以尝试在filter.commit()之前添加以下行:

size_t colorStride = width * 3 * sizeof(float);
size_t outputStride = width * 3 * sizeof(float);
filter.setImage("color", colorPtr, oidn::Format::Float3, width, height, colorStride);
filter.setImage("output", outputPtr, oidn::Format::Float3, width, height, outputStride);

相关问题