Skip to content

Conversation

@abhijith-trenser
Copy link

@abhijith-trenser abhijith-trenser commented Oct 28, 2025

Context

Changes & Results

  • Added Radius, Mean, Maximum, and Minimum metrics to TID300 for Circle, Ellipse, and Polyline tools.
  • Introduced a helper function buildContentSequence to eliminate repetitive graphic data usage across tools.

What are the effects of this change?

The following tools in Cornerstone3D, Length, Bidirectional, Ellipse, Circle, Rectangle, and Freehand now include all annotation metrics without requiring rendering.

This feature applies only to newly created SRs. Existing SR files will not reflect these changes unless re-saved.

Testing

  • Launch a Study using /local
  • Draw annotations in different slices using different tools.
  • Open right side panel
  • Click 'Create SR' and save the SR with a file name.
  • Launch the same study along with the downloaded SR
  • Load the SR into viewport and confirm to track the study
  • Observe the annotations and all annotaions display all metrics without rendering it.

Checklist

PR

  • My Pull Request title is descriptive, accurate and follows the
    semantic-release format and guidelines.

Code

  • My code has been well-documented (function documentation, inline comments,
    etc.)

Public Documentation Updates

  • The documentation page has been updated as necessary for any public API
    additions or removals.

Tested Environment

  • OS: Windows 11
  • Node version: 22
  • Browser: Chrome 141.0.7390.123

@netlify
Copy link

netlify bot commented Oct 28, 2025

Deploy Preview for dcmjs2 ready!

Name Link
🔨 Latest commit 7de9823
🔍 Latest deploy log https://app.netlify.com/projects/dcmjs2/deploys/6941509fc5d23f00094c8013
😎 Deploy Preview https://deploy-preview-460--dcmjs2.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@abhijith-trenser abhijith-trenser marked this pull request as ready for review October 28, 2025 12:15
@sen-trenser
Copy link

@sedghi Could you please review this or suggest anyone that can help with approving the PR in dcmjs?
This is related to cornerstonejs/cornerstone3D#2392

@wayfarer3130
Copy link
Contributor

@sen-trenser - could you:

  1. Attach an example dcm file for a planar freeform with 2 different types of measurement values?
  2. Run dciodvfy on the example dcm file
  3. Annotate a dcmdump verison of the example with your changes?
    It would just help a lot to have it well documented as to what the changes look like in terms of generated output.

@nithin-trenser
Copy link

@wayfarer3130 We found some errors when run dciodvfy on the example dcm file. Currently resolving these errors.

@nithin-trenser
Copy link

@wayfarer3130
Please find the attachment below.

  1. Attach an example dcm file for a planar freeform with 2 different types of measurement values?
  2. Annotate a dcmdump verison of the example with your changes?

@sen-trenser
Copy link

@wayfarer3130 We had some modifications to fix errors reported by the dciodvfy tool. Could you please check the attached data @nithin-trenser provided above?

Please check the area marked with text #################### in the sr-all-annotations.txt to see the new content changes.

@wayfarer3130
Copy link
Contributor

There is the concept of INFERRED FROM allowing references to a common layout to be used - that basically looks like below:
Note the ReferencedContentItemIdentifier
It is legal to put those under ONLY the second and subsequent measurement. That isn't the "preferred" DICOM way, but it is legal DICOM as far as I know, and I believe is compliant with our parsing. The problem with just repeating data is that there isn't a way to tell it is actually the same/consistent data, and there are circumstances when it actually uses different data.
Would it be possible for you to make that tweak as well to reference the first set of data?

