From 9833dae84535cbda449fe38d7fbd0763d9573836 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Tue, 17 Dec 2024 16:02:16 +0000 Subject: [PATCH 01/12] Ensure we're testing the correct modalities in the dcmd tests --- pixl_dcmd/tests/test_main.py | 22 +++++++++++----------- pytest-pixl/src/pytest_pixl/dicom.py | 12 ++++++++++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/pixl_dcmd/tests/test_main.py b/pixl_dcmd/tests/test_main.py index 951c5870d..5af897b6f 100644 --- a/pixl_dcmd/tests/test_main.py +++ b/pixl_dcmd/tests/test_main.py @@ -24,6 +24,7 @@ import pydicom import pytest import sqlalchemy +from pytest_check import check from core.db.models import Image from core.dicom_tags import ( PrivateDicomTag, @@ -200,19 +201,18 @@ def test_anonymise_and_validate_dicom(caplog, request, yaml_file) -> None: WHEN the anonymisation and validation process is run THEN the dataset should be anonymised and validated without any warnings or errors """ - caplog.clear() caplog.set_level(logging.WARNING) config = load_project_config(yaml_file.stem) - modality = config.project.modalities[0] - dicom_image = request.getfixturevalue(f"vanilla_dicom_image_{modality}") - - validation_errors = anonymise_and_validate_dicom( - dicom_image, - config=config, - ) - - assert "WARNING" not in [record.levelname for record in caplog.records] - assert not validation_errors + for modality in config.project.modalities: + caplog.clear() + dicom_image = generate_dicom_dataset(Modality=modality) + validation_errors = anonymise_and_validate_dicom( + dicom_image, + config=config, + ) + with check: + assert "WARNING" not in [record.levelname for record in caplog.records] + assert not validation_errors @pytest.mark.usefixtures("row_for_single_dicom_testing") diff --git a/pytest-pixl/src/pytest_pixl/dicom.py b/pytest-pixl/src/pytest_pixl/dicom.py index 87735239e..a91b4c155 100644 --- a/pytest-pixl/src/pytest_pixl/dicom.py +++ b/pytest-pixl/src/pytest_pixl/dicom.py @@ -62,6 +62,15 @@ def write_volume(filename_pattern: str) -> None: "pixel_data": None, } +# From: +# https://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_b.5.html +MODALITY_TO_CLASS_UID = { + "CR": "1.2.840.10008.5.1.4.1.1.1", + "CT": "1.2.840.10008.5.1.4.1.1.2", + "DX": "1.2.840.10008.5.1.4.1.1.1.1", + "MR": "1.2.840.10008.5.1.4.1.1.4", + "PT": "1.2.840.10008.5.1.4.1.1.128", +} def generate_dicom_dataset(tag_values: dict = TAGS_DICT, **kwargs: Any) -> Dataset: """ @@ -111,6 +120,9 @@ def generate_dicom_dataset(tag_values: dict = TAGS_DICT, **kwargs: Any) -> Datas msg = f"Tag {key} is not a valid DICOM tag" raise ValueError(msg) + if "Modality" in kwargs and "SOPClassUID" not in kwargs: + ds.SOPClassUID = MODALITY_TO_CLASS_UID[kwargs["Modality"]] + return ds From 2d433059b4ebaa206ecdf5c001064279678dd7e3 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 12:35:56 +0000 Subject: [PATCH 02/12] ensure tags are not duplicated across base configs --- pixl_dcmd/tests/test_main.py | 4 +- pixl_dcmd/tests/test_tag_schemes.py | 9 +++-- projects/configs/tag-operations/base.yaml | 20 ++++++++++ projects/configs/tag-operations/mri.yaml | 24 ------------ .../test-extract-uclh-omop-cdm.yaml | 9 +---- projects/configs/tag-operations/xray.yaml | 37 ++----------------- .../test-extract-uclh-omop-cdm-dicomweb.yaml | 3 +- .../test-extract-uclh-omop-cdm-xnat.yaml | 1 + .../configs/test-extract-uclh-omop-cdm.yaml | 5 ++- pytest-pixl/src/pytest_pixl/dicom.py | 4 ++ 10 files changed, 42 insertions(+), 74 deletions(-) diff --git a/pixl_dcmd/tests/test_main.py b/pixl_dcmd/tests/test_main.py index 5af897b6f..6a9b1a85d 100644 --- a/pixl_dcmd/tests/test_main.py +++ b/pixl_dcmd/tests/test_main.py @@ -72,7 +72,7 @@ def _get_mri_diffusion_tags( so we can test whether the manufacturer overrides work during anonymisation """ tag_ops = load_tag_operations(config) - mri_diffusion_overrides = tag_ops.manufacturer_overrides[0] + mri_diffusion_overrides = tag_ops.manufacturer_overrides[1] manufacturer_overrides = [ override @@ -94,7 +94,7 @@ def mri_diffusion_dicom_image(test_project_config: PixlConfig) -> pydicom.Datase test whether the anonymisation process works as expected when defining overrides. """ manufacturer = "Philips" - ds = generate_dicom_dataset(Manufacturer=manufacturer, Modality="DX") + ds = generate_dicom_dataset(Manufacturer=manufacturer, Modality="MR") tags = _get_mri_diffusion_tags( config=test_project_config, manufacturer=manufacturer ) diff --git a/pixl_dcmd/tests/test_tag_schemes.py b/pixl_dcmd/tests/test_tag_schemes.py index 108bb1e39..442bf6ec0 100644 --- a/pixl_dcmd/tests/test_tag_schemes.py +++ b/pixl_dcmd/tests/test_tag_schemes.py @@ -16,6 +16,7 @@ from pathlib import Path import pytest +import pytest_check from core.project_config import load_project_config from core.project_config.tag_operations import TagOperations, load_tag_operations from decouple import config @@ -39,7 +40,7 @@ def test_merge_base_only_tags(base_only_tag_scheme): THEN the result should be the same as the base file """ tags = merge_tag_schemes(base_only_tag_scheme) - expected = [*base_only_tag_scheme.base[0], *base_only_tag_scheme.base[1]] + expected = [tag for base in base_only_tag_scheme.base for tag in base] count_tags = dict() for tag in expected: key = f"{tag['group']:04x},{tag['element']:04x}" @@ -49,9 +50,9 @@ def test_merge_base_only_tags(base_only_tag_scheme): count_tags[key] = 1 for key, values in count_tags.items(): - assert ( - values == 1 - ), f"{key} is replicated please check config files to remove it" + pytest_check.equal( + values, 1, msg=f"{key} is replicated please check config files to remove it" + ) assert tags == expected diff --git a/projects/configs/tag-operations/base.yaml b/projects/configs/tag-operations/base.yaml index d5271ab15..0e06d697d 100644 --- a/projects/configs/tag-operations/base.yaml +++ b/projects/configs/tag-operations/base.yaml @@ -95,6 +95,14 @@ group: 0x0008 element: 0x9205 op: "keep" +- name: "Volumetric Properties" + group: 0x0008 + element: 0x9206 + op: "keep" +- name: "Volume Based Calculation Technique" + group: 0x0008 + element: 0x9207 + op: "keep" #################################### 0010 Group ################################### # # @@ -136,7 +144,19 @@ group: 0x0018 element: 0x1020 op: "keep" +- name: "Field Of View Dimension" + group: 0x0018 + element: 0x1149 + op: "keep" #CT, MR, PET, US, X-Ray, and RT Images +- name: "Imager Pixel Spacing" + group: 0x0018 + element: 0x1164 + op: "keep" +- name: "Grid" + group: 0x0018 + element: 0x1166 + op: "keep" - name: "Focal Spot" group: 0x0018 element: 0x1190 diff --git a/projects/configs/tag-operations/mri.yaml b/projects/configs/tag-operations/mri.yaml index 77415f15f..ef5944358 100644 --- a/projects/configs/tag-operations/mri.yaml +++ b/projects/configs/tag-operations/mri.yaml @@ -32,14 +32,6 @@ group: 0x0008 element: 0x0033 op: replace -- name: "Volumetric Properties" - group: 0x0008 - element: 0x9206 - op: "keep" -- name: "Volume Based Calculation Technique" - group: 0x0008 - element: 0x9207 - op: "keep" - name: "Complex Image Component" group: 0x0008 element: 0x9208 @@ -124,22 +116,6 @@ group: 0x0018 element: 0x0094 op: "keep" -#https://dicom.innolitics.com/ciods/mr-image/mr-image/00180094 -#https://dicom.innolitics.com/ciods/mr-spectroscopy/mr-spectroscopy-multi-frame-functional-groups/52009229/00189103/00180094 -#https://dicom.innolitics.com/ciods/enhanced-mr-image/enhanced-mr-image-multi-frame-functional-groups/52009229/00189125/00180094 -#https://dicom.innolitics.com/ciods/enhanced-mr-color-image/enhanced-mr-color-image-multi-frame-functional-groups/52009229/00189125/00180094 -- name: "Field Of View Dimension" - group: 0x0018 - element: 0x1149 - op: "keep" -- name: "Imager Pixel Spacing" - group: 0x0018 - element: 0x1164 - op: "keep" -- name: "Grid" - group: 0x0018 - element: 0x1166 - op: "keep" - name: "Receive Coil Name" group: 0x0018 element: 0x1250 diff --git a/projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml b/projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml index f31e7af13..0d3e06cb8 100644 --- a/projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml +++ b/projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml @@ -14,11 +14,4 @@ # Configuration for extracting data from UCLH OMOP CDM DICOM files -- name: "VR OB Creator" - group: 0x0013 - element: 0x0010 - op: "keep" -- name: "VR OB sequence" - group: 0x0013 - element: 0x1010 - op: "replace" +[] \ No newline at end of file diff --git a/projects/configs/tag-operations/xray.yaml b/projects/configs/tag-operations/xray.yaml index 947b0879a..f8fbc57db 100644 --- a/projects/configs/tag-operations/xray.yaml +++ b/projects/configs/tag-operations/xray.yaml @@ -14,39 +14,6 @@ # Default configuration to extend base for x-rays -- name: "Volumetric Properties" - group: 0x0008 - element: 0x9206 - op: "keep" -- name: "Volume Based Calculation Technique" - group: 0x0008 - element: 0x9207 - op: "keep" -- name: "Field Of View Dimension" - group: 0x0018 - element: 0x1149 - op: "keep" -#https://dicom.innolitics.com/ciods/x-ray-angiographic-image/dx-detector/00181149 -#https://dicom.innolitics.com/ciods/x-ray-angiographic-image/dx-detector/00181149 -#https://dicom.innolitics.com/ciods/x-ray-radiofluoroscopic-image/x-ray-acquisition/00181149 -#https://dicom.innolitics.com/ciods/x-ray-angiographic-image/x-ray-acquisition/00181149 -#https://dicom.innolitics.com/ciods/digital-x-ray-image/dx-detector/00181149 -#https://dicom.innolitics.com/ciods/digital-mammography-x-ray-image/dx-detector/00181149 -#https://dicom.innolitics.com/ciods/digital-intra-oral-x-ray-image/dx-detector/00181149 -- name: "Imager Pixel Spacing" - group: 0x0018 - element: 0x1164 - op: "keep" -#https://dicom.innolitics.com/ciods/x-ray-angiographic-image/dx-detector/00181164 -#https://dicom.innolitics.com/ciods/x-ray-radiofluoroscopic-image/x-ray-acquisition/00181164 -#https://dicom.innolitics.com/ciods/x-ray-angiographic-image/x-ray-acquisition/00181164 -#https://dicom.innolitics.com/ciods/digital-x-ray-image/dx-detector/00181164 -#https://dicom.innolitics.com/ciods/digital-mammography-x-ray-image/dx-detector/00181164 -#https://dicom.innolitics.com/ciods/digital-intra-oral-x-ray-image/dx-detector/00181164 -- name: "Grid" - group: 0x0018 - element: 0x1166 - op: "keep" #https://dicom.innolitics.com/ciods/x-ray-radiofluoroscopic-image/x-ray-acquisition/00181166 #https://dicom.innolitics.com/ciods/x-ray-angiographic-image/x-ray-acquisition/00181166 #https://dicom.innolitics.com/ciods/digital-x-ray-image/x-ray-grid/00181166 @@ -87,3 +54,7 @@ element: 0x1041 op: "keep" #X-Ray +- name: "Presentation LUT Shape" + group: 0x2050 + element: 0x0020 + op: "keep" diff --git a/projects/configs/test-extract-uclh-omop-cdm-dicomweb.yaml b/projects/configs/test-extract-uclh-omop-cdm-dicomweb.yaml index bec9c9bc3..a2463fb51 100644 --- a/projects/configs/test-extract-uclh-omop-cdm-dicomweb.yaml +++ b/projects/configs/test-extract-uclh-omop-cdm-dicomweb.yaml @@ -15,12 +15,13 @@ project: name: "test-extract-uclh-omop-cdm-dicomweb" azure_kv_alias: "test" - modalities: ["DX", "CR"] + modalities: ["DX", "CR", "MR"] tag_operation_files: base: - "base.yaml" #Expected base config file for any project - "mri.yaml" + - "xray.yaml" manufacturer_overrides: ["mri.yaml", "mri-diffusion.yaml"] series_filters: diff --git a/projects/configs/test-extract-uclh-omop-cdm-xnat.yaml b/projects/configs/test-extract-uclh-omop-cdm-xnat.yaml index 9db5648d5..2ed67c450 100644 --- a/projects/configs/test-extract-uclh-omop-cdm-xnat.yaml +++ b/projects/configs/test-extract-uclh-omop-cdm-xnat.yaml @@ -21,6 +21,7 @@ tag_operation_files: base: - "base.yaml" #Expected base config file for any project - "mri.yaml" + - "xray.yaml" manufacturer_overrides: ["mri.yaml", "mri-diffusion.yaml"] series_filters: diff --git a/projects/configs/test-extract-uclh-omop-cdm.yaml b/projects/configs/test-extract-uclh-omop-cdm.yaml index 7ff106a1f..9f7d1d6b8 100644 --- a/projects/configs/test-extract-uclh-omop-cdm.yaml +++ b/projects/configs/test-extract-uclh-omop-cdm.yaml @@ -15,14 +15,15 @@ project: name: "test-extract-uclh-omop-cdm" azure_kv_alias: "test" - modalities: ["DX", "CR"] + modalities: ["DX", "CR", "MR"] tag_operation_files: base: - "base.yaml" #Expected base config file for any project - "mri.yaml" + - "xray.yaml" - "test-extract-uclh-omop-cdm.yaml" - manufacturer_overrides: ["mri-diffusion.yaml"] + manufacturer_overrides: ["mri.yaml", "mri-diffusion.yaml"] series_filters: - "localizer" diff --git a/pytest-pixl/src/pytest_pixl/dicom.py b/pytest-pixl/src/pytest_pixl/dicom.py index a91b4c155..f7478390a 100644 --- a/pytest-pixl/src/pytest_pixl/dicom.py +++ b/pytest-pixl/src/pytest_pixl/dicom.py @@ -71,6 +71,10 @@ def write_volume(filename_pattern: str) -> None: "MR": "1.2.840.10008.5.1.4.1.1.4", "PT": "1.2.840.10008.5.1.4.1.1.128", } +MODALITY_TAGS = { + "DX": {"Presentation LUT Shape": "IDENTITY"}, +} + def generate_dicom_dataset(tag_values: dict = TAGS_DICT, **kwargs: Any) -> Dataset: """ From 0af69fd774a403ca271e2368a7f1646e97fdf879 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 12:49:09 +0000 Subject: [PATCH 03/12] Add missing tags to config files --- .../uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml | 4 ++++ projects/configs/tag-operations/xray.yaml | 5 +++++ pytest-pixl/src/pytest_pixl/dicom.py | 3 +-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/projects/configs/tag-operations/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml b/projects/configs/tag-operations/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml index 718d2fecf..0e0c48836 100644 --- a/projects/configs/tag-operations/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml +++ b/projects/configs/tag-operations/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml @@ -430,6 +430,10 @@ group: 0x0040 element: 0xA124 op: "replace_UID" +- name: "Presentation LUT Shape" + group: 0x2050 + element: 0x0020 + op: "keep" - name: "Referenced Frame of Reference UID" group: 0x3006 element: 0x0024 diff --git a/projects/configs/tag-operations/xray.yaml b/projects/configs/tag-operations/xray.yaml index f8fbc57db..de8f88ccb 100644 --- a/projects/configs/tag-operations/xray.yaml +++ b/projects/configs/tag-operations/xray.yaml @@ -14,6 +14,11 @@ # Default configuration to extend base for x-rays +- name: "Body Part Examined" + group: 0x0018 + element: 0x0015 + op: "keep" + #https://dicom.innolitics.com/ciods/x-ray-radiofluoroscopic-image/x-ray-acquisition/00181166 #https://dicom.innolitics.com/ciods/x-ray-angiographic-image/x-ray-acquisition/00181166 #https://dicom.innolitics.com/ciods/digital-x-ray-image/x-ray-grid/00181166 diff --git a/pytest-pixl/src/pytest_pixl/dicom.py b/pytest-pixl/src/pytest_pixl/dicom.py index f7478390a..9d09f264b 100644 --- a/pytest-pixl/src/pytest_pixl/dicom.py +++ b/pytest-pixl/src/pytest_pixl/dicom.py @@ -62,8 +62,7 @@ def write_volume(filename_pattern: str) -> None: "pixel_data": None, } -# From: -# https://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_b.5.html +# Mapping based on: https://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_b.5.html MODALITY_TO_CLASS_UID = { "CR": "1.2.840.10008.5.1.4.1.1.1", "CT": "1.2.840.10008.5.1.4.1.1.2", From c6e32027786bcab7b59681f2dcf3b47250e81c95 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 13:12:48 +0000 Subject: [PATCH 04/12] remove unused fixtures --- pixl_dcmd/tests/conftest.py | 89 +------------------------ pixl_dcmd/tests/test_dicom_validator.py | 28 ++++---- pixl_dcmd/tests/test_main.py | 42 ++++++------ 3 files changed, 38 insertions(+), 121 deletions(-) diff --git a/pixl_dcmd/tests/conftest.py b/pixl_dcmd/tests/conftest.py index 15011f94a..7a259d2eb 100644 --- a/pixl_dcmd/tests/conftest.py +++ b/pixl_dcmd/tests/conftest.py @@ -126,67 +126,6 @@ def row_for_testing_image_with_pseudo_patient_id( return db_session -def ids_for_parameterised_test(val: pathlib.Path) -> str: - """Generate test ID for parameterised tests""" - return str(val.stem) - - -@pytest.fixture() -@pytest.mark.parametrize( - ("yaml_file"), PROJECT_CONFIGS_DIR.glob("*.yaml"), ids=ids_for_parameterised_test -) -def row_for_dicom_testing(db_session, yaml_file) -> Session: - """ - Insert a test row for the fake DICOM dataset generated by - pytest_pixl.dicom.generate_dicom_dataset. - """ - - config = load_project_config(yaml_file.stem) - modality = config.project.modalities[0] - - extract = Extract(slug=config.project.name) - ds = pytest_pixl.dicom.generate_dicom_dataset(Modality=modality) - study_info = get_study_info(ds) - - image_not_exported = Image( - mrn=study_info.mrn, - accession_number=study_info.accession_number, - study_uid=study_info.study_uid, - study_date=STUDY_DATE, - extract=extract, - ) - with db_session: - db_session.add_all([extract, image_not_exported]) - db_session.commit() - - return db_session - - -@pytest.fixture() -def row_for_single_dicom_testing(db_session) -> Session: - """ - Insert a test row for the fake DICOM dataset generated by - pytest_pixl.dicom.generate_dicom_dataset. - """ - - extract = Extract(slug=TEST_PROJECT_SLUG) - ds = pytest_pixl.dicom.generate_dicom_dataset() - study_info = get_study_info(ds) - - image_not_exported = Image( - mrn=study_info.mrn, - accession_number=study_info.accession_number, - study_uid=study_info.study_uid, - study_date=STUDY_DATE, - extract=extract, - ) - with db_session: - db_session.add_all([extract, image_not_exported]) - db_session.commit() - - return db_session - - @pytest.fixture() def directory_of_mri_dicoms() -> Generator[pathlib.Path, None, None]: """Directory containing MRI DICOMs suitable for testing.""" @@ -279,41 +218,15 @@ def mock_get(key, default) -> Optional[str]: @pytest.fixture() -def vanilla_dicom_image_DX(row_for_dicom_testing) -> Dataset: - """ - A DICOM image with diffusion data to test the anonymisation process. - Private tags were added to match the tag operations defined in the project config, so we can - test whether the anonymisation process works as expected when defining overrides. - The row_for_mri_dicom_testing dependency is to make sure the database is populated with the - project slug, which is used to anonymise the DICOM image. - """ - return generate_dicom_dataset(Modality="DX") - - -@pytest.fixture() -def vanilla_single_dicom_image_DX(row_for_single_dicom_testing) -> Dataset: +def vanilla_dicom_image_DX() -> Dataset: """ A DICOM image with diffusion data to test the anonymisation process. Private tags were added to match the tag operations defined in the project config, so we can test whether the anonymisation process works as expected when defining overrides. - The row_for_single_dicom_testing dependency is to make sure the database is populated with the - project slug, which is used to anonymise the DICOM image. """ return generate_dicom_dataset(Modality="DX") -@pytest.fixture() -def vanilla_dicom_image_MR(row_for_dicom_testing) -> Dataset: - """ - A DICOM image with MX data to test the anonymisation process. - Private tags were added to match the tag operations defined in the project config, so we can - test whether the anonymisation process works as expected when defining overrides. - The row_for_mri_dicom_testing dependency is to make sure the database is populated with the - project slug, which is used to anonymise the DICOM image. - """ - return generate_dicom_dataset(Modality="MR") - - @pytest.fixture(scope="module") def test_project_config() -> PixlConfig: return load_project_config(TEST_PROJECT_SLUG) diff --git a/pixl_dcmd/tests/test_dicom_validator.py b/pixl_dcmd/tests/test_dicom_validator.py index fe58adf54..a1f96e5a1 100644 --- a/pixl_dcmd/tests/test_dicom_validator.py +++ b/pixl_dcmd/tests/test_dicom_validator.py @@ -20,19 +20,19 @@ from pydicom import Dataset -def test_validation_check_works(vanilla_single_dicom_image_DX: Dataset) -> None: +def test_validation_check_works(vanilla_dicom_image_DX: Dataset) -> None: """ GIVEN a DICOM dataset WHEN the dataset is validated against itself (withouth anonymisation) THEN no errors should be raised """ validator = DicomValidator() - validator.validate_original(vanilla_single_dicom_image_DX) - assert not validator.validate_anonymised(vanilla_single_dicom_image_DX) + validator.validate_original(vanilla_dicom_image_DX) + assert not validator.validate_anonymised(vanilla_dicom_image_DX) def test_validation_after_anonymisation_works( - vanilla_single_dicom_image_DX: Dataset, + vanilla_dicom_image_DX: Dataset, test_project_config, ) -> None: """ @@ -41,17 +41,17 @@ def test_validation_after_anonymisation_works( THEN no errors should be raised """ validator = DicomValidator() - validator.validate_original(vanilla_single_dicom_image_DX) - anonymise_dicom(vanilla_single_dicom_image_DX, config=test_project_config) + validator.validate_original(vanilla_dicom_image_DX) + anonymise_dicom(vanilla_dicom_image_DX, config=test_project_config) - assert not validator.validate_anonymised(vanilla_single_dicom_image_DX) + assert not validator.validate_anonymised(vanilla_dicom_image_DX) @pytest.fixture() -def non_compliant_dicom_image(vanilla_single_dicom_image_DX: Dataset) -> Dataset: +def non_compliant_dicom_image(vanilla_dicom_image_DX: Dataset) -> Dataset: """A DICOM dataset that is not compliant with the DICOM standard.""" - del vanilla_single_dicom_image_DX.PatientName - return vanilla_single_dicom_image_DX + del vanilla_dicom_image_DX.PatientName + return vanilla_dicom_image_DX def test_validation_passes_for_non_compliant_dicom(non_compliant_dicom_image) -> None: @@ -66,7 +66,7 @@ def test_validation_passes_for_non_compliant_dicom(non_compliant_dicom_image) -> def test_validation_fails_after_invalid_tag_modification( - vanilla_single_dicom_image_DX, + vanilla_dicom_image_DX, ) -> None: """ GIVEN a DICOM dataset @@ -74,9 +74,9 @@ def test_validation_fails_after_invalid_tag_modification( THEN validation should return a non-empty list of errors """ validator = DicomValidator() - validator.validate_original(vanilla_single_dicom_image_DX) - del vanilla_single_dicom_image_DX.PatientName - validation_result = validator.validate_anonymised(vanilla_single_dicom_image_DX) + validator.validate_original(vanilla_dicom_image_DX) + del vanilla_dicom_image_DX.PatientName + validation_result = validator.validate_anonymised(vanilla_dicom_image_DX) assert len(validation_result) == 1 assert "Patient" in validation_result.keys() diff --git a/pixl_dcmd/tests/test_main.py b/pixl_dcmd/tests/test_main.py index 6a9b1a85d..cd740e18e 100644 --- a/pixl_dcmd/tests/test_main.py +++ b/pixl_dcmd/tests/test_main.py @@ -46,7 +46,6 @@ ) from pytest_pixl.dicom import generate_dicom_dataset from pytest_pixl.helpers import run_subprocess -from conftest import ids_for_parameterised_test if typing.TYPE_CHECKING: from core.project_config.pixl_config_model import PixlConfig @@ -116,26 +115,26 @@ def test_enforce_allowlist_removes_overlay_plane() -> None: def test_anonymisation( - vanilla_single_dicom_image_DX: pydicom.Dataset, + vanilla_dicom_image_DX: pydicom.Dataset, test_project_config: PixlConfig, ) -> None: """ Test whether anonymisation works as expected on a vanilla DICOM dataset """ - orig_patient_id = vanilla_single_dicom_image_DX.PatientID - orig_patient_name = vanilla_single_dicom_image_DX.PatientName - orig_study_date = vanilla_single_dicom_image_DX.StudyDate + orig_patient_id = vanilla_dicom_image_DX.PatientID + orig_patient_name = vanilla_dicom_image_DX.PatientName + orig_study_date = vanilla_dicom_image_DX.StudyDate - anonymise_dicom(vanilla_single_dicom_image_DX, config=test_project_config) + anonymise_dicom(vanilla_dicom_image_DX, config=test_project_config) - assert vanilla_single_dicom_image_DX.PatientID != orig_patient_id - assert vanilla_single_dicom_image_DX.PatientName != orig_patient_name - assert vanilla_single_dicom_image_DX.StudyDate != orig_study_date + assert vanilla_dicom_image_DX.PatientID != orig_patient_id + assert vanilla_dicom_image_DX.PatientName != orig_patient_name + assert vanilla_dicom_image_DX.StudyDate != orig_study_date def test_anonymise_unimplemented_tag( - vanilla_single_dicom_image_DX: pydicom.Dataset, + vanilla_dicom_image_DX: pydicom.Dataset, test_project_config: PixlConfig, ) -> None: """ @@ -151,16 +150,14 @@ def test_anonymise_unimplemented_tag( nested_block.add_new(0x0011, "OB", b"") # create private sequence tag with the nested dataset - block = vanilla_single_dicom_image_DX.private_block( - 0x0013, "VR OB CREATOR", create=True - ) + block = vanilla_dicom_image_DX.private_block(0x0013, "VR OB CREATOR", create=True) block.add_new(0x0010, "SQ", [nested_ds]) - anonymise_dicom(vanilla_single_dicom_image_DX, config=test_project_config) + anonymise_dicom(vanilla_dicom_image_DX, config=test_project_config) - assert (0x0013, 0x0010) in vanilla_single_dicom_image_DX - assert (0x0013, 0x1010) in vanilla_single_dicom_image_DX - sequence = vanilla_single_dicom_image_DX[(0x0013, 0x1010)] + assert (0x0013, 0x0010) in vanilla_dicom_image_DX + assert (0x0013, 0x1010) in vanilla_dicom_image_DX + sequence = vanilla_dicom_image_DX[(0x0013, 0x1010)] assert (0x0013, 0x1011) not in sequence[0] @@ -191,6 +188,11 @@ def test_anonymise_and_validate_as_external_user( assert dataset != pydicom.dcmread(dataset_path) +def ids_for_parameterised_test(val: pathlib.Path) -> str: + """Generate test ID for parameterised tests""" + return str(val.stem) + + @pytest.mark.parametrize( ("yaml_file"), PROJECT_CONFIGS_DIR.glob("*.yaml"), ids=ids_for_parameterised_test ) @@ -215,7 +217,7 @@ def test_anonymise_and_validate_dicom(caplog, request, yaml_file) -> None: assert not validation_errors -@pytest.mark.usefixtures("row_for_single_dicom_testing") +@pytest.mark.usefixtures() def test_anonymisation_with_overrides( mri_diffusion_dicom_image: pydicom.Dataset, test_project_config: PixlConfig, @@ -417,7 +419,9 @@ def test_should_exclude_series(dicom_series_to_exclude, dicom_series_to_keep): def test_can_nifti_convert_post_anonymisation( - row_for_single_dicom_testing, tmp_path, directory_of_mri_dicoms, tag_scheme + tmp_path, + directory_of_mri_dicoms, + tag_scheme, ): """Can a DICOM image that has passed through our tag processing be converted to NIFTI""" # Create a directory to store anonymised DICOM files From a56fbcb82027c54f80ae48366f0b8430d0707382 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 13:27:46 +0000 Subject: [PATCH 05/12] remove unused MODALITY_TAGS dict --- pytest-pixl/src/pytest_pixl/dicom.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pytest-pixl/src/pytest_pixl/dicom.py b/pytest-pixl/src/pytest_pixl/dicom.py index 9d09f264b..baed0f2c9 100644 --- a/pytest-pixl/src/pytest_pixl/dicom.py +++ b/pytest-pixl/src/pytest_pixl/dicom.py @@ -70,9 +70,6 @@ def write_volume(filename_pattern: str) -> None: "MR": "1.2.840.10008.5.1.4.1.1.4", "PT": "1.2.840.10008.5.1.4.1.1.128", } -MODALITY_TAGS = { - "DX": {"Presentation LUT Shape": "IDENTITY"}, -} def generate_dicom_dataset(tag_values: dict = TAGS_DICT, **kwargs: Any) -> Dataset: From 1e7227ef1e08b0cca2a193b75e512dcf5b125140 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 13:46:59 +0000 Subject: [PATCH 06/12] update pixl_core test to reflect change in test project config --- pixl_core/tests/project_config/test_project_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixl_core/tests/project_config/test_project_config.py b/pixl_core/tests/project_config/test_project_config.py index 3a09ae6d5..112b037c9 100644 --- a/pixl_core/tests/project_config/test_project_config.py +++ b/pixl_core/tests/project_config/test_project_config.py @@ -30,7 +30,7 @@ def test_config_from_file(): project_config = load_project_config(TEST_CONFIG) assert project_config.project.name == "test-extract-uclh-omop-cdm" - assert project_config.project.modalities == ["DX", "CR"] + assert project_config.project.modalities == ["DX", "CR", "MR"] assert project_config.destination.dicom == "ftps" assert project_config.destination.parquet == "ftps" From 5e66ca57da50560b842dc8fe4a8c69d9eacaf749 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 15:45:14 +0000 Subject: [PATCH 07/12] remove MR as a supported modality in the test project config otherwise system tests fail --- projects/configs/test-extract-uclh-omop-cdm.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/configs/test-extract-uclh-omop-cdm.yaml b/projects/configs/test-extract-uclh-omop-cdm.yaml index 9f7d1d6b8..1045d9ae4 100644 --- a/projects/configs/test-extract-uclh-omop-cdm.yaml +++ b/projects/configs/test-extract-uclh-omop-cdm.yaml @@ -15,7 +15,7 @@ project: name: "test-extract-uclh-omop-cdm" azure_kv_alias: "test" - modalities: ["DX", "CR", "MR"] + modalities: ["DX", "CR"] tag_operation_files: base: From 3bb65e1fa2527327e498e36a51573f4cdac67fbb Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 15:49:45 +0000 Subject: [PATCH 08/12] Remove MR from list of modalities in project config tests in core --- pixl_core/tests/project_config/test_project_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixl_core/tests/project_config/test_project_config.py b/pixl_core/tests/project_config/test_project_config.py index 112b037c9..3a09ae6d5 100644 --- a/pixl_core/tests/project_config/test_project_config.py +++ b/pixl_core/tests/project_config/test_project_config.py @@ -30,7 +30,7 @@ def test_config_from_file(): project_config = load_project_config(TEST_CONFIG) assert project_config.project.name == "test-extract-uclh-omop-cdm" - assert project_config.project.modalities == ["DX", "CR", "MR"] + assert project_config.project.modalities == ["DX", "CR"] assert project_config.destination.dicom == "ftps" assert project_config.destination.parquet == "ftps" From 52a9833170dd257b23bef01972cdb60a57781e99 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 16:00:35 +0000 Subject: [PATCH 09/12] set mri diffusion dataset modality to DX otherwise instance is dropped due to unsupported modality --- pixl_dcmd/tests/test_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixl_dcmd/tests/test_main.py b/pixl_dcmd/tests/test_main.py index cd740e18e..99e7d490d 100644 --- a/pixl_dcmd/tests/test_main.py +++ b/pixl_dcmd/tests/test_main.py @@ -93,7 +93,7 @@ def mri_diffusion_dicom_image(test_project_config: PixlConfig) -> pydicom.Datase test whether the anonymisation process works as expected when defining overrides. """ manufacturer = "Philips" - ds = generate_dicom_dataset(Manufacturer=manufacturer, Modality="MR") + ds = generate_dicom_dataset(Manufacturer=manufacturer, Modality="DX") tags = _get_mri_diffusion_tags( config=test_project_config, manufacturer=manufacturer ) From 7d2692b981862332b5a07097a0e6527aa10f7f82 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 16:33:24 +0000 Subject: [PATCH 10/12] remove projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml as it's empty --- .../test-extract-uclh-omop-cdm.yaml | 17 ----------------- .../configs/test-extract-uclh-omop-cdm.yaml | 1 - 2 files changed, 18 deletions(-) delete mode 100644 projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml diff --git a/projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml b/projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml deleted file mode 100644 index 0d3e06cb8..000000000 --- a/projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) University College London Hospitals NHS Foundation Trust -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Configuration for extracting data from UCLH OMOP CDM DICOM files - -[] \ No newline at end of file diff --git a/projects/configs/test-extract-uclh-omop-cdm.yaml b/projects/configs/test-extract-uclh-omop-cdm.yaml index 1045d9ae4..52199ef1e 100644 --- a/projects/configs/test-extract-uclh-omop-cdm.yaml +++ b/projects/configs/test-extract-uclh-omop-cdm.yaml @@ -22,7 +22,6 @@ tag_operation_files: - "base.yaml" #Expected base config file for any project - "mri.yaml" - "xray.yaml" - - "test-extract-uclh-omop-cdm.yaml" manufacturer_overrides: ["mri.yaml", "mri-diffusion.yaml"] series_filters: From fdf230866e8b7e53aaa922e6b6ce464538c38505 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Wed, 18 Dec 2024 16:48:56 +0000 Subject: [PATCH 11/12] remove mention of test-extract-uclh-omop-cdm.yaml tag operation file as it have been removed --- pixl_core/src/core/dicom_tags.py | 1 - pixl_core/tests/project_config/test_project_config.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pixl_core/src/core/dicom_tags.py b/pixl_core/src/core/dicom_tags.py index 8f6d6ca81..684085429 100644 --- a/pixl_core/src/core/dicom_tags.py +++ b/pixl_core/src/core/dicom_tags.py @@ -16,7 +16,6 @@ This information is currently duplicated in - pixl_imaging/tests/orthanc_raw_config/orthanc.json - orthanc/orthanc-raw/config/orthanc.json - - projects/configs/tag-operations/test-extract-uclh-omop-cdm.yaml For now you will have to manually keep these in step. """ diff --git a/pixl_core/tests/project_config/test_project_config.py b/pixl_core/tests/project_config/test_project_config.py index 3a09ae6d5..56ae5964d 100644 --- a/pixl_core/tests/project_config/test_project_config.py +++ b/pixl_core/tests/project_config/test_project_config.py @@ -41,7 +41,7 @@ def base_yaml_data(): return { "project": {"name": "myproject", "modalities": ["DX", "CR"]}, "tag_operation_files": { - "base": ["test-extract-uclh-omop-cdm.yaml"], + "base": ["base.yaml"], "manufacturer_overrides": ["mri-diffusion.yaml"], }, "destination": {"dicom": "ftps", "parquet": "ftps"}, From 07d4baf5c60000a581baa0134e62cfd253486392 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Thu, 19 Dec 2024 12:18:25 +0000 Subject: [PATCH 12/12] move uclh-nasogastric-tube-project-ngt-only-full-dataset tags into xray config and move duplicated tags into base --- projects/configs/tag-operations/base.yaml | 21 +- projects/configs/tag-operations/mri.yaml | 4 - ...ic-tube-project-ngt-only-full-dataset.yaml | 448 ------------------ projects/configs/tag-operations/xray.yaml | 187 ++++++-- ...ic-tube-project-ngt-only-full-dataset.yaml | 2 +- 5 files changed, 162 insertions(+), 500 deletions(-) delete mode 100644 projects/configs/tag-operations/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml diff --git a/projects/configs/tag-operations/base.yaml b/projects/configs/tag-operations/base.yaml index 0e06d697d..8b7c3fc58 100644 --- a/projects/configs/tag-operations/base.yaml +++ b/projects/configs/tag-operations/base.yaml @@ -51,7 +51,7 @@ group: 0x0008 element: 0x0020 op: "replace" -- name: "General Study" +- name: "Study Time" group: 0x0008 element: 0x0030 op: "replace" @@ -83,7 +83,7 @@ group: 0x0008 element: 0x1090 op: "keep" -- name: "Referenced Series Sequence" +- name: "Referenced SOP Instance UID" group: 0x0008 element: 0x1155 op: "replace_UID" @@ -135,11 +135,15 @@ #################################### 0018 Group ################################### # # -- name: "Scan Options Attribute" +- name: "Scan Options" group: 0x0018 element: 0x0022 op: "replace" #CT, MR, X-Ray +- name: Slice Thickness + group: 0x0018 + element: 0x0050 + op: keep - name: "Software Version" group: 0x0018 element: 0x1020 @@ -149,14 +153,10 @@ element: 0x1149 op: "keep" #CT, MR, PET, US, X-Ray, and RT Images -- name: "Imager Pixel Spacing" - group: 0x0018 - element: 0x1164 - op: "keep" -- name: "Grid" +- name: kVp group: 0x0018 - element: 0x1166 - op: "keep" + element: 0x0060 + op: keep - name: "Focal Spot" group: 0x0018 element: 0x1190 @@ -372,6 +372,7 @@ element: 0x0140 op: "replace_UID" #CT, MR, PET, US, X-Ray, and RT Images + #################################### 3006 Group ################################### # # diff --git a/projects/configs/tag-operations/mri.yaml b/projects/configs/tag-operations/mri.yaml index ef5944358..cf8f5a722 100644 --- a/projects/configs/tag-operations/mri.yaml +++ b/projects/configs/tag-operations/mri.yaml @@ -62,10 +62,6 @@ group: 0x0018 element: 0x0024 op: "keep" -- name: "Slice Thickness" - group: 0x0018 - element: 0x0050 - op: "keep" - name: "Repetition Time" group: 0x0018 element: 0x0080 diff --git a/projects/configs/tag-operations/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml b/projects/configs/tag-operations/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml deleted file mode 100644 index 0e0c48836..000000000 --- a/projects/configs/tag-operations/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml +++ /dev/null @@ -1,448 +0,0 @@ -# Copyright (c) University College London Hospitals NHS Foundation Trust -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Configuration for extracting data from UCLH Nasogastric Tube Project DICOM files - -- name: "Specific Character Set" - group: 0x0008 - element: 0x0005 - op: "keep" -- name: "Image Type" - group: 0x0008 - element: 0x0008 - op: "keep" -- name: "SOP Class UID" - group: 0x0008 - element: 0x0016 - op: "keep" -- name: "SOP Instance UID" - group: 0x0008 - element: 0x0018 - op: "replace_UID" -- name: "Study Date" - group: 0x0008 - element: 0x0020 - op: "replace" -- name: "Instance Creator UID" - group: 0x0008 - element: 0x0014 - op: "replace_UID" -- name: "Study Time" - group: 0x0008 - element: 0x0030 - op: "replace" -- name: "Accession Number" - group: 0x0008 - element: 0x0050 - op: "replace" -- name: "Modality" - group: 0x0008 - element: 0x0060 - op: "keep" -- name: "Modalities In Study" - group: 0x0008 - element: 0x0061 - op: "keep" -- name: "Manufacturer" - group: 0x0008 - element: 0x0070 - op: "keep" -- name: "Referring Physicians Name" - group: 0x0008 - element: 0x0090 - op: "replace" -- name: "Study Description" - group: 0x0008 - element: 0x1030 - op: "keep" -- name: "Series Description" - group: 0x0008 - element: 0x103e - op: "keep" -- name: "Manufacturers Model Name" - group: 0x0008 - element: 0x1090 - op: "keep" -- name: "Referenced SOP Instance UID" - group: 0x0008 - element: 0x1155 - op: "replace_UID" -- name: "Patients Name" - group: 0x0010 - element: 0x0010 - op: "replace" -- name: "Patient ID" - group: 0x0010 - element: 0x0020 - op: "secure-hash" -- name: "Patients Birth Date" - group: 0x0010 - element: 0x0030 - op: "replace" -- name: "Patients Sex" - group: 0x0010 - element: 0x0040 - op: "keep" -- name: "Patients Size" - group: 0x0010 - element: 0x1020 - op: "keep" -- name: "Patients Weight" - group: 0x0010 - element: 0x1030 - op: "keep" -- name: "Body Part Examined" - group: 0x0018 - element: 0x0015 - op: "keep" -- name: "Scanning Sequence" - group: 0x0018 - element: 0x0020 - op: "keep" -- name: "Scanning Variant" - group: 0x0018 - element: 0x0021 - op: "keep" -- name: "Scan Options" - group: 0x0018 - element: 0x0022 - op: "keep" -- name: "MR Acquisition Type" - group: 0x0018 - element: 0x0023 - op: "keep" -- name: "Slice Thickness" - group: 0x0018 - element: 0x0050 - op: "keep" -- name: "kVp" - group: 0x0018 - element: 0x0060 - op: "keep" -- name: "Echo Time" - group: 0x0018 - element: 0x0081 - op: "keep" -- name: "Echo Train Length" - group: 0x0018 - element: 0x0091 - op: "keep" -- name: "Software Version" - group: 0x0018 - element: 0x1020 - op: "keep" -- name: "Field Of View Dimension" - group: 0x0018 - element: 0x1149 - op: "keep" -- name: "Exposure Time" - group: 0x0018 - element: 0x1150 - op: "keep" -- name: "X Ray Tube Current" - group: 0x0018 - element: 0x1151 - op: "keep" -- name: "Exposure" - group: 0x0018 - element: 0x1152 - op: "keep" -- name: "Exposure In Uas" - group: 0x0018 - element: 0x1153 - op: "keep" -- name: "Image Area Dose Product" - group: 0x0018 - element: 0x115e - op: "keep" -- name: "Imager Pixel Spacing" - group: 0x0018 - element: 0x1164 - op: "keep" -- name: "Grid" - group: 0x0018 - element: 0x1166 - op: "keep" -- name: "Focal Spot" - group: 0x0018 - element: 0x1190 - op: "keep" -- name: "Acquisition Device Processing Description" - group: 0x0018 - element: 0x1400 - op: "keep" -- name: "Exposure Index" - group: 0x0018 - element: 0x1411 - op: "keep" -- name: "Target Exposure Index" - group: 0x0018 - element: 0x1412 - op: "keep" -- name: "Deviation Index" - group: 0x0018 - element: 0x1413 - op: "keep" -- name: "Positioner Type" - group: 0x0018 - element: 0x1508 - op: "keep" -- name: "Collemator Shape" - group: 0x0018 - element: 0x1700 - op: "keep" -- name: "Vertices Of The Polygonal Collimator" - group: 0x0018 - element: 0x1720 - op: "keep" -- name: "Patient Position" - group: 0x0018 - element: 0x5100 - op: "keep" -- name: "View Position" - group: 0x0018 - element: 0x5101 - op: "keep" -- name: "Sensitivity" - group: 0x0018 - element: 0x6000 - op: "keep" -- name: "Detector Temperature" - group: 0x0018 - element: 0x7001 - op: "keep" -- name: "Detector Type" - group: 0x0018 - element: 0x7004 - op: "keep" -- name: "Detector Configuration" - group: 0x0018 - element: 0x7005 - op: "keep" -- name: "Detector ID" - group: 0x0018 - element: 0x700a - op: "keep" -- name: "Detector Binning" - group: 0x0018 - element: 0x701a - op: "keep" -- name: "Detector Element Physical Size" - group: 0x0018 - element: 0x7020 - op: "keep" -- name: "Detector Element Spacing" - group: 0x0018 - element: 0x7022 - op: "keep" -- name: "Detector Active Shape" - group: 0x0018 - element: 0x7024 - op: "keep" -- name: "Detector Active Dimensions" - group: 0x0018 - element: 0x7026 - op: "keep" -- name: "Field Of View Origin" - group: 0x0018 - element: 0x7030 - op: "keep" -- name: "Field Of View Rotation" - group: 0x0018 - element: 0x7032 - op: "keep" -- name: "Field Of View Horizontal Flip" - group: 0x0018 - element: 0x7034 - op: "keep" -- name: "Grid Focal Distance" - group: 0x0018 - element: 0x704c - op: "keep" -- name: "Exposure Control Mode" - group: 0x0018 - element: 0x7060 - op: "keep" -- name: "Study Instance UID" - group: 0x0020 - element: 0x000d - op: "replace_UID" -- name: "Series Instance UID" - group: 0x0020 - element: 0x000e - op: "replace_UID" -- name: "Study ID" - group: 0x0020 - element: 0x0010 - op: "replace" -- name: "Series Number" - group: 0x0020 - element: 0x0011 - op: "keep" -- name: "Image Number" - group: 0x0020 - element: 0x0013 - op: "keep" -- name: "Patient Orientation" - group: 0x0020 - element: 0x0020 - op: "keep" -- name: "Image Position (Patient)" - group: 0x0020 - element: 0x0032 - op: "keep" -- name: "Image Orientation (Patient)" - group: 0x0020 - element: 0x0037 - op: "keep" -- name: "Position Reference Indicator" - group: 0x0020 - element: 0x1040 - op: "keep" -- name: "Patient Orientation Code Sequence" - group: 0x0054 - element: 0x0410 - op: "keep" -- name: "Image Laterality" - group: 0x0020 - element: 0x0062 - op: "keep" -- name: "Samples Per Pixel" - group: 0x0028 - element: 0x0002 - op: "keep" -- name: "Photometric Interpretation" - group: 0x0028 - element: 0x0004 - op: "keep" -- name: "Rows" - group: 0x0028 - element: 0x0010 - op: "keep" -- name: "Columns" - group: 0x0028 - element: 0x0011 - op: "keep" -- name: "Pixel Spacing" - group: 0x0028 - element: 0x0030 - op: "keep" -- name: "Bits Allocated" - group: 0x0028 - element: 0x0100 - op: "keep" -- name: "Bits Stored" - group: 0x0028 - element: 0x0101 - op: "keep" -- name: "High Bit" - group: 0x0028 - element: 0x0102 - op: "keep" -- name: "Pixel Representation" - group: 0x0028 - element: 0x0103 - op: "keep" -- name: "Quality Control Image" - group: 0x0028 - element: 0x0300 - op: "keep" -- name: "Burned In Annotation" - group: 0x0028 - element: 0x0301 - op: "keep" -- name: "Pixel Spacing Calibration Type" - group: 0x0028 - element: 0x0a02 - op: "keep" -- name: "Pixel Spacing Calibration Description" - group: 0x0028 - element: 0x0a04 - op: "keep" -- name: "Pixel Intensity Relationship" - group: 0x0028 - element: 0x1040 - op: "keep" -- name: "Pixel Intensity Relationship Sign" - group: 0x0028 - element: 0x1041 - op: "keep" -- name: "Window Center" - group: 0x0028 - element: 0x1050 - op: "keep" -- name: "Window Width" - group: 0x0028 - element: 0x1051 - op: "keep" -- name: "Rescale Intercept" - group: 0x0028 - element: 0x1052 - op: "keep" -- name: "Rescale Slope" - group: 0x0028 - element: 0x1053 - op: "keep" -- name: "Rescale Type" - group: 0x0028 - element: 0x1054 - op: "keep" -- name: "Window Center And Width Explanation" - group: 0x0028 - element: 0x1055 - op: "keep" -- name: "Lossy Image Compression" - group: 0x0028 - element: 0x2110 - op: "keep" -- name: "VOI LUT Sequence" - group: 0x0028 - element: 0x3010 - op: "keep" -- name: "View Code Sequence" - group: 0x0054 - element: 0x0220 - op: "keep" -- name: "Frame of Reference UID" - group: 0x0020 - element: 0x0052 - op: "replace_UID" -- name: "Synchronization Frame of Reference UID" - group: 0x0020 - element: 0x0200 - op: "replace_UID" -- name: "Storage Media File-set UID" - group: 0x0088 - element: 0x0140 - op: "replace_UID" -- name: "UID" - group: 0x0040 - element: 0xA124 - op: "replace_UID" -- name: "Presentation LUT Shape" - group: 0x2050 - element: 0x0020 - op: "keep" -- name: "Referenced Frame of Reference UID" - group: 0x3006 - element: 0x0024 - op: "replace_UID" -- name: "Related Frame of Reference UID" - group: 0x3006 - element: 0x00C2 - op: "replace_UID" -- name: "Pixel Data" - group: 0x7fe0 - element: 0x0010 - op: "keep" diff --git a/projects/configs/tag-operations/xray.yaml b/projects/configs/tag-operations/xray.yaml index de8f88ccb..e7952c767 100644 --- a/projects/configs/tag-operations/xray.yaml +++ b/projects/configs/tag-operations/xray.yaml @@ -12,54 +12,167 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Default configuration to extend base for x-rays - -- name: "Body Part Examined" +- name: Patients Size + group: 0x0010 + element: 0x1020 + op: keep +- name: Patients Weight + group: 0x0010 + element: 0x1030 + op: keep +- name: Body Part Examined group: 0x0018 element: 0x0015 - op: "keep" - -#https://dicom.innolitics.com/ciods/x-ray-radiofluoroscopic-image/x-ray-acquisition/00181166 -#https://dicom.innolitics.com/ciods/x-ray-angiographic-image/x-ray-acquisition/00181166 -#https://dicom.innolitics.com/ciods/digital-x-ray-image/x-ray-grid/00181166 -#https://dicom.innolitics.com/ciods/digital-mammography-x-ray-image/x-ray-grid/00181166 -#https://dicom.innolitics.com/ciods/digital-intra-oral-x-ray-image/x-ray-grid/00181166 -#https://dicom.innolitics.com/ciods/x-ray-3d-craniofacial-image/x-ray-3d-craniofacial-acquisition/00189507/00181166 -#https://dicom.innolitics.com/ciods/x-ray-3d-angiographic-image/x-ray-3d-angiographic-acquisition/00189507/00181166 -#https://dicom.innolitics.com/ciods/breast-projection-x-ray-image/breast-projection-x-ray-image-multi-frame-functional-groups/52009229/00189555/00181166 -- name: "Acquisition Device Processing Description" + op: keep +- name: Exposure Time + group: 0x0018 + element: 0x1150 + op: keep +- name: X Ray Tube Current + group: 0x0018 + element: 0x1151 + op: keep +- name: Exposure + group: 0x0018 + element: 0x1152 + op: keep +- name: Exposure In Uas + group: 0x0018 + element: 0x1153 + op: keep +- name: Image Area Dose Product + group: 0x0018 + element: 0x115e + op: keep +- name: Imager Pixel Spacing + group: 0x0018 + element: 0x1164 + op: keep +- name: Grid + group: 0x0018 + element: 0x1166 + op: keep +- name: Acquisition Device Processing Description group: 0x0018 element: 0x1400 - op: "keep" -#https://dicom.innolitics.com/ciods/x-ray-radiofluoroscopic-image/x-ray-image/00181400 -#https://dicom.innolitics.com/ciods/x-ray-angiographic-image/x-ray-image/00181400 -#https://dicom.innolitics.com/ciods/digital-x-ray-image/dx-image/00181400 -#https://dicom.innolitics.com/ciods/digital-mammography-x-ray-image/dx-image/00181400 -#https://dicom.innolitics.com/ciods/digital-intra-oral-x-ray-image/dx-image/00181400 -#https://dicom.innolitics.com/ciods/x-ray-3d-craniofacial-image/x-ray-3d-craniofacial-image-contributing-sources/00189506/00181400 -#https://dicom.innolitics.com/ciods/x-ray-3d-angiographic-image/x-ray-3d-angiographic-image-contributing-sources/00189506/00181400 -#https://dicom.innolitics.com/ciods/breast-projection-x-ray-image/breast-projection-x-ray-image-multi-frame-functional-groups/52009229/00189412/00181400 -- name: "Pixel Spacing Calibration Type" + op: keep +- name: Exposure Index + group: 0x0018 + element: 0x1411 + op: keep +- name: Target Exposure Index + group: 0x0018 + element: 0x1412 + op: keep +- name: Deviation Index + group: 0x0018 + element: 0x1413 + op: keep +- name: Positioner Type + group: 0x0018 + element: 0x1508 + op: keep +- name: Collemator Shape + group: 0x0018 + element: 0x1700 + op: keep +- name: Vertices Of The Polygonal Collimator + group: 0x0018 + element: 0x1720 + op: keep +- name: View Position + group: 0x0018 + element: 0x5101 + op: keep +- name: Sensitivity + group: 0x0018 + element: 0x6000 + op: keep +- name: Detector Temperature + group: 0x0018 + element: 0x7001 + op: keep +- name: Detector Type + group: 0x0018 + element: 0x7004 + op: keep +- name: Detector Configuration + group: 0x0018 + element: 0x7005 + op: keep +- name: Detector ID + group: 0x0018 + element: 0x700a + op: keep +- name: Detector Binning + group: 0x0018 + element: 0x701a + op: keep +- name: Detector Element Physical Size + group: 0x0018 + element: 0x7020 + op: keep +- name: Detector Element Spacing + group: 0x0018 + element: 0x7022 + op: keep +- name: Detector Active Shape + group: 0x0018 + element: 0x7024 + op: keep +- name: Detector Active Dimensions + group: 0x0018 + element: 0x7026 + op: keep +- name: Field Of View Origin + group: 0x0018 + element: 0x7030 + op: keep +- name: Field Of View Rotation + group: 0x0018 + element: 0x7032 + op: keep +- name: Field Of View Horizontal Flip + group: 0x0018 + element: 0x7034 + op: keep +- name: Grid Focal Distance + group: 0x0018 + element: 0x704c + op: keep +- name: Exposure Control Mode + group: 0x0018 + element: 0x7060 + op: keep +- name: Quality Control Image + group: 0x0028 + element: 0x0300 + op: keep +- name: Pixel Spacing Calibration Type group: 0x0028 element: 0x0a02 - op: "keep" -#RT, X-Ray -- name: "Pixel Spacing Calibration Description" + op: keep +- name: Pixel Spacing Calibration Description group: 0x0028 element: 0x0a04 - op: "keep" -#X-Ray -- name: "Pixel Intensity Relationship" + op: keep +- name: Pixel Intensity Relationship group: 0x0028 element: 0x1040 - op: "keep" -#X-Ray -- name: "Pixel Intensity Relationship Sign" + op: keep +- name: Pixel Intensity Relationship Sign group: 0x0028 element: 0x1041 - op: "keep" -#X-Ray -- name: "Presentation LUT Shape" + op: keep +- name: View Code Sequence + group: 0x0054 + element: 0x1050 + op: keep +- name: Patient Orientation Code Sequence + group: 0x0054 + element: 0x0410 + op: keep +- name: Presentation LUT Shape group: 0x2050 element: 0x0020 - op: "keep" + op: keep diff --git a/projects/configs/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml b/projects/configs/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml index 6b49a09e5..c54eac399 100644 --- a/projects/configs/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml +++ b/projects/configs/uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml @@ -20,7 +20,7 @@ project: tag_operation_files: base: - "base.yaml" #Expected base config file for any project - - "uclh-nasogastric-tube-project-ngt-only-full-dataset.yaml" + - "xray.yaml" manufacturer_overrides: null destination: dicom: "ftps"