Skip to content

Commit

Permalink
test(dicom): Add IDC test data and cases
Browse files Browse the repository at this point in the history
  • Loading branch information
jadh4v committed Oct 30, 2024
1 parent 007e79a commit 5cf9780
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 6 deletions.
2 changes: 1 addition & 1 deletion packages/dicom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"build:python:versionSync": "itk-wasm pnpm-script build:python:versionSync",
"publish:python": "itk-wasm pnpm-script publish:python",
"test": "pnpm test:data:download && pnpm build:gen:python && pnpm test:python",
"test:data:download": "dam download test/data test/data.tar.gz bafybeicfhacth6jwhtqd2caxwtepoydf54kv3zzr36zpoj7og5iuzptv7u https://data.kitware.com/api/v1/file/66c62d8faf422925a42121ab/download",
"test:data:download": "dam download test/data test/data.tar.gz bafybeiaqmwshl3vrcp5soxvmsez4nfhugcv7p432k6ndmb3jecspnvvv6u https://data.kitware.com/api/v1/file/6706def5fb903c47575aa6cc/download",
"test:data:pack": "dam pack test/data test/data.tar.gz",
"test:python:wasi": "itk-wasm pnpm-script test:python:wasi",
"test:python:emscripten": "itk-wasm pnpm-script test:python:emscripten",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from pathlib import Path
import numpy as np
from test_helper import compare_json

testPathPrefix = '../../test/data/input/'
Expand All @@ -20,4 +21,27 @@ def test_read_segmentation():
assert outputJSON is not None
baselineJsonFile = 'dicom-images/SEG/MR_ref_3DSAGT2SPACE_tumor_seg.json'
baselineJsonFilePath = Path(baselinePathPrefix, baselineJsonFile)
assert compare_json(baselineJsonFilePath, outputJSON)
assert compare_json(baselineJsonFilePath, outputJSON)

def test_read_segmentation_idc1():
from itkwasm_dicom_wasi import read_segmentation
fileName = 'dicom-images/IDC/nlst/100010/1.2.840.113654.2.55.236467930500313421847662756581858562399/SEG_1.2.276.0.7230010.3.1.3.313263360.35955.1706319184.882151/0ec3f890-c11a-4b33-8a37-17a68a5c7545.dcm'
testFilePath = Path(testPathPrefix, fileName)
outputImage, outputJSON = read_segmentation(testFilePath)
assert outputImage is not None
assert outputImage.data is not None
assert outputImage.imageType.dimension == 3
assert outputImage.imageType.componentType == 'int16'
assert outputImage.imageType.pixelType == 'Scalar'
assert outputImage.imageType.components == 1

assert np.array_equal(outputImage.origin, [ -174.5, 174.316528, 9.04000854 ])
assert np.array_equal(outputImage.spacing, [ 0.683594, 0.683594, 2.5 ])
assert np.array_equal(np.array(outputImage.direction).flatten(), [ 1, 0, 0, 0, -1, 0, 0, 0, -1 ])
assert np.array_equal(outputImage.size, [ 512, 512, 137 ])
assert (outputImage.data.size == 35913728)

assert outputJSON is not None
baselineJsonFile = 'dicom-images/IDC/nlst/100010/1.2.840.113654.2.55.236467930500313421847662756581858562399/SEG_1.2.276.0.7230010.3.1.3.313263360.35955.1706319184.882151/metaInfo.json'
baselineJsonFilePath = Path(testPathPrefix, baselineJsonFile)
assert compare_json(baselineJsonFilePath, outputJSON)
11 changes: 10 additions & 1 deletion packages/dicom/python/itkwasm-dicom-wasi/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,13 @@
test_input_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "input"
test_baseline_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "baseline"
test_output_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "output" / "python"
test_output_path.mkdir(parents=True, exist_ok=True)
test_output_path.mkdir(parents=True, exist_ok=True)

def compare_rounded_float(a: float, b: float, n: int) -> bool:
return round(a, n) == round(b, n)

def compare_array_float(a, b) -> bool:
for x in range(len(a)):
if not compare_rounded_float(a[x], b[x], 3):
return False
return True
Original file line number Diff line number Diff line change
@@ -1,8 +1,48 @@
# Generated file. To retain edits, remove this comment.

from itkwasm_dicom_wasi import read_image_dicom_file_series

from .common import test_input_path, test_output_path
from .common import test_input_path, test_output_path, compare_array_float

from pathlib import Path
import numpy as np
from glob import glob

testDataInputDirectory = Path("../../test/data/input").resolve()

def test_read_image_dicom_file_series():
pass

def test_read_image_dicom_file_series_idc1():
nmFileName = "dicom-images/IDC/acrin_nsclc_fdg_pet/ACRIN-NSCLC-FDG-PET-134/1.3.6.1.4.1.14519.5.2.1.7009.2403.154904565437993902842316547208/NM_1.3.6.1.4.1.14519.5.2.1.7009.2403.484725606860278331095617627781/0d6c2de3-168b-4ea5-a1c8-c7d7438faa15.dcm"
testFilePath = Path(testDataInputDirectory, nmFileName)
output = read_image_dicom_file_series([testFilePath])
outputImage = output[0]
assert outputImage is not None
assert outputImage.data is not None
assert outputImage.imageType.dimension == 3
assert outputImage.imageType.componentType == 'uint16'
assert outputImage.imageType.pixelType == 'Scalar'
assert outputImage.imageType.components == 1

assert compare_array_float(outputImage.origin, [-204.602, -399.602, 1759.7])
assert compare_array_float(outputImage.spacing, [2.8125, 2.8125, 2])
assert compare_array_float(np.array(outputImage.direction).flatten(), [1, 0, 0, 0, 1, 0, 0, 0, -1])
assert np.array_equal(outputImage.size, [128, 128, 196])
assert (outputImage.data.size == 3211264)

def test_read_image_dicom_file_series_idc2():
dirPath = 'dicom-images/IDC/nsclc_radiomics_genomics/LUNG3-49/1.3.6.1.4.1.32722.99.99.278496019127563640059579120768864824043/CT_1.3.6.1.4.1.32722.99.99.239963936032720978832553442140518002510'
testDicomSeriesFiles = glob(f"{Path(testDataInputDirectory, dirPath)}/*.dcm")
output = read_image_dicom_file_series(testDicomSeriesFiles)
outputImage = output[0]
assert outputImage is not None
assert outputImage.data is not None
assert outputImage.imageType.dimension == 3
assert outputImage.imageType.componentType == 'int16'
assert outputImage.imageType.pixelType == 'Scalar'
assert outputImage.imageType.components == 1

assert compare_array_float(outputImage.origin, [ -171, -102, 673.3 ])
assert compare_array_float(outputImage.spacing, [ 0.672, 0.672, 4.0])
assert compare_array_float(np.array(outputImage.direction).flatten(), [ 1, 0, 0, 0, 1, 0, 0, 0, -1 ])
assert np.array_equal(outputImage.size, [ 512, 512, 89 ])
assert (outputImage.data.size == 23330816)
32 changes: 32 additions & 0 deletions packages/dicom/typescript/test/node/dcmqi.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,35 @@ test('itk2dcm_makeSEG_seg_size', async t => {
t.assert(r1.metrics.maximumDifference < 1e-8)
}
})

// ========= IDC data tests =============
test('IDC: DICOM segmentation', async t => {
const segFileName = 'dicom-images/IDC/nlst/100010/1.2.840.113654.2.55.236467930500313421847662756581858562399/SEG_1.2.276.0.7230010.3.1.3.313263360.35955.1706319184.882151/0ec3f890-c11a-4b33-8a37-17a68a5c7545.dcm'
const testFilePath = path.join(testPathPrefix, segFileName)
const output = await readSegmentationNode(testFilePath)
console.log(output)
console.log(output.segImage.imageType)
console.log(output.segImage.data)
console.log(JSON.stringify(output.metaInfo))

t.assert(output.segImage != null)
t.assert(output.segImage.data != null)
t.deepEqual(output.segImage.imageType, {
dimension: 3,
componentType: 'int16',
pixelType: 'Scalar',
components: 1
})
t.deepEqual(output.segImage.origin, [ -174.5, 174.316528, 9.04000854 ])
t.deepEqual(output.segImage.spacing, [ 0.683594, 0.683594, 2.5 ])
t.assert(arrayEquals(output.segImage.direction, [ 1, 0, 0, 0, -1, 0, 0, 0, -1 ]))
t.deepEqual(output.segImage.size, [ 512, 512, 137 ])
t.deepEqual(output.segImage.data.length, 35913728)

// The json file is simply generated from a previous call to readSegmentationNode. It is therefore, simply testing for regressions.
const baselineJsonFile = '/dicom-images/IDC/nlst/100010/1.2.840.113654.2.55.236467930500313421847662756581858562399/SEG_1.2.276.0.7230010.3.1.3.313263360.35955.1706319184.882151/metaInfo.json'
const baselineJsonFilePath = path.join(testPathPrefix, baselineJsonFile)
const baselineJsonFileBuffer = fs.readFileSync(baselineJsonFilePath)
const baselineJsonObject = JSON.parse(baselineJsonFileBuffer)
t.assert(JSON.stringify(baselineJsonObject) === JSON.stringify(output.metaInfo))
})
57 changes: 57 additions & 0 deletions packages/dicom/typescript/test/node/gdcm.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ function arrayEquals(a, b) {
return (a.length === b.length && a.every((val, idx) => val === b[idx]))
}

function roundToThreePlaces(a) {
return Math.round((a + Number.EPSILON) * 1000) / 1000
}

function floatCompare(a, b) {
return (roundToThreePlaces(a) === roundToThreePlaces(b))
}

function floatCompareArray(a, b) {
return (a.length === b.length && a.every((val, idx) => floatCompare(val, b[idx])))
}

function verifyImage (t, image, expectedComponentType, expectedPixelType) {
let componentType = IntTypes.Int16
if (expectedComponentType) {
Expand Down Expand Up @@ -335,3 +347,48 @@ test('DICOM SOP: Nuclear Medicine Image.', async t => {
]))
t.deepEqual(outputImage.size, [128, 128, 69])
})

// ========= IDC data tests =============
test('IDC: Nuclear Medicine with negative SpacingBetweenSlices Test', async t => {
const nmFileName = 'dicom-images/IDC/acrin_nsclc_fdg_pet/ACRIN-NSCLC-FDG-PET-134/1.3.6.1.4.1.14519.5.2.1.7009.2403.154904565437993902842316547208/NM_1.3.6.1.4.1.14519.5.2.1.7009.2403.484725606860278331095617627781/0d6c2de3-168b-4ea5-a1c8-c7d7438faa15.dcm'
const testFilePath = path.join(testDataInputDirectory, nmFileName)
const output = await readImageDicomFileSeriesNode({inputImages: [testFilePath]})
t.assert(output)
const outputImage = output.outputImage
t.assert(outputImage != null)
t.assert(outputImage.imageType != null)
t.deepEqual(outputImage.imageType, {
dimension: 3,
componentType: 'uint16',
pixelType: 'Scalar',
components: 1
})
t.deepEqual(outputImage.origin, [ -204.60240003467, -399.60240003467, 1759.7 ])
t.deepEqual(outputImage.spacing, [ 2.8125, 2.8125, 2 ])
// Z-axis in direction matrix is flipped/negative due to the negative SpacingBetweenSlices
t.assert(arrayEquals(outputImage.direction, [ 1, 0, 0, 0, 1, 0, 0, 0, -1 ]))
t.deepEqual(outputImage.size, [ 128, 128, 196 ])
t.deepEqual(outputImage.data.length, 3211264)
})

test('IDC: CT with negative SpacingBetweenSlices Test', async t => {
const dirPath = 'dicom-images/IDC/nsclc_radiomics_genomics/LUNG3-49/1.3.6.1.4.1.32722.99.99.278496019127563640059579120768864824043/CT_1.3.6.1.4.1.32722.99.99.239963936032720978832553442140518002510'
const testDirPath = path.join(testDataInputDirectory, dirPath)
const testDicomSeriesFiles = glob.sync(`${testDirPath}/*.dcm`)
const output = await readImageDicomFileSeriesNode({inputImages: testDicomSeriesFiles})
t.assert(output)
const outputImage = output.outputImage
t.assert(outputImage != null)
t.assert(outputImage.imageType != null)
t.deepEqual(outputImage.imageType, {
dimension: 3,
componentType: 'int16',
pixelType: 'Scalar',
components: 1
})
t.assert(floatCompareArray(outputImage.origin, [ -171, -102, 673.300 ]))
t.assert(floatCompareArray(outputImage.spacing, [ 0.672, 0.672, 4.0]))
t.assert(arrayEquals(outputImage.direction, [ 1, 0, 0, 0, 1, 0, 0, 0, -1 ]))
t.deepEqual(outputImage.size, [ 512, 512, 89 ])
t.deepEqual(outputImage.data.length, 23330816)
})

0 comments on commit 5cf9780

Please sign in to comment.