mind-ar
Version:
web augmented reality framework
121 lines (98 loc) • 3.19 kB
JavaScript
import {compute as hammingCompute} from './hamming-distance.js';
import {createRandomizer} from '../utils/randomizer.js';
const MIN_FEATURE_PER_NODE = 16;
const NUM_ASSIGNMENT_HYPOTHESES = 128;
const NUM_CENTERS = 8;
const _computeKMedoids = (options) => {
const {points, pointIndexes, randomizer} = options;
const randomPointIndexes = [];
for (let i = 0; i < pointIndexes.length; i++) {
randomPointIndexes.push(i);
}
let bestSumD = Number.MAX_SAFE_INTEGER;
let bestAssignmentIndex = -1;
const assignments = [];
for (let i = 0; i < NUM_ASSIGNMENT_HYPOTHESES; i++) {
randomizer.arrayShuffle({arr: randomPointIndexes, sampleSize: NUM_CENTERS});
let sumD = 0;
const assignment = [];
for (let j = 0; j < pointIndexes.length; j++) {
let bestD = Number.MAX_SAFE_INTEGER;
for (let k = 0; k < NUM_CENTERS; k++) {
const centerIndex = pointIndexes[randomPointIndexes[k]];
const d = hammingCompute({v1: points[pointIndexes[j]].descriptors, v2: points[centerIndex].descriptors});
if (d < bestD) {
assignment[j] = randomPointIndexes[k];
bestD = d;
}
}
sumD += bestD;
}
assignments.push(assignment);
if (sumD < bestSumD) {
bestSumD = sumD;
bestAssignmentIndex = i;
}
}
return assignments[bestAssignmentIndex];
}
// kmedoids clustering of points, with hamming distance of FREAK descriptor
//
// node = {
// isLeaf: bool,
// children: [], list of children node
// pointIndexes: [], list of int, point indexes
// centerPointIndex: int
// }
const build = ({points}) => {
const pointIndexes = [];
for (let i = 0; i < points.length; i++) {
pointIndexes.push(i);
}
const randomizer = createRandomizer();
const rootNode = _build({points: points, pointIndexes: pointIndexes, centerPointIndex: null, randomizer});
return {rootNode};
}
// recursive build hierarchy clusters
const _build = (options) => {
const {points, pointIndexes, centerPointIndex, randomizer} = options;
let isLeaf = false;
if (pointIndexes.length <= NUM_CENTERS || pointIndexes.length <= MIN_FEATURE_PER_NODE) {
isLeaf = true;
}
const clusters = {};
if (!isLeaf) {
// compute clusters
const assignment = _computeKMedoids({points, pointIndexes, randomizer});
for (let i = 0; i < assignment.length; i++) {
if (clusters[pointIndexes[assignment[i]]] === undefined) {
clusters[pointIndexes[assignment[i]]] = [];
}
clusters[pointIndexes[assignment[i]]].push(pointIndexes[i]);
}
}
if (Object.keys(clusters).length === 1) {
isLeaf = true;
}
const node = {
centerPointIndex: centerPointIndex
}
if (isLeaf) {
node.leaf = true;
node.pointIndexes = [];
for (let i = 0; i < pointIndexes.length; i++) {
node.pointIndexes.push(pointIndexes[i]);
}
return node;
}
// recursive build children
node.leaf = false;
node.children = [];
Object.keys(clusters).forEach((centerIndex) => {
node.children.push(_build({points: points, pointIndexes: clusters[centerIndex], centerPointIndex: centerIndex, randomizer}));
});
return node;
}
export {
build,
};