| Server IP : 217.154.3.148 / Your IP : 216.73.216.90 Web Server : nginx/1.30.3 System : Linux blissful-wright.217-154-3-148.plesk.page 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64 User : gracious-boyd_hfhh1h8vo9n ( 10000) PHP Version : 8.3.31 Disable Function : opcache_get_status MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs/lib/ |
Upload File : |
/**
* RANSAC-style refinement for a 1D lattice: lines ≈ a + k · T.
* Estimates the step size T robustly from differences, phase a from modulo, and
* regenerates the complete grid. Returns the refined lines plus metadata.
*/
export type Grid1D = { lines: number[]; extent: number };
export type Refined = { lines: number[]; T: number; a: number; conf: number };
function median(values: number[]): number {
if (!values.length) return 0;
const sorted = [...values].sort((a, b) => a - b);
const mid = Math.floor(sorted.length / 2);
return sorted.length % 2 === 0 ? 0.5 * (sorted[mid - 1] + sorted[mid]) : sorted[mid];
}
function histPeak(values: number[], bin = 1, minT = 6, maxT = 1024): number {
const hist = new Map<number, number>();
for (const v of values) {
if (!Number.isFinite(v)) continue;
if (v < minT || v > maxT) continue;
const bucket = Math.round(v / bin) * bin;
hist.set(bucket, (hist.get(bucket) || 0) + 1);
}
let best = minT;
let count = -1;
for (const [k, v] of hist) {
if (v > count) {
best = k;
count = v;
}
}
return best;
}
function phaseFromModulo(xs: number[], T: number): number {
if (T <= 0) return 0;
const remainders = xs.map((x) => ((x % T) + T) % T);
return median(remainders);
}
function generateGrid(a: number, T: number, extent: number): number[] {
const result: number[] = [];
if (T <= 0 || extent <= 0) return result;
let k = Math.floor((0 - a) / T) - 1;
for (let i = 0; i < 10000; i++) {
const x = a + k * T;
if (x > extent) break;
if (x >= 0) result.push(Math.round(x));
k += 1;
if (result.length > 1) {
const last = result[result.length - 1];
const prev = result[result.length - 2];
if (last - prev > 2 * extent) break;
}
}
return Array.from(new Set(result)).sort((x, y) => x - y);
}
export function refine1D(input: Grid1D): Refined {
const xs = [...new Set(input.lines.filter((v) => Number.isFinite(v) && v >= 0 && v <= input.extent))].sort((a, b) => a - b);
if (xs.length < 2) {
return { lines: xs, T: 0, a: xs[0] ?? 0, conf: 0 };
}
const diffs: number[] = [];
for (let i = 0; i < xs.length; i++) {
for (let j = i + 1; j < Math.min(xs.length, i + 10); j++) {
diffs.push(xs[j] - xs[i]);
}
}
const fallbackT = xs.length > 1 ? xs[1] - xs[0] : 0;
let T = histPeak(diffs, 1, 6, Math.max(12, Math.floor(input.extent / 2)));
if (!Number.isFinite(T) || T <= 0) {
T = median(diffs) || fallbackT;
}
const a = phaseFromModulo(xs, T);
const grid = generateGrid(a, T, input.extent);
const tol = Math.max(2, Math.round(0.1 * T));
let inliers = 0;
for (const x of xs) {
if (grid.some((g) => Math.abs(g - x) <= tol)) {
inliers += 1;
}
}
const conf = xs.length ? inliers / xs.length : 0;
return { lines: grid, T, a, conf };
}
export function refineGridRansac(w: number, h: number, vlines: number[], hlines: number[]) {
const vertical = refine1D({ lines: vlines, extent: w });
const horizontal = refine1D({ lines: hlines, extent: h });
return {
vlines: vertical.lines,
hlines: horizontal.lines,
meta: {
v: { T: vertical.T, a: vertical.a, conf: vertical.conf },
h: { T: horizontal.T, a: horizontal.a, conf: horizontal.conf },
},
};
}