简体   繁体   English

使用 stb_image 库加载图像作为浮点输出错误值

[英]Loading image with stb_image library as float outputs wrong values

When I load an image as float using STB_Image the values seem to be off.当我使用STB_Image将图像加载为浮点数时,值似乎已关闭。 I created an image to test it我创建了一个图像来测试它测试图片 . . (The used RGB code here is [127, 255, 32]) (这里使用的 RGB 代码是 [127, 255, 32])
When I load this image as unsigned char using stbi_load() I get the correct values.当我使用stbi_load()将此图像加载为unsigned char我得到了正确的值。 But when I load it as float using stbi_loadf() I get wrong values which don't really make sense to me.但是当我使用stbi_loadf()它加载为float我得到了错误的值,这对我来说没有意义。

This is the code I used for testing:这是我用于测试的代码:

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#include <sstream>
#include <iomanip>
#include <iostream>
#include <string>

struct ColorF {
  float r;
  float g;
  float b;
  float a;

  std::string toString() {
    std::stringstream stream;

    stream << std::fixed << std::setprecision(2) << "[" << this->r << ", " << this->g << ", " << this->b << ", " << this->a << "]";

    return stream.str();
  }
};

struct ColorUC {
  unsigned char r;
  unsigned char g;
  unsigned char b;
  unsigned char a;

  std::string toString() {
    std::stringstream stream;

    stream << "[" << (float) this->r / 255.0f << ", " << (float) this->g / 255.0f << ", " << (float) this->b / 255.0f << ", " << (float) this->a / 255.0f << "]";

    return stream.str();
  }
};

int main() {
  int width, height, channels;
  float* image = stbi_loadf("test.png", &width, &height, &channels, STBI_rgb_alpha);

  // print content of first pixel of the image
  std::cout << ((ColorF*) image)->toString() << std::endl;

  unsigned char* jpeg = stbi_load("test.png", &width, &height, &channels, STBI_rgb_alpha);

  // print content of first pixel of the image
  std::cout << ((ColorUC*) jpeg)->toString() << std::endl;  

  stbi_image_free(image);
  stbi_image_free(jpeg);

  return 0;
}

The test output I get is this:我得到的测试输出是这样的:

[0.22, 1.00, 0.01, 1.00] [0.22, 1.00, 0.01, 1.00]
[0.50, 1.00, 0.13, 1.00] [0.50, 1.00, 0.13, 1.00]

In theory this should print out the same values, the bottom one being the correct one, on both lines but for some reason it doesn't.从理论上讲,这应该打印出相同的值,底部的值是正确的值,在两行上,但由于某种原因它没有。
Now i could of course use the unsigned char values and write myself a function that converts everything to the proper float values but I feel like there should be a way to do this just using STB_Image itself.现在我当然可以使用 unsigned char 值并为自己编写一个函数,将所有内容转换为正确的浮点值,但我觉得应该有一种方法可以仅使用 STB_Image 本身来做到这一点。

From the stb_image.h header comments:stb_image.h标题注释:

// If you load LDR images through this interface, those images will
// be promoted to floating point values, run through the inverse of
// constants corresponding to the above:
//
//     stbi_ldr_to_hdr_scale(1.0f);
//     stbi_ldr_to_hdr_gamma(2.2f);

That means the stbi_loadf() function uses built-in gamma correction to return its float values.这意味着stbi_loadf()函数使用内置伽马校正来返回其浮点值。

The gamma correction formula looks like this:伽马校正公式如下所示:

Vout = (Vin / 255)^γ; Where γ = 2.2

When you put [127, 255, 32] through the gamma correction formula, you get the result you are seeing:当你把[127, 255, 32]通过伽马校正公式时,你会得到你看到的结果:

R: 0.22 = (127 / 255)^2.2
G: 1.00 = (255 / 255)^2.2 
B: 0.01 = ( 32 / 255)^2.2

You can set the stb_image gamma factor with stbi_ldr_to_hdr_gamma(1.0f) as a quick fix.您可以使用stbi_ldr_to_hdr_gamma(1.0f)设置 stb_image 伽马系数作为快速修复。

However, stb_image defines the stbi_loadf() specifically to support non-linear encoded images (HDR or gamma corrected).但是,stb_image 专门定义了stbi_loadf()以支持非线性编码图像(HDR 或伽马校正)。 If you were to load an actual HDR image with that function, setting the gamma to 1.0 would negatively impact the accuracy of the image when drawn;如果要使用该功能加载实际的 HDR 图像,将 gamma 设置为1.0会对绘制图像的准确性产生负面影响; So it is best to only use stbi_loadf() if you actually need the image to be loaded with gamma correction.因此,如果您确实需要使用伽马校正加载图像,最好只使用stbi_loadf()

Now i could of course use the unsigned char values and write myself a function that converts everying to the proper float values but I feel like there should be a way to do this just using STB_Image itself.现在我当然可以使用 unsigned char 值并为自己编写一个函数,将每个值转换为正确的浮点值,但我觉得应该有一种方法可以仅使用 STB_Image 本身来做到这一点。

Manually converting the 8-bit image data to a float using Vout = (float)Vin / 255f is an obvious tell to readers of your code that the image data is not gamma corrected.使用Vout = (float)Vin / 255f手动将 8 位图像数据转换为浮点数明显告诉代码的读者,图像数据没有经过伽马校正。 Using stbi_loadf() with stbi_ldr_to_hdr_gamma(1.0f) can obscure this important detail.stbi_loadf()stbi_ldr_to_hdr_gamma(1.0f)可能会掩盖这一重要细节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM