Closed fedorov closed 2 years ago
We have assumed so far that measurements and qualitative evaluations provided via TID 1501 would apply to all images referenced in the SR document via either the Current Requested Procedure Evidence Sequence or the Pertinent Other Evidence Sequence.
We explicitly did not allow users to reference a SCOORD (row 10c) or SCOORD3D (row 10e) content item via TID 1501 (highdicom.sr.MeasurementsAndQualitativeEvaluations
), because our opinion is that TID 1410 (highdicom.sr.PlanarROIMeasurementsAndQualitativeEvaluations
) or TID 1411 (highdicom.sr.VolumetricROIMeasurementsAndQualitativeEvaluations
) should be used for that purpose.
We could allow users to reference one or more IMAGE (row 10b) content items. I can see that this could be useful for classifying individual image frames of a multi-frame image or a single-frame image of a series.
I've actually wondered about this myself in the past but didn't notice that this was an option in the template. I would vote strongly in favour of adding this (for IMAGE at least, I agree that other TIDs should be used for ROIs). It would be relatively straightforward. It would also be nice to make this searchable in the deocding API via an additional option in MeasurementReport.get_image_measurement_groups()
. I'm happy to work on this at some point.
@fedorov if you have an immediate need, it's simple to do this yourself before a change is made to the library by just appending your own ImageContentItem
to the template:
import highdicom as hd
meas_group = hd.sr.MeasurementsAndQualitativeEvaluations(...)
source_image = hd.sr.ImageContentItem(
name=hd.sr.CodedConcept('260753009', 'SCT', 'Source'),
referenced_sop_class_uid=...,
referenced_sop_instance_uid=...,
relationship_type=hd.sr.RelationshipTypeValue.CONTAINS
)
meas_group.append(source_image)
Thank you guys, this is very helpful. Indeed, this is a for a very specific immediate need use case to encode the results produced by this tool: https://github.com/mic-dkfz/bodypartregression. But it will also be applicable for this one that's also relevant to IDC: https://wiki.cancerimagingarchive.net/pages/viewpage.action?pageId=80969742 (image-level COVID findings).
A related issue is that currently tracking ID/UID are mandatory for MeasurementsAndQualitativeEvaluations
, but they are definitely not required by TID 1501, and for the situation described in this issue I do not think they should be required under any circumstances. There is no annotation to track.
A related issue is that currently tracking ID/UID are mandatory for
MeasurementsAndQualitativeEvaluations
, but they are definitely not required by TID 1501, and for the situation described in this issue I do not think they should be required under any circumstances. There is no annotation to track.
This was a design decision. I think one should always provide identifiers, even if there is no intention to track (at the time of creation)
Ok, I understand. To clarify, it's not that there is no intention to track, it is that it is not clear what those identifiers would refer to. There will be nothing in the container other than the image and the code content items.
@CPBridge I followed your advice re workaround, and the IMAGE content item is added outside of the container. Is there something I am not doing correctly?
for i in range(10):
measurements_group = MeasurementsAndQualitativeEvaluations(
tracking_identifier=TrackingIdentifier(
uid=generate_uid(),
identifier=str(f"Tracking ID {i}")
),
qualitative_evaluations=[qualitative_evaluation]
)
reference_dcm_file = os.path.join(os.environ["DOWNLOAD_DEST"], os.listdir(os.environ["DOWNLOAD_DEST"])[i])
image_dataset = dcmread(reference_dcm_file)
evidence.append(image_dataset)
# which image is annotated
source_image = hd.sr.ImageContentItem(
name=hd.sr.CodedConcept('260753009', 'SCT', 'Source'),
referenced_sop_class_uid=image_dataset.SOPClassUID,
referenced_sop_instance_uid=image_dataset.SOPInstanceUID,
relationship_type=RelationshipTypeValues.CONTAINS
)
measurements_group.append(source_image)
imaging_measurements.append(
measurements_group
)
measurement_report = MeasurementReport(
observation_context=observation_context,
procedure_reported=procedure_code,
imaging_measurements=imaging_measurements
)
Result:
<contains CONTAINER:(,,"Imaging Measurements")=CONTINUOUS>
<contains CONTAINER:(,,"Measurement Group")=CONTINUOUS>
<has obs context TEXT:(,,"Tracking Identifier")="Tracking ID 0">
<has obs context UIDREF:(,,"Tracking Unique Identifier")="1.2.826.0.1.3680043.8.498.10832312462833275132331249495185225587">
<contains CODE:(,,"Body part examined")=(39607008,SCT,"Lung")>
<contains IMAGE:(,,"Source")=(CT image,)>
So I am thinking to instead manually populate the container as follows:
container = hd.sr.ContainerContentItem(hd.sr.CodedConcept("125007","DCM","Measurement Group"), relationship_type=RelationshipTypeValues.CONTAINS)
container_content = hd.sr.ContentSequence()
container_content.append(source_image)
finding_type_item = CodeContentItem(
name = CodedConcept(
value="temp1",
meaning="Body part examined",
scheme_designator="99andrey"
),
value = CodedConcept(
value="39607008",
meaning="Lung",
scheme_designator="SCT"
),
relationship_type=RelationshipTypeValues.CONTAINS
)
container_content.append(finding_type_item)
container.ContentSequence = container_content
measurements_group.append(container)
This seems to work as expected:
<contains CONTAINER:(,,"Measurement Group")=CONTINUOUS>
<contains IMAGE:(,,"Source")=(CT image,)>
<contains CODE:(,,"Body part examined")=(39607008,SCT,"Lung")>
This seems to work as expected
Except this is not going to work, since MeasurementReport
would not accept my list of containers in place of list of MeasurementsAndQualitativeEvaluations
, so I am not sure how to proceed.
HI @fedorov my apologies: I made a mistake in my initial snippet, you should append the new ImageContentItem
(source_image
) to the ContentSequence
of the MeasurementsAndQualitativeEvaluations
, and not the object itself.
I.e. adapting your first snippet, change this:
measurements_group.append(source_image)
to this:
measurements_group.ContentSequence.append(source_image)
However I have already addressed this issue in pull request #169, so that you can do everything through the constructors as you would expect. So I would suggest that you use that branch instead. @hackermd approved that PR but I'm not sure why he didn't merge it to master yet, I think we both agreed it's good to go as is.
On that branch, you can do this instead:
for i in range(10):
reference_dcm_file = os.path.join(os.environ["DOWNLOAD_DEST"], os.listdir(os.environ["DOWNLOAD_DEST"])[i])
image_dataset = dcmread(reference_dcm_file)
evidence.append(image_dataset)
# There is a new object that encapsulates the source image as a content
# item with the correct codes and relationship type, and can be
# automatically created from the source dataset
source_image = hd.sr.SourceImageForMeasurementGroup.from_source_image(image_dataset)
# Then just pass this as the `source_images` parameter of the constructor
measurements_group = MeasurementsAndQualitativeEvaluations(
tracking_identifier=TrackingIdentifier(
uid=hd.UID(),
identifier=str(f"Tracking ID {i}")
),
qualitative_evaluations=[qualitative_evaluation],
source_images=[source_image]
)
imaging_measurements.append(measurements_group)
measurement_report = MeasurementReport(
observation_context=observation_context,
procedure_reported=procedure_code,
imaging_measurements=imaging_measurements
)
Thank you for your help with this. I wanted to try it out, but am experiencing issues with importing packages while installing using setup.py
- import pydicom
is failing for me, here's the notebook with the steps: https://colab.research.google.com/drive/1OHzeZY03gG7PdJTK85DOAaPC-fp2YwHA?usp=sharing. Am I supposed to use python setup.py install
to install the version that does not have a release, or there is some other process?
Try pip install .
from the root directory of the cloned repo, rather than directly invoking setup.py
Thank you! This worked. Is this something that everyone else other than me is expected to know, or maybe this can be added to the documentation?
Resolved by #169
In fact it's already there ;)
https://highdicom.readthedocs.io/en/latest/installation.html
It is also a standard way of setting up Python packages these days so that they play nicely with pip
@fedorov version 0.17.0 is now available on PyPI: https://pypi.org/project/highdicom/0.17.0/
TID 1501 allows to capture qualitative evaluations assigned per image (without specifying any annotation) - see rows 10b/11b in https://dicom.nema.org/medical/dicom/current/output/chtml/part16/chapter_A.html#sect_TID_1501.
This does not appear to be possible using highdicom - I don't see how I could specify image in the constructor of TID1501: https://github.com/herrmannlab/highdicom/blob/master/src/highdicom/sr/templates.py#L2420. Am I correct, or I am missing something?