Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix UN VR setting during naturalization/denaturalization #379

Merged
merged 8 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/DicomMetaDictionary.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ class DicomMetaDictionary {
// when the vr is data-dependent, keep track of the original type
naturalDataset._vrMap[naturalName] = data.vr;
}

if (data.vr == "UN") {
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @pieper that this should be a separate step that should be configurable - maybe as an option going into the parse step, but also as a stand alone filter that works on any JSON DICOMweb metadata instance. That filter should then have some way to register named fixes and a way to disable fixes individually.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you please clarify this point, I want to make sure that I understood you correctly. Do you mean that I should add an option(flag) to naturalizeDataset/denaturalizeDataset and depending on this option(flag) apply or skip for this logic?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I was thinking you could have a special-purpose piece of code at the application level that is coded based on the unique information that it will be accepting data from a source (kpacs) that has known limitations in terms of generating standard dicom objects. I.e. in this case you know that certain tag values will have incorrect values. This special-purpose code should read the instance and apply whatever fixes are needed to make the instance standards-compliant and then send it to the dcmjs code.

We may want to provide a standard place for this kind of special-purpose code to happen. Perhaps in dcmjs-dimse there could be a hook to apply a standardizing transform to the incoming instance data. If there end up being very common ones they could be bundled as add-on packages (e.g. a set of transforms for kpacs, ones for non-standard microCT scanners, etc).

Choose a reason for hiding this comment

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

We don't have access to this low-level data on the application level as the application provides C-Store service only thing we have from dcmjs-dimse is Dataset without any VR information. dcmjs-dimse relies on dcmjs while reading the Dataset. In this case, we don't know if something is wrong until we have read the data.
What you propose is rewriting parts of dcmjs and dcmjs-dimse that are receiving binary data over the network and naturalizing the dataset.
The other thing is that we don't have access to the KPacs dictionary and can't compare it to dcmjs Dictionary to find out which tags can have the wrong VRs.

Copy link
Collaborator

Choose a reason for hiding this comment

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

From what I understand if dcmjs-dimse is processing a c-store you should be able to access the instance as it is received. From there you can read it as pure dicom json model and you can look at each of the tags in the instance and see if they have the non-standard form that leads to the issue based on the dicom dictionary and your knowledge of the deficiencies with kpacs. (That is, if you see that a tag with a know standard VR has been set to UN by kpacs). If you see an issue, you can modify the instances and save them back before further processing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At the application level in CStore we do not have DICOM json, we only have naturalized Dataset. At this level, there is no way how we could get the original VR for tag.
image

DICOM json object is present inside dsmjs-dmse in the buffer/file reading functions.
image
image

If we talk about saving the original UN VR and saving it to a file without getting an error (as suggested in PR). I think it’s impossible to do without changes in dcmjs. The denaturalizeDataset takes the VR based only on the value in the dictionary, which leads to a mismatch between the VR and the value. If we talk about converting UN VR value to VR from the dictionary, it looks like a more difficult task to handle all possible VRs. @PantelisGeorgiadis do you have any ideas how this issue could be solved at the dcmjs-dimse level?

naturalDataset._vrMap[naturalName] = data.vr;
}
}

if (data.Value === undefined) {
Expand Down Expand Up @@ -218,7 +222,10 @@ class DicomMetaDictionary {
}
// process this one entry
var dataItem = ValueRepresentation.addTagAccessors({
vr: entry.vr
vr:
dataset._vrMap && dataset._vrMap[naturalName]
? dataset._vrMap[naturalName]
: entry.vr
});
dataItem.Value = dataset[naturalName];

Expand Down
19 changes: 19 additions & 0 deletions test/data.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,25 @@ describe("The same DICOM file loaded from both DCM and JSON", () => {
});
});

describe("test_un_vr", () => {
it("UN vr should save in _vrMap during naturalization", async () => {
const testDictWithUnVr = { "00181411": {vr: "UN", Value: Array(1)} };
const dataset = DicomMetaDictionary.naturalizeDataset(testDictWithUnVr);

expect(dataset._vrMap).toHaveProperty("ExposureIndex", "UN");
});

it("UN vr should set for tag during denaturalization", async () => {
const testDatasetWithUnVr = { ...minimalDataset };
testDatasetWithUnVr["ExposureIndex"] = Array(1);
testDatasetWithUnVr["_vrMap"] = { ExposureIndex: "UN" };

const dict = DicomMetaDictionary.denaturalizeDataset(testDatasetWithUnVr);
expect(dict).toHaveProperty("00181411");
expect(dict["00181411"]).toHaveProperty("vr", "UN");
});
});

it.each([
[1.0, "1"],
[0.0, "0"],
Expand Down
Loading