实现一个DICOM浏览工具 ——显示图像

实现一个DICOM浏览工具——显示图像

在通过fo-dicom解析图像后,需要把图像显示到窗体中,在xaml中添加Image控件,命名为 DcmImage。

  public async Task OpenAsync(string filename)
      {
          var file = await DicomFile.OpenAsync(filename);
          if (file.Dataset.Contains(DicomTag.PixelData))
          {
              var dicomImage = new DicomImage(file.Dataset);
              // fo-dicom中默认是用WinFormImageManager进行图像管理的,如果想在wpf中使用,需要指定为WpfImageManager类
              // 之所以要在这里指定ImageMnager,是因为在DicomImage的RenderImage方法中会调用ImageManager实现类的CreateImageImpl方法获取相对应的图像数据
              ImageManager.SetImplementation(ViewerImageManager.Instance); 
              var frames = Enumerable.Range(0, dicomImage.NumberOfFrames)
                  .Select(frame => dicomImage.RenderImage(frame).As<ImageSource>())
                  .ToList();
              if (frames.Count > 0)
              {
                  DcmImage.Source = frames[0];
              }
          }
      }

在fo-dicom源码中包含了WPFImageManager,但是我通过nuget安装后的找不到这个类,不知道为什么,后边没办法,只能参考github上边的自己写了一个ImageManager类,用来做图像处理的管理工具,具体代码如下:

namespace DcmViewer
    {
    using Dicom.Imaging;
    public sealed class ViewerImageManager : ImageManager
    {
        #region FIELDS
        public static readonly ImageManager Instance;
        #endregion

        #region CONSTRUCTORS
        
        static ViewerImageManager()
        {
            Instance = new ViewerImageManager();
        }

        #endregion

        #region PROPERTIES 
        public override bool IsDefault { 
            get
            {
                return false;
            }
        }
        #endregion


        #region METHODS

        protected override IImage CreateImageImpl(int width, int height)
        {
            return new ViewerImage(width, height);
        }

        #endregion

    }
  }

上边的ViewerImageManager还缺少一个对应的ViewerImage类,代码如下:

namespace DcmViewer
{
    public sealed class ViewerImage : ImageBase<WriteableBitmap>
    {
        #region FIELDS
        private const double DPI = 96;
        #endregion

        #region CONSTRUCTORS

        public ViewerImage(int width, int height): base(width, height, new Dicom.IO.PinnedIntArray(width * height), null)
        {            
        }

        private ViewerImage(int widht, int height, PinnedIntArray pixels, WriteableBitmap image) : base(widht, height, pixels, image)
        {
        }
        #endregion

        #region METHODS
        
        public override void Render(int components, bool flipX, bool flipY, int rotation)
        {
            var bitmap = CreateBitMap(width, height, components, pixels.Data);
            image = ApplyFlipRotate(bitmap, flipX, flipY, rotation);
        }

        public override void DrawGraphics(IEnumerable<IGraphic> graphics)
        {
            foreach (var graphic in graphics)
            {
                var layer = graphic.RenderImage(null).As<WriteableBitmap>();

                var overlay = new int[graphic.ScaledWidth * graphic.ScaledHeight];
                var stride = 4 * graphic.ScaledWidth;
                layer.CopyPixels(overlay, stride, 0);

                image.WritePixels(
                    new Int32Rect(
                        graphic.ScaledOffsetX,
                        graphic.ScaledOffsetY,
                        graphic.ScaledWidth,
                        graphic.ScaledHeight),
                    overlay,
                    stride,
                    0);
            }
        }

        public override IImage Clone()
        {
            return new ViewerImage(
                width,
                height,
                new PinnedIntArray(pixels.Data),
                image == null ? null : new WriteableBitmap(image));
        }

        private static WriteableBitmap CreateBitMap(int width, int height, int components, int[] pixelData)
        {
            var format = components == 4 ? PixelFormats.Bgra32 : PixelFormats.Bgr32;
            var bitmap = new WriteableBitmap(width, height, DPI, DPI, format, null);
            bitmap.Lock();
            Marshal.Copy(pixelData, 0, bitmap.BackBuffer, pixelData.Length);
            bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
            bitmap.Unlock();
            return bitmap;
        }

        private static WriteableBitmap ApplyFlipRotate(WriteableBitmap bitmap, bool flipX, bool flipY, int rotation)
        {
            if (rotation == 0 && !flipX && !flipY)
            {
                return bitmap;
            }

            var rotFlipTransform = new TransformGroup();
            rotFlipTransform.Children.Add(new RotateTransform(rotation));
            rotFlipTransform.Children.Add(new ScaleTransform(flipX ? -1 : 1, flipY ? -1 : 1));

            return new WriteableBitmap(new TransformedBitmap(bitmap, rotFlipTransform));
        }
        #endregion
    }
}

在实现类OpenButton的响应函数后,实现初步的简单显示效果如下:

原文地址:https://www.cnblogs.com/NoPolar/p/14416283.html