LAUREL BRIDGE

LaurelBridge.DCFExamples.SplitMultiframeImage Namespace

DICOM Connectivity Framework V3.4
The SplitMultiframeImage example demonstrates how to use DCF to split a multiframe image into a series of single frame datasets.
Classes

  ClassDescription
Public classOptions
Command line options class for parsing user options for SplitMultiframeImage
Public classProgram
Shows how to read a multiframe images and split it into individual frames.
Remarks

Supported OS Platforms:

  • Windows - .Net Framework 4.7.2 64-bit and 32-bit
  • Windows - .Net Core 2.1 64-bit and 32-bit
  • Linux - .Net Core 2.1 64-bit

Examples

SplitMultiframeImage Sample Code
public class Program
{
    private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

    /// <summary>
    /// Main entry point for SplitMultiframeImage.
    /// </summary>
    /// <param name="args">command line arguments</param>
    [STAThread]
    private static void Main(string[] args)
    {
        try
        {
            Options options;
            if (!Options.TryParse(args, out options))
            {
                throw new ArgumentException("bad command line parameters");
            }

            DicomSessionSettings sessionSettings = new DicomSessionSettings();
            sessionSettings.EnableStreamingMode = true;
            // turn off large element handling to avoid problems with reading elements multiple times
            sessionSettings.LargeElementThreshold = 0;

            DicomFileInput dfi = new DicomFileInput(options.InputFileName, sessionSettings);
            dfi.Open();
            DicomDataSet ds = dfi.ReadDataSet();
            dfi.Close();

            DicomStreamableDataElement pixelElement = ds.GetElement(Tags.PixelData) as DicomStreamableDataElement;
            if (pixelElement != null)
            {
                string sopInstanceUid = ds.GetElementStringValue(Tags.SOPInstanceUID);
                ImageInfo imageInfo = new ImageInfo(ds);
                ds.RemoveElement(Tags.PixelData);
                pixelElement.Producer.BeginStreamingModeTransfer();

                // create a buffer which we'll reuse
                // 
                // *** account for odd frame sizes, which are legal in a
                // multi-frame data set, but not as the pixel element
                // length for the to-be-created single frame data sets.
                // We'll create the buffer with the pad byte, but then
                // set the limit to one less so the read() fetches the
                // correct size. After the read, we move the limit back
                // up by one so the element ctor sees the even length.
                // 
                int frameSize = imageInfo.FrameSize;
                int bufferSize = ((frameSize & 1) == 0) ? frameSize : frameSize + 1;
                ByteBuffer buf = ByteBuffer.Allocate(bufferSize);

                // change frame count for all data sets
                ds.Insert(new DicomISElement(Tags.NumberOfFrames, "1"));
                // we probably should change some other things
                // in the new data-set, e.g., maybe the sop-instance-uid
                // and perhaps set type to DERIVED and add
                // a derivation-description or something that says
                // where the image came from...

                int fieldLength = imageInfo.NumberOfFrames.ToString().Length;
                string fmt = "{0}.{1," + fieldLength + ":D" + fieldLength + "}.dcm";
                if (!Directory.Exists(options.OutputDirectory))
                {
                    Directory.CreateDirectory(options.OutputDirectory);
                }

                string baseName = Path.GetFileNameWithoutExtension(options.InputFileName);
                for (int i = 0; i < imageInfo.NumberOfFrames; i++)
                {
                    // create new sop instance uid by appending frame number to sopInstanceUid
                    String newSopInstanceUid = sopInstanceUid + "." + i;
                    String outputFileName = Path.Combine(options.OutputDirectory, String.Format(fmt, baseName, i));

                    // do this each time, since we're reusing the
                    // buffer as we save the individual frames.
                    buf.Limit = frameSize;

                    int count = pixelElement.Producer.GetBuf(buf);
                    if (count != imageInfo.FrameSize)
                    {
                        throw new DCSException("failed to read frame data");
                    }

                    // set the limit to count the pad byte.
                    buf.Limit = bufferSize;

                    DicomStreamableDataElement frameDataElement;
                    if (pixelElement is DicomOWElement)
                    {
                        frameDataElement = new DicomOWElement(Tags.PixelData, buf);
                    }
                    else
                    {
                        frameDataElement = new DicomOBElement(Tags.PixelData, buf);
                    }

                    // keep overwriting the pixel element with the pixels for the
                    // current frame and the sop instance uid
                    ds.Insert(frameDataElement);

                    DicomUIElement instanceUid = new DicomUIElement(Tags.SOPInstanceUID, newSopInstanceUid);
                    DicomUIElement mediaStorageInstanceUid =
                        new DicomUIElement(Tags.MediaStorageSOPInstanceUID, newSopInstanceUid);
                    ds.Insert(instanceUid);

                    if (ds.ContainsElement(Tags.MediaStorageSOPInstanceUID))
                    {
                        ds.Insert(mediaStorageInstanceUid);
                    }

                    DicomFileOutput dfo = new DicomFileOutput(outputFileName, options.OutputTransferSyntax, sessionSettings);
                    dfo.Open();
                    dfo.WriteDataSet(ds);
                    dfo.Close();
                }

                DicomDataSet trailingElements = pixelElement.Producer.EndStreamingModeTransfer();
                if (trailingElements.Count > 0)
                {
                    Logger.Warn("multi-frame data set had elements following pixel data which were ignored");
                }

            }
            else
            {
                Logger.Error("no pixels to split");
            }

        }
        catch (Exception e)
        {
            Logger.Error(e, "Exception:");
            Environment.ExitCode = 1;
        }
        finally
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                Console.Write("Press any key to continue . . . ");
                Console.ReadKey();
            }
        }
    }
}