Skip to content

Commit

Permalink
Add basic dicom SR parsing, fixes #1689
Browse files Browse the repository at this point in the history
  • Loading branch information
ivmartel committed Jun 26, 2024
1 parent 6bbe3da commit d26de5f
Show file tree
Hide file tree
Showing 9 changed files with 943 additions and 0 deletions.
106 changes: 106 additions & 0 deletions src/dicom/dicomImageReference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {
getSopInstanceReference,
getDicomSopInstanceReferenceItem
} from './dicomSopInstanceReference';

// doc imports
/* eslint-disable no-unused-vars */
import {DataElement} from './dataElement';
/* eslint-enable no-unused-vars */

/**
* Related DICOM tag keys.
*/
const tagKeys = {
ReferencedFrameNumber: '00081160',
ReferencedSOPSequence: '00081199',
ReferencedSegmentNumber: '0062000B'
};

/**
* DICOM image reference: item of a SR content sequence.
*
* Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.4.html#table_C.18.4-1}.
*/
export class ImageReference {
/**
* @type {object}
*/
referencedSOPSequence;

/**
* @type {object}
*/
referencedFrameNumber;

/**
* @type {string}
*/
referencedSegmentNumber;

/**
* @type {string}
*/
fiducialUID;

/**
* Get a string representation of this object.
*
* @returns {string} The object as string.
*/
toString() {
return this.referencedSOPSequence.toString();
};
};

/**
* Get a reference object from a dicom element.
*
* @param {Object<string, DataElement>} dataElements The dicom element.
* @returns {ImageReference} A reference object.
*/
export function getImageReference(dataElements) {
const ref = new ImageReference();

if (typeof dataElements[tagKeys.ReferencedFrameNumber] !== 'undefined') {
ref.referencedFrameNumber =
dataElements[tagKeys.ReferencedFrameNumber].value[0];
}
if (typeof dataElements[tagKeys.ReferencedSOPSequence] !== 'undefined') {
ref.referencedSOPSequence = getSopInstanceReference(
dataElements[tagKeys.ReferencedSOPSequence].value[0]);
}
if (typeof dataElements[tagKeys.ReferencedSegmentNumber] !== 'undefined') {
ref.referencedSegmentNumber =
dataElements[tagKeys.ReferencedSegmentNumber].value[0];
}

return ref;
};

/**
* Get a simple dicom element item from a reference object.
*
* @param {ImageReference} ref The reference object.
* @returns {Object<string, any>} The item as a list of (key, value) pairs.
*/
export function getDicomImageReferenceItem(ref) {
// dicom item (tags are in group/element order)
const item = {};

if (typeof ref.referencedFrameNumber !== 'undefined') {
item.ReferencedFrameNumber = ref.referencedFrameNumber;
}
if (typeof ref.referencedSOPSequence !== 'undefined') {
item.ReferencedSOPSequence = {
value: [getDicomSopInstanceReferenceItem(ref.referencedSOPSequence)]
};
}
if (typeof ref.referencedSegmentNumber !== 'undefined') {
item.ReferencedSegmentNumber =
ref.referencedSegmentNumber;
}

// return
return item;
}
128 changes: 128 additions & 0 deletions src/dicom/dicomMeasuredValue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import {
getCode,
getDicomCodeItem
} from './dicomCode';

// doc imports
/* eslint-disable no-unused-vars */
import {DataElement} from './dataElement';
/* eslint-enable no-unused-vars */

/**
* Related DICOM tag keys.
*/
const tagKeys = {
NumericValue: '0040A30A',
FloatingPointValue: '0040A161',
RationalNumeratorValue: '0040A162',
RationalDenominatorValue: '0040A163',
MeasurementUnitsCodeSequence: '004008EA'
};

/**
* DICOM measured value: property of a numeric measurement.
*
* Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.html#table_C.18.1-1}.
*/
export class MeasuredValue {
/**
* @type {number}
*/
numericValue;

/**
* @type {number}
*/
floatingPointValue;

/**
* @type {number}
*/
rationalNumeratorValue;

/**
* @type {number}
*/
rationalDenominatorValue;

/**
* @type {object}
*/
measurementUnitsCode;

/**
* Get a string representation of this object.
*
* @returns {string} The object as string.
*/
toString() {
return this.numericValue + ' ' +
this.measurementUnitsCode.toString();
};

};

