UNPKG

image-js

Version:

Image processing and manipulation in JavaScript

100 lines (97 loc) 3.16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = fromMaskConnectedComponentLabelingAlgorithm; var _mlDisjointSet = _interopRequireDefault(require("ml-disjoint-set")); var _RoiMap = _interopRequireDefault(require("../RoiMap")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /* This algorithm is nice and is therefore kept here However it seems to be slower than the get mask and also provides only the positive ROI We therefore don't expose it in the roiManager */ const direction4X = [-1, 0]; const direction4Y = [0, -1]; const neighbours4 = [null, null]; const direction8X = [-1, -1, 0, 1]; const direction8Y = [0, -1, -1, -1]; const neighbours8 = [null, null, null, null]; /* Implementation of the connected-component labeling algorithm */ function fromMaskConnectedComponentLabelingAlgorithm(mask, options = {}) { const { allowCorners = false } = options; let neighbours = 4; if (allowCorners) { neighbours = 8; } let directionX; let directionY; let neighboursList; if (neighbours === 8) { directionX = direction8X; directionY = direction8Y; neighboursList = neighbours8; } else if (neighbours === 4) { directionX = direction4X; directionY = direction4Y; neighboursList = neighbours4; } else { throw new RangeError(`unsupported neighbours count: ${neighbours}`); } const size = mask.size; const width = mask.width; const height = mask.height; const labels = new Array(size); const data = new Uint32Array(size); const linked = new _mlDisjointSet.default(); let currentLabel = 1; for (let j = 0; j < height; j++) { for (let i = 0; i < width; i++) { // true means out of background const index = i + j * width; if (mask.getBit(index)) { let smallestNeighbour = null; for (let k = 0; k < neighboursList.length; k++) { const ii = i + directionX[k]; const jj = j + directionY[k]; if (ii >= 0 && jj >= 0 && ii < width && jj < height) { const index = ii + jj * width; let neighbour = labels[index]; if (!neighbour) { neighboursList[k] = null; } else { neighboursList[k] = neighbour; if (!smallestNeighbour || neighboursList[k].value < smallestNeighbour.value) { smallestNeighbour = neighboursList[k]; } } } } if (!smallestNeighbour) { labels[index] = linked.add(currentLabel++); } else { labels[index] = smallestNeighbour; for (let k = 0; k < neighboursList.length; k++) { if (neighboursList[k] && neighboursList[k] !== smallestNeighbour) { linked.union(smallestNeighbour, neighboursList[k]); } } } } } } for (let j = 0; j < height; j++) { for (let i = 0; i < width; i++) { const index = i + j * width; if (mask.getBit(index)) { data[index] = linked.find(labels[index]).value; } } } return new _RoiMap.default(mask, data); }