/// <summary>
        /// Gets the specified functional group for a specific frame in the data set.
        /// </summary>
        /// <remarks>
        /// This method automatically handles getting the correct functional group IOD class for the specified frame, regardless
        /// whether the functional group exists in the Per-Frame Functional Groups Sequence, or the Shared Functional Groups Sequence.
        /// </remarks>
        /// <param name="functionalGroupDescriptor">The functional group type (derived class of <see cref="FunctionalGroupMacro"/>).</param>
        /// <param name="dataSet">The DICOM data set of the composite image SOP instance.</param>
        /// <param name="frameNumber">The DICOM frame number to be retrieved (1-based index).</param>
        /// <param name="isFrameSpecific">Returns True if the functional group was invoked in the Per-Frame Functional Groups Sequence (5200,9230); returns False otherwise.</param>
        /// <returns>A new instance of <paramref name="functionalGroupDescriptor"/> wrapping the sequence item pertaining to the specified frame,.</returns>
        public static FunctionalGroupMacro GetFunctionalGroup(FunctionalGroupDescriptor functionalGroupDescriptor, IDicomAttributeProvider dataSet, int frameNumber, out bool isFrameSpecific)
        {
            Platform.CheckForNullReference(functionalGroupDescriptor, "functionalGroupType");
            Platform.CheckForNullReference(dataSet, "dataSet");
            Platform.CheckPositive(frameNumber, "frameNumber");
            isFrameSpecific = false;

            DicomAttribute sqAttribute;

            if (dataSet.TryGetAttribute(DicomTags.PerFrameFunctionalGroupsSequence, out sqAttribute) && sqAttribute.Count >= frameNumber)
            {
                var sequenceItem    = ((DicomAttributeSQ)sqAttribute)[frameNumber - 1];
                var functionalGroup = functionalGroupDescriptor.Create(sequenceItem);
                if (functionalGroup.HasValues())
                {
                    isFrameSpecific = true;
                    return(functionalGroup);
                }
            }

            if (dataSet.TryGetAttribute(DicomTags.SharedFunctionalGroupsSequence, out sqAttribute) && sqAttribute.Count > 0)
            {
                var sequenceItem    = ((DicomAttributeSQ)sqAttribute)[0];
                var functionalGroup = functionalGroupDescriptor.Create(sequenceItem);
                functionalGroup.DicomSequenceItem = sequenceItem;
                if (functionalGroup.HasValues())
                {
                    return(functionalGroup);
                }
            }

            return(null);
        }
        public void ListAmbiguousTagsBySopClass()
        {
            foreach (var uid in _multiframeSopClassUids)
            {
                const string msg = "SOP Class: {0}";
                Console.WriteLine(msg, SopClass.GetSopClass(uid).Name);
                ListTagsByParentSequence(FunctionalGroupDescriptor.GetApplicableFunctionalGroups(uid).Select(f => f.Create()), true);

                Console.WriteLine(new string('=', 32));
                Console.WriteLine();
            }
        }
        public void TestTagMappingBySopClass()
        {
            foreach (var uid in _multiframeSopClassUids)
            {
                var sopClass         = SopClass.GetSopClass(uid).Name;
                var functionalGroups = FunctionalGroupDescriptor.GetApplicableFunctionalGroups(uid).ToList();
                var tagGroups        = functionalGroups.Select(f => f.Create())
                                       .SelectMany(f => f.NestedTags.Select(t => new { TagValue = t, FunctionalGroup = f }))
                                       .GroupBy(u => u.TagValue).OrderBy(u => u.Key).ToList();

                foreach (var group in tagGroups)
                {
                    var dcmTag = DicomTagDictionary.GetDicomTag(group.Key);

                    // asserts that any tag defined in 'singleton' functional groups (those whose sequence can have at most 1 item) should have at least some mapping
                    var fgType = FunctionalGroupDescriptor.GetFunctionalGroupByTag(uid, group.Key);
                    if (fgType == null)
                    {
                        foreach (var entry in group)
                        {
                            Assert.IsTrue(entry.FunctionalGroup.CanHaveMultipleItems, "At least one singleton functional group defines tag {0} for SOP class {1}", dcmTag, sopClass);
                        }
                    }

                    // explicitly assert the mapping for any tag defined by multiple 'singleton' functional groups - so that if new tags are introduced later, we would explicitly consider what is the correct mapping
                    if (group.Count(g => !g.FunctionalGroup.CanHaveMultipleItems) > 1)
                    {
                        const string wrongMapMsg = "SOP Class {0} maps tag {1} to the wrong functional group";

                        if (uid == SopClass.EnhancedXaImageStorageUid)
                        {
                            switch (group.Key)
                            {
                            case DicomTags.TableHorizontalRotationAngle:
                            case DicomTags.TableHeadTiltAngle:
                            case DicomTags.TableCradleTiltAngle:
                                Assert.AreEqual(new FunctionalGroupDescriptor(typeof(XRayTablePositionFunctionalGroup)), fgType, wrongMapMsg, sopClass, dcmTag);
                                break;

                            default:
                                Assert.Fail("SOP Class {0} shouldn't have an ambiguous mapping for tag {1} - if new tags were added, please explicitly update the expected mapping in this unit test", sopClass, dcmTag);
                                break;
                            }
                        }
                        else
                        {
                            Assert.Fail("SOP Class {0} shouldn't have any ambiguous mappings - if new tags were added, please explicitly update the expected mapping in this unit test", sopClass);
                        }
                    }
                }
            }
        }
        public void TestFunctionalGroupApplicabilityBySopClass()
        {
            var commonGroups = new[]
            {
                typeof(PixelMeasuresFunctionalGroup),
                typeof(FrameContentFunctionalGroup),
                typeof(PlanePositionPatientFunctionalGroup),
                typeof(PlaneOrientationPatientFunctionalGroup),
                typeof(ReferencedImageFunctionalGroup),
                typeof(DerivationImageFunctionalGroup),
                typeof(CardiacSynchronizationFunctionalGroup),
                typeof(FrameAnatomyFunctionalGroup),
                typeof(PixelValueTransformationFunctionalGroup),
                // IdentityPixelValueTransformationFunctionalGroup is just PixelValueTransformationFunctionalGroup plus restrictions
                // FrameVoiLutFunctionalGroup is just a subset of FrameVoiLutWithLutFunctionalGroup
                typeof(FrameVoiLutWithLutFunctionalGroup),
                typeof(RealWorldValueMappingFunctionalGroup),
                typeof(ContrastBolusUsageFunctionalGroup),
                typeof(PixelIntensityRelationshipLutFunctionalGroup),
                typeof(FramePixelShiftFunctionalGroup),
                typeof(PatientOrientationInFrameFunctionalGroup),
                typeof(FrameDisplayShutterFunctionalGroup),
                typeof(RespiratorySynchronizationFunctionalGroup),
                typeof(IrradiationEventIdentificationFunctionalGroup),
                typeof(RadiopharmaceuticalUsageFunctionalGroup),
                typeof(PatientPhysiologicalStateFunctionalGroup),
                typeof(PlanePositionVolumeFunctionalGroup),
                typeof(PlaneOrientationVolumeFunctionalGroup),
                typeof(TemporalPositionFunctionalGroup),
                typeof(ImageDataTypeFunctionalGroup)
            };

            // asserts that a set exists for the empty string, and that it's only the 'common' functional groups defined in PS 3.3 C.7.6.16
            Assert.AreEqual(commonGroups.Select(t => new FunctionalGroupDescriptor(t)).OrderBy(t => t.Name).ToList(),
                            FunctionalGroupDescriptor.GetApplicableFunctionalGroups(string.Empty).OrderBy(t => t.Name).ToList(),
                            "A functional group set should exist that consists only of common (non-modality specific) functional groups");

            // asserts that GetApplicableFunctionalGroups returns common functional groups for unrecognized SOP classes
            Assert.AreEqual(FunctionalGroupDescriptor.GetApplicableFunctionalGroups(string.Empty).OrderBy(t => t.Name).ToList(),
                            FunctionalGroupDescriptor.GetApplicableFunctionalGroups("1.2.3.4").OrderBy(t => t.Name).ToList(),
                            "Unrecognized SOP classes should only return the common functional groups");

            // asserts that GetApplicableFunctionalGroups returns distinct functional groups
            foreach (var uid in _multiframeSopClassUids)
            {
                var results = FunctionalGroupDescriptor.GetApplicableFunctionalGroups(uid).ToList();
                Assert.IsTrue(results.Count == results.Distinct().Count(), "Non unique functional groups defined for {0}", SopClass.GetSopClass(uid).Name);
            }
        }
        public static bool TryGetMultiFrameAttribute(IDicomAttributeProvider dataSet, int frameNumber, uint dicomTag, out DicomAttribute dicomAttribute)
        {
            Platform.CheckForNullReference(dataSet, "dataSet");
            Platform.CheckPositive(frameNumber, "frameNumber");

            DicomAttribute attribute;
            var            sopClassUid = dataSet.TryGetAttribute(DicomTags.SopClassUid, out attribute) ? attribute.ToString() : string.Empty;

            var functionalGroupType = FunctionalGroupDescriptor.GetFunctionalGroupByTag(sopClassUid, dicomTag);

            if (functionalGroupType != null)
            {
                var functionalGroup = GetFunctionalGroup(functionalGroupType, dataSet, frameNumber);
                var item            = functionalGroup != null ? functionalGroup.SingleItem : null;
                if (item != null)
                {
                    return(item.TryGetAttribute(dicomTag, out dicomAttribute));
                }
            }

            dicomAttribute = null;
            return(false);
        }
Example #6
0
 private static IDictionary <uint, FunctionalGroupDescriptor> GetFunctionalGroupMap(ISopDataSource sopDataSource)
 {
     return(new MultiFrameFunctionalGroupsModuleIod(sopDataSource).HasValues() ? FunctionalGroupDescriptor.GetFunctionalGroupMap(sopDataSource.SopClassUid) : null);
 }
        /// <summary>
        /// Gets the specified functional group for a specific frame in the data set.
        /// </summary>
        /// <remarks>
        /// This method automatically handles getting the correct functional group IOD class for the specified frame, regardless
        /// whether the functional group exists in the Per-Frame Functional Groups Sequence, or the Shared Functional Groups Sequence.
        /// </remarks>
        /// <param name="functionalGroupDescriptor">The functional group type (derived class of <see cref="FunctionalGroupMacro"/>).</param>
        /// <param name="dataSet">The DICOM data set of the composite image SOP instance.</param>
        /// <param name="frameNumber">The DICOM frame number to be retrieved (1-based index).</param>
        /// <returns>A new instance of <paramref name="functionalGroupDescriptor"/> wrapping the sequence item pertaining to the specified frame.</returns>
        public static FunctionalGroupMacro GetFunctionalGroup(FunctionalGroupDescriptor functionalGroupDescriptor, IDicomAttributeProvider dataSet, int frameNumber)
        {
            bool dummy;

            return(GetFunctionalGroup(functionalGroupDescriptor, dataSet, frameNumber, out dummy));
        }
			public FrameFunctionalGroupKey(FunctionalGroupDescriptor functionalGroupDescriptor, int frameNumber)
			{
				_functionalGroupDescriptor = functionalGroupDescriptor;
				_frameNumber = frameNumber;
			}
        /// <summary>
        /// Initializes a new instance of <see cref="FunctionalGroupMapCache"/>.
        /// </summary>
        /// <param name="dataSet">The data set.</param>
        /// <param name="sopClassUid">Overrides the detected SOP class UID of the data set.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="dataSet"/> is NULL.</exception>
        public FunctionalGroupMapCache(IDicomAttributeProvider dataSet, string sopClassUid)
        {
            Platform.CheckForNullReference(dataSet, "dataSet");

            if (string.IsNullOrEmpty(sopClassUid))
            {
                sopClassUid = dataSet[DicomTags.SopClassUid].ToString();
            }

            _dataSet = dataSet;
            _cache   = new Dictionary <FrameFunctionalGroupKey, FrameFunctionalGroupValue>();
            _tagMap  = new MultiFrameFunctionalGroupsModuleIod(dataSet).HasValues() ? FunctionalGroupDescriptor.GetFunctionalGroupMap(sopClassUid) : null;
        }
 public FrameFunctionalGroupKey(FunctionalGroupDescriptor functionalGroupDescriptor, int frameNumber)
 {
     _functionalGroupDescriptor = functionalGroupDescriptor;
     _frameNumber = frameNumber;
 }