(0040,a730) SQ (Sequence with undefined length #=3) # u/l, 1 ContentSequence
(fffe,e000) na (Item with undefined length #=7) # u/l, 1 Item 1: SCOORD ROI
(0040,a010) CS [CONTAINS] # 10, 1 RelationshipType
(0040,a040) CS [SCOORD] # 6, 1 ValueType
(0040,a043) SQ (Sequence with undefined length #=1) # u/l, 1 ConceptNameCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [121071] # 6, 1 CodeValue (example: “Region of Interest”)
(0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [ROI] # 4, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(0040,a730) SQ (Sequence with undefined length #=1) # u/l, 1 ContentSequence (child: IMAGE)
(fffe,e000) na (Item with undefined length #=4) # u/l, 1 Item 1.1: IMAGE
(0040,a010) CS [SELECTED FROM] # 14, 1 RelationshipType
(0040,a040) CS [IMAGE] # 6, 1 ValueType
(0008,1199) SQ (Sequence with undefined length #=1) # u/l, 1 ReferencedSOPSequence
(fffe,e000) na (Item with undefined length #=2) # u/l, 1 Item
(0008,1150) UI =CTImageStorage # 26, 1 ReferencedSOPClassUID
(0008,1155) UI [1.2.3.4.5.6.7.8.9] # xx, 1 ReferencedSOPInstanceUID (PUT YOUR UID HERE)
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(0070,0022) FL 202.8033\60.46706\202.8033\114.96518\193.98744\87.716118\211.61917 # 32, 8 GraphicData
(0070,0023) CS [ELLIPSE] # 8, 1 GraphicType
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem

(fffe,e000) na (Item with undefined length #=6) # u/l, 1 Item 2: NUM Measurement #1
(0040,a010) CS [CONTAINS] # 10, 1 RelationshipType
(0040,a040) CS [NUM] # 4, 1 ValueType
(0040,a043) SQ (Sequence with undefined length #=1) # u/l, 1 ConceptNameCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [121206] # 6, 1 CodeValue (example: “Length”)
(0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [Length] # 6, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(0040,a300) SQ (Sequence with undefined length #=1) # u/l, 1 MeasuredValueSequence
(fffe,e000) na (Item with undefined length #=4) # u/l, 1 Item
(0040,a30a) DS [12.3] # 4, 1 NumericValue (PUT YOUR VALUE)
(0040,08ea) SQ (Sequence with undefined length #=1) # u/l, 1 MeasurementUnitsCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [mm] # 2, 1 CodeValue
(0008,0102) SH [UCUM] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [millimeter] # 10, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(0040,a730) SQ (Sequence with undefined length #=1) # u/l, 1 ContentSequence (evidence: by-reference)
(fffe,e000) na (Item with undefined length #=2) # u/l, 1 Item 2.1: by-reference to SCOORD
(0040,a010) CS [INFERRED FROM] # 14, 1 RelationshipType
(0040,db73) UL 1 # 4, 1 ReferencedContentItemIdentifier (REFERS TO ITEM 1)
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem

(fffe,e000) na (Item with undefined length #=6) # u/l, 1 Item 3: NUM Measurement #2
(0040,a010) CS [CONTAINS] # 10, 1 RelationshipType
(0040,a040) CS [NUM] # 4, 1 ValueType
(0040,a043) SQ (Sequence with undefined length #=1) # u/l, 1 ConceptNameCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [121207] # 6, 1 CodeValue (example: “Area”)
(0008,0102) SH [DCM] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [Area] # 4, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(0040,a300) SQ (Sequence with undefined length #=1) # u/l, 1 MeasuredValueSequence
(fffe,e000) na (Item with undefined length #=4) # u/l, 1 Item
(0040,a30a) DS [45.6] # 4, 1 NumericValue (PUT YOUR VALUE)
(0040,08ea) SQ (Sequence with undefined length #=1) # u/l, 1 MeasurementUnitsCodeSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(0008,0100) SH [mm2] # 3, 1 CodeValue
(0008,0102) SH [UCUM] # 4, 1 CodingSchemeDesignator
(0008,0104) LO [square millimeter] # 17, 1 CodeMeaning
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(0040,a730) SQ (Sequence with undefined length #=1) # u/l, 1 ContentSequence (evidence: by-reference)
(fffe,e000) na (Item with undefined length #=2) # u/l, 1 Item 3.1: by-reference to SCOORD
(0040,a010) CS [INFERRED FROM] # 14, 1 RelationshipType
(0040,db73) UL 1 # 4, 1 ReferencedContentItemIdentifier (REFERS TO ITEM 1)
(fffe,e00d) na (ItemDelimitationItem) # 0, 0
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem

@wayfarer3130
Copy link
Contributor

@pieper - for the saving of SR annotations, I'm proposing that second and subsequent measurements use references to the annotation definition in the first measurement value - that is, a structure like:

measurement value 1:
max value MAX
annotation graphic data ....
measurement value 2:
min value: MIN
annotation reference: 1/1 (refers to first sub-sequence of the shared measurement value, starting from the shared parent.)

The TID 1500 canonical way I believe is:
annotation graphic data: ...
measurement value 1:
max value MAX
annotation reference: 1
measurement value 2:
min value MIN
annotation reference: 2

As I read part 16, I THINK either way is acceptable, but I'm not 100% sure. The point in either one is to avoid duplicating the image/graphic data references so that there is no chance that they are different. That is only done when they actually ARE the same - things like bidirectional are not the same annotations first/second.

Might ask David what he thinks about this? I'd very much prefer not to go down something not standards compliant.

@nithin-trenser
Copy link

@wayfarer3130
Please find attached the dcmdump for the new SR report generated with the ReferencedContentItemIdentifier tag. Could you take a look and provide your feedback?
all-annotations.txt
cc: @sen-trenser

];
if (radius) {
measurements.push({
RelationshipType: "CONTAINS",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with this as it is, but it would be nice to have simple helper classes that just constructed this object via arguments, eg:
measurements.push(new RadiusReference(radius, annotationIndex))
Or maybe RadiusMeasuredValue.

];

if (max) {
measurements.push({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, all of these would become simpler if you just reference a structure class like MaximumValueReference(max, modalityUnit, annotationIndex)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created helper function for this.

use3DSpatialCoordinates
});

const graphicContentSequence = buildContentSequence({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely find the new version easier to read

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defined new class and used it here.

]);
];

if (max) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might even extract the full set of reference values here as a standard extractor for "area" measurements rather than including it in each measurement type. Again, not required, just suggesting ways to clean things up a bit more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created helper function for this.

* Builds a DICOM SR ContentSequence block for geometric measurements
* that share the same structure across tools (Circle, Ellipse, Polyline, etc.)
*/
export default function buildContentSequence({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pieper - is there a better name for this that says exactly what this does? content sequence is a bit too generic.

Also, the general dcmjs pattern for this is as a constructor.

How about:
class Tid320ContentItem

constructor({
graphicType,
graphicData,
use3DSpatialCoordinates = false,
referencedSOPSequence,
referencedFrameOfReferenceUID}

and then assign to this.
I believe that meets the pattern.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done as suggested. Created a class Tid320ContentItem for create content sequence.

if (!codingUnit) {
log.error("Unspecified units", units);
return MM_UNIT;
return generateUnitMap(units);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much as I like this change, it isnt actually valid and can result in ill defined units.
You can expand the list of UCUM units that are available, but not create a new one arbitrarily. If you want to do it this way, then use coding scheme designator "99dcmjsUnit and omit the scheme version, or set it to the version this got added in.

Copy link

@nithin-trenser nithin-trenser Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve updated the implementation to include support for all DICOM-defined UCUM-compatible measurement units.
DICOM explicitly states that:
DICOM has now adopted the Unified Codes for Units of Measurement (UCUM) standard for all units of measurement.
This Coding Scheme allows for the construction of pre-coordinated codes from atomic components.

To ensure correctness, the supported units now come from the official DICOM
context groups that define UCUM and UCUM-compatible extensions:

cc: @sen-trenser

Copy link

@dclunie dclunie Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case you want to check the validity of any UCUM code values that you generate (or adopt from the DICOM standard or someone else's examples), you may find my UCUMAnalyzer helpful, available at this site.
Note that the unistofmeasure.org site referenced therein seems to be dead (archived at https://web.archive.org/web/20190310234558/http://unitsofmeasure.org/trac), and ucum.org seems to be the new site.

E.g.:

% java -cp ./pixelmed_ucum.jar:./antlr-2.7.5.jar com.pixelmed.ucum.UCUMAnalyzer "mm2"
Canonical form = ( / ( . 1.0E-6  m m ) ( . null ) )

% java -cp ./pixelmed_ucum.jar:./antlr-2.7.5.jar com.pixelmed.ucum.UCUMAnalyzer "[hnsf'U]"
Canonical form = ( / ( . 1.0  [hnsf'U] ) ( . null ) )

There are other UCUM tools available than mine, but I don''t have a current list.

Copy link
Contributor

@wayfarer3130 wayfarer3130 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two nice to haves to extract the functionality for creating TID320 content items and sets of content items, and one must change to avoid creating invalid UCUM units.

Copy link
Contributor

@wayfarer3130 wayfarer3130 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pieper - I'm good with this PR now. Are you ok with me merging it?

@pieper
Copy link
Collaborator

pieper commented Dec 2, 2025

There's a test failing. CoPilot says it's due to unicode for mm2, can you look into making the tests pass?

In general I'm good with this but haven't looked at the details. I would like to run the resulting files past @dclunie.

Are you able to create some examples using the latest version of this code? Is it possible to run something like viewer.ohif.org/local using the PR branches and then share the files so they can be dropped onto the update ohif?

@dclunie
Copy link

dclunie commented Dec 3, 2025

@wayfarer3130 - You can find a bunch of TID 1500 based SRs in IDC, e.g., search on modality SR AND CT or similar.

One example with a single ROI with lots of derived measurements (though not, as it happens, area, and with the ROI defined by a referenced SEG object rather than SCOORDs) is the SR in Study 1.2.840.113654.2.55.187766322555605983451267194286230980878 Series 1.2.276.0.7230010.3.1.3.313263360.24152.1706320739.615770 that you can get from s3://idc-open-data/808d0675-a028-441c-b6d8-602115d2ebec/90470bd5-0949-436c-b4dd-5d725353192e.dcm 90470bd5-0949-436c-b4dd-5d725353192e.dcm.

It uses TID 1411 rather than TID 1410 since it is referring to a volume rather than a planar region, but you get the idea. Both have Row 5 versus Row 7 alternatives for SCOORD or IMAGE (SEG) specification of the region.

You may recall that @fedorov et al worked on this sort of think in QIICR, but unfortunately the QIN-HEADNECK collection is no longer publicly available since TCIA's masters became concerned about faces, then their masters about controlled data access policy.

@dclunie
Copy link

dclunie commented Dec 3, 2025

Short version: (1,UCUM,"no units") if nothing more specific (like ([hnsf'U], UCUM, "Hounsfield unit")) known.

TL;DNR:

@wayfarer3130 - wrt. "Gy is the UCUM value that CS3D uses 'px' for" - "Grey" (UCUM 'Gy') is a unit of ionizing radiation dose, and has nothing to do with "greyscale" "intensity" interpretation of a pixel value.

I gather from "what UCUM unit is used for RGB probe values" that you are looking for units for the pixel intensity in different settings, but don't confuse "units" with the "quantity" - e.g., see the discussion in the context of real-world value mapping in PS3.3.

Compare CID 7180 Abstract Multi-dimensional Image Model Component Semantic with CID 7181 Abstract Multi-dimensional Image Model Component Unit.

E.g., the measurement at a single point might be (112031,DCM,"Attenuation Coefficient") or (110852,DCM,"MR signal intensity"), or for a non-point region, the mean or similar thereof (perhaps described as derivation), but the units would then be ([hnsf'U], UCUM, "Hounsfield unit") or dimensionless if unspecified or unknown (e.g., by using (1,UCUM,"no units"), or ({0:255}, UCUM, "range: 0:255") if you wanted to specify the dimensionless range, e.g., derived from BitsStored).

Note that for the physical quantity (not the unit), DICOM does define in CID 7180 Abstract Multi-dimensional Image Model Component Semantic codes for the R, G and B component of an image; but these were not intended to be used as units.

I understand that it can be difficult to determine what to encoded as a finding, a measurement, a method, a derivation and what to specify as units, and how this relates to the concept of a quantity, and very often the concept is left to be implicit (and or bound into some pre-coordinated concept for the measurement rather than being post-coordinated). E.g., in the case of the radiomics example I referred you to earlier, we have:

		>>CONTAINS: CONTAINER: (125007,DCM,"Measurement Group")  [SEPARATE] (DCMR,1411)
			>>> ...
			>>>CONTAINS: CODE: (121071,DCM,"Finding")  = (123037004,SCT,"Anatomical Structure")
			>>> ...
			>>>HAS CONCEPT MOD: CODE: (363698007,SCT,"Finding Site")  = (68455001,SCT,"Iliopsoas muscle")
				>>>>HAS CONCEPT MOD: CODE: (272741003,SCT,"Laterality")  = (24028007,SCT,"Right")
			>>>CONTAINS: NUM: (QG58,IBSI,"10th percentile")  = -223.6 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (8DWT,IBSI,"90th percentile")  = 262.2 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (N8CA,IBSI,"Energy")  = 3971162 ([hnsf'U]2,UCUM,"square Hounsfield Unit")
			>>>CONTAINS: NUM: (TLU2,IBSI,"Intensity Histogram Entropy")  = 4.533 (1,UCUM,"no units")
			>>>CONTAINS: NUM: (SALO,IBSI,"Interquartile range")  = 240.0 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (84IY,IBSI,"Maximum grey level")  = 512 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (4FUA,IBSI,"Mean absolute deviation")  = 137.214 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (Q4LE,IBSI,"Mean")  = 46.208 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (Y12H,IBSI,"Median")  = 64.0 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (1GSF,IBSI,"Minimum grey level")  = -292 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (2OJQ,IBSI,"Range")  = 804 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (1128,IBSI,"Robust mean absolute deviation")  = 94.997 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (5ZWQ,IBSI,"Root mean square")  = 178.239 ([hnsf'U],UCUM,"Hounsfield Unit")
			>>>CONTAINS: NUM: (KE2A,IBSI,"Skewness")  = -0.109 (1,UCUM,"no units")
			>>>CONTAINS: NUM: (BJ5W,IBSI,"Intensity histogram uniformity")  = 0.05 (1,UCUM,"no units")
			>>>CONTAINS: NUM: (ECT3,IBSI,"Variance")  = 29634.117 ([hnsf'U]2,UCUM,"square Hounsfield Unit")
			>>>CONTAINS: NUM: (IPH6,IBSI,"Kurtosis")  = -0.418 (1,UCUM,"no units")

I.e., the fact that all of these measurements are measurements of attenuation coefficient is never explicitly described.

BTW., In case you are not aware of it, the IBSI work is a great reference, and we use many of their codes in DICOM PS3.16 and recognize them as a coding scheme; see the manual and the Radiology paper and their github repo. They are grayscale MR focussed but most of their concepts are generalizable.

@dclunie
Copy link

dclunie commented Dec 4, 2025

Wrt. code meanings for UCUM measurements, PS3.16 is very inconsistent wrt. various different patterns for the "code meaning" (what HL7 calls the "display name"); in the past we have not obsessed about this since it is the code value that matters from precision of communication, and machine recognition perspectives.

However, there are some folks who want to rationalize this, and to quote from a recent proposed new DICOM CP:

Variations include:
- short forms versus long forms: “mm” (125x) vs. “millimeter” (20x) 
- different capitalization (“Year” vs. “year” / “week” vs. “Week”)
- variations in plural (“day” vs. “days” / 
...
Prominent examples are:
UCUM CodeValue with CodeMeanings  : 
“s”		“s” (32x) 	 “Second” (1x) 		“second” (3x) 	“seconds” (1x)
“deg”		“Degree” (1x)  	“deg” (59x)		“degree” (3x)	 “degrees” (3x)
...
For all CodeValues, check ... the CodeMeaning ...
- The most used form shall be given precedence
- There shall be only one entry per CodeValue ...

Though the current text about what can be used in code meaning is fairly flexible:

  • the "print" value specified in UCUM (e.g., "mmHg" for Code Value mm[Hg])
  • the same string as sent in the Code Value (e.g., "ml/s")
  • constructed from the "names" of individual components using the Americanized form of name (e.g., "milliliters/second")
  • constructed from the "names" of individual components using the European form of name (e.g., " millilitres /second")

it is possible this will get modified (e.g., to recommend singular rather than plural forms, or to more strongly emphasize the use of the UCUM "print" value when it is encodable in the default character set).

It is also possible that explicit use of different code meanings in different contxet groups will change (e.g., to use one pattern uniformly in all context groups, despite the possibly variants that are recognized).

The general rules for what to include in code meaning remain applicable though:

Code Meaning (0008,0104) is a purely annotative, descriptive Attribute ... This does not imply that Code Meaning (0008,0104) can be filled with arbitrary free text. Available values from the Coding Scheme or translation in the chosen language shall be used.

CodingSchemeDesignator: "UCUM",
CodingSchemeVersion: "1.4",
CodeMeaning: "px"
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this one was missed - @dclunie commented that it should be fixed I believe.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, don't use CodingSchemeVersion

@sen-trenser
Copy link

wrt. "Gy is the UCUM value that CS3D uses 'px' for" - "Grey" (UCUM 'Gy') is a unit of ionizing radiation dose, and has nothing to do with "greyscale" "intensity" interpretation of a pixel value.

I gather from "what UCUM unit is used for RGB probe values" that you are looking for units for the pixel intensity in different settings, but don't confuse "units" with the "quantity" - e.g., see the discussion in the context of real-world value mapping in PS3.3.

@wayfarer3130 What would be the recommended way to represent pixels count?

Measurement Units Code Sequence (0040,08EA) = (130922,DCM,"Number of pixels")
or
Quantity Definition Sequence (0040,9220)=(246205007,SCT,"Quantity")
https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.16.2.html#sect_C.7.6.16.2.11.1.2:~:text=The%20quantity%20that%20the%20Real%20World%20Values%20represent%20may%20be%20described%20by%20the%20Quantity%20Definition%20Sequence%20(0040%2C9220

@wayfarer3130
Copy link
Contributor

wrt. "Gy is the UCUM value that CS3D uses 'px' for" - "Grey" (UCUM 'Gy') is a unit of ionizing radiation dose, and has nothing to do with "greyscale" "intensity" interpretation of a pixel value.
I gather from "what UCUM unit is used for RGB probe values" that you are looking for units for the pixel intensity in different settings, but don't confuse "units" with the "quantity" - e.g., see the discussion in the context of real-world value mapping in PS3.3.

@wayfarer3130 What would be the recommended way to represent pixels count?

Measurement Units Code Sequence (0040,08EA) = (130922,DCM,"Number of pixels") or Quantity Definition Sequence (0040,9220)=(246205007,SCT,"Quantity") https://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.16.2.html#sect_C.7.6.16.2.11.1.2:~:text=The%20quantity%20that%20the%20Real%20World%20Values%20represent%20may%20be%20described%20by%20the%20Quantity%20Definition%20Sequence%20(0040%2C9220

According to the earlier bit of the post from someone who wrote a good bit of the DICOM standard, the correct answer is:

Short version: (1,UCUM,"no units") if nothing more specific (like ([hnsf'U], UCUM, "Hounsfield unit")) known.

If the attribute being measured is clearly in the context of a pixel/area measurement or probe, then no units is clearly equivalent to px as that is actually what we are trying to convey with px that there isn't a unit with it. I'd prefer something more exact but there doeesn't seem to be anything.

@dclunie
Copy link

dclunie commented Dec 8, 2025

What would be the recommended way to represent pixels count?

This depends a lot on whether the count is relative to an unspecified area or volume (and therefore multiples of unity), or counts per a defined measure of space (e.g., count/mm2).

So flavors of unity will often work, even some variant of the thing being counted ({pixels}), but sometimes you want to be more specific, e.g., see CID 4290, which is one of the few examples of this in PS3.16, which actually are specific about what they are counting to (cells).

PS. We are not clear yet on whether the thing in curly braces should be singular or plural (e.g., '{pixel}' versus '{pixels}'), or if either is OK.

@sen-trenser
Copy link

sen-trenser commented Dec 15, 2025

@wayfarer3130 As we are aiming to include this MR in the upcoming OHIF 3.12 release, we would appreciate a review of the remaining open items, the proposed implementation approaches, and any clarifications needed on the points outlined below.

1. Replace non-standard or incorrect units with proper UCUM units

Requested change

Replace usages such as (HU, 99dcmjsUnit, "HU") with standard UCUM units, e.g. ([hnsf'U], UCUM, "Hounsfield unit")

Status

Planned. Some additional unit support is already introduced in this PR; remaining normalization can be completed.

2. Normalize UCUM CodeMeaning values

Requested change

Shorten the verbose CodeMeaning values "SquareMilliMeter" to "mm2"

Status

Partially implemented

Clarification needed

Should we consistently prefer UCUM canonical form (mm2), or UCUM print form for CodeMeaning Millimeter**2 or Square millimeter as given in this table ?

3. Dimensionless measurements

Requested change

Use (1, UCUM, "no units") when a measurement is dimensionless or has no meaningful unit (eg: px, px2).

Current behavior

Measurements without units are currently treated as px.

Clarification / Dependency

This behavior currently originates from the CS3D layer.

  • If it records as no units, how can viewer identify and differentiate perimeter (px), area (px2) etc. when reading and restoring the values when reading back from a saved SR report?
  • Please clarify whether dcmjs should explicitly emit (1, UCUM, "no units"), or CS3D should remain responsible for unit selection.

4. SCT (SNOMED CT) code adoption

Requested change

Replace SRT codes with SCT (SNOMED CT) codes

e.g. (G-A166, SRT, "Area") to (42798000, SCT, "Area")

Status

Partially implemented

5. Avoid custom placeholder codes (99dcmjs)

Requested change

Avoid codes such as (1, 99dcmjs, "Unknown procedure")

Use CID 100 or modality-appropriate standard codes, e.g. (363679005, SCT, "Imaging procedure")

Status

Planned

6. Appearance related data in SR content

Requested change

Do not include appearance or UI-related elements like (TextPosition, 99CS3D, "Text Annotation Position"). SR content should store semantic meaning only.

Related requirement

For all SCOORD items, GraphicType is mandatory and must be populated.

Status

GraphicType handling appears fixed in generated SR, we will revisit and confirm this;
Appearance-only elements will be removed where still present.

Clarification and planning

Does this break compatibility with already created SR reports and how end users uses the data?

7. Correct use of R-INFERRED FROM and content item referencing

Although TID 1501/TID 320 R-INFERRED FROM is allowed, it must reference the correct hierarchically indexed shared graphic item content, using ReferencedContentItemIdentifier.

The current annotationIndex usage is incorrect, it should use the element position reference in the SR report DICOM structure to reference geometry from other places

Status

Planned.
No errors or warnings are currently reported by

  • dcmdump
  • dciodvfy
  • dsrdump

Any changes on SR DICOM structure after dcmjs DICOM generation will break the reference numbers. Warn in documentation that users must not modify generated SR data on-before or on-after SR data generation or save.

Reference correctness is under analysis. This may need an index tracker to ensure correct hierarchy levels are tracked and used for referencing data.

8. TID 1410 adoption and other compatibility

Requested change

There is a strong recommendation to adopt TID 1410 (multiple measurements under a single ROI) in place of the current TID 1501 / TID 320–based structure.

In addition, the generated SR structure should be aligned with established references and best practices, including

  • TID 1410 / TID 1411 structural patterns
  • IBSI-recommended unit representations
  • IDC reference examples
  • QIICR precedents for SR loading and interpretation in 3D Slicer

Impact

This change represents a significant structural refactor and would require coordinated updates across multiple codebases, including

  • dcmjs
  • Cornerstone3D
  • OHIF

Additionally, a clear strategy for backward compatibility with existing stored SR measurements would need to be defined and implemented.

Clarification and planning

Given the scope and cross-repository impact of this change, and they may not be a blocker for this PR, we would like to request clarification on preferred approach.

Should this be planned and executed as a separate, dedicated refactoring effort, or is it preferable to address this in a single coordinated change, to avoid multiple SR format transitions and potential compatibility issues?

Thanks!

@dclunie
Copy link

dclunie commented Dec 15, 2025

@sen-trenser The tools you mention are not sufficient to detect failure to comply with the IOD constraints on value and relationship types, nor failure to comply with the template structure.

You need to use is DicomSRValidator from PixelMed or similar for that.

If you do not either (a) correct or (b) explain away the output of DicomSRValidator, then it is very likely that your SR objects are invalid.

Planned. No errors or warnings are currently reported by

  • dcmdump
  • dciodvfy
  • dsrdump

@dclunie
Copy link

dclunie commented Dec 15, 2025

@sen-trenser

Can whether a measurement is a linear distance, area, volume, or something else, not be determined from the measurement itself and not the units, i.e., from the ConceptNameCodeSequence of the NUM that is the measurement?

You are using codes for Area, Perimeter, etc. for that, right?

  • If it records as no units, how can viewer identify and differentiate perimeter (px), area (px2) etc. when reading and restoring the values when reading back from a saved SR report?

@sen-trenser
Copy link

We will verify with the Pixelmed DicomSRValidator as well. Thank you for creating these applications.

@sen-trenser The tools you mention are not sufficient to detect failure to comply with the IOD constraints on value and relationship types, nor failure to comply with the template structure.

You need to use is DicomSRValidator from PixelMed or similar for that.

If you do not either (a) correct or (b) explain away the output of DicomSRValidator, then it is very likely that your SR objects are invalid.

Yes. We can use the SCT code in ConceptNameCodeSequence for differentiating perimeter, area etc.

Currently, the SR records AREA, Perimeter in SRT also. We should be converting those to SCT. However, we should look into backward compatibility with previous OHIF generated SR data as well.

@sen-trenser

Can whether a measurement is a linear distance, area, volume, or something else, not be determined from the measurement itself and not the units, i.e., from the ConceptNameCodeSequence of the NUM that is the measurement?

You are using codes for Area, Perimeter, etc. for that, right?

Thank you!

@wayfarer3130
Copy link
Contributor

@wayfarer3130 As we are aiming to include this MR in the upcoming OHIF 3.12 release, we would appreciate a review of the remaining open items, the proposed implementation approaches, and any clarifications needed on the points outlined below.

1. Replace non-standard or incorrect units with proper UCUM units

Requested change

Replace usages such as (HU, 99dcmjsUnit, "HU") with standard UCUM units, e.g. ([hnsf'U], UCUM, "Hounsfield unit")

Status

Planned. Some additional unit support is already introduced in this PR; remaining normalization can be completed.

Do you mean that the remaining normalization can be completed in the CS3D codebase, or is there more work to be done in the dcmjs codebase?

2. Normalize UCUM CodeMeaning values

Requested change

Shorten the verbose CodeMeaning values "SquareMilliMeter" to "mm2"

Status

Partially implemented

Can this be completed as far as the dcmjs codebase is concerned?

Clarification needed

Should we consistently prefer UCUM canonical form (mm2), or UCUM print form for CodeMeaning Millimeter**2 or Square millimeter as given in this table ?

Prefer mm2 UCUM canonical form please.

3. Dimensionless measurements

Requested change

Use (1, UCUM, "no units") when a measurement is dimensionless or has no meaningful unit (eg: px, px2).

Current behavior

Measurements without units are currently treated as px.

As suggested elsewhere, please include the no units in order to be compliant with the spec, and then determine what it means based on the fact that it is area/volume/max/min etc.

Clarification / Dependency

This behavior currently originates from the CS3D layer.

  • If it records as no units, how can viewer identify and differentiate perimeter (px), area (px2) etc. when reading and restoring the values when reading back from a saved SR report?
  • Please clarify whether dcmjs should explicitly emit (1, UCUM, "no units"), or CS3D should remain responsible for unit selection.

CS3D should be responsible for unit selection, and dcmjs should provide all the constants/mapping for the unit codes so that CS3D can easily just select the appropriate code and it could be fixed/updated in the future for specific text value etc.

4. SCT (SNOMED CT) code adoption

Requested change

Replace SRT codes with SCT (SNOMED CT) codes

e.g. (G-A166, SRT, "Area") to (42798000, SCT, "Area")

Status

Partially implemented

Although a nice to have, this is a deprecated value that is permitted. It would be nice to update the remaining codes to SCT codes, but I don't think that should be required to accept the PR.

5. Avoid custom placeholder codes (99dcmjs)

Requested change

Avoid codes such as (1, 99dcmjs, "Unknown procedure")

Use CID 100 or modality-appropriate standard codes, e.g. (363679005, SCT, "Imaging procedure")

Status

Planned

Lets get this one updated. Just use Imaging Procedure on anything unknown should be sufficient. Please ensure there is a constant exported for this so that CS3D can just use the exported constant.

6. Appearance related data in SR content

Requested change

Do not include appearance or UI-related elements like (TextPosition, 99CS3D, "Text Annotation Position"). SR content should store semantic meaning only.

Related requirement

For all SCOORD items, GraphicType is mandatory and must be populated.

I KNOW this isn't in keeping with the recommendation for semantic meaning only, but storing this in this way in useful for a lot of users. Make it work for real users trumps intended use of some of the data that is still compliant with the actual standard. Please keep this in. We should update the storage on the CS3D side to only include this when the position has been updated.

Status

GraphicType handling appears fixed in generated SR, we will revisit and confirm this; Appearance-only elements will be removed where still present.

PLEASE do not remove appearance only items

Clarification and planning

Does this break compatibility with already created SR reports and how end users uses the data?

7. Correct use of R-INFERRED FROM and content item referencing

Although TID 1501/TID 320 R-INFERRED FROM is allowed, it must reference the correct hierarchically indexed shared graphic item content, using ReferencedContentItemIdentifier.

The current annotationIndex usage is incorrect, it should use the element position reference in the SR report DICOM structure to reference geometry from other places

Status

Planned. No errors or warnings are currently reported by

  • dcmdump
  • dciodvfy
  • dsrdump

Any changes on SR DICOM structure after dcmjs DICOM generation will break the reference numbers. Warn in documentation that users must not modify generated SR data on-before or on-after SR data generation or save.

Actually, the parsing side of things completely ignores the R-INFERRED FROM information, so as long as it is correct for the SR verify tool when created, I don't think you need to be too careful about it.

Reference correctness is under analysis. This may need an index tracker to ensure correct hierarchy levels are tracked and used for referencing data.

8. TID 1410 adoption and other compatibility

Requested change

There is a strong recommendation to adopt TID 1410 (multiple measurements under a single ROI) in place of the current TID 1501 / TID 320–based structure.

In addition, the generated SR structure should be aligned with established references and best practices, including

  • TID 1410 / TID 1411 structural patterns
  • IBSI-recommended unit representations
  • IDC reference examples
  • QIICR precedents for SR loading and interpretation in 3D Slicer

Impact

This change represents a significant structural refactor and would require coordinated updates across multiple codebases, including

  • dcmjs
  • Cornerstone3D
  • OHIF

Additionally, a clear strategy for backward compatibility with existing stored SR measurements would need to be defined and implemented.

Clarification and planning

Given the scope and cross-repository impact of this change, and they may not be a blocker for this PR, we would like to request clarification on preferred approach.

Should this be planned and executed as a separate, dedicated refactoring effort, or is it preferable to address this in a single coordinated change, to avoid multiple SR format transitions and potential compatibility issues?

Please do this as a planned approach as a separate PR. I'd love to have it in this one, it just doesn't make sense to update this further when there are already existing creators out there doing it the way you have currently updated it to.

Thanks!

@sen-trenser
Copy link

sen-trenser commented Dec 15, 2025

@wayfarer3130 Thank you for the quick reply.

1. Replace non-standard or incorrect units with proper UCUM units

Requested change
Replace usages such as (HU, 99dcmjsUnit, "HU") with standard UCUM units, e.g. ([hnsf'U], UCUM, "Hounsfield unit")
Status
Planned. Some additional unit support is already introduced in this PR; remaining normalization can be completed.

Do you mean that the remaining normalization can be completed in the CS3D codebase, or is there more work to be done in the dcmjs codebase?

The planned items are to be done in this dcmjs PR.

2. Normalize UCUM CodeMeaning values

Requested change
Shorten the verbose CodeMeaning values "SquareMilliMeter" to "mm2"
Status
Partially implemented

Can this be completed as far as the dcmjs codebase is concerned?

Yes

Clarification needed
Should we consistently prefer UCUM canonical form (mm2), or UCUM print form for CodeMeaning Millimeter**2 or Square millimeter as given in this table ?

Prefer mm2 UCUM canonical form please.

Okay. Thanks for confirming.

3. Dimensionless measurements

Requested change
Use (1, UCUM, "no units") when a measurement is dimensionless or has no meaningful unit (eg: px, px2).
Current behavior
Measurements without units are currently treated as px.

As suggested elsewhere, please include the no units in order to be compliant with the spec, and then determine what it means based on the fact that it is area/volume/max/min etc.

We will update it.

Clarification / Dependency
This behavior currently originates from the CS3D layer.

  • If it records as no units, how can viewer identify and differentiate perimeter (px), area (px2) etc. when reading and restoring the values when reading back from a saved SR report?
  • Please clarify whether dcmjs should explicitly emit (1, UCUM, "no units"), or CS3D should remain responsible for unit selection.

CS3D should be responsible for unit selection, and dcmjs should provide all the constants/mapping for the unit codes so that CS3D can easily just select the appropriate code and it could be fixed/updated in the future for specific text value etc.

Okay. We will add the currently used mappings in dcmjs.

Although not planned in the scope of this PR, as there are lots of SCT codes defined, and CS3D annotations can be extended, wouldn't it be a good idea for later to allow DCMJS consumers to register TID converters which can provide their own standard SCT ConceptNameCodeSequence definitions and MeasurementUnitsCodeSequence definitions to record custom data into SR and restore later?

4. SCT (SNOMED CT) code adoption

Requested change
Replace SRT codes with SCT (SNOMED CT) codes
e.g. (G-A166, SRT, "Area") to (42798000, SCT, "Area")
Status
Partially implemented

Although a nice to have, this is a deprecated value that is permitted. It would be nice to update the remaining codes to SCT codes, but I don't think that should be required to accept the PR.

Okay. We will check if we can modify this without breaking SR backward compatibility.

5. Avoid custom placeholder codes (99dcmjs)

Requested change
Avoid codes such as (1, 99dcmjs, "Unknown procedure")
Use CID 100 or modality-appropriate standard codes, e.g. (363679005, SCT, "Imaging procedure")
Status
Planned

Lets get this one updated. Just use Imaging Procedure on anything unknown should be sufficient. Please ensure there is a constant exported for this so that CS3D can just use the exported constant.

Okay. We may need to recheck if validators complains about any other fields.

6. Appearance related data in SR content

Requested change
Do not include appearance or UI-related elements like (TextPosition, 99CS3D, "Text Annotation Position"). SR content should store semantic meaning only.
Related requirement
For all SCOORD items, GraphicType is mandatory and must be populated.

I KNOW this isn't in keeping with the recommendation for semantic meaning only, but storing this in this way in useful for a lot of users. Make it work for real users trumps intended use of some of the data that is still compliant with the actual standard. Please keep this in. We should update the storage on the CS3D side to only include this when the position has been updated.

Status
GraphicType handling appears fixed in generated SR, we will revisit and confirm this; Appearance-only elements will be removed where still present.

PLEASE do not remove appearance only items

Okay. We will keep it as is. We may need to check if other validation tools will complain about these or not.

Clarification and planning
Does this break compatibility with already created SR reports and how end users uses the data?

7. Correct use of R-INFERRED FROM and content item referencing

Although TID 1501/TID 320 R-INFERRED FROM is allowed, it must reference the correct hierarchically indexed shared graphic item content, using ReferencedContentItemIdentifier.
The current annotationIndex usage is incorrect, it should use the element position reference in the SR report DICOM structure to reference geometry from other places
Status
Planned. No errors or warnings are currently reported by

  • dcmdump
  • dciodvfy
  • dsrdump

Any changes on SR DICOM structure after dcmjs DICOM generation will break the reference numbers. Warn in documentation that users must not modify generated SR data on-before or on-after SR data generation or save.

Actually, the parsing side of things completely ignores the R-INFERRED FROM information, so as long as it is correct for the SR verify tool when created, I don't think you need to be too careful about it.

Eventhough OHIF may not be parsing this, we are not yet sure if this needs to be updated properly for other applications like slicer to properly read the data. We will start with correcting for the SR verify tool when addressing this.

Reference correctness is under analysis. This may need an index tracker to ensure correct hierarchy levels are tracked and used for referencing data.

8. TID 1410 adoption and other compatibility

Requested change
There is a strong recommendation to adopt TID 1410 (multiple measurements under a single ROI) in place of the current TID 1501 / TID 320–based structure.
In addition, the generated SR structure should be aligned with established references and best practices, including

  • TID 1410 / TID 1411 structural patterns
  • IBSI-recommended unit representations
  • IDC reference examples
  • QIICR precedents for SR loading and interpretation in 3D Slicer

Impact
This change represents a significant structural refactor and would require coordinated updates across multiple codebases, including

  • dcmjs
  • Cornerstone3D
  • OHIF

Additionally, a clear strategy for backward compatibility with existing stored SR measurements would need to be defined and implemented.
Clarification and planning
Given the scope and cross-repository impact of this change, and they may not be a blocker for this PR, we would like to request clarification on preferred approach.
Should this be planned and executed as a separate, dedicated refactoring effort, or is it preferable to address this in a single coordinated change, to avoid multiple SR format transitions and potential compatibility issues?

Please do this as a planned approach as a separate PR. I'd love to have it in this one, it just doesn't make sense to update this further when there are already existing creators out there doing it the way you have currently updated it to.

Thanks! We shall split this into a feature request in dcmjs.


tl;dr; We can skip items 4,6 and 8 from the above list as they are not required for merging the PR. Other review comments will be attempted in this PR itself.

@fedorov
Copy link
Collaborator

fedorov commented Dec 15, 2025

  1. Dimensionless measurements
    Requested change
    Use (1, UCUM, "no units") when a measurement is dimensionless or has no meaningful unit (eg: px, px2).
    Current behavior
    Measurements without units are currently treated as px.

As suggested elsewhere, please include the no units in order to be compliant with the spec, and then determine what it means based on the fact that it is area/volume/max/min etc.

We will update it.

You are contradicting yourself here. If you measure area or perimeter, it won't be dimensionless - I don't think you can do "no units" for those. Are you suggesting that you would like to measure area in the units of pixels squared, and perimeter in pixels, instead of mm2? Is there a use case for such a measurement?

@wayfarer3130
Copy link
Contributor

  1. Dimensionless measurements
    Requested change
    Use (1, UCUM, "no units") when a measurement is dimensionless or has no meaningful unit (eg: px, px2).
    Current behavior
    Measurements without units are currently treated as px.

As suggested elsewhere, please include the no units in order to be compliant with the spec, and then determine what it means based on the fact that it is area/volume/max/min etc.
We will update it.

You are contradicting yourself here. If you measure area or perimeter, it won't be dimensionless - I don't think you can do "no units" for those. Are you suggesting that you would like to measure area in the units of pixels squared, and perimeter in pixels, instead of mm2? Is there a use case for such a measurement?

px are a simple count of number of pixels and thus in UCUM are "no units". Those are the linear dimensions for measurements that aren't associated with any calibration. An area of an image that isn't calibrated is still a count of pixel^2, so is still dimensionless.

@pieper
Copy link
Collaborator

pieper commented Dec 15, 2025

... appearance or UI-related elements like (TextPosition, 99CS3D, "Text Annotation Position").

I KNOW this isn't in keeping with the recommendation for semantic meaning only, but storing this in this way in useful for a lot of users. Make it work for real users trumps intended use of some of the data that is still compliant with the actual standard. Please keep this in. We should update the storage on the CS3D side to only include this when the position has been updated.

I'll just chime in that I agree with this.

@fedorov
Copy link
Collaborator

fedorov commented Dec 15, 2025

... appearance or UI-related elements like (TextPosition, 99CS3D, "Text Annotation Position").

I KNOW this isn't in keeping with the recommendation for semantic meaning only, but storing this in this way in useful for a lot of users. Make it work for real users trumps intended use of some of the data that is still compliant with the actual standard. Please keep this in. We should update the storage on the CS3D side to only include this when the position has been updated.

I'll just chime in that I agree with this.

I have to say that I also agree with the decision to keep those codes. Those are private codes, so it is up to the application to use them as needed. This approach is not ideal, but there are no good alternatives: adding support for presentation states to communicate this would probably be a huge effort risking alienating existing users and would be even more difficult to interoperate, deviating from the standard template or adding this content to private tags would be much worse in my view.

While I understand combining SR with PR for this use case is ideal, I have yet to see any actual open-source implementations and examples that demonstrate how to do it right. So they would need to be trail-blazers most likely. Every time we try to implement something from the standard for the first time (meaning, when there are no open source tools and no sample datasets demonstrating how it can be done), it always requires dedicated effort and expertise to interpret the standard, go through CPs to fix issues, and major implementation effort. Trying to be that ambitious without having the appropriate resources risks killing the entire initiative altogether.

const measurements = [
...measurementConfigs
.filter(config => config.value !== undefined)
.map((config, index) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't the .map already produce an array - so you don't need [ ...measurementConfigs ?

@wayfarer3130
Copy link
Contributor

@abhijith-trenser - could you attach an updated SR with two measurements, Elliptical ROI and Planar Freeform (closed), without moving the text box annotation. I'd like to see how all the updates go together to create a new SR and run the Dicom SR Validator that was suggested to look at some of the internals.
Can you also attach a second example WITH the annotation text box moved, and probe, length added?

Would like to get this in quite soon if at all possible so we can include in OHIF 3.12

@nithin-trenser
Copy link

nithin-trenser commented Dec 18, 2025

  • if you use R-INFERRED FROM you can't store it in the Enhanced SR Storage SOP Class, which does not allow that relationship (see the Relationship Constraints for the IOD), you need to use Comprehensive or more general
  • that said, if you must use R-INFERRED FROM, use it correctly, i.e., the target has to be the correct hierarchically indexed content item, e.g., in:
		>>1.5.3: CONTAINS: CONTAINER: (125007,DCM,"Measurement Group")  [SEPARATE]
			>>>1.5.3.1: HAS OBS CONTEXT: TEXT: (112039,DCM,"Tracking Identifier")  = "Cornerstone3DTools@^0.1.0:EllipticalROI"
			>>>1.5.3.2: HAS OBS CONTEXT: UIDREF: (112040,DCM,"Tracking Unique Identifier")  = "2.25.191275216183160604929998481545985156409"
			>>>1.5.3.3: CONTAINS: NUM: (G-D7FE,SRT,"AREA")  = 1108.55967785040 (mm2,UCUM,"SquareMilliMeter")
				>>>>1.5.3.3.1: INFERRED FROM: SCOORD:  = ELLIPSE {189.105514526367,162.746765136719,189.105514526367,223.851104736328,168.138336181641,193.298950195312,210.072677612305,193.298950195312}
					>>>>>1.5.3.3.1.1: SELECTED FROM: IMAGE:  = (1.2.840.10008.5.1.4.1.1.2,1.3.6.1.4.1.14519.5.2.1.119975830994577378983611145263)
			>>>1.5.3.4: CONTAINS: NUM: (56851009,SCT,"Maximum")  = 157 (HU,99dcmjsUnit,"HU")
				>>>>1.5.3.4.1: R-INFERRED FROM: 1.1.3
			>>>1.5.3.5: CONTAINS: NUM: (255605001,SCT,"Minimum")  = -921 (HU,99dcmjsUnit,"HU")

the 1.1.3 referenced content item does not exist, and should presumably be 1.5.3.3.1

Anyway, that's probably not everything, but hopefully it is helpful.

We are working on correcting the use of R-INFERRED FROM and content item referencing. We attempted a basic implementation based on the values suggested in your comments; however, the generated DICOM files still produce the same errors when validated with the PixelMed SR validator.

@dclunie The generated SR report with updated value is attached.
3.000000-AXIAL ST 5.0 X 5.0-41783.zip

cc: @wayfarer3130 @sen-trenser

@nithin-trenser
Copy link

@abhijith-trenser - could you attach an updated SR with two measurements, Elliptical ROI and Planar Freeform (closed), without moving the text box annotation. I'd like to see how all the updates go together to create a new SR and run the Dicom SR Validator that was suggested to look at some of the internals. Can you also attach a second example WITH the annotation text box moved, and probe, length added?

Would like to get this in quite soon if at all possible so we can include in OHIF 3.12

@wayfarer3130 Please find the required SR reports attached.
3.000000-AXIAL ST 5.0 X 5.0-41783.zip

cc: @sen-trenser

@wayfarer3130
Copy link
Contributor

wayfarer3130 commented Dec 18, 2025

I have a set of changes, NOT including the reference item - that one won't work at all unfortunately as the structure is wrong. The parsing is going to have to change a bit to fix things, but I think it will be ok with that.

The changes are:

  1. Add ROI SCOORD as a sibling item under the Measurement Group

Find the EllipticalROI Measurement Group’s 0040A730.Value array (it starts with Tracking Identifier + Tracking UID, then Area, etc.).

Insert this new item right after the Tracking UID item (or anywhere before the NUMs).
See the attached JSON file just after the tracking identifier

2a) Remove the SCOORD that’s currently under Area
Your Area NUM currently ends with this 0040A730 that contains the SCOORD.
Delete that entire 0040A730 block from the Area item (since the ROI is now at group level).

2b) Remove the by-reference “INFERRED FROM” blocks under the stats NUMs
For Maximum (and similarly Minimum/Mean/StdDev), delete the sequence containing the INFERRED FROM blocks

  1. In the language of content etc, replace eng with en to be the correct code.
    I've attached the JSON before and after. If you run dcm4che toolkit:
    json2dcm -j fix-sr.json -o fix-sr.dcm
    dicomsrvalidator fix-sr.dcm
    you will see no remaining errors.

comprehensive.json
fix-sr.json

Copy link
Contributor

@wayfarer3130 wayfarer3130 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to get it passing the DICOM SR Validator - unfortunately, I was mistaken in what the inferred from block means - it is what OTHER measurements this measurement is inferred from, not what other graphic data it is inferred from.
I've attached a valid sample that passes the DICOM SR Validator checks and avoids duplicating the data. I think this is in fact the 1410 structure.

@sen-trenser
Copy link

@wayfarer3130 Thank you for the detailed review and for raising the concern regarding TID 1410 compatibility. We appreciate the time and attention you have given to this pull request.

After careful consideration with our team and PO, we would like to clarify that supporting TID 1410 compatibility and backward compatibility would require additional changes and significant effort outside of the intended scope of this contribution in this and other PRs.

This pull request is planned for inclusion in the upcoming 3.12 release and is currently blocking two dependent changes (CS3D PR 2430 and OHIF PR 5600) that are also targeted for the same release. To avoid further delays and to keep this change focused and scoped appropriately, we would like to ask whether it would be acceptable to proceed without incorporating TID 1410 compatibility. Our goal is to keep this PR focused on the current functionality and get aligned with the 3.12 release timeline.

We appreciate your guidance on whether proceeding on this basis would be acceptable.

Thank you again for your review and for maintaining the project available for everyone!

@wayfarer3130
Copy link
Contributor

@wayfarer3130 Thank you for the detailed review and for raising the concern regarding TID 1410 compatibility. We appreciate the time and attention you have given to this pull request.

After careful consideration with our team and PO, we would like to clarify that supporting TID 1410 compatibility and backward compatibility would require additional changes and significant effort outside of the intended scope of this contribution in this and other PRs.

This pull request is planned for inclusion in the upcoming 3.12 release and is currently blocking two dependent changes (CS3D PR 2430 and OHIF PR 5600) that are also targeted for the same release. To avoid further delays and to keep this change focused and scoped appropriately, we would like to ask whether it would be acceptable to proceed without incorporating TID 1410 compatibility. Our goal is to keep this PR focused on the current functionality and get aligned with the 3.12 release timeline.

We appreciate your guidance on whether proceeding on this basis would be acceptable.

Thank you again for your review and for maintaining the project available for everyone!

Unfortunately there isn't a good backwards/forwards compatible option for this that doesn't leave us with a lot of invalid DICOM. I understand it adds scope, but not adding scope means forever maintaining future scope for backwards compatibility for multiple attributes, as well as not passing connectathons and things like that on the stored data.
It is one thing to have a warning message, but something else to produce either invalid DICOM or DICOM that repeats the data elements so that it becomes necessary to re-validate whether the instances are all the same, and what it means if some instances got changed differently from others.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants