医学影像处理 Window/level

现在咱们开讲。 
图像显示和打印面临的一个问题是:图像的亮度和对比度能否充分突出关键部分。这里所指的“关键部分”在 CT 里的例子有软组织、骨头、脑组织、肺、腹部等等。

 

技术问题:

 

o 显示器往往只有 8-bit, 而数据有 12- 至 16-bits。

o 如果将数据的 min 和 max 间 (dynamic range) 的之间转换到 8-bit 0-255 去,过程是个有损转换, 而且出来的图像往往突出的是些噪音。 针对这些问题,研究人员先提出一些要求 (requirements),然后根据这些要求提出了一些算法。这些算法现在都很成熟。

 

要求一:充分利用 0-255 间的显示有效值域

要求二:尽量减少值域压缩带来的损失

要求三:不能损失应该突出的组织部分

 

算法分析

 

A. 16-bit 到 8-bit 直接转换:

computeMinMax(pixel_val, min, max); // 先算图像的最大和最小值

 

for (i = 0; i < nNumPixels; i++)

disp_pixel_val[i] = (pixel_val[i] - min)*255.0/(double)(max - min);

 

这个算法必须有,对不少种类的图像是很有效的:如 8-bit 图像,MRI, ECT, CR 等等。

B. Window-leveling 算法:

W/L 是专门为 CT 设计的。原理很简单:CT 图像里不同组织的密度 (用 Hounsfield 单位) 是在固定的值域, 与具体设备和成像软件没有关系。因此,要看头颅时, 我们只需将头颅的值域转换到 0-255 就行了。 CT W/L 不讲头颅值域的 min 和 max, 而说 max - min (即 window_width) 和 (max+min)/2 (即 window_center)。 我们还可以用原来的公式,只是 min 和 max 的算法不一样。

// 先算图像的最大和最小值

 

min = (2*window_center - window_width)/2.0 + 0.5;

max = (2*window_center + window_width)/2.0 + 0.5;

for (i = 0; i < nNumPixels; i++)

disp_pixel_val[i] = (pixel_val[i] - min)*255.0/(double)(max - min);

 

请注意,CT 图像必须先转换成 Hounsfield 值再做 window-level。 这个转换包括将多余高位 bits 变成 0 (clipping), 和用 recale slope 和 rescale intercept 来做单位转换。

 

HU[i] = pixel_val[i]*rescale_slope + rescale_intercept

 

C.非线性转换

我刚刚说的是将 min 和 max 间的数值线性转换到 0-255 之间。 如果 max - min 出来是个很大的数值,比如说 25500, 那就说每 100 原始密度会压缩成一个显示灰度。 这样的损失可能会很大。 因为人眼对灰度地反应式是非线性的,非线性转换可以解决一些问题。 常用算法有 log 和 gamma 两种。gamma 比较好调 gamma 值,因此用得比较多。

for (i = 0; i < nNumPixels; i++)

disp_pixel_val[i] = 255.0 * pow(pixel_value[i]/(max-min), 1.0/gamma);

D. 有效值域:CT 的 Window-level 有标准的定义,请参看 “Practical CT Techniques", by Wladyslaw Gedroyc and Sheila Rankin, Springer-Verlag。最常用到的有 WW = 400, WL = 40 (实用许多部位); WW = 100, WL = 36 (头);WW = 3200, WL = 200 (骨头),等等。

 

补充几点:

  • 在做任何转换时要注意有效灰度域外的数值的处理。 最好先用 int 而非 unsigned char 来算,再转入矩阵,以避免 overflow 和 underflow。
 1 double dFactor = 255.0/(double)(max - min);
 2 
 3 int nPixelVal;
 4 
 5 for (i = 0; i < nNumPixels; i++)
 6 
 7 {
 8 
 9 nPixelVal = (int) ((pixel_val[i] - min)*dFactor);
10 
11 if (nPixelVal < 0)
12 
13 disp_pixel_val[i] = 0;
14 
15 else if (nPixelVal > 255)
16 
17 disp_pixel_val[i] = 255;
18 
19 else
20 
21 disp_pixel_val[i] = nPixelVal;
22 
23 }

 

 

 

 

  • 做 window-level 时要注意 min 和 max 之外原始数据的处理

 

 1 double dFactor, min, max;
 2 
 3 int nPixelVal;
 4 
 5 min = (2*window_center - window_width)/2.0 + 0.5;
 6 
 7 max = (2*window_center + window_width)/2.0 + 0.5;
 8 
 9 dFactor = 255.0/(double)(max - min);
10 
11 for (i = 0; i < nNumPixels; i++)
12 
13 {
14 
15 if (pixel_val[i] < min)
16 
17 {
18 
19 disp_pixel_val[i] = 0;
20 
21 continue;
22 
23 }
24 
25 if (pixel_val[i] > max)
26 
27 {
28 
29 disp_pixel_val[i] = 255;
30 
31 continue;
32 
33 }
34 
35 nPixelVal = (int)((pixel_val[i] - min)*dFactor);
36 
37 if (nPixelVal < 0)
38 
39 disp_pixel_val[i] = 0;
40 
41 else if (nPixelVal > 255)
42 
43 disp_pixel_val[i] = 255;
44 
45 else
46 
47 disp_pixel_val[i] = nPixelVal;
48 
49 }

 

 

 

posted @ 2012-12-26 10:19  微笑的艾米  阅读(1492)  评论(1编辑  收藏  举报