image-js
Version:
Image processing and manipulation in JavaScript
86 lines (85 loc) • 3.37 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = localMaxima;
/**
* Returns an array of object with position.
* @memberof Image
* @instance
* @param {object} [options]
* @param {Image} [options.mask] - Region of the image that is analyzed. The rest is omitted.
* @param {number} [options.region=3] - 1, 2 or 3. Define the region around each points that is analyzed. 1 corresponds to 4 cross points, 2 to
* the 8 points around and 3 to the 12 points around the central pixel.
* @param {number} [options.removeClosePoints=0] - Remove pts which have a distance between them smaller than this param.
* @param {boolean} [options.invert=false] - Search for minima instead of maxima
* @param {number} [options.maxEquals=2] - Maximal number of values that may be equal to the maximum
* @return {number[]} Array whose size is the number of channels
*/
function localMaxima(options = {}) {
let {
mask,
region = 3,
removeClosePoints = 0,
invert = false,
maxEquals = 2
} = options;
let image = this;
this.checkProcessable('localMaxima', {
bitDepth: [8, 16],
components: 1
});
region *= 4;
let maskExpectedValue = invert ? 0 : 1;
let dx = [+1, 0, -1, 0, +1, +1, -1, -1, +2, 0, -2, 0, +2, +2, -2, -2];
let dy = [0, +1, 0, -1, +1, -1, +1, -1, 0, +2, 0, -2, +2, -2, +2, -2];
let shift = region <= 8 ? 1 : 2;
let points = [];
for (let currentY = shift; currentY < image.height - shift; currentY++) {
for (let currentX = shift; currentX < image.width - shift; currentX++) {
if (mask && mask.getBitXY(currentX, currentY) !== maskExpectedValue) {
continue;
}
let counter = 0;
let nbEquals = 0;
let currentValue = image.data[currentX + currentY * image.width];
for (let dir = 0; dir < region; dir++) {
if (invert) {
// we search for minima
if (image.data[currentX + dx[dir] + (currentY + dy[dir]) * image.width] > currentValue) {
counter++;
}
} else {
if (image.data[currentX + dx[dir] + (currentY + dy[dir]) * image.width] < currentValue) {
counter++;
}
}
if (image.data[currentX + dx[dir] + (currentY + dy[dir]) * image.width] === currentValue) {
nbEquals++;
}
}
if (counter + nbEquals === region && nbEquals <= maxEquals) {
points.push([currentX, currentY]);
}
}
}
// TODO How to make a more performant and general way
// we don't deal correctly here with groups of points that should be grouped if at the
// beginning one of them is closer to another
// Seems that we would ened to calculate a matrix and then split this matrix in 'independant matrices'
// Or to assign a cluster to each point and regroup them if 2 clusters are close to each other
// later approach seems much better
if (removeClosePoints > 0) {
for (let i = 0; i < points.length; i++) {
for (let j = i + 1; j < points.length; j++) {
if (Math.sqrt(Math.pow(points[i][0] - points[j][0], 2) + Math.pow(points[i][1] - points[j][1], 2)) < removeClosePoints) {
points[i][0] = points[i][0] + points[j][0] >> 1;
points[i][1] = points[i][1] + points[j][1] >> 1;
points.splice(j, 1);
j--;
}
}
}
}
return points;
}