Blur + remove background: cut out from the clean photo, clip the blur to it - #47
Merged
Merged
Conversation
… to it Blurring faces and then removing the background left an opaque blurred rectangle where the face was. The segmentation model was being handed the already-blurred bake: with no detail left inside the redaction it keeps the whole blurred block as foreground, so the "background" inside that block survived the cut-out. Model the blur as a layer *above* the background edit instead, so the two compose in either order: - `removeBackground` always segments the clean, un-blurred image (`faceOriginal` when a redaction is applied), so the matte is computed from real pixels. - The redaction is then re-baked over the finished cut-out, rendered from the opaque pre-removal photo and stencilled by the cut-out's alpha (`renderRedacted`'s new `mask` argument, a `destination-in` composite). The blurred layer is deleted in exactly the same places the background is, and rendering from the opaque original keeps the silhouette crisp — resampling the transparent cut-out directly would smear its alpha. - `bgOriginal` / `bgCutout` now always hold clean snapshots, and `faceOriginal` holds the un-blurred image for whichever background state is current, so Restore background / Remove blur both stay available and undo independently. Restoring the background re-bakes the blur onto the full image rather than silently un-redacting it. - Both re-bakes run before the new bitmap is swapped in, so neither action ever shows an un-redacted frame, and face detection after a removal runs on the opaque original rather than a subject against black. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PWVk4ejHQqT27pjX4wgcQq
Deploying universal-images with
|
| Latest commit: |
21dcd2f
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://52249aeb.universal-images-60x.pages.dev |
| Branch Preview URL: | https://claude-blur-face-remove-bg-o.universal-images-60x.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
Blurring faces and then removing the background left an opaque blurred rectangle where the face was — the hair around it cut out cleanly, but the background inside the blur square survived.
removeBackgroundwas running the segmentation model onimg.file, which after a redaction is the baked blurred PNG. With no detail left inside the blur, the model classifies the entire blurred block as foreground, so nothing inside it gets cut away.The fix
The blur is now modelled as a layer above the background edit, so the two compose in either order:
removeBackgroundalways segments the clean, un-blurred image (faceOriginalwhen a redaction is applied), so the matte is computed from real pixels.renderRedacted's newmaskargument, adestination-incomposite. The blurred layer is deleted in exactly the same places the background is. Rendering from the opaque original (rather than blurring the transparent cut-out) keeps the silhouette crisp; resampling transparency directly would smear the alpha and fray the edge.bgOriginal/bgCutoutnow always hold clean snapshots, andfaceOriginalholds the un-blurred image for whichever background state is current. Restore background and Remove blur stay available and undo independently, in any order. Restoring the background re-bakes the blur onto the full image rather than silently un-redacting the faces.bakeFaceBluris pure and touches no store state), so neither action ever shows an un-redacted frame.Verification
npm run typecheckandnpm run buildpass.The real
renderRedactedwas also driven in headless Chromium against a synthetic photo + cut-out, with a face box deliberately straddling the cut-out edge:[0,0,0,0]— removed[0,0,0,0]— blur erased with the background255Round-trips checked by trace: blur → remove bg → restore bg → remove bg (cache hit) returns to a consistent state at each step, with no leaked or double-revoked object URLs.
Generated by Claude Code