import getNumberValues from "./getNumberValues"; import isNMReconstructable from "./isNMReconstructable"; /** * Get a subpart of Image Type dicom tag defined by index * @param {*} dataSet * @param {*} index 0 based index of the subtype */ function getImageTypeSubItemFromDataset(dataSet, index) { const imageType = dataSet.string("x00080008"); if (imageType) { const subTypes = imageType.split("\\"); if (subTypes.length > index) { return subTypes[index]; } } return undefined; } // DICOM 标准中针对 Enhanced CT/MR/PET 等“增强型多帧”(Enhanced Multi-frame)影像, 强制要求为每一帧显式记录真实的独立空间坐标 。 // - 它们的数据通常存放在: Per-frame Functional Groups Sequence (5200,9230) -> 对应的 Frame Item -> Plane Position Sequence (0020,9113) -> ImagePositionPatient (0020,0032) 。 function getSharedFunctionalGroupsDataSet(dataSet) { const seq = dataSet?.elements?.x52009229; if (!seq?.items?.length) { return; } return seq.items[0].dataSet; } function getPerFrameFunctionalGroupsDataSet(dataSet, frameIndex) { const seq = dataSet?.elements?.x52009230; if (!seq?.items?.length) { return; } if ( !Number.isInteger(frameIndex) || frameIndex < 0 || frameIndex >= seq.items.length ) { return; } return seq.items[frameIndex].dataSet; } function getOrientationFromPlaneOrientationSequence(dataSet) { const seq = dataSet?.elements?.x00209116; if (!seq?.items?.length) { return; } return getNumberValues(seq.items[0].dataSet, "x00200037", 6); } function getPositionFromPlanePositionSequence(dataSet) { const seq = dataSet?.elements?.x00209113; if (!seq?.items?.length) { return; } return getNumberValues(seq.items[0].dataSet, "x00200032", 3); } function getPixelSpacingFromPixelMeasuresSequence(dataSet) { const seq = dataSet?.elements?.x00289110; if (!seq?.items?.length) { return; } return getNumberValues(seq.items[0].dataSet, "x00280030", 2); } function getSliceThicknessFromPixelMeasuresSequence(dataSet) { const seq = dataSet?.elements?.x00289110; if (!seq?.items?.length) { return; } if (!seq.items[0]?.dataSet?.elements?.x00180050) { return; } return seq.items[0].dataSet.floatString("x00180050"); } /** * Extracts the orientation from NM multiframe dataset, if image type * equal to RECON TOMO or RECON GATED TOMO * @param {*} dataSet * @returns */ function extractOrientationFromNMMultiframeDataset(dataSet) { let imageOrientationPatient; const modality = dataSet.string("x00080060"); if (modality?.includes("NM")) { const imageSubType = getImageTypeSubItemFromDataset(dataSet, 2); if (imageSubType && isNMReconstructable(imageSubType)) { if (dataSet.elements.x00540022) { imageOrientationPatient = getNumberValues( dataSet.elements.x00540022.items[0].dataSet, "x00200037", 6 ); } } } return imageOrientationPatient; } /** * Extracts the position from NM multiframe dataset, if image type * equal to RECON TOMO or RECON GATED TOMO * @param {*} dataSet * @returns */ function extractPositionFromNMMultiframeDataset(dataSet) { let imagePositionPatient; const modality = dataSet.string("x00080060"); if (modality?.includes("NM")) { const imageSubType = getImageTypeSubItemFromDataset(dataSet, 2); if (imageSubType && isNMReconstructable(imageSubType)) { if (dataSet.elements.x00540022) { imagePositionPatient = getNumberValues( dataSet.elements.x00540022.items[0].dataSet, "x00200032", 3 ); } } } return imagePositionPatient; } function isMultiFrame(dataSet) { const numberOfFrames = dataSet.string("x00280008") || dataSet.uint16("x00280008"); return numberOfFrames !== undefined && Number(numberOfFrames) > 1; } /** * Extract orientation information from a dataset. It tries to get the orientation * from the Detector Information Sequence (for NM images) if image type equal * to RECON TOMO or RECON GATED TOMO * @param {*} dataSet * @returns */ function extractOrientationFromDataset(dataSet) { // let imageOrientationPatient; // if (isMultiFrame(dataSet)) { // const perFrameDataSet = getPerFrameFunctionalGroupsDataSet( // dataSet, // frameIndex // ); // imageOrientationPatient = // getOrientationFromPlaneOrientationSequence(perFrameDataSet); // if (!imageOrientationPatient) { // const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet); // imageOrientationPatient = // getOrientationFromPlaneOrientationSequence(sharedDataSet); // } // } // if (!imageOrientationPatient) { // imageOrientationPatient = getNumberValues(dataSet, "x00200037", 6); // } let imageOrientationPatient = getNumberValues(dataSet, "x00200037", 6) // Trying to get the orientation from the Plane Orientation Sequence if (!imageOrientationPatient && dataSet.elements.x00209116) { imageOrientationPatient = getNumberValues( dataSet.elements.x00209116.items[0].dataSet, "x00200037", 6 ); } // If orientation not valid to this point, trying to get the orientation // from the Detector Information Sequence (for NM images) with image type // equal to RECON TOMO or RECON GATED TOMO if (!imageOrientationPatient) { imageOrientationPatient = extractOrientationFromNMMultiframeDataset(dataSet); } return imageOrientationPatient; } /** * Extract position information from a dataset. It tries to get the position * from the Detector Information Sequence (for NM images) if image type equal * to RECON TOMO or RECON GATED TOMO * @param {*} dataSet * @returns */ function extractPositionFromDataset(dataSet) { // let imagePositionPatient; // if (isMultiFrame(dataSet)) { // const perFrameDataSet = getPerFrameFunctionalGroupsDataSet( // dataSet, // frameIndex // ); // imagePositionPatient = // getPositionFromPlanePositionSequence(perFrameDataSet); // if (!imagePositionPatient) { // const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet); // imagePositionPatient = // getPositionFromPlanePositionSequence(sharedDataSet); // } // } // if (!imagePositionPatient) { // imagePositionPatient = getNumberValues(dataSet, "x00200032", 3); // } let imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3); // Trying to get the position from the Plane Position Sequence if (!imagePositionPatient && dataSet.elements.x00209113) { imagePositionPatient = getNumberValues( dataSet.elements.x00209113.items[0].dataSet, "x00200032", 3 ); } // If position not valid to this point, trying to get the position // from the Detector Information Sequence (for NM images) if (!imagePositionPatient) { imagePositionPatient = extractPositionFromNMMultiframeDataset(dataSet); } return imagePositionPatient; } /** * Extract the pixelSpacing information. If exists, extracts this information * from Pixel Measures Sequence * @param {*} dataSet * @returns */ function extractSpacingFromDataset(dataSet) { // let pixelSpacing = getNumberValues(dataSet, 'x00280030', 2); // // If pixelSpacing not valid to this point, trying to get the spacing // // from the Pixel Measures Sequence // if (!pixelSpacing && dataSet.elements.x00289110) { // pixelSpacing = getNumberValues( // dataSet.elements.x00289110.items[0].dataSet, // 'x00280030', // 2 // ); // } // return pixelSpacing; let rowPixelSpacing = null; let columnPixelSpacing = null; // let pixelSpacing; // if (isMultiFrame(dataSet)) { // const perFrameDataSet = getPerFrameFunctionalGroupsDataSet( // dataSet, // frameIndex // ); // const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet); // pixelSpacing = // getPixelSpacingFromPixelMeasuresSequence(perFrameDataSet) || // getPixelSpacingFromPixelMeasuresSequence(sharedDataSet); // } // if (!pixelSpacing) { // pixelSpacing = // getNumberValues(dataSet, "x00280030", 2) || // getPixelSpacingFromPixelMeasuresSequence(dataSet); // } let pixelSpacing = getNumberValues(dataSet, 'x00280030', 2); const imagePixelSpacing = getNumberValues(dataSet, "x00181164", 2); const estimatedRadiographicMagnificationFactor = getNumberValues( dataSet, "x00181114", 2 ); if (pixelSpacing) { rowPixelSpacing = pixelSpacing[0]; columnPixelSpacing = pixelSpacing[1]; } else if (imagePixelSpacing && estimatedRadiographicMagnificationFactor) { rowPixelSpacing = imagePixelSpacing[0] / estimatedRadiographicMagnificationFactor[0]; columnPixelSpacing = imagePixelSpacing[1] / estimatedRadiographicMagnificationFactor[1]; } else if (imagePixelSpacing && !estimatedRadiographicMagnificationFactor) { rowPixelSpacing = imagePixelSpacing[0]; columnPixelSpacing = imagePixelSpacing[1]; } return rowPixelSpacing !== null ? [rowPixelSpacing, columnPixelSpacing] : undefined; } /** * Extract the sliceThickness information. If exists, extracts this information * from Pixel Measures Sequence * @param {*} dataSet * @returns */ function extractSliceThicknessFromDataset(dataSet) { let sliceThickness; if (dataSet.elements.x00180050) { sliceThickness = dataSet.floatString('x00180050'); } else if (dataSet.elements.x00289110 && dataSet.elements.x00289110.items.length && dataSet.elements.x00289110.items[0].dataSet.elements.x00180050) { sliceThickness = dataSet.elements.x00289110.items[0].dataSet.floatString('x00180050'); } // if (sliceThickness === undefined && isMultiFrame(dataSet)) { // const perFrameDataSet = getPerFrameFunctionalGroupsDataSet( // dataSet, // frameIndex // ); // const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet); // sliceThickness = // getSliceThicknessFromPixelMeasuresSequence(perFrameDataSet) || // getSliceThicknessFromPixelMeasuresSequence(sharedDataSet); // } return sliceThickness; } export { getImageTypeSubItemFromDataset, extractOrientationFromDataset, extractPositionFromDataset, extractSpacingFromDataset, extractSliceThicknessFromDataset, };