在一些情况下需要可视化一份数据, 可能是一份温度的数据,也可能是一份高度图,最常见的思路就是将这些数据转化为图片,直观地观察数据是否为预期的值。
如果数据的范围不大,最小值和最大值差
256
以内(如:红外摄像头的输入),可以直接把数据映射到[0, 255]
,灰度也好,只利用红色通道也好,都是切实可行的方案,这种方案实现起来比较简单,代码量不大。如果对于精度要求不高,只为验证数据正确性的话, 其实更大的范围也能按比例映射到[0,255]
。
现在考虑一个最小值和最大值相差1536
以内的映射方案
为什么是
1536
?因为是 256 ∗ 6 = 1536 256*6=1536 256∗6=1536,也就是把映射到[0, 255]
的方案扩大了6倍,在原本的基础上增加了一些精度。
考虑到数据是连续的,映射为颜色后也希望颜色是连续的,才不至于产生断层,显得突兀,先提出下列要求:
- 设计6段独立的色彩区间,用于对应6段不同的数据区间
- 两个相邻的色彩区间是连续的
- 用纯黑和纯白表示低于和高于待观测数据区间的值(过滤)
- 在有效数据点处避免出现纯白和纯黑的情况
从而设计出如下的色彩区间的端点:
- | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
R | 0 | 0 | 0 | 255 | 255 | 255 |
G | 0 | 255 | 255 | 255 | 0 | 0 |
B | 255 | 255 | 0 | 0 | 0 | 255 |
从纯蓝色开始,到紫色为止,进行渐变,如下:
代码:
_max = 8752
_min = -407
_range = _max - _min + 1
# 将_data映射到不同的色彩区间中
def convert_data(_data):
if _data < _min:
return [0, 0, 0]
r = (_data - _min) / _range
step = int(_range / 5)
idx = int(r * 5)
h = (idx + 1) * step + _min
m = idx * step + _min
local_r = (_data - m) / (h - m)
if _data < _min:
return [0, 0, 0]
if _data > _max:
return [255, 255, 255]
if idx == 0:
return [0, int(local_r * 255), 255]
if idx == 1:
return [0, 255, int((1 - local_r) * 255)]
if idx == 2:
return [int(local_r * 255), 255, 0]
if idx == 3:
return [255, int((1 - local_r) * 255), 0]
if idx == 4:
return [255, 0, int(local_r * 255)]
这只是一个简化的设计,最理想的情况是将
255
∗
255
∗
255
=
16581375
255*255*255=16581375
255∗255∗255=16581375种颜色映射到线性空间中,并且依旧能保证色彩是连续的,就能很精确地可视化最值差达到16581375
的数据。
附上一张利用上述方法可视化地球海拔数据的效果图: