LAUREL BRIDGE

LaurelBridge.DCF.Examples.LoadImageFrames Namespace

DICOM Connectivity Framework V3.4
The LoadImageFrames example demonstrates using the IFrameProducer interface to perform parallel loading of pixel data frames to a byte buffer from either a multi-frame DICOM file or from multiple single-frame DICOM files.
Classes

  ClassDescription
Public classProgram
This example demonstrates how to load all the pixel data image frames from a single multi-frame dataset, or from a set of single frame datasets into a byte array.
Examples

LoadImageFrames Sample Code
public class Program
{
    private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();
    private static string[] _imageFiles;
    private static ImageInfo _imageInfo;
    private static string _tsUid;
    private static DicomDataSet[] _dataSets;
    private static DicomSessionSettings _sessionSettings;
    private static byte[] _frameBuffer;
    private static readonly bool _breakOnFailure = true;
    private static int _failures;
    private static readonly object _sync = new Object();

    /// <summary>
    /// Main entry point for LoadImageFrames.
    /// </summary>
    /// <param name="args">A single parameter that specifies a file or directory.  If none is provied the 'mr-knee.dcm' file is used.</param>
    [STAThread]
    public static void Main(string[] args)
    {
        try
        {
            string path = args.Length == 0 ? "mr-knee.dcm" : args[0];
            _imageFiles = GetImageFiles(path);
            Stopwatch sw = Stopwatch.StartNew();
            if (_imageFiles.Length == 1)
            {
                LoadSingleFileImages();
            }
            else
            {
                LoadMultiFileImages();
            }
            sw.Stop();
            Debug.Assert(_imageFiles != null && _imageInfo != null && _tsUid != null);
            Console.WriteLine("path({0}), files({1}), frames({2}), kind({3}), frameSize({4}), tsuid({5}), failures({6}), elapsed({7:F3}s)",
                path,
                _imageFiles.Length,
                _imageInfo.NumberOfFrames * _imageFiles.Length,
                _imageInfo.DecodedPhotometricInterpretation,
                _imageInfo.FrameSize,
                _tsUid,
                _failures,
                sw.Elapsed.TotalSeconds);
        }
        catch (Exception e)
        {
            Logger.Error(e, "Problem loading image frames");
        }

        if (Debugger.IsAttached)
        {
            Console.Write("Press any key to continue . . . ");
            Console.ReadKey();
        }
    }

    /// <summary>
    /// Create the list of files for this example.  Path should be a file or directory path.
    /// </summary>
    /// <param name="path">the path to check</param>
    /// <returns>A list of one or more files.</returns>
    private static string[] GetImageFiles(string path)
    {
        FileAttributes attr = File.GetAttributes(path);
        if (!attr.HasFlag(FileAttributes.Directory))
            return new string[] { path };
        string[] dcmFiles = Directory.GetFiles(path, "*.dcm", SearchOption.TopDirectoryOnly);
        if (dcmFiles.Length == 0)
            throw new FileNotFoundException("no .dcm files found for directory", path);
        Array.Sort(dcmFiles);
        return dcmFiles;
    }

    #region Multiple DataSet Load
    /// <summary>
    /// Load a series of single frame images.
    /// </summary>
    private static void LoadMultiFileImages()
    {
        Debug.Assert(_imageFiles != null && _imageFiles.Length > 0);
        _dataSets = new DicomDataSet[_imageFiles.Length];
        _sessionSettings = new DicomSessionSettings() { EnableStreamingMode = true };
        ParallelLoopResult result = Parallel.For(0, _imageFiles.Length, LoadUniFrame);
        if (!result.IsCompleted)
            Logger.ErrorFormat("LoadMultiFileImages failed at iteration {0}", result.LowestBreakIteration);
    }

    /// <summary>
    /// An Action for the Parallel For in <see cref="LoadMultiFileImages"/>.
    /// </summary>
    /// <param name="index">The index of the dataset to load.</param>
    /// <param name="loopState">A loop state to assist in breaking the loop on error.</param>
    private static void LoadUniFrame(int index, ParallelLoopState loopState)
    {
        Debug.Assert(_imageFiles != null && _imageFiles.Length > index && _imageFiles[index] != null);
        try
        {
            using (DicomFileInput dfi = new DicomFileInput(_imageFiles[index], _sessionSettings))
            {
                Debug.Assert(_dataSets[index] == null);
                DicomDataSet dataSet = _dataSets[index] = dfi.ReadDataSet();
                using (IFrameProducer fp = FrameProducer.CreateFromDataSet(dataSet, null, _sessionSettings))
                {
                    if (!fp.IsValid())
                        throw new InvalidOperationException("frame producer is invalid");
                    ImageInfo ii = fp.ImageInfo;
                    if (ii.NumberOfFrames != 1)
                        throw new InvalidOperationException("expected exactly one frame");
                    lock (_sync)
                    {
                        // first guy in will initialize image info and create the frame buffer
                        if (_imageInfo == null)
                        {
                            _frameBuffer = new byte[_dataSets.Length * ii.FrameSize];
                            _imageInfo = ii;
                            _tsUid = fp.TransferSyntax;
                        }
                    }
                    Debug.Assert(_frameBuffer != null);
                    Debug.Assert(_imageInfo != null);
                    CheckFrameSizeAndImageType(ii);
                    using (MemoryStream ms = new MemoryStream(_frameBuffer, index * ii.FrameSize, ii.FrameSize, true))
                    {
                        if (!fp.GetRawPixels(0, ms))
                            throw new InvalidDataException("problem getting raw pixels");
                    }
                }
            }
        }
        catch (Exception e)
        {
            lock (_sync)
            {
                _failures++;
            }
            Logger.ErrorFormat(e, "problem converting image frame({0}), file: {1}", index, _imageFiles[index]);
            if (_breakOnFailure)
                loopState.Break();
        }
    }

    /// <summary>
    /// Throw an exception if the specified image info is different from the first image info.
    /// </summary>
    /// <param name="ii">The ImageInfo to check.</param>
    private static void CheckFrameSizeAndImageType(ImageInfo ii)
    {
        Debug.Assert(ii != null);
        Debug.Assert(_imageInfo != null);
        string actualType = ii.DecodedPhotometricInterpretation;
        string expectedType = _imageInfo.DecodedPhotometricInterpretation;
        if (actualType == null || expectedType == null || !actualType.Equals(expectedType))
        {
            throw new InvalidOperationException("image type(" + actualType + ")" + "does not match expected(" + expectedType + ")");
        }
        if (ii.FrameSize != _imageInfo.FrameSize)
        {
            throw new InvalidOperationException("frame size(" + ii.FrameSize + ") does not match expected(" + _imageInfo.FrameSize + ")");
        }
    }
    #endregion

    #region Single DataSet Load
    /// <summary>
    /// Load all the frames of a single image.
    /// </summary>
    private static void LoadSingleFileImages()
    {
        Debug.Assert(_imageFiles != null && _imageFiles.Length == 1);
        try
        {
            _dataSets = new DicomDataSet[1];
            _sessionSettings = new DicomSessionSettings() { EnableStreamingMode = true };
            using (DicomFileInput dfi = new DicomFileInput(_imageFiles[0], _sessionSettings))
            {
                Debug.Assert(_dataSets[0] == null);
                DicomDataSet dataSet = _dataSets[0] = dfi.ReadDataSet();
                using (FrameProducer fp = FrameProducer.CreateFromDataSet(dataSet, null, _sessionSettings))
                {
                    if (!fp.IsValid())
                        throw new InvalidOperationException("frame producer is invalid");
                    ImageInfo ii = fp.ImageInfo;
                    _frameBuffer = new byte[ii.NumberOfFrames * ii.FrameSize];
                    _tsUid = fp.TransferSyntax;
                    _imageInfo = ii;
                    Debug.Assert(_frameBuffer != null);
                    Debug.Assert(_imageInfo != null);
                    ParallelFrameLoaderAdapter pfla = new ParallelFrameLoaderAdapter(fp);
                    ParallelLoopResult result = Parallel.For(0, _imageInfo.NumberOfFrames, pfla.LoadMultiFrame);
                    if (!result.IsCompleted)
                        Logger.ErrorFormat("LoadMultiFileImages failed at iteration {0}", result.LowestBreakIteration);
                }
            }
        }
        catch (Exception e)
        {
            _failures++;
            Logger.ErrorFormat(e, "problem converting image file: {1}", _imageFiles[0]);
        }
    }

    /// <summary>
    /// Adapter for Parallel For used to load the image frames of a multi-frame image.
    /// </summary>
    private class ParallelFrameLoaderAdapter
    {
        private readonly IFrameProducer _frameProducer;

        /// <summary>
        /// Construct a ParallelFrameLoaderAdapter with the given frame producer.
        /// </summary>
        /// <param name="frameProducer">The frame producer.</param>
        public ParallelFrameLoaderAdapter(IFrameProducer frameProducer)
        {
            _frameProducer = frameProducer;
            Debug.Assert(_frameProducer != null && _frameBuffer != null && _imageInfo != null);
            Debug.Assert(_frameBuffer.Length == _imageInfo.NumberOfFrames * _imageInfo.FrameSize);
        }

        public void LoadMultiFrame(int index, ParallelLoopState loopState)
        {
            try
            {
                Debug.Assert(index < _imageInfo.NumberOfFrames);
                using (MemoryStream ms = new MemoryStream(_frameBuffer, index * _imageInfo.FrameSize, _imageInfo.FrameSize, true))
                {
                    if (!_frameProducer.GetRawPixels(index, ms))
                        throw new InvalidDataException("problem getting raw pixels");
                }

            }
            catch (Exception e)
            {
                lock (_sync)
                {
                    _failures++;
                }
                Debug.Assert(_imageFiles != null && _imageFiles.Length > 0);
                Logger.ErrorFormat(e, "problem converting image frame({0}), file: {1}", index, _imageFiles[0]);
                if (_breakOnFailure)
                    loopState.Break();
            }
        }
    }
    #endregion
}