具有平滑过渡的 16 位灰度值的颜色映射

Color mapping for 16-bit greyscale values with smooth transitions

我的数据精度为 16 位。尝试以 8 位灰度显示此数据会导致明显的条带。我的想法是我可以用颜色存储这些 16 位值。例如,前 8 位可以在红色通道中,接下来的 8 位可以在绿色通道中。

但是,这会导致突然过渡。从 65280 (255,0,0) 到 65279 (254,255,0) 会导致颜色立即从红色变为黄色。这对人类解释真的没有帮助。

我知道 HSB 可以很容易地提供 360 度的变化,但 360 色值并不比我已经拥有的 256 色值多多少,灰度为 8。

根据以对人类有意义的方式过渡的颜色来表示 0-65535 之间的值的最合适方法是什么?

我不清楚为什么要以 (255, 0, 0) 跟在 (254, 255, 0) 之后的方式计算 RGB 值。它似乎应该以以下形式进行:

(0, 0, 0) -> (254, 0, 0) -> (254, 1, 0) -> (254, 254, 0) -> (254, 254, 1) -> (254, 254, 254).

这表示从黑色到白色,经过红色、橙色和黄色的过渡,没有任何突然的变化。由于我们的眼睛工作的非线性方式,它可能不会被认为是完美平滑的,但您应该能够在没有明显条纹的情况下做到这一点。例如:

let canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');

let rgb = [0, 0, 0]
// fill channels fromgre
for (let j = 0; j < 3; j++){
  for (let i = 0; i < 254; i++) {
    rgb[j]++
    ctx.fillStyle = `rgba(${rgb.join(",")}, 1)`
    ctx.fillRect(i +254*j, 0, 1, 50);
  }
}
<canvas id="canvas" width="765"></canvas>

或者从另一端开始穿过蓝色:

let canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');

let rgb = [0, 0, 0]
// fill channels fromgre
for (let j = 0; j < 3; j++){
  for (let i = 0; i < 254; i++) {
    rgb[2-j]++
    ctx.fillStyle = `rgba(${rgb.join(",")}, 1)`
    ctx.fillRect(i +254*j, 0, 1, 50);
  }
}
<canvas id="canvas" width="765"></canvas>

这是不可能的,如果你想保留一个属性:相似的数字应该有相似的颜色,或者更好的相反:非常不同的数字永远不应该有相似的颜色。

但是如果你写了关于条带的文章,它可能看起来数据是渐变的,所以如果两个不同的"number zone"有相似的颜色,我的眼睛会更容易被原谅,因为附近颜色的上下文。

我不会使用完整的 16 位(这太多了,我们无法清楚地看到所有 RGB 颜色,而且很少有人拥有真正好的显示器)。可能你可以建立一个界面,可以放大,并在有限范围内增加更多对比度。

对于更少的位,您可以从蓝绿色 (0,x,​​x) 开始 [x 从 0 到 255],然后移动到绿色 (0,255,x) [从 255 到 0],然后到黑色 (0, x, 0),从 255 到 0,然后到黄色 (x,x,0),然后到红色 (255,0,0),然后到黑色然后到紫色 (x,0,x) ,然后是蓝色,然后是黑色,最后是白色 (x,x,x)。

所以 10 个尺度,这给了我们 3 个额外的信息。

我可能永远不会变黑(如您所见,它会重复),但只是 x 直到 5 或 10,这将减少位数。但是所以我认为你还有11位的信息,而且人眼可以区分比例。

在这个例子中我使用了6种原色+二次色(+灰度),所以它们很容易区分。理论上可以使用额外的中间色,但我认为这会更加混淆我们的眼睛。

我会提供额外的输入来向上和向下移动原始数据编号,以便用户可以检查某些区域的更多细节(并获得更多位)。但是如果附近的数字之间没有太多极端变化,这很好地工作,