dcmjs-org / dcmjs

Javascript implementation of DICOM manipulation
https://dcmjs.netlify.com/
MIT License
287 stars 108 forks source link

Process UN VR with DicomDictionary #352

Closed jimOnAir closed 5 months ago

jimOnAir commented 1 year ago

Hello. I have an issue with receiving images from KPacs with dcmjs-dimse library:

value.toExponential is not a function : TypeError: value.toExponential is not a function >>     at DecimalString.formatValue

After some investigation I have found that KPacs replaces VR of some tags with UN. Original file:

(0002,0000) UL FileMetaInformationGroupLength = 176
(0002,0001) OB FileMetaInformationVersion = <bin: 0x0001>
(0002,0002) UI MediaStorageSOPClassUID = 1.2.840.10008.5.1.4.1.1.1.1
(0002,0003) UI MediaStorageSOPInstanceUID = 1.3.6.1.4.1.18047.1.6.1005961685460676437
(0002,0010) UI TransferSyntaxUID = 1.2.840.10008.1.2.4.70
(0002,0012) UI ImplementationClassUID = 1.2.40.0.13.1.3
(0002,0013) SH ImplementationVersionName = dcm4che-5.17.0
(0008,0005) CS SpecificCharacterSet = ISO_IR 100
(0008,0008) CS ImageType = ORIGINAL\PRIMARY
(0008,0016) UI SOPClassUID = 1.2.840.10008.5.1.4.1.1.1.1
(0008,0018) UI SOPInstanceUID = 1.3.6.1.4.1.18047.1.6.1005961685460676437
(0008,0020) DA StudyDate = 19000101
(0008,0021) DA SeriesDate = 19000101
(0008,0022) DA AcquisitionDate = 19000101
(0008,0023) DA ContentDate = 19000101
(0008,0030) TM StudyTime = 111111
(0008,0031) TM SeriesTime = 111111
(0008,0032) TM AcquisitionTime = 111111
(0008,0033) TM ContentTime = 111111
(0008,0050) SH AccessionNumber = AccNum_1
(0008,0060) CS Modality = DX
(0008,0068) CS PresentationIntentType = FOR PRESENTATION
(0008,0070) LO Manufacturer =
(0008,0080) LO InstitutionName =
(0008,0090) PN ReferringPhysicianName =
(0008,1010) SH StationName =
(0008,1030) LO StudyDescription = ELBOW LT
(0008,103E) LO SeriesDescription = ELBOW LT AP
(0008,1040) LO InstitutionalDepartmentName =
(0008,1050) PN PerformingPhysicianName =
(0008,1070) PN OperatorsName =
(0008,1090) LO ManufacturerModelName =
(0010,0010) PN PatientName = Anonymous^Patient1
(0010,0020) LO PatientID = AnonymID_1
(0010,0021) LO IssuerOfPatientID =
(0010,0030) DA PatientBirthDate = 19000101
(0010,0040) CS PatientSex = <empty string>
(0010,1000) LO OtherPatientIDs =
(0010,1010) AS PatientAge = 000Y
(0010,2201) LO PatientSpeciesDescription =
(0010,2203) CS PatientSexNeutered = <undefined>
(0010,2210) CS AnatomicalOrientationType = <undefined>
(0010,2292) LO PatientBreedDescription =
(0010,2297) PN ResponsiblePerson =
(0010,2298) CS ResponsiblePersonRole = <undefined>
(0010,4000) LT PatientComments =
(0018,0015) CS BodyPartExamined = ELBOW LT
(0018,0060) DS KVP = 55
(0018,1020) LO SoftwareVersions =
(0018,1030) LO ProtocolName = AP
(0018,1150) IS ExposureTime = 17
(0018,1151) IS XRayTubeCurrent = 300
(0018,1152) IS Exposure = 5
(0018,115E) DS ImageAndFluoroscopyAreaDoseProduct = 0
(0018,1164) DS ImagerPixelSpacing = 0.140\0.140
(0018,1411) DS ExposureIndex = 662
(0018,1412) DS TargetExposureIndex = 1010
(0018,1413) DS DeviationIndex = -1.835
(0018,5101) CS ViewPosition = AP
(0018,7004) CS DetectorType = SCINTILLATOR
(0020,000D) UI StudyInstanceUID = 1.3.6.1.4.1.18047.1.6.1005961685460676435
(0020,000E) UI SeriesInstanceUID = 1.3.6.1.4.1.18047.1.6.1005961685460676436
(0020,0010) SH StudyID =
(0020,0011) IS SeriesNumber = 1
(0020,0013) IS InstanceNumber = 1
(0020,0020) CS PatientOrientation = <undefined>
(0020,0022) IS OverlayNumber = 1
(0020,0062) CS ImageLaterality = B
(0020,4000) LT ImageComments =
(0028,0002) US SamplesPerPixel = 1
(0028,0004) CS PhotometricInterpretation = MONOCHROME2
(0028,0008) IS NumberOfFrames = 1
(0028,0010) US Rows = 1968
(0028,0011) US Columns = 1466
(0028,0030) DS PixelSpacing = 0.140\0.140
(0028,0100) US BitsAllocated = 16
(0028,0101) US BitsStored = 14
(0028,0102) US HighBit = 13
(0028,0103) US PixelRepresentation = 0
(0028,1040) CS PixelIntensityRelationship = LIN
(0028,1041) SS PixelIntensityRelationshipSign = -1
(0028,1050) DS WindowCenter = 6822
(0028,1051) DS WindowWidth = 12628
(0028,1052) DS RescaleIntercept = 0
(0028,1053) DS RescaleSlope = 1
(0028,1054) LO RescaleType = US
(0038,0400) LO PatientInstitutionResidence =
(7FE0,0010) OB PixelData = <binary data of length: 3319254>

