Expand preview and center dominant sampling

This commit is contained in:
wuyanwanwu
2026-08-14 01:11:38 +08:00
parent 5a312f5039
commit 552ed5e6fa
15 changed files with 30 additions and 26 deletions
+8 -4
View File
@@ -214,7 +214,9 @@ function sampleDominantRegions(
cropX: number,
cropY: number,
) {
const scale = 4;
// An odd sampling grid has a real center point and avoids directional ties
// at object boundaries (the former 4x4 grid favored one side on exact ties).
const scale = 5;
const sample = document.createElement("canvas");
sample.width = width * scale;
sample.height = height * scale;
@@ -228,7 +230,7 @@ function sampleDominantRegions(
for (let row = 0; row < height; row++) {
for (let column = 0; column < width; column++) {
const groups: Array<{ count: number; lab: Oklab; samples: Array<{ rgb: [number, number, number]; lab: Oklab }> }> = [];
const groups: Array<{ count: number; lab: Oklab; samples: Array<{ rgb: [number, number, number]; lab: Oklab }>; containsCenter: boolean }> = [];
let transparentCount = 0;
for (let offsetY = 0; offsetY < scale; offsetY++) {
for (let offsetX = 0; offsetX < scale; offsetX++) {
@@ -239,6 +241,7 @@ function sampleDominantRegions(
}
const rgb: [number, number, number] = [source[sourceIndex], source[sourceIndex + 1], source[sourceIndex + 2]];
const lab = rgbToOklab(rgb);
const isCenter = offsetX === Math.floor(scale / 2) && offsetY === Math.floor(scale / 2);
let closest: (typeof groups)[number] | undefined;
let closestDistance = Number.POSITIVE_INFINITY;
for (const group of groups) {
@@ -253,8 +256,9 @@ function sampleDominantRegions(
closest.lab = closest.lab.map((value, channel) => (value * closest.count + lab[channel]) / total) as Oklab;
closest.count = total;
closest.samples.push({ rgb, lab });
closest.containsCenter ||= isCenter;
} else {
groups.push({ count: 1, lab: [...lab], samples: [{ rgb, lab }] });
groups.push({ count: 1, lab: [...lab], samples: [{ rgb, lab }], containsCenter: isCenter });
}
}
}
@@ -264,7 +268,7 @@ function sampleDominantRegions(
confidence[row * width + column] = transparentCount / (scale * scale);
continue;
}
const dominant = groups.sort((a, b) => b.count - a.count)[0];
const dominant = groups.sort((a, b) => b.count - a.count || Number(b.containsCenter) - Number(a.containsCenter))[0];
const representative = dominant.samples.reduce((best, current) =>
oklabDistance(current.lab, dominant.lab) < oklabDistance(best.lab, dominant.lab) ? current : best,
);