你要求一个算法,我来给你一个。
在使用Python3.5、Pyglet和MongoDB从HYG数据库中呈现数据时,我研究了这个主题。我对我的星图中的星星外观感到满意。这些颜色可以在此答案底部找到。
1. 颜色指数 (B-V) 转温度 (K)
这是我用于从列表中提取的 B-V(ci) 数据的函数,该列表来自HYG数据库。在此示例中,ci是我正在运行的列表中的一个 B-V 值。
temp = 4600 * (1 / (0.92 * ci + 1.7) + 1 / (0.92 * ci + 0.62))
2. 获取一个大表格。
我选择了这个表格,建议您也这样做。选择温度列和 RGB 或 rgb 值列作为参考。
3. 预处理数据。
从 RGB 表格数据中,我生成了三个有序列表(n = 391)(我的方法是使用电子表格软件和一个能够同时拥有数百万光标的文本编辑器进行清理和选择,然后将结果导入到 mongoDB 中,以便通过 pymongo 封装器在 python 中轻松处理值的列表,而不会在脚本文件中产生太多混乱)。我要介绍的方法的好处是,您可以从其他可能使用 CMYK 或 HSV 的表格中提取颜色数据并进行相应的调整。甚至可以交叉参考。但是,您应该最终得到类似于我建议的 (s)RGB 表格的列表,如下所示;
reds = [255, 255, ... , 155, 155]
greens = [56, 71, ..., 188,188]
blues = [0, 0, ..., 255, 255]
""" this temps list is also (n=391) and corresponds to the table values."""
temps = []
for i in range(1000,40100,100):
temps.append(i)
接下来,我对这些列表应用了一些高斯平滑(它有助于获得更好的多项式,因为它消除了一些波动),然后使用numpy包中的polyfit()方法(多项式回归)将温度值相对于R、G和B值进行拟合:
colors = [reds,greens,blues]
""" you can tweak the degree value to see if you can get better coeffs. """
def smoothListGaussian2(myarray, degree=3):
myarray = np.pad(myarray, (degree-1,degree-1), mode='edge')
window=degree*2-1
weight=np.arange(-degree+1, degree)/window
weight = np.exp(-(16*weight**2))
weight /= sum(weight)
smoothed = np.convolve(myarray, weight, mode='valid')
return smoothed
i=0
for color in colors:
color = smoothListGaussian2(color)
x = np.array(temps)
y = np.array(color)
names = ["reds","greens","blues"]
""" raise/lower the k value (third one) in c """
z = np.polyfit(x, y, 20)
f = np.poly1d(z)
print("%sPoly = " % names[i], z)
i += 1
plt.show()
这样可以为形式为的多项式提供(n)个系数(a)。
现在想想看,您可能可以使用polyfit来生成系数以将CI直接转换为RGB…并跳过CI到温度转换步骤,但是通过先转换为温度,温度和所选颜色空间之间的关系更加清晰。
4. 实际算法:将温度值插入RGB多项式
正如我之前所说,您可以使用其他光谱数据和其他颜色空间来拟合多项式曲线,此步骤仍然相同(稍作修改)。
无论如何,这是我用的完整简单代码(还要注意,这是k=20多项式):
import numpy as np
redco = [ 1.62098281e-82, -5.03110845e-77, 6.66758278e-72, -4.71441850e-67, 1.66429493e-62, -1.50701672e-59, -2.42533006e-53, 8.42586475e-49, 7.94816523e-45, -1.68655179e-39, 7.25404556e-35, -1.85559350e-30, 3.23793430e-26, -4.00670131e-22, 3.53445102e-18, -2.19200432e-14, 9.27939743e-11, -2.56131914e-07, 4.29917840e-04, -3.88866019e-01, 3.97307766e+02]
greenco = [ 1.21775217e-82, -3.79265302e-77, 5.04300808e-72, -3.57741292e-67, 1.26763387e-62, -1.28724846e-59, -1.84618419e-53, 6.43113038e-49, 6.05135293e-45, -1.28642374e-39, 5.52273817e-35, -1.40682723e-30, 2.43659251e-26, -2.97762151e-22, 2.57295370e-18, -1.54137817e-14, 6.14141996e-11, -1.50922703e-07, 1.90667190e-04, -1.23973583e-02,-1.33464366e+01]
blueco = [ 2.17374683e-82, -6.82574350e-77, 9.17262316e-72, -6.60390151e-67, 2.40324203e-62, -5.77694976e-59, -3.42234361e-53, 1.26662864e-48, 8.75794575e-45, -2.45089758e-39, 1.10698770e-34, -2.95752654e-30, 5.41656027e-26, -7.10396545e-22, 6.74083578e-18, -4.59335728e-14, 2.20051751e-10, -7.14068799e-07, 1.46622559e-03, -1.60740964e+00, 6.85200095e+02]
redco = np.poly1d(redco)
greenco = np.poly1d(greenco)
blueco = np.poly1d(blueco)
def temp2rgb(temp):
red = redco(temp)
green = greenco(temp)
blue = blueco(temp)
if red > 255:
red = 255
elif red < 0:
red = 0
if green > 255:
green = 255
elif green < 0:
green = 0
if blue > 255:
blue = 255
elif blue < 0:
blue = 0
color = (int(red),
int(green),
int(blue))
print(color)
return color
另外还有一些注释和图像...
根据我的多项式函数,OBAFGKM黑体温度刻度:
RGB [0-255] 对温度 [0-40000K] 的绘图,
- + : 表数据
- 曲线 : 多项式拟合
最低保真度值的放大图:
这是紫色
正如你所看到的,虽然有些偏差,但肉眼几乎不可察觉,如果你真的想改进它(我不想),你可以选择其他选项:
- 将绿色值最高的列表部分分开,并查看新左右列表的更好多项式函数。就像这样:
- 编写异常规则(也许是简单的k=2或k=3多项式函数),针对保真度较低的窗口值。
- 在使用polyfit()之前尝试其他平滑算法。
- 尝试其他来源或颜色空间。
我的多项式函数的整体性能也让我很满意。当我在我的星图中加载大约120000个星体对象时,每个对象至少有18个彩色顶点,只需要几秒钟,这让我非常惊讶。然而,仍有改进的空间。为了获得更加逼真的效果(而不仅仅是黑体辐射光),我可以添加引力透镜、大气效应、相对论多普勒效应等...
哦,还有紫色,像承诺的那样。
一些其他有用的链接:
temp <--> BV
(包括开尔文和摄氏度)之间的转换例程,以及RGB -> BV
的转换例程... - Spektre