File from KPacs:

(0002,0000) UL FileMetaInformationGroupLength = 204
(0002,0001) OB FileMetaInformationVersion = <bin: 0x0001>
(0002,0002) UI MediaStorageSOPClassUID = 1.2.840.10008.5.1.4.1.1.1.1
(0002,0003) UI MediaStorageSOPInstanceUID = 1.3.6.1.4.1.18047.1.6.1005961685460676437
(0002,0010) UI TransferSyntaxUID = 1.2.840.10008.1.2.4.70
(0002,0012) UI ImplementationClassUID = 1.2.826.0.1.3680043.2.1396.999
(0002,0013) SH ImplementationVersionName = CharruaVista
(0002,0016) AE SourceApplicationEntityTitle = KPServer
(0008,0005) CS SpecificCharacterSet = ISO_IR 100
(0008,0008) CS ImageType = ORIGINAL\PRIMARY
(0008,0016) UI SOPClassUID = 1.2.840.10008.5.1.4.1.1.1.1
(0008,0018) UI SOPInstanceUID = 1.3.6.1.4.1.18047.1.6.1005961685460676437
(0008,0020) DA StudyDate = 19000101
(0008,0021) DA SeriesDate = 19000101
(0008,0022) DA AcquisitionDate = 19000101
(0008,0023) DA ContentDate = 19000101
(0008,0030) TM StudyTime = 111111
(0008,0031) TM SeriesTime = 111111
(0008,0032) TM AcquisitionTime = 111111
(0008,0033) TM ContentTime = 111111
(0008,0050) SH AccessionNumber = AccNum_1
(0008,0060) CS Modality = DX
(0008,0068) CS PresentationIntentType = FOR PRESENTATION
(0008,0070) LO Manufacturer =
(0008,0080) LO InstitutionName =
(0008,0090) PN ReferringPhysicianName =
(0008,1010) SH StationName =
(0008,1030) LO StudyDescription = ELBOW LT
(0008,103E) LO SeriesDescription = ELBOW LT AP
(0008,1040) LO InstitutionalDepartmentName =
(0008,1050) PN PerformingPhysicianName =
(0008,1070) PN OperatorsName =
(0008,1090) LO ManufacturerModelName =
(0010,0010) PN PatientName = Anonymous^Patient1
(0010,0020) LO PatientID = AnonymID_1
(0010,0021) LO IssuerOfPatientID =
(0010,0030) DA PatientBirthDate = 19000101
(0010,0040) CS PatientSex = <undefined>
(0010,1000) LO OtherPatientIDs =
(0010,1010) AS PatientAge = 000Y
(0010,2201) UN PatientSpeciesDescription = <bin: 0x>
(0010,2203) UN PatientSexNeutered = <bin: 0x>
(0010,2210) UN AnatomicalOrientationType = <bin: 0x>
(0010,2292) UN PatientBreedDescription = <bin: 0x>
(0010,2297) UN ResponsiblePerson = <bin: 0x>
(0010,2298) UN ResponsiblePersonRole = <bin: 0x>
(0010,4000) LT PatientComments =
(0018,0015) CS BodyPartExamined = ELBOW LT
(0018,0060) DS KVP = 55
(0018,1020) LO SoftwareVersions =
(0018,1030) LO ProtocolName = AP
(0018,1150) IS ExposureTime = 17
(0018,1151) IS XRayTubeCurrent = 300
(0018,1152) IS Exposure = 5
(0018,115E) DS ImageAndFluoroscopyAreaDoseProduct = 0
(0018,1164) DS ImagerPixelSpacing = 0.140\0.140
(0018,1411) UN ExposureIndex = 662
(0018,1412) UN TargetExposureIndex = 1010
(0018,1413) UN DeviationIndex = -1.835
(0018,5101) CS ViewPosition = AP
(0018,7004) CS DetectorType = SCINTILLATOR
(0020,000D) UI StudyInstanceUID = 1.3.6.1.4.1.18047.1.6.1005961685460676435
(0020,000E) UI SeriesInstanceUID = 1.3.6.1.4.1.18047.1.6.1005961685460676436
(0020,0010) SH StudyID =
(0020,0011) IS SeriesNumber = 1
(0020,0013) IS InstanceNumber = 1
(0020,0020) CS PatientOrientation = <undefined>
(0020,0022) IS OverlayNumber = 1
(0020,0062) CS ImageLaterality = B
(0020,4000) LT ImageComments =
(0028,0002) US SamplesPerPixel = 1
(0028,0004) CS PhotometricInterpretation = MONOCHROME2
(0028,0008) IS NumberOfFrames = 1
(0028,0010) US Rows = 1968
(0028,0011) US Columns = 1466
(0028,0030) DS PixelSpacing = 0.140\0.140
(0028,0100) US BitsAllocated = 16
(0028,0101) US BitsStored = 14
(0028,0102) US HighBit = 13
(0028,0103) US PixelRepresentation = 0
(0028,1040) CS PixelIntensityRelationship = LIN
(0028,1041) SS PixelIntensityRelationshipSign = -1
(0028,1050) DS WindowCenter = 6822
(0028,1051) DS WindowWidth = 12628
(0028,1052) DS RescaleIntercept = 0
(0028,1053) DS RescaleSlope = 1
(0028,1054) LO RescaleType = US
(0038,0400) LO PatientInstitutionResidence =
(7FE0,0010) OW PixelData = <binary data of length: 3228514>

