使用 stb_image 库加载图像作为 float 输出错误的值
Loading image with stb_image library as float outputs wrong values
当我使用 STB_Image the values seem to be off. I created an image to test it 将图像加载为浮动时。 (这里使用的RGB码是[127, 255, 32])
当我使用 stbi_load()
将此图像加载为 unsigned char
时,我得到了正确的值。但是当我使用 stbi_loadf()
将它加载为 float
时,我得到了错误的值,这对我来说真的没有意义。
这是我用来测试的代码:
#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;
}
我得到的测试输出是这样的:
[0.22, 1.00, 0.01, 1.00]
[0.50, 1.00, 0.13, 1.00]
理论上,这应该在两行上打印出相同的值,底部的值是正确的,但由于某些原因它没有。
现在我当然可以使用 unsigned char 值并为自己编写一个函数,将所有内容转换为正确的 float 值,但我觉得应该有一种方法可以只使用 STB_Image 本身来做到这一点。
来自 stb_image.h
header 条评论:
// 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);
这意味着 stbi_loadf()
函数对 return 其浮点值使用 built-in 伽玛校正。
伽玛校正公式如下所示:
Vout = (Vin / 255)^γ; Where γ = 2.2
当您将 [127, 255, 32]
通过伽玛校正公式时,您会得到您所看到的结果:
R: 0.22 = (127 / 255)^2.2
G: 1.00 = (255 / 255)^2.2
B: 0.01 = ( 32 / 255)^2.2
您可以使用 stbi_ldr_to_hdr_gamma(1.0f)
设置 stb_image 伽马系数作为快速修复。
但是,stb_image 专门定义了 stbi_loadf()
以支持 non-linear 编码图像(HDR 或伽马校正)。如果您要使用该函数加载实际的 HDR 图像,将伽马设置为 1.0
会对绘制时图像的准确性产生负面影响;所以最好只使用 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.
使用 Vout = (float)Vin / 255f
手动将 8 位图像数据转换为浮点数可以明显地告诉代码的读者图像数据 未 伽玛校正。将 stbi_loadf()
与 stbi_ldr_to_hdr_gamma(1.0f)
结合使用会掩盖这一重要细节。
当我使用 STB_Image the values seem to be off. I created an image to test it
当我使用 stbi_load()
将此图像加载为 unsigned char
时,我得到了正确的值。但是当我使用 stbi_loadf()
将它加载为 float
时,我得到了错误的值,这对我来说真的没有意义。
这是我用来测试的代码:
#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;
}
我得到的测试输出是这样的:
[0.22, 1.00, 0.01, 1.00]
[0.50, 1.00, 0.13, 1.00]
理论上,这应该在两行上打印出相同的值,底部的值是正确的,但由于某些原因它没有。
现在我当然可以使用 unsigned char 值并为自己编写一个函数,将所有内容转换为正确的 float 值,但我觉得应该有一种方法可以只使用 STB_Image 本身来做到这一点。
来自 stb_image.h
header 条评论:
// 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);
这意味着 stbi_loadf()
函数对 return 其浮点值使用 built-in 伽玛校正。
伽玛校正公式如下所示:
Vout = (Vin / 255)^γ; Where γ = 2.2
当您将 [127, 255, 32]
通过伽玛校正公式时,您会得到您所看到的结果:
R: 0.22 = (127 / 255)^2.2
G: 1.00 = (255 / 255)^2.2
B: 0.01 = ( 32 / 255)^2.2
您可以使用 stbi_ldr_to_hdr_gamma(1.0f)
设置 stb_image 伽马系数作为快速修复。
但是,stb_image 专门定义了 stbi_loadf()
以支持 non-linear 编码图像(HDR 或伽马校正)。如果您要使用该函数加载实际的 HDR 图像,将伽马设置为 1.0
会对绘制时图像的准确性产生负面影响;所以最好只使用 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.
使用 Vout = (float)Vin / 255f
手动将 8 位图像数据转换为浮点数可以明显地告诉代码的读者图像数据 未 伽玛校正。将 stbi_loadf()
与 stbi_ldr_to_hdr_gamma(1.0f)
结合使用会掩盖这一重要细节。