The Method of Programming Medical Imaging

Ⅰ.ウィンドウレベル変換

モノクロで言えば、白と黒の階調表示を指定するタグを使って、グレースケールの濃淡を調整することです。
一般的な、パソコンのモニターは、8ビットのグレースケールに対応しています。
2^8 = 256 ですので、256階調の白黒の濃淡を表せるということになります。
10ビットマシンなど、高性能な輝度表示を行うことができるデバイスがありますが、
かなり高価です。
2^10 = 1024 ですので、1024階調の白黒の濃淡を表せるということになります。
グラフィックスボードも、10ビット対応のモノが必要です。
医用画像専用のモノになると、バルコというメーカーが有名です。
プロ仕様です。

Ⅱ.コード

/// 
/// Create Encoded Bitmap data from Dicom file.
/// 
/// '7FE0,0010' chunk pixcel image data
/// dicom definitioned width
/// dicom definitioned heigh
/// 
private Bitmap CreateBitmap(byte[] source, int width, int height, double window_center, double window_width)
{
	Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
	BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, width, height),
							ImageLockMode.ReadWrite, bitmap.PixelFormat);
	IntPtr ptr = bmpData.Scan0;
	byte[] rgb = new byte[width * height * 3];


	for (int i = 0; i < width * height; i++)
	{
		int value = source[2 * i] + source[2 * i + 1] * 256;

		double val = value;

		if (value >= window_width)
		{
			val = 255;
		}
		else if (value < 0)
		{
			val = 0;
		}
		else
		{
			val = val / window_width;
			val = val * 255;
		}

		value = (int)val;

		rgb[3 * i] = (byte)value;
		rgb[3 * i + 1] = (byte)value;
		rgb[3 * i + 2] = (byte)value;
	}

	System.Runtime.InteropServices.Marshal.Copy(rgb, 0, ptr, width * height * 3);
	bitmap.UnlockBits(bmpData);

	
	return bitmap;
}

上記は、Windows ビットマップファイルを作成する部分のコードです。
double val = value;

if (value >= window_width)
{
	val = 255;
}
else if (value < 0)
{
	val = 0;
}
else
{
	val = val / window_width;
	val = val * 255;
}

ウィンドウレベル変換に関するコードを抜粋しました。
ココでは、8ビットのグレースケールに変換するため、
デジタル信号が、ウィンドウ幅以上だった場合には、値255を、
デジタル信号が、0より低い値だった場合には、値0を、
それ以外の場合には、デジタル信号をウィンドウ幅で割った値に255を掛けた値を計算するものです。
そもそも、デジタル信号がマイナスである場合はないと思われますので、
else if(value < 0) のパスを通る場合はないと思われます。

ココで、ウィンドウレベルつまり、ウィンドウセンター値はどこに使うのかというお尋ねがあろうかと思われますが、
結論から言うと使いません。
いや、正確にいうのであれば、使うのだろうとおもいますが、
コード表現上の論理で考えた場合、使う余地がありません。

気を効かせて、忖度したコードが以下になります。

double val = value;

if (value >= window_width)
{
	val = 255;
}
else if (value < 0)
{
	val = 0;
}
else if (value < window_center)
{
	val = val / window_center;
	val = 127 * val;
}
else if (value >= window_center)
{
	double tmp = (window_width - window_center) / window_width;
	val = 127 + (val - window_center) * tmp;
}	

Ex 1:
window_center(window_level) = 511
window_width = 1024

Ex 2:
window_center(window_level) = 4468.7402
window_width = 11062.5195

Ex 1 では、ウィンドウセンター値が、ウィンドウ幅のちょうど半分になっていることに気づきます。
つまり、デジタル信号の最小値から最大値までの変化率の傾きは一定です。

しかしながら、Ex 2 では、ウィンドウセンター値は、ウィンドウ幅の半分にはなっていませんね。
つまり、デジタル信号の最小値からウィンドウセンター値までの傾きと、
ウィンドウセンター値からデジタル信号の最大値までの傾きが異なるのです。

何がしらかの影響を加味したデータの交換がなされていたのであるならば、
細かい部分で、グレースケールにも影響を与えます。
つまりこういうことです。
下図を見てください。



しかしながら、このコードを実際ののモダリティで撮影された Dicom 画像に適用すると、
グレースケールにムラができ、正しく表示できません。
他のモダリティで撮影された画像も、失敗します。
正しく表示されるという意味では、
先に挙げた、ウィンドウセンター値を用いない方法での傾き一定で計算する方法が正しいようです。

前のページ <<< >>> 次のページ