UNPKG

image-js

Version:

Image processing and manipulation in JavaScript

78 lines 3.49 kB
import { match } from 'ts-pattern'; import { getCirclePoints, getCompassPoints, } from '../../utils/geometry/getCirclePoints.js'; import { getIndex } from '../../utils/getIndex.js'; import { surroundingPixels } from '../../utils/surroundingPixels.js'; import checkProcessable from '../../utils/validators/checkProcessable.js'; import { getFastScore } from './getFastScore.js'; import { getHarrisScore } from './getHarrisScore.js'; import { getShiTomasiScore } from "./getShiTomasiScore.js"; import { isFastKeypoint } from './isFastKeypoint.js'; /** * Find the features in a GREY image according to the FAST (Features from Accelerated Segment Test) algorithm. * Based on the paper Machine Learning for High-Speed Corner Detection. * DOI: https://doi.org/10.1007/11744023_34. * @param image - The image to process. * @param options - Get FAST keypoints options. * @returns The FAST keypoints. */ export function getFastKeypoints(image, options = {}) { const { fastRadius = 3, scoreAlgorithm = 'FAST', scoreOptions } = options; const circlePoints = getCirclePoints(fastRadius); const compassPoints = getCompassPoints(fastRadius); const { maxNbFeatures = 500, nbContiguousPixels = (3 / 4) * circlePoints.length, threshold = 20, nonMaxSuppression = true, } = options; checkProcessable(image, { channels: [1], alpha: false, }); function harrisScore(image, corner) { return getHarrisScore(image, corner, scoreOptions); } function fastScore(image, corner) { return getFastScore(image, corner, threshold, circlePoints); } function tomasiScore(image, corner) { return getShiTomasiScore(image, corner, scoreOptions); } const getScore = match(scoreAlgorithm) .with('HARRIS', () => harrisScore) .with('FAST', () => fastScore) .with('TOMASI', () => tomasiScore) .exhaustive(); const allKeypoints = []; const scoreArray = new Float64Array(image.size).fill(Number.NEGATIVE_INFINITY); for (let row = 0; row < image.height; row++) { for (let column = 0; column < image.width; column++) { const corner = { row, column }; if (isFastKeypoint(corner, image, circlePoints, compassPoints, { nbContiguousPixels, threshold, })) { const score = getScore(image, corner); scoreArray[getIndex(corner.column, corner.row, image, 0)] = score; allKeypoints.push({ origin: corner, score }); } } } let keypoints = []; if (!nonMaxSuppression) { keypoints = allKeypoints; } else { // Non-Maximal Suppression for (const keypoint of allKeypoints) { const currentScore = scoreArray[getIndex(keypoint.origin.column, keypoint.origin.row, image, 0)]; for (let i = 0; i < surroundingPixels.length; i++) { const neighbour = surroundingPixels[i]; const neighbourScore = scoreArray[getIndex(keypoint.origin.column + neighbour.column, keypoint.origin.row + neighbour.row, image, 0)]; if (neighbourScore > currentScore) break; if (i === surroundingPixels.length - 1) { keypoints.push(keypoint); } } } } keypoints.sort((a, b) => b.score - a.score); return keypoints.slice(0, maxNbFeatures); } //# sourceMappingURL=getFastKeypoints.js.map