Protect object corners during color cleanup

This commit is contained in:
wuyanwanwu
2026-08-14 00:54:45 +08:00
parent c999334671
commit b890ce4035
13 changed files with 30 additions and 19 deletions
+14 -3
View File
@@ -272,25 +272,36 @@ function cleanLowConfidenceIsolatedColors(
const protectedDetail = current.lab[0] < 0.32 || current.lab[0] > 0.96 || chroma > 0.14;
if (protectedDetail) continue;
const neighborCounts = new Map<string, { color: BeadColor; count: number }>();
const neighborCounts = new Map<string, { color: BeadColor; count: number; confidentCount: number }>();
let neighborTotal = 0;
let sameColorNeighbors = 0;
for (const rowOffset of offsets) {
for (const columnOffset of offsets) {
if (rowOffset === 0 && columnOffset === 0) continue;
const neighborRow = row + rowOffset;
const neighborColumn = column + columnOffset;
if (neighborRow < 0 || neighborColumn < 0 || neighborRow >= height || neighborColumn >= width) continue;
const neighbor = colors[neighborRow * width + neighborColumn];
const entry = neighborCounts.get(neighbor.code) ?? { color: neighbor, count: 0 };
const neighborIndex = neighborRow * width + neighborColumn;
const neighbor = colors[neighborIndex];
if (neighbor.code === current.code) sameColorNeighbors += 1;
const entry = neighborCounts.get(neighbor.code) ?? { color: neighbor, count: 0, confidentCount: 0 };
entry.count += 1;
if (confidence[neighborIndex] >= 0.625) entry.confidentCount += 1;
neighborCounts.set(neighbor.code, entry);
neighborTotal += 1;
}
}
// A boundary corner is still part of a continuous object. Only a color with
// no same-color support in all eight neighboring cells counts as isolated.
if (sameColorNeighbors > 0) continue;
const majority = [...neighborCounts.values()].sort((a, b) => b.count - a.count)[0];
if (!majority || majority.color.code === current.code) continue;
const requiredCount = neighborTotal >= 7 ? 5 : Math.max(2, Math.ceil(neighborTotal * 0.67));
if (majority.count < requiredCount) continue;
if (majority.confidentCount < Math.min(3, majority.count)) continue;
// Large color jumps describe a real object boundary rather than an
// anti-aliased transition color, so never let cleanup cross that edge.
if (oklabDistance(current.lab, majority.color.lab) > 0.075) continue;
cleaned[index] = majority.color;
changed += 1;
}