You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Fo-Dicom中创建并显示Overlay?代码异常排查求助

在Fo-Dicom中创建并显示Overlay层的问题排查与修复

你的代码无法显示Overlay的核心问题在于Dicom Overlay的位序规则未遵守,以及数据长度计算、像素映射逻辑存在偏差,以下是具体问题点和修复方案:

核心问题分析

  1. 位序错误:Dicom标准规定,Overlay的每个字节内,像素位是从**最高位(Bit7)到最低位(Bit0)**对应图像的从左到右像素,而你的代码直接将BitArray按默认顺序拷贝,导致位序完全反转。
  2. 数据长度计算不严谨:代码中用bits.Length / 8计算字节数,当像素总数不是8的倍数时,会丢失最后几个像素位,应该向上取整。
  3. 像素映射的行顺序问题:虽然RenderTargetBitmap的行顺序与Dicom一致,但未针对每行的位序做反转处理,导致Overlay显示错位。

修复后的代码

DicomFile dicomFile = DicomFile.Open(sourceDicomFileName, FileReadOption.ReadAll);
ushort width = dicomFile.Dataset.GetSingleValue<ushort>(DicomTag.Columns);
ushort height = dicomFile.Dataset.GetSingleValue<ushort>(DicomTag.Rows);
byte[] packedbitarray = Array.Empty<byte>();

Application.Current.Dispatcher.Invoke(() =>
{
    var grid = new Grid { Width = width, Height = height };
    var text = new TextBlock
    {
        Text = "OVERLAY",
        FontSize = 32,
        FontWeight = FontWeights.Bold,
        HorizontalAlignment = HorizontalAlignment.Center,
        VerticalAlignment = VerticalAlignment.Center // 确保文本垂直居中
    };
    grid.Children.Add(text);
    grid.Measure(new Size(grid.Width, grid.Height));
    grid.Arrange(new Rect(new Size(grid.Width, grid.Height)));

    var rtb = new RenderTargetBitmap(
                        (int)grid.Width,
                        (int)grid.Height,
                        96,
                        96,
                        PixelFormats.Pbgra32);
    rtb.Render(grid);

    int stride = rtb.PixelWidth * 4;
    int size = rtb.PixelHeight * stride;
    byte[] coloredPixels = new byte[size];
    rtb.CopyPixels(coloredPixels, stride, 0);

    // 计算Overlay所需字节数:向上取整(宽*高 / 8)
    int overlayByteCount = (int)Math.Ceiling((width * height) / 8.0);
    packedbitarray = new byte[overlayByteCount];

    // 逐行处理,修正位序
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            // 取Alpha通道判断像素是否可见
            int pixelIndex = (y * stride) + (x * 4) + 3;
            bool isPixelSet = coloredPixels[pixelIndex] != 0;

            // 计算当前位在字节中的位置:行内左到右对应Bit7到Bit0
            int bitPosition = 7 - (x % 8);
            int byteIndex = (y * width + x) / 8;

            if (isPixelSet)
            {
                packedbitarray[byteIndex] |= (byte)(1 << bitPosition);
            }
        }
    }
});

// 用AddOrUpdate避免重复标签异常,确保Overlay属性正确
dicomFile.Dataset.AddOrUpdate(new DicomUnsignedShort(DicomTag.OverlayColumns, width));
dicomFile.Dataset.AddOrUpdate(new DicomUnsignedShort(DicomTag.OverlayRows, height));
dicomFile.Dataset.AddOrUpdate(new DicomCodeString(DicomTag.OverlayType, "G"));
dicomFile.Dataset.AddOrUpdate(new DicomSignedShort(DicomTag.OverlayOrigin, new short[] { 1, 1 }));
dicomFile.Dataset.AddOrUpdate(new DicomUnsignedShort(DicomTag.OverlayNumber, 1));
dicomFile.Dataset.AddOrUpdate(new DicomUnsignedShort(DicomTag.OverlayBitsPerPixel, 0));
dicomFile.Dataset.AddOrUpdate(new DicomOtherByte(DicomTag.OverlayData, packedbitarray));

dicomFile.Save(destDicomFileName);

额外注意事项

  • 部分Dicom阅读器默认关闭Overlay显示,需在阅读器设置中开启Overlay渲染开关。
  • 确保Overlay的尺寸(Columns/Rows)与主图像完全一致,否则会显示错位或不显示。

内容的提问来源于stack exchange,提问作者Basavaprasad Kotarki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 12:15:57