Published
Edited
Jul 10, 2020
Insert cell
md `# Medical Image Segmentation Clustering and Benchmarking`
Insert cell
md`## Load all files in folder`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
comparison = html `<div id="comparison" class="container"></div>`
Insert cell
Insert cell
Insert cell
function setCanvas(id, caseNo, sliceNo, addCheckbox) {
return html`<div style="display: flex; flex-direction: column">
<div style="display: flex;">
${addCheckbox ?
html`<input type="checkbox" name="selectScan" data-id=${ id+'/'+caseNo+'/'+sliceNo }/>`
: null}
<canvas id=${id} class="scan"></canvas>
</div>
<span style="word-break: break-all">${id}</span>
<div>`
}
Insert cell
function compare(){
const checkboxes = Array.from(document.getElementsByName('selectScan'))
const selected = checkboxes.filter(c => c.checked)
if(selected.length === 2) {
const selectedIds = selected.map(ch => ch.dataset.id);
drawComparisonCanvas(selectedIds, 'comparisonCanvas');
} else {
const container = document.getElementById('comparison');
comparison.innerHTML = `<p class="error">You can select only 2 scans to compare</p>`
}
}
Insert cell
function drawComparisonCanvas(canvasIds, targetId) {
const canvasContainer = document.getElementById('comparison');
canvasContainer.innerHTML='';
let inputData = [];
canvasIds.map(canvas => {
const canvasData = canvas.split("/"); // To separate id, caseNo and SliceNo
// inputData.push({
// id: canvasData[0],
// case: canvasData[1],
// slice: canvasData[2],
// imageFile: loadImage(canvasData[0], canvasData[1], canvasData[2])
// });
inputData.push(loadImage(canvasData[0], canvasData[1], canvasData[2]));
})
console.log(inputData);
multiSample(loadImage("images", caseNo, sliceNo), inputData, targetId);
const canvasToCompare = html`
<div style="display: flex; flex-direction: column">
<div style="display: flex;">
<canvas id='${targetId}' class="scan"></canvas>
</div>
<span style="word-break: break-all">${targetId}</span>
</div>`
canvasContainer.appendChild(canvasToCompare);
// const groundTruth = loadImage("segmentations_without_variations", canvasData[1], canvasData[2]);
// sample(loadImage("images", canvasData[1], canvasData[2]), loadImage(canvasData[0], canvasData[1], canvasData[2]), groundTruth, 'selected'+canvasData[0]);
}
Insert cell
loadImage = function(subDir, caseNo, sliceNo) {
if (multiFileDict[subDir][caseNo] != undefined &&
multiFileDict[subDir][caseNo][sliceNo] != undefined) {
var file = multiFileDict[subDir][caseNo][sliceNo].file;
if (file != undefined) {
return file;
}
}
}
Insert cell
multiSample = (background, inputArray, targetId) => {
const bg_image = new Image();
bg_image.src = URL.createObjectURL(background);
let images = [];
inputArray.forEach(function(inputFile) {
const image = new Image();
image.src = URL.createObjectURL(inputFile);
images.push(image);
});
let targetImage = null;
let cols = 0;
let rows = 0;
let bgImageLoaded = new Promise((resolve, reject) => {
bg_image.onload = function() {
const { cv } = window;

targetImage = new cv.imread(bg_image);
cols = targetImage.cols;
rows = targetImage.rows;
resolve();
}
});
bgImageLoaded.then(function() {
let actions = images.map( function(image) {
return new Promise((resolve, reject) => {
image.onload = function() {
const { cv } = window;

// Source image
const contour_src = new cv.imread(image);

// Convert to binary
cv.cvtColor(contour_src, contour_src, cv.COLOR_RGBA2GRAY, 0);
cv.threshold(contour_src, contour_src, 120, 200, cv.THRESH_BINARY);

// Find contours
let contours = new cv.MatVector();
let hierarchy = new cv.Mat();
cv.findContours(contour_src, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE);

// Draw contours on destination image
let color = new cv.Scalar(0, 255, 0, 255);
cv.drawContours(targetImage, contours, -1, color, 1, cv.LINE_8, hierarchy, 32);

// Cleanup
contour_src.delete(); contours.delete(); hierarchy.delete();
resolve();
}
})
});
let results = Promise.all(actions);
results.then(function() {
const { cv } = window;
cv.imshow(targetId, targetImage);
targetImage.delete();
})
});
return
}
Insert cell
sample = (background, input, groundTruth, targetId) => {
const bg_image = new Image();
bg_image.src = URL.createObjectURL(background);
if(input && groundTruth) {
const image = new Image();
image.src = URL.createObjectURL(input);

const imgGroundTruth = new Image();
imgGroundTruth.src = URL.createObjectURL(groundTruth);

image.onload = function() {
const { cv } = window;

// Source and destination images
const contour_src = new cv.imread(image);
const ct_scan = new cv.imread(bg_image);
const cols = ct_scan.cols;
const rows = ct_scan.rows;

cv.imshow(targetId, ct_scan);

// Convert to binary
cv.cvtColor(contour_src, contour_src, cv.COLOR_RGBA2GRAY, 0);
cv.threshold(contour_src, contour_src, 120, 200, cv.THRESH_BINARY);

// Find contours
let contours = new cv.MatVector();
let hierarchy = new cv.Mat();
cv.findContours(contour_src, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE);

// Draw contours on destination image
const matContour = cv.Mat.zeros(contour_src.cols, contour_src.rows, cv.CV_8UC1);
let color = new cv.Scalar(255);
cv.drawContours(matContour, contours, -1, color, 1, cv.LINE_8, hierarchy, 32);

// Ring overlap
let matMask = getGroundTruthMask(imgGroundTruth);
let green = new cv.Mat(matMask.cols, matMask.rows, cv.CV_8UC4, new cv.Scalar(0,255,0,255));
let greenMask = cv.Mat.zeros(cols, rows, cv.CV_8UC1);
cv.bitwise_and(matMask, matContour, greenMask)
green.copyTo(ct_scan, greenMask);

// Not ring overlap
let matInvMask = new cv.Mat();
cv.bitwise_not(matMask, matInvMask);
let red = new cv.Mat(matMask.cols, matMask.rows, cv.CV_8UC4, new cv.Scalar(255,0,0,255));
let redMask = cv.Mat.zeros(cols, rows, cv.CV_8UC1);
cv.bitwise_and(matInvMask, matContour, redMask);
red.copyTo(ct_scan, redMask);

// Show result and clean up
cv.imshow(targetId, ct_scan); //getGroundTruthMask(imgGroundTruth));
contour_src.delete(); ct_scan.delete(); contours.delete(); hierarchy.delete();

};
}
return
}
Insert cell
getGroundTruthMask = (imgGroundTruth) => {
const { cv } = window;
const matGroundTruth = new cv.imread(imgGroundTruth);
// Convert to binary
cv.cvtColor(matGroundTruth, matGroundTruth, cv.COLOR_RGBA2GRAY, 0);
cv.threshold(matGroundTruth, matGroundTruth, 120, 200, cv.THRESH_BINARY);

// Find contours
let contours = new cv.MatVector();
let hierarchy = new cv.Mat();
cv.findContours(matGroundTruth, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE);

// Draw contours on destination image
let matContours = cv.Mat.ones(matGroundTruth.cols, matGroundTruth.rows, cv.CV_8U);
let color2 = new cv.Scalar(0);
cv.drawContours(matContours, contours, -1, color2, 1, cv.LINE_8, hierarchy, 160);

// Calculate distance transform
let matDist = new cv.Mat();
cv.distanceTransform(matContours, matDist, cv.DIST_L2, 3);
// Threshold (range 0 .. 1)
let matThreshold = new cv.Mat();
cv.threshold(matDist, matThreshold, distance_threshold, 1, cv.THRESH_BINARY_INV);
// Convert to 8U, range 0 .. 255
let matConvert = new cv.Mat();
matThreshold.convertTo(matConvert, cv.CV_8U, 255, 0);

return matConvert;
}
Insert cell
surfaceDiceHighlight = (background, input, targetId) => {
const bg_image = new Image();
bg_image.src = URL.createObjectURL(background);
const image = new Image();
image.src = URL.createObjectURL(input);

image.onload = function() {
const { cv } = window;
// Source and destination images
const contour_src = new cv.imread(image);
const ct_scan = new cv.imread(bg_image);
cv.imshow(targetId, ct_scan);
// Convert to binary
cv.cvtColor(contour_src, contour_src, cv.COLOR_RGBA2GRAY, 0);
cv.threshold(contour_src, contour_src, 120, 200, cv.THRESH_BINARY);
// Find contours
let contours = new cv.MatVector();
let hierarchy = new cv.Mat();
cv.findContours(contour_src, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE);
// Draw contours on destination image
let contour_img_for_distance = cv.Mat.ones(contour_src.cols, contour_src.rows, cv.CV_8UC1);
let contour_img_for_coloring = new cv.Mat(contour_src.cols, contour_src.rows, cv.CV_8UC4, new cv.Scalar(0,0,0,255));
let color = new cv.Scalar(0, 255, 0, 255);
let color2 = new cv.Scalar(0);
let color3 = new cv.Scalar(255, 255, 255, 255);
cv.drawContours(ct_scan, contours, -1, color, 1, cv.LINE_8, hierarchy, 160);
cv.drawContours(contour_img_for_distance, contours, -1, color2, 1, cv.LINE_8, hierarchy, 160);
cv.drawContours(contour_img_for_coloring, contours, -1, color3, 1, cv.LINE_8, hierarchy, 160);
// Calculate distance transform
let dist = new cv.Mat(contour_src.cols, contour_src.rows, cv.CV_8UC1);
cv.distanceTransform(contour_img_for_distance, dist, cv.DIST_L2, 3);
let threshold = new cv.Mat(contour_src.cols, contour_src.rows, cv.CV_8UC1);
cv.threshold(dist, threshold, distance_threshold, 255, cv.THRESH_BINARY_INV);
let imgNormalize = new cv.Mat(contour_src.cols, contour_src.rows, cv.CV_8UC1);
console.log(type2str(imgNormalize.type()));
cv.normalize(threshold, imgNormalize, 0, 1.0, cv.NORM_MINMAX);
console.log(type2str(imgNormalize.type()));
imgNormalize.convertTo(imgNormalize, cv.CV_8UC4);
console.log(type2str(imgNormalize.type()));
cv.cvtColor(imgNormalize, imgNormalize, cv.COLOR_GRAY2RGB);
console.log(type2str(imgNormalize.type()));
let diff = new cv.Mat(contour_src.cols, contour_src.rows, cv.CV_8UC4, new cv.Scalar(0,0,0,255));
// console.log(type2str(contour_img_for_coloring.type()));
// cv.cvtColor(contour_img_for_coloring, contour_img_for_coloring, cv.COLOR_RGB2RGBA);
// console.log(type2str(contour_img_for_coloring.type()));
// cv.cvtColor(imgNormalize, imgNormalize, cv.COLOR_GRAY2RGB);
// console.log(type2str(imgNormalize.type()));
// cv.absdiff(contour_img_for_coloring, imgNormalize, diff);
// Show result and clean up
cv.imshow(targetId, contour_img_for_coloring);
contour_src.delete(); ct_scan.delete(); contours.delete(); hierarchy.delete(); contour_img_for_distance.delete(); dist.delete(); threshold.delete();
imgNormalize.delete();
diff.delete();
// mask.delete();
contour_img_for_coloring.delete();
};
}
Insert cell
Insert cell
Insert cell
import {html, svg} from "@observablehq/htl"
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more