多图预警。
“用于显示的灰度图像通常用每个采样像素 8 位的非线性尺度来保存,这样可以有 256 级灰度。这种精度刚刚能够避免可见的条带失真,并且非常易于编程。在医学图像与遥感图像这些技术应用中经常采用更多的级数以充分利用每个采样 10 或 12 位的传感器精度,并且避免计算时的近似误差。在这样的应用领域每个采样 16 位即 65536 级得到流行。”[1]
搜索从灰度图到彩色图转换的方法,只找到了256级转换的方式(包括skimage、opencv这两个库,转换也是按256来的),如CT显示用的查表法,虽然HU的取值范围从-1000到1000,在实际检查中,可以针对不同的器官选择窗口值,最终需要处理的灰度到彩色转换仍然是256级。[2]
从灰度图到彩色图的转换方法,大多采用HSV色彩空间->RGB彩色空间。[3]
用HSV色彩空间作为目标颜色范围,人眼最大能区分128种色彩(Hue),130种色饱和度(Saturation),23种明暗度(Value)。理想情况下目标颜色空间能容纳:
128 * 130 * 23 = 382720 个灰度值,16位的灰度数据大致占这段区间的20%,但是按这个转换方式实测下来(线性变换),效果并不好。
下图是对某个slice着色的效果,如果用skimage保存成png,会提示对比度过低。
然后从两个方向去尝试改进效果:
一、写代码观察hue、saturation和value取值对显示效果的影响
比如,如果s和v的值不变,仅hue变化,色彩连续;如果把s值固定成1,对v按区间取值,会发现v值为0.1、0.2时,颜色接近黑色;s和v均区间变化,当s和v都从0.5开始时,其颜色表现接近仅hue变化。
变化hue的效果:
变化hue+value的效果:
变化hue+saturation+value的效果:
变化hue+saturation+value的效果(saturation从0.5开始取值):
变化hue+saturation+value的效果(saturation和value均从0.5开始取值)
二、观察灰度值分布情况
散点图
(待续) 2016-08-23
--------------------------------------------
2016-08-26更新:
>观察有多少个离散的灰度值:
ua, uind = np.unique(slice_0, return_inverse=True)
count = np.bincount(uind)
测试用的一张slice有6千多个离散值
>按位数观察灰度值分布:
print '0~2048', ( slice_0 < 2048 ).sum()
print '2048~4096', ( (slice_0>=2048) & (slice_0 < 4096) ).sum()
print '4096~8192', ( (slice_0>=4096) & (slice_0 < 8192) ).sum()
>尝试将灰度值取值范围压缩到3000以内
slice_norm = slice_0.astype(np.float32)
slice_norm *= 3000. / slice_norm.max()
slice_norm = slice_norm.astype(np.uint16)
还尝试过几种处理方式,曾经得到类似上图的效果,结论是,如果不引入位置相关的平滑算法,颜色数越多,生成的图像颗粒化越严重,如果想看到和灰度图类似的形状,只能采用映射的方式,比如把65536中灰度映射到512中颜色当中,用hsv计算颜色时,仅hue变化,saturation和value固定,下图是其中一张的着色效果(另,当前医学影像着色的主流研发方向似乎是用机器学习来处理):
虽然变化saturation和value能生成大量颜色,这些颜色看起来还是太像了,难怪章毓晋在《图像工程》第12章中说“虽然人眼仅能分辨几十种不同深浅的灰度级,但却能分辨几千种不同的颜色” -- 在医学影像领域,说人眼能识别一千万种颜色是没有意义。比如下图,是用3000中颜色组成的(ndarray中的每一个元素的RGB值都不同),可是看起来似乎只有红和黄两种颜色:[4]
参考:
[4]图像工程 第三版 上册