/**
* Get a measured value object from a dicom element.
*
* @param {Object<string, DataElement>} dataElements The dicom element.
* @returns {MeasuredValue} A measured value object.
*/
export function getMeasuredValue(dataElements) {
const value = new MeasuredValue();

if (typeof dataElements[tagKeys.NumericValue] !== 'undefined') {
value.numericValue = dataElements[tagKeys.NumericValue].value[0];
}
if (typeof dataElements[tagKeys.FloatingPointValue] !== 'undefined') {
value.floatingPointValue =
dataElements[tagKeys.FloatingPointValue].value[0];
}
if (typeof dataElements[tagKeys.RationalNumeratorValue] !== 'undefined') {
value.rationalNumeratorValue =
dataElements[tagKeys.RationalNumeratorValue].value[0];
}
if (typeof dataElements[tagKeys.RationalDenominatorValue] !== 'undefined') {
value.rationalDenominatorValue =
dataElements[tagKeys.RationalDenominatorValue].value[0];
}
if (typeof dataElements[tagKeys.MeasurementUnitsCodeSequence] !==
'undefined') {
value.measurementUnitsCode = getCode(
dataElements[tagKeys.MeasurementUnitsCodeSequence].value[0]);
}

return value;
};

/**
* Get a simple dicom element item from a measured value object.
*
* @param {MeasuredValue} value The measured value object.
* @returns {Object<string, any>} The item as a list of (key, value) pairs.
*/
export function getDicomMeasuredValueItem(value) {
// dicom item (tags are in group/element order)
const item = {};

if (typeof value.measurementUnitsCode !== 'undefined') {
item.MeasurementUnitsCodeSequence = {
value: [getDicomCodeItem(value.measurementUnitsCode)]
};
}
if (typeof value.floatingPointValue !== 'undefined') {
item.FloatingPointValue = value.floatingPointValue;
}
if (typeof value.rationalNumeratorValue !== 'undefined') {
item.RationalNumeratorValue = value.rationalNumeratorValue;
}
if (typeof value.rationalDenominatorValue !== 'undefined') {
item.RationalDenominatorValue = value.rationalDenominatorValue;
}
if (typeof value.numericValue !== 'undefined') {
item.NumericValue = value.numericValue;
}

// return
return item;
}
98 changes: 98 additions & 0 deletions src/dicom/dicomNumericMeasurement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import {
getCode,
getDicomCodeItem
} from './dicomCode';
import {
getMeasuredValue,
getDicomMeasuredValueItem
} from './dicomMeasuredValue';

// doc imports
/* eslint-disable no-unused-vars */
import {DataElement} from './dataElement';
/* eslint-enable no-unused-vars */

/**
* Related DICOM tag keys.
*/
const tagKeys = {
MeasuredValueSequence: '0040A300',
NumericValueQualifierCodeSequence: '0040A301'
};

/**
* DICOM numeric measurement: item of a SR content sequence.
*
* Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.18.html#table_C.18.1-1}.
*/
export class NumericMeasurement {
/**
* @type {object}
*/
measuredValue;

/**
* @type {object}
*/
numericValueQualifierCode;

/**
* Get a string representation of this object.
*
* @returns {string} The object as string.
*/
toString() {
let res = this.measuredValue.toString();
if (typeof this.numericValueQualifierCode !== 'undefined') {
res += ' ' + this.numericValueQualifierCode.toString();
}
return res;
}
};

/**
* Get a measurement object from a dicom element.
*
* @param {Object<string, DataElement>} dataElements The dicom element.
* @returns {NumericMeasurement} A measurement object.
*/
export function getNumericMeasurement(dataElements) {
const measurement = new NumericMeasurement();

if (typeof dataElements[tagKeys.MeasuredValueSequence] !== 'undefined') {
measurement.measuredValue = getMeasuredValue(
dataElements[tagKeys.MeasuredValueSequence].value[0]);
}
if (typeof dataElements[tagKeys.NumericValueQualifierCodeSequence] !==
'undefined') {
measurement.numericValueQualifierCode = getCode(
dataElements[tagKeys.NumericValueQualifierCodeSequence].value[0]);
}

return measurement;
};

/**
* Get a simple dicom element item from a measurement object.
*
* @param {NumericMeasurement} measurement The measurement object.
* @returns {Object<string, any>} The item as a list of (key, value) pairs.
*/
export function getDicomNumericMeasurementItem(measurement) {
// dicom item (tags are in group/element order)
const item = {};

if (typeof measurement.measuredValue !== 'undefined') {
item.MeasuredValueSequence = {
value: [getDicomMeasuredValueItem(measurement.measuredValue)]
};
}
if (typeof measurement.numericValueQualifierCode !== 'undefined') {
item.NumericValueQualifierCodeSequence = {
value: [getDicomCodeItem(measurement.numericValueQualifierCode)]
};
}

// return
return item;
}
Loading

0 comments on commit d26de5f

Please sign in to comment.