计算位图的 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);
}