fix(cli): correct u2net_human_seg std + reject signal-killed ffmpeg exits

Address Miguel's review on #612.

- Normalization std was (1, 1, 1) — that's the base u2net session, not
  u2net_human_seg. Switch to ImageNet (0.229, 0.224, 0.225) to match
  rembg's U2netHumanSegSession reference. Add a parity test pinning the
  exact MEAN/STD values.
- waitForExit treated `code === null` as success, but per Node child_process
  docs that's the signal-killed case — a SIGTERM'd ffmpeg encoder was
  reporting success with a partial output. Switch to (code, signal) and
  reject with the signal in the error message. Add four signal-handling
  tests (clean exit, signal-killed, non-zero code, SIGKILL).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
James
2026-05-04 04:46:01 +00:00
co-authored by Claude Opus 4.7
parent d2ca45ef75
commit 010c4f5576
4 changed files with 79 additions and 7 deletions
@@ -0,0 +1,18 @@
import { describe, expect, it } from "vitest";
import { MEAN, STD } from "./inference.js";
// Regression: the u2net_human_seg model was trained with ImageNet
// normalization. Drifting away from these exact values changes the input
// tensor at every pixel and shifts the predicted alpha mask noticeably
// (Miguel reproduced 8,317 pixel changes with delta up to 78/255 when std
// was set to (1, 1, 1)). Reference:
// https://github.com/danielgatis/rembg/blob/main/rembg/sessions/u2net_human_seg.py#L33
describe("background-removal/inference — rembg u2net_human_seg parity", () => {
it("MEAN matches U2netHumanSegSession reference", () => {
expect(MEAN).toEqual([0.485, 0.456, 0.406]);
});
it("STD matches U2netHumanSegSession reference (ImageNet, not the base u2net's (1,1,1))", () => {
expect(STD).toEqual([0.229, 0.224, 0.225]);
});
});