计算位图的 window 宽度和 window 中心
Calculate window width and window center for a bitmap
我正在尝试实现一个 dicom 查看器。对于 dicom 文件,我可以通过 fo-dicom framework. But sometimes I need set the parameters for a bitmap. I have found how to can do it 设置 window 宽度和 window 中心,但它不能正常工作。
private Bitmap setWinWidthAndCenter(Bitmap bmp)
{
int center = (int)vsWindowCenter.Value;
int width = (int)vsWindowWidth.Value;
var wyMin = center - 0.5 - (width - 1) / 2;
var wMax = center - 0.5 + (width - 1) / 2;
System.Drawing.Color color;
for (int i = 0; i < bmp.Width; i++)
{
for (int j = 0; j < bmp.Height; j++)
{
color = bmp.GetPixel(i, j);
if (color.R <= wyMin)
color = System.Drawing.Color.FromArgb(0, 0, 0);
else if (color.R > wMax)
color = System.Drawing.Color.FromArgb(255, 255, 255);
else
{
var val = (int)(((color.R - (center - 0.5)) / (width - 1) + 0.5) * 255);
color = System.Drawing.Color.FromArgb(val, val, val);
}
bmp.SetPixel(i, j, color);
}
}
return bmp;
}
可能有人知道哪里出了问题。
编辑 1:
左图是通过 fo-dicom 库收到的预期结果。右图是我函数处理后的结果
查看您的中心值和宽度值。它们可能特定于 12 位或 16 位单色图像。这将使它们与您正在使用的限制性 0-255 RGB 位图明显不同。
您要么必须正确缩放中心值和宽度值,要么使用原始单色数据。
我觉得你的台词
var val = (int)(((color.R - (center - 0.5)) / (width - 1) + 0.5) * 255);
不太正确。我想你想要
var val = (int)(( (color.R - wyMin) / (width - 1) + 0.5) * 255);
您正在尝试建立一个分段线性变换来映射
x 值小于 wyMin 为 0,值大于 wMax 为 255,中间 x 值为介于 0 和 255 之间的中间值。
我找到了问题的解决方案。
该算法是正确的,但有一点:位图的初始值为 window 宽度和中心,有 Window 中心:127 和 window 宽度 255。
我们需要做的就是计算 dicom 文件中的初始值与我们要设置的值之间的差异。然后我们可以将获得的值添加到初始位图值。
右边的代码如下所示。
public Bitmap setWinWidthAndCenterForBitmap(Bitmap bmp, double defaultCenter, double defaultWidth, double currentCenter, double currentWidth)
{
double difCenter = currentCenter - defaultCenter;
double difWidth = currentWidth - defaultWidth;
int WinCenter = 127 + (int)difCenter;
int WinWidth = 255 + (int)difWidth;
var wMin = WinCenter - 0.5 - (WinWidth - 1) / 2;
var wMax = WinCenter - 0.5 + (WinWidth - 1) / 2;
System.Drawing.Color color;
for (int i = 0; i < bmp.Width; i++)
{
for (int j = 0; j < bmp.Height; j++)
{
color = bmp.GetPixel(i, j);
color = System.Drawing.Color.FromArgb(
calculateColor(color.R, wMin, wMax, WinCenter, WinWidth),
calculateColor(color.G, wMin, wMax, WinCenter, WinWidth),
calculateColor(color.B, wMin, wMax, WinCenter, WinWidth));
bmp.SetPixel(i, j, color);
}
}
return bmp;
}
private byte calculateColor(byte c, double wMin, double wMax, double WinCenter, double WinWidth)
{
if (c <= wMin)
return 0;
else if (c > wMax)
return 255;
else
return (byte)(((c - (WinCenter - 0.5)) / (WinWidth - 1) + 0.5) * 255);
}
我正在尝试实现一个 dicom 查看器。对于 dicom 文件,我可以通过 fo-dicom framework. But sometimes I need set the parameters for a bitmap. I have found how to can do it 设置 window 宽度和 window 中心,但它不能正常工作。
private Bitmap setWinWidthAndCenter(Bitmap bmp)
{
int center = (int)vsWindowCenter.Value;
int width = (int)vsWindowWidth.Value;
var wyMin = center - 0.5 - (width - 1) / 2;
var wMax = center - 0.5 + (width - 1) / 2;
System.Drawing.Color color;
for (int i = 0; i < bmp.Width; i++)
{
for (int j = 0; j < bmp.Height; j++)
{
color = bmp.GetPixel(i, j);
if (color.R <= wyMin)
color = System.Drawing.Color.FromArgb(0, 0, 0);
else if (color.R > wMax)
color = System.Drawing.Color.FromArgb(255, 255, 255);
else
{
var val = (int)(((color.R - (center - 0.5)) / (width - 1) + 0.5) * 255);
color = System.Drawing.Color.FromArgb(val, val, val);
}
bmp.SetPixel(i, j, color);
}
}
return bmp;
}
可能有人知道哪里出了问题。
编辑 1:
左图是通过 fo-dicom 库收到的预期结果。右图是我函数处理后的结果
查看您的中心值和宽度值。它们可能特定于 12 位或 16 位单色图像。这将使它们与您正在使用的限制性 0-255 RGB 位图明显不同。
您要么必须正确缩放中心值和宽度值,要么使用原始单色数据。
我觉得你的台词
var val = (int)(((color.R - (center - 0.5)) / (width - 1) + 0.5) * 255);
不太正确。我想你想要
var val = (int)(( (color.R - wyMin) / (width - 1) + 0.5) * 255);
您正在尝试建立一个分段线性变换来映射 x 值小于 wyMin 为 0,值大于 wMax 为 255,中间 x 值为介于 0 和 255 之间的中间值。
我找到了问题的解决方案。
该算法是正确的,但有一点:位图的初始值为 window 宽度和中心,有 Window 中心:127 和 window 宽度 255。
我们需要做的就是计算 dicom 文件中的初始值与我们要设置的值之间的差异。然后我们可以将获得的值添加到初始位图值。
右边的代码如下所示。
public Bitmap setWinWidthAndCenterForBitmap(Bitmap bmp, double defaultCenter, double defaultWidth, double currentCenter, double currentWidth)
{
double difCenter = currentCenter - defaultCenter;
double difWidth = currentWidth - defaultWidth;
int WinCenter = 127 + (int)difCenter;
int WinWidth = 255 + (int)difWidth;
var wMin = WinCenter - 0.5 - (WinWidth - 1) / 2;
var wMax = WinCenter - 0.5 + (WinWidth - 1) / 2;
System.Drawing.Color color;
for (int i = 0; i < bmp.Width; i++)
{
for (int j = 0; j < bmp.Height; j++)
{
color = bmp.GetPixel(i, j);
color = System.Drawing.Color.FromArgb(
calculateColor(color.R, wMin, wMax, WinCenter, WinWidth),
calculateColor(color.G, wMin, wMax, WinCenter, WinWidth),
calculateColor(color.B, wMin, wMax, WinCenter, WinWidth));
bmp.SetPixel(i, j, color);
}
}
return bmp;
}
private byte calculateColor(byte c, double wMin, double wMax, double WinCenter, double WinWidth)
{
if (c <= wMin)
return 0;
else if (c > wMax)
return 255;
else
return (byte)(((c - (WinCenter - 0.5)) / (WinWidth - 1) + 0.5) * 255);
}