我的答案是基于Fast RGB to Spectrum Conversion for Reflectances。由于 RGB 数据文件中只有 3 个自由度 (DOF),并且在连续光谱中实际上存在无限自由度,因此该映射不会是唯一的。
输出光谱由下式给出:
其中、和是归一化为的 RGB 三元组范围 0 到 1,以及、和如下所示。ρ(λ)=rρR(λ)+gρG(λ)+bρB(λ)
rgbρR(λ)ρG(λ)ρB(λ)
rho_R
0.021592459, 0.020293111, 0.021807906, 0.023803297, 0.025208132,
0.025414957, 0.024621282, 0.020973705, 0.015752802, 0.01116804,
0.008578277, 0.006581877, 0.005171723, 0.004545205, 0.00414512,
0.004343112, 0.005238155, 0.007251939, 0.012543656, 0.028067132,
0.091342277, 0.484081092, 0.870378324, 0.939513128, 0.960926994,
0.968623763, 0.971263883, 0.972285819, 0.971898742, 0.972691859,
0.971734812, 0.972344540, 0.971503390, 0.970857997, 0.970553866, 0.969671404
rho_G
0.010542406, 0.010878976, 0.011063512, 0.010736566, 0.011681813,
0.012434719, 0.014986907, 0.020100392, 0.030356263, 0.063388962,
0.173423837, 0.568321142, 0.827791998, 0.916560468, 0.952002841,
0.964096452, 0.970590861, 0.972502542, 0.969148203, 0.955344651,
0.892637233, 0.500364100, 0.116236717, 0.047951391, 0.027873526,
0.020057963, 0.017382174, 0.015429109, 0.015438080, 0.014546826,
0.015197773, 0.014285896, 0.015069123, 0.015506263, 0.015545797, 0.016302839
rho_B
0.967865135, 0.968827912, 0.967128582, 0.965460137, 0.963110055,
0.962150324, 0.960391811, 0.958925903, 0.953890935, 0.925442998,
0.817997886, 0.425096960, 0.167036273, 0.078894327, 0.043852038,
0.031560435, 0.024170984, 0.020245519, 0.018308140, 0.016588218,
0.01602049, 0.0155548080, 0.013384959, 0.012535491, 0.011199484,
0.011318274, 0.011353953, 0.012285073, 0.012663188, 0.012761325,
0.013067426, 0.013369566, 0.013427487, 0.013635740, 0.013893597, 0.014025757
在这些表中,第一个条目是 380 nm,整体之间有 10 nm 步长。
现在您处于频谱域中,您可以执行过滤。
要返回 RGB 域,我通常会进行从频谱到XYZ的转换,然后再到 RGB。我在下面包含了我的代码。有关更多背景信息,您可以访问 Wikipedia CIE 1931 颜色空间页面。
频谱到 XYZ
double piecewise_gaussian(double x, double alpha, double mu, double sigma1,
double sigma2) {
double t = (x - mu) / (x < mu ? sigma1 : sigma2);
return alpha * std::exp(-(t * t) / 2);
}
color_xyz wavelength_to_xyz(double lambda) {
color_xyz xyz;
xyz.c[0] = piecewise_gaussian(lambda, 1.056, 599.8, 37.9, 31.0)
+ piecewise_gaussian(lambda, 0.362, 442.0, 16.0, 26.7)
+ piecewise_gaussian(lambda, -0.065, 501.1, 20.4, 26.2);
xyz.c[1] = piecewise_gaussian(lambda, 0.821, 568.8, 46.9, 40.5)
+ piecewise_gaussian(lambda, 0.286, 530.9, 16.3, 31.1);
xyz.c[2] = piecewise_gaussian(lambda, 1.217, 437.0, 11.8, 36.0)
+ piecewise_gaussian(lambda, 0.681, 459.0, 26.0, 13.8);
return xyz;
}
XYZ 为 RBG
color_rgb xyz_to_rgb(color_xyz xyz) {
color_rgb rgb;
rgb.c[0] = 0.4184700 * xyz.c[0] - 0.1586600 * xyz.c[1] - 0.082835 * xyz.c[2];
rgb.c[1] = -0.0911690 * xyz.c[0] + 0.2524300 * xyz.c[1] + 0.015708 * xyz.c[2];
rgb.c[2] = 0.0009209 * xyz.c[0] - 0.0025498 * xyz.c[1] + 0.178600 * xyz.c[2];
return rgb;
}
从上面的 RBG -> 频谱 -> 到 RBG 的完整循环是未归一化的。对于我使用它的应用程序来说,这并不重要。我推荐的合理标准化策略如下:
- 从 RGB 白色值 (1, 1, 1) 开始
- 转换为等效光谱
- 转换回 RGB 空间
- 计算新 RGB 值的“亮度”,RGB 值可能不再是所有三个分量相同值的三倍(这就是我使用引号的原因)
- 使用新值的计算亮度的倒数作为所有转换的恒定比例因子