VR is replaced for tags:

(0010,2201) UN PatientSpeciesDescription = <bin: 0x>
(0010,2203) UN PatientSexNeutered = <bin: 0x>
(0010,2210) UN AnatomicalOrientationType = <bin: 0x>
(0010,2292) UN PatientBreedDescription = <bin: 0x>
(0010,2297) UN ResponsiblePerson = <bin: 0x>
(0010,2298) UN ResponsiblePersonRole = <bin: 0x>
(0018,1411) UN ExposureIndex = 662
(0018,1412) UN TargetExposureIndex = 1010
(0018,1413) UN DeviationIndex = -1.835

Therefore values for this tags are parsed as ArrayBuffer in Dataset and can't and next can't be saved to file.

I thought that actuall VR of tag can be obtained from DicomDictionary, but current value should be procceded based on UN encoding. I've tried this fix for files and it's working. Please review and let me know if something needs to be changed.

pieper commented 1 year ago

Thanks for proposing this. Since dicom-dimse is involved, perhaps @PantelisGeorgiadis could have a look?

Also we like to have tests for anything that changes core functions. As you know dicom parsing can be very fragile and we don't want unintended side effects now or in the future. Can you add a test and test data for the dcmjs-org/data repository?

PantelisGeorgiadis commented 1 year ago

Hello @jimOnAir! Very strange behavior! Have you tried to understand why KPacs is doing that? Maybe the internal DICOM dictionary is too old to know about these tags and, therefore, it converts them to UN? How do other clients behave when sending the same datasets?

Is there a chance the changes proposed by @andreidubov in https://github.com/PantelisGeorgiadis/dcmjs-dimse/issues/47 to fit your needs so we can avoid having this logic in the core library?

jimOnAir commented 1 year ago

Thank you @pieper, I'll try to add tests later.

@PantelisGeorgiadis KPacs is too old to support the current standard. Version 1.6 was released in 2008. But since it is free, some organizations still using it.

https://github.com/PantelisGeorgiadis/dcmjs-dimse/issues/47 aims on sending parsed dataset over the network, but here we have an issue with dataset parsing.

jimOnAir commented 5 months ago

Hello. @andreidubov thank you for your solution, it seems like it is way better than mine.