LAUREL BRIDGE

LaurelBridge.DCF.Examples.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 classProgram
Shows how to read a multiframe images and split it into individual frames.
Examples

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

    private static readonly string HelpString = String.Join(Environment.NewLine,
        "This example program works better with command line arguments.",
        "usage: SplitMultiFrameImage input_file_name output_directory [output_transfer_syntax]",
        "If output_transfer_syntax is unspecified, ELE will be used."
    );

    /// <summary>
    /// Main entry point for SplitMultiframeImage.
    /// </summary>
    /// <param name="args">command line arguments</param>
    [STAThread]
    private static void Main(string[] args)
    {
        try
        {
            if (args.Length < 2 || args.Length > 3)
            {
                Logger.Warn(HelpString);
                Environment.ExitCode = 1;
                return;
            }

            string inputFile = args[0];
            string outputDirectory = args[1];
            string outputTS = args.Length == 3 ? args[2] : Uids.ELE;

            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(inputFile, 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.GetProducer().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(outputDirectory))
                {
                    Directory.CreateDirectory(outputDirectory);
                }
                string baseName = Path.GetFileNameWithoutExtension(inputFile);
                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(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.GetProducer().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, outputTS, sessionSettings);
                    dfo.Open();
                    dfo.WriteDataSet(ds);
                    dfo.Close();
                }
                DicomDataSet trailingElements = pixelElement.GetProducer().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:");
        }

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