/// <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); }
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; }