繁体   English   中英

Fo-Dicom Window 变化缓慢

[英]Fo-Dicom Window Change is slow

我正在使用以下渲染代码。 这是一个稍微修改过的代码,因为在实际代码中,我从 FTP 服务器获取所有文件。 CurrentWindowCenter 和 CurrentWindowWidth 保存 WL 和 WW 的当前值。 可以从 UI 更改此值。 我使用 canvas 中的图像组件直接向用户显示渲染的 WritableBitmap。但是图像的渲染速度非常慢。 特别是对于 X 射线等文件较大的图像。 所以,WW 和 WL 的变化也很慢,因为它也使用渲染 function。我对此不是很了解。 但是有没有办法让渲染或者WW/WL变化的更快呢? 有没有办法在每次 WW/WL 发生变化时跳过图像的渲染? 对正确方向的任何建议表示赞赏。 提前致谢。

// assume filePath holds an actual file location. 
 var filePath = "";
 var dicomFile = new DicomFile.Open(filePath);
 var dicomImage = new DicomImage(dicomFile.DataSet);
 if (CurrentWindowCenter.HasValue && CurrentWindowWidth.HasValue)
 {
     dicomImage.WindowCenter = Convert.ToDouble(CurrentWindowCenter.Value);
     dicomImage.WindowWidth = Convert.ToDouble(CurrentWindowWidth.Value);
 }
 dicomImage.RenderImage().AsWriteableBitmap();

环境

  • Fo-Dicom (4.0.8)
  • .NET 框架 4.8
  • WPF

我的猜测是 fo-dicom 并不是真正为高性能而设计的,更多的是为了兼容性。 为了获得最佳性能,您应该通过 DirectX、OpenCL 或类似工具使用 GPU。 第二好的应该是一些紧密优化的 SIMD 代码,可能使用 c++。

但仅使用 c# 可能会有一些改进。从外观上看,fo-dicom 创建了一个新图像,将像素复制到该图像,然后创建一个 writeableBitmap 并执行另一个副本。 这些步骤将花费一些额外的时间。

我复制像素和应用 lut/transfer function 的代码如下所示:

public static unsafe void Mono16ToMono8(
    byte* source,
    byte* target,
    int sourceStride,
    int targetStride,
    int width,
    int height,
    byte[] lut)
{
    Parallel.For(0, height, y =>
    {
        var ySource = source + y * sourceStride;
        var yTarget = target + y * targetStride;
        var srcUshort = (ushort*)ySource;
        for (int x = 0; x < width; x++)
        {
            var sample = srcUshort[x];
            yTarget[x] = lut[sample];
        }
    });
}

以及对可写 bitmap 进行实际更新的代码:

public static unsafe void Update(
    this WriteableBitmap self,
    IImage source,
    byte[] lut)
{
    self.Lock();
    try
    {
        var targetPtr = (byte*)self.BackBuffer;
        fixed (byte* sourcePtr = source.Data)
        {
            if (source.PixelFormat == PixelType.Mono16)
            {
                Mono16ToMono8(
                    sourcePtr,
                    targetPtr,
                    source.Stride,
                    self.BackBufferStride,
                    source.Width,
                    source.Height,
                    lut);
            }
        }
        self.AddDirtyRect(new Int32Rect(0, 0, (int)self.Width, (int)self.Height));
    }
    finally
    {
        self.Unlock();
    }
}

这使用内部 IImage 格式,其中source.DataReadOnlySpan<byte> ,但也可以是byte[] 我希望大多数其他属性都是不言自明的。 我希望这段代码会更快一些,因为它避免了分配和一些复制步骤。

所有这些都假设图像是 16 位无符号格式,这在 dicom 中很常见,但不是唯一的格式。 它还假设您实际上可以获得指向实际像素缓冲区的指针,以及将每个可能的像素值映射到一个字节的 lut 数组。 它还假定具有正确大小和颜色空间的可写位图。

如前所述,如果您既想要高性能,又想要处理所有可能的图像格式,您可能需要投入时间来构建自己的图像渲染管道。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM