Skip to content

Commit

Permalink
fix: 🐛 IDC1346, convert fractional segs into binary
Browse files Browse the repository at this point in the history
  • Loading branch information
Punzo committed Sep 14, 2022
1 parent 42a7ca7 commit b94f07f
Showing 1 changed file with 63 additions and 14 deletions.
77 changes: 63 additions & 14 deletions src/adapters/Cornerstone/Segmentation_4X.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ function _createSegFromImages(images, isMultiframe, options) {
* @param {*} metadataProvider.
* @param {bool} skipOverlapping - skip checks for overlapping segs, default value false.
* @param {number} tolerance - default value 1.e-3.
* @param {bool} binarizeFractionalSegs - binarize fractional segmentation by thresholding - default value true.
* @param {number} fractionalSegsThreshold - thresholding parameter for fractional segmentations - default value 0.8 (80% respect to the maximum value).
*
* @return {[]ArrayBuffer}a list of array buffer for each labelMap
* @return {Object} an object from which the segment metadata can be derived
Expand All @@ -276,7 +278,9 @@ function generateToolState(
arrayBuffer,
metadataProvider,
skipOverlapping = false,
tolerance = 1e-3
tolerance = 1e-3,
binarizeFractionalSegs = true,
fractionalSegsThreshold = 0.8
) {
const dicomData = DicomMessage.readFile(arrayBuffer);
const dataset = DicomMetaDictionary.naturalizeDataset(dicomData.dict);
Expand Down Expand Up @@ -337,7 +341,11 @@ function generateToolState(
return;
}
} else {
pixelData = unpackPixelData(multiframe);
pixelData = unpackPixelData(
multiframe,
binarizeFractionalSegs,
fractionalSegsThreshold
);

if (!pixelData) {
throw new Error("Fractional segmentations are not yet supported");
Expand Down Expand Up @@ -1218,9 +1226,15 @@ function checkIfPerpendicular(iop1, iop2, tolerance) {
* unpackPixelData - Unpacks bitpacked pixelData if the Segmentation is BINARY.
*
* @param {Object} multiframe The multiframe dataset.
* @param {bool} binarizeFractionalSegs - binarize fractional segmentation by thresholding.
* @param {number} fractionalSegsThreshold - thresholding parameter for fractional segmentations.
* @return {Uint8Array} The unpacked pixelData.
*/
function unpackPixelData(multiframe) {
function unpackPixelData(
multiframe,
binarizeFractionalSegs,
fractionalSegsThreshold
) {
const segType = multiframe.SegmentationType;

let data;
Expand All @@ -1240,21 +1254,56 @@ function unpackPixelData(multiframe) {

const pixelData = new Uint8Array(data);

const max = multiframe.MaximumFractionalValue;
const onlyMaxAndZero =
pixelData.find(element => element !== 0 && element !== max) ===
undefined;
// IDC: we encountered segmentations defined as fractional with a constant value which is not the MaximumFractionalValue.
// Here we add the following check: if the labelmap has a constant value (independently by the value itself), it is considered a binary segmentation
const firstNonZeroIndex = pixelData.findIndex(element => element > 0);
const firstNonZeroValue = pixelData[firstNonZeroIndex];
const onlyOneValueAndZero =
pixelData.find(
element => element !== 0 && element !== firstNonZeroValue
) === undefined;

if (onlyOneValueAndZero) {
log.warn(
"This segmentation object is actually binary... processing as such."
);

if (!onlyMaxAndZero) {
// This is a fractional segmentation, which is not currently supported.
return;
return pixelData;
}

log.warn(
"This segmentation object is actually binary... processing as such."
);
// This is a fractional segmentation, which is not currently supported.
if (binarizeFractionalSegs) {
console.warn(
"This segmentation object is fractional. Fractional segmentations are not supported. Computing binary labelMap by thresholding (80% from the maximum value)."
);
// IDC: binarize fractional segmentation if requested

// we calculcate the maximum since unfortunatly it looks like
// (at least for IDC datasets) the maximum value is the array
// is not the DICOM attirbute MaximumFractionalValue
let max = -Number.MAX_VALUE;
pixelData.forEach(element => {
if (element > max) {
max = element;
}
});
max = Math.min(max, multiframe.MaximumFractionalValue);

// use as threshold: max * factor (default 80%)
const thershold = max * fractionalSegsThreshold;

for (let i = 0; i < pixelData.length; i++) {
if (pixelData[i] < thershold) {
pixelData[i] = 0;
} else {
pixelData[i] = 1;
}
}

return pixelData;
}

return pixelData;
return;
}

/**
Expand Down

0 comments on commit b94f07f

Please sign in to comment.