c++ - 将 exr/pfm 保存为小端

标签 c++ image image-processing visual-c++ cimg

我将一个 bmp 文件加载到一个 CImg 对象中,并将它保存到 pfm 文件中。成功的。我将这个 .pfm 文件用于另一个库,但是这个库不接受大端,只接受小端

    CImg<float> image;
    image.load_bmp(_T("D:\\Temp\\memorial.bmp"));
    image.normalize(0.0, 1.0);
    image.save_pfm(_T("D:\\Temp\\memorial.pfm"));

那么,如何将bmp 文件保存为pfm 文件little endian不是 big endian。 .这可能吗?

稍后编辑:

我检查了 .pfm 头文件中的前 5 个元素。这是没有invert_endianness的结果:

CImg<float> image;
image.load_bmp(_T("D:\\Temp\\memorial.bmp"));
image.normalize(0.0, 1.0);
image.save_pfm(_T("D:\\Temp\\memorial.pfm"));

PF
512
768
1.0
=øøù=€€=‘>

这是invert_endianness的结果:

CImg<float> image;
image.load_bmp(_T("D:\\Temp\\memorial.bmp"));
image.invert_endianness();
image.normalize(0.0, 1.0);
image.save_pfm(_T("D:\\Temp\\memorial.pfm"));

PF
512
768
1.0
?yôx?!ù=‚ì:„ç‹?

结果是一样的。

最佳答案

这绝对不是一个正确的答案,但暂时可以作为一种解决方法。

我没有找到如何使用 CImg 的函数正确地反转字节顺序,所以我修改了生成的文件。这是一个黑客。结果在 GIMP 中打开很好,看起来非常接近原始图像,但我不能说它是否适用于您正在使用的库。可能值得一试。

代码中的注释:

#include "CImg/CImg.h"

#include <algorithm>
#include <filesystem> // >= C++17 must be selected as Language Standard
#include <ios>
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>

using namespace cimg_library;
namespace fs = std::filesystem;

// a class to remove temporary files
class remove_after_use {
public:
    remove_after_use(const std::string& filename) : name(filename) {}
    remove_after_use(const remove_after_use&) = delete;
    remove_after_use& operator=(const remove_after_use&) = delete;

    const char* c_str() const { return name.c_str(); }
    operator std::string const& () const { return name; }

    ~remove_after_use() {
        try {
            fs::remove(name);
        }
        catch (const std::exception & ex) {
            std::cerr << "remove_after_use: " << ex.what() << "\n";
        }
    }
private:
    std::string name;
};

// The function to hack the file saved by CImg
template<typename T>
bool save_pfm_endianness_inverted(const T& img, const std::string& filename) {
    remove_after_use tempfile("tmp.pfm");

    // get CImg's endianness inverted image and save it to a temporary file
    img.get_invert_endianness().save_pfm(tempfile.c_str());

    // open the final file
    std::ofstream os(filename, std::ios::binary);

    // read "tmp.pfm" and modify
    // The Scale Factor / Endianness line
    if (std::ifstream is; os && (is = std::ifstream(tempfile, std::ios::binary))) {
        std::string lines[3];
        // Read the 3 PFM header lines as they happen to be formatted by
        // CImg. Will maybe not work with another library.
        size_t co = 0;
        for (; co < std::size(lines) && std::getline(is, lines[co]); ++co);

        if (co == std::size(lines)) { // success
            // write the first two lines back unharmed:
            os << lines[0] << '\n' << lines[1] << '\n';

            if (lines[2].empty()) {
                std::cerr << "something is wrong with the pfm header\n";
                return false;
            }

            // add a '-' if it's missing, remove it if it's there: 
            if (lines[2][0] == '-') {       // remove the - to invert
                os << lines[2].substr(1);
            }
            else {                          // add a - to invert
                os << '-' << lines[2] << '\n';
            }

            // copy all the rest as-is:
            std::copy(std::istreambuf_iterator<char>(is),
                std::istreambuf_iterator<char>{},
                std::ostreambuf_iterator<char>(os));
        }
        else {
            std::cerr << "failed reading pfm header\n";
            return false;
        }
    }
    else {
        std::cerr << "opening files failed\n";
        return false;
    }
    return true;
}

int main()
{
    CImg<float> img("memorial.bmp");
    img.normalize(0.f, 1.f);
    std::cout << "saved ok: " << std::boolalpha
              << save_pfm_endianness_inverted(img, "memorial.pfm") << "\n";
}

关于c++ - 将 exr/pfm 保存为小端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59192684/

相关文章:

css - 如何根据图像更改文章的大小?

image-processing - 将 RGB 转换为灰度/强度

ruby - 比较 Ruby 中的字节

c++ - 我究竟如何使用函数 push_back 和 pop_back()?我在下面的链接中查找了它们,但仍然不明白

php - 添加黑条以创建 16x9 图像

c++ - Swift 中的 OpenCV HoughTransformation

html - 无序列表中 img 下方的奇怪空白

python - 为什么 inpaint 方法不能从 IC 图像中删除文本?

c++ - 您的计算机缺少 mspdb140.dll

c++ - 将数据从父类实例复制到子类的有效方法