03d3fcf460
Lower the axial body threshold while retaining fringe rejection, minimize length-only tip inset, and make sheet sensitivity curves testable and conservative at zero.
37 lines
1.3 KiB
TypeScript
37 lines
1.3 KiB
TypeScript
/**
|
||
* Sheet-vs-slab keep predicates used by the mask worker.
|
||
* Extracted so unit tests can cover sensitivity curves without the worker.
|
||
*/
|
||
|
||
/** Keep slab pixels on a green sheet. Higher s widens the green-sheet match. */
|
||
export function greenKeep(r: number, g: number, b: number, s: number): boolean {
|
||
const t = Math.max(0, Math.min(100, s)) / 100;
|
||
// s=0 removes only strongly green sheet; increasing sensitivity widens the match.
|
||
const isSheet = g - Math.max(r, b) > 45 - 35 * t;
|
||
return !isSheet;
|
||
}
|
||
|
||
/**
|
||
* Keep slab pixels on a black sheet.
|
||
* At s=0 only near-black sheet (very low lum) is removed so dark live-edge /
|
||
* bark (lum ~25–50) stays. The match widens monotonically toward s=100 (#74).
|
||
*/
|
||
export function blackKeep(r: number, g: number, b: number, s: number): boolean {
|
||
const t = Math.max(0, Math.min(100, s)) / 100;
|
||
const lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||
// Old floor 40 ate dark wood at minimum sensitivity. Floor 10 isolates near-black.
|
||
const isSheet = lum < 10 + 140 * t;
|
||
return !isSheet;
|
||
}
|
||
|
||
export function autoPickSheet(
|
||
samples: { r: number; g: number; b: number }[],
|
||
): 'green' | 'black' {
|
||
let gr = 0, gl = 0;
|
||
for (const p of samples) {
|
||
if (p.g - Math.max(p.r, p.b) > 20) gr++;
|
||
if (0.2126 * p.r + 0.7152 * p.g + 0.0722 * p.b < 70) gl++;
|
||
}
|
||
return gl >= gr ? 'black' : 'green';
|
||
}
|