/
thresholdSegmentationByRange.ts
129 lines (113 loc) · 3.84 KB
/
thresholdSegmentationByRange.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { Types } from '@cornerstonejs/core';
import { pointInShapeCallback } from '../../utilities';
import { triggerSegmentationDataModified } from '../../stateManagement/segmentation/triggerSegmentationEvents';
import {
getVoxelOverlap,
processVolumes,
ThresholdInformation,
} from './utilities';
/**
* It thresholds a segmentation volume based on a set of threshold values with
* respect to a list of volumes and respective threshold ranges.
* @param segmentationVolume - the segmentation volume to be modified
* @param segmentationIndex - the index of the segmentation to modify
* @param thresholdVolumeInformation - array of objects containing volume data
* and a range (lower and upper values) to threshold
* @param overlapType - indicates if the user requires all voxels pass
* (overlapType = 1) or any voxel pass (overlapType = 0)
* @returns
*/
function thresholdSegmentationByRange(
segmentationVolume: Types.IImageVolume,
segmentationIndex: number,
thresholdVolumeInformation: ThresholdInformation[],
overlapType: number
): Types.IImageVolume {
const scalarData = segmentationVolume.getScalarData();
// prepare a list of volume information objects for callback functions
const { baseVolumeIdx, volumeInfoList } = processVolumes(
segmentationVolume,
thresholdVolumeInformation
);
/**
* This function will test all overlaps between a voxel in base volume
* (the reference for segmentation volume creation) and voxels in other
* volumes.
* If the segmentation volume and the image volume are the same size,
* checks if the scalar data at each point is within the threshold values.
* If the segmentation volume and the image volume are different sizes,
* checks the voxel overlap
*/
volumeInfoList.forEach((volumeInfo) => {
const { volumeSize } = volumeInfo;
if (volumeSize === scalarData.length) {
_handleSameSizeVolume(scalarData, segmentationIndex, volumeInfo);
} else {
_handleDifferentSizeVolume(
scalarData,
segmentationIndex,
volumeInfo,
volumeInfoList,
baseVolumeIdx,
overlapType
);
}
});
triggerSegmentationDataModified(segmentationVolume.volumeId);
return segmentationVolume;
}
function _handleDifferentSizeVolume(
scalarData: Types.PixelDataTypedArray,
segmentationIndex: number,
volumeInfo: any,
volumeInfoList: any,
baseVolumeIdx: number,
overlapType: number
) {
const { imageData, lower, upper, dimensions } = volumeInfo;
let total, overlaps, range;
for (let i = 0; i < scalarData.length; i++) {
if (scalarData[i] === segmentationIndex) {
const overlapBounds = getVoxelOverlap(
imageData,
dimensions,
volumeInfoList[baseVolumeIdx].spacing,
volumeInfoList[baseVolumeIdx].imageData.getPoint(i)
);
const callbackOverlap = ({ value }) => {
total = total + 1;
if (value >= range.lower && value <= range.upper) {
overlaps = overlaps + 1;
}
};
total = 0;
overlaps = 0;
range = { lower, upper };
let overlapTest = false;
// check all voxel overlaps
pointInShapeCallback(
imageData,
() => true,
callbackOverlap,
overlapBounds
);
overlapTest = overlapType === 0 ? overlaps > 0 : overlaps === total;
scalarData[i] = overlapTest ? segmentationIndex : 0;
}
}
return { total, range, overlaps };
}
function _handleSameSizeVolume(
scalarData: Types.PixelDataTypedArray,
segmentationIndex: number,
volumeInfo: any
) {
const { referenceValues, lower, upper } = volumeInfo;
for (let i = 0; i < scalarData.length; i++) {
if (scalarData[i] === segmentationIndex) {
const value = referenceValues[i];
scalarData[i] = value >= lower && value <= upper ? segmentationIndex : 0;
}
}
}
export default thresholdSegmentationByRange;