Skip to main content

RadVeil

Fast, verified face and ear anonymization for volumetric head imaging.
MRI and CT · NIfTI / DICOM / raw arrays · Rust core, Python API, C bindings, CLI

CI Release PyPI crates.io License: Apache-2.0

Website · Documentation · Browser demo · Quickstart · Examples · Legal notes

MRHead sample, input after adaptive anonymization side view after face+ears with the ears cut voxels: region outlined brain (blue) and anonymization region (amber)
3D Slicer's public "MRHead" sample: input · adaptive · face + ears (ears cut) · the voxels that changed · the region (amber) vs the extracted brain (blue), 5 mm apart.

RadVeil finds the face the way an attacker would — by rendering the volume as a 3D portrait and running a face detector on it — removes it, and accepts the result only when the detector fails on the output. Ears are removed on request and located by measuring the surface, not by assuming an offset. Every voxel outside the anonymized region is preserved bit-exact: same datatype, same scaling, same header.

Quick start

pip install radveil                        # prebuilt wheels, no model download, no compiler
cargo install radveil-cli                  # or: the single-binary CLI
import radveil

report = radveil.deface_auto("t1.nii.gz", "t1_defaced.nii.gz", mode="adaptive")
# {'views_detected': 3, 'residual_detections': 0, 'eye_dist_mm': 63.1, ...}

# the pinna is biometric too — opt in (face-only remains the default)
report = radveil.deface_auto("t1.nii.gz", "t1_defaced.nii.gz",
                             region="face+ears", mode="adaptive", ear_mode="cut")
# rois: [{'label': 'ear_left', 'detected': True, 'protrusion_mm': 14.0}, ...]
radveil auto t1.nii.gz t1_defaced.nii.gz --report report.json

The face detector is built in: the MediaPipe BlazeFace and Face Mesh models (Apache-2.0) are embedded in the library and run by RadVeil's own small pure-Rust SIMD inference engine. There is no ML framework, Bazel or TensorFlow in the build, and no Python is needed for the CLI or C API. dlib is available in Python as an optional second detector or fallback (fallback_detector="dlib"); either way, the output is verified against the built-in detector too.

Why RadVeil

  • Attacker-model localization — no atlas, no registration. A 2D face detector on CPU-rendered surface views pinpoints the face, and per-pixel position maps lift the 2D landmarks into scanner space. Detections must agree in 3D across views (shape consensus) before anything is modified.
  • Closed-loop verification — the output is re-rendered and re-attacked from the detection views and a grid around them (verify_effort: fast, balanced, thorough). Blur escalates, and an opaque fill guarantees termination. If no plausible face exists (non-head data, already-defaced scans, a "face" on a field-of-view cut) it refuses loudly instead of modifying anything.
  • Skin-deep and auditable — the face region follows the measured skin (~4.5 mm deep, skin_depth_mm, chosen to stay above the skull). Only voxels inside the exported binary mask change.
  • Brain-aware — on the public SynthStrip evaluation set (201 scans processed, the rest refused) the face region touched the expert brain mask on none; median clearance 6.6 mm. The opt-in brain guard (brain_guard=True, --brain-guard) never modifies the brain or anything within 3 mm of it.
  • Zero tuning — geometric parameters auto-scale from the detected inter-eye distance; works across sequences, resolutions, storage orientations (LPS/RAS/oblique/wrong affines), head sizes, MRI and CT.
  • Fast, CPU-only — ~0.3 s per volume in a warm process, ~11 volumes/s batched on a laptop CPU (deployment, performance). SIMD kernels with runtime dispatch and a portable fallback.

Modes and regions

mode effect
adaptive (recommended) gradient-weighted averaging — the stronger a facial feature, the heavier the local kernel
blur Gaussian blur of the region
cut remove (fill with background: 0 on MRI, air on CT)
block opaque slab (also the guaranteed final escalation step)
region effect
face (default) face-aligned ROI, depth-anchored to the measured eye-skin surface
ears both pinnae, located by surface-protrusion detection
face+ears both; ear_mode can pick a different mode for the ears (e.g. adaptive face, cut ears)

The ear is a stable biometric identifier that survives most defacers, but no landmark model emits ear points. RadVeil ray-marches the volume into a surface height map, derives the scalp baseline by morphological opening, and detects each pinna as a protrusion blob of the right shape and position. Every ear ROI reports detected and protrusion_mm; an ear outside the field of view is flagged, never silently missed.

Opt-in refinements (all off by default):

option what it does
level_face measures the face skin along the level head axes, removing much more of the lower lip and chin
spare_air leaves background air bit-exact, roughly halving the changed volume
auto_threshold retries noisy, dim scans (e.g. infant T1s) at higher surface thresholds
partial_face handles axial slabs that cut through the face (no mouth in the field of view)

Details, measurements and every knob: parameters & tuning.

Interfaces

  • Python — deface_auto (file → file), deface_volume (in memory: DICOM series via any reader, raw arrays via Volume.from_array, uploads via Volume.from_bytes / to_bytes), deface_batch (multi-threaded cohorts), plus a step-by-step API (render / detect_landmarks / lift_landmarks / Volume.deface). anonymization_mask returns the region without modifying anything, for callers who process it themselves.
  • CLI — radveil auto (one step, --report JSON), radveil deskull (brain extraction), radveil conform, plus info | render | deface.
  • C — libradveil + radveil.h: radveil_deface_auto, radveil_anonymization_mask, radveil_deskull, and the low-level load / render / deface / save calls.
  • Bring your own detector — any callable returning 68 landmarks (detector=f(rgb, try_rotations)).

Brain extraction

radveil deskull / radveil.deskull() / radveil_deskull() write a binary brain mask, the skull-stripped volume, or both:

radveil deskull t1.nii.gz -o t1_brain.nii.gz --mask-out brain_mask.nii.gz
  • synthstrip (default) — the SynthStrip network (Hoopes et al., NeuroImage 2022) reimplemented in pure Rust with embedded weights (MIT). Works on any MRI contrast, CT and PET. Masks match the reference mri_synthstrip at Dice 0.992–1.000, in ~3.5 s on a 1 mm 256³ MPRAGE on a laptop CPU.
  • classical — model-free; a BET-style deformable surface for MRI (optionally anchored by the detected face), bone-enclosed soft tissue for CT.
  • rvbrain — experimental; loads your own smaller .rvb network (format in rvbrain.rs). No trained weights ship yet.
Method (SynthStrip eval set, mean Dice) All Worst contrast
synthstrip 0.969 0.955 (QIN T2)
classical --face (466 held-out) 0.798 0.298 (qT1)
classical (466 held-out) 0.682 0.298 (qT1)

radveil auto --brain-check reports how many brain voxels the anonymization touched and how close it came; the CLI exits with status 3 if any were modified, so a batch can stop on it.

If you publish results from the synthstrip method, please cite Hoopes et al., NeuroImage 260 (2022) 119474.

Guarantees and limits

  • Voxels outside the mask are bit-identical to the input (tested in CI on synthetic phantoms).
  • Output keeps the input datatype, scl_slope / scl_inter, affine and header. Header metadata is deliberately not scrubbed — that is your de-identification pipeline's job (legal notes).
  • Verification demonstrates resistance to the embedded detector class, not to every conceivable attack; the exported mask supports independent audit.
  • 3D volumes only (split 4D series first). CT is validated on synthetic Hounsfield phantoms; multi-subject CT evaluation is pending.

Building from source

cargo build --release                                   # core + CLI (+ C lib: -p radveil-capi)
pip install maturin && maturin develop --release        # Python module
cargo test --workspace --release && pytest tests/       # phantoms only, no data needed

Releases are automated from version tags: wheels, the CLI and the C library for Linux, macOS and Windows, with SBOMs and checksums (release.yml, RELEASING.md, SBOM). Contributions are welcome — see CONTRIBUTING.md; report vulnerabilities via SECURITY.md.

Citing

If RadVeil is part of your anonymization pipeline, please cite it — it makes your de-identification reproducible.

@software{radveil,
  author  = {Gródek, Piotr},
  title   = {{RadVeil: CPU-only face and ear anonymization for volumetric head imaging}},
  url     = {https://github.com/rAum/radveil},
  version = {0.1.0},
  year    = {2026}
}

A methods sentence you can adapt: "Facial and auricular surfaces were removed with RadVeil v0.1.0 (region="face+ears", mode="adaptive"), which verifies each output by re-rendering the volume and re-running the face detector; all voxels outside the anonymization mask are unchanged." Machine-readable metadata: CITATION.cff.

License

Copyright 2026 Piotr Gródek and the RadVeil contributors. Licensed under the Apache License, Version 2.0; see also NOTICE.

Bundled third-party components keep their own licenses (THIRD_PARTY_LICENSES.txt):

  • MediaPipe BlazeFace and Face Mesh model weights — © Google LLC, Apache-2.0, embedded in a converted format (provenance).
  • SynthStrip weights — Hoopes et al., MIT.
  • dlib (optional, Boost license) — defaults to dlib's CC0 5-point model; its research-only 68-point models are used only if you pass one explicitly.

A default install contains only permissively licensed components; see the commercial-use summary. No imaging data is contained in this repository: tests use synthetic phantoms, and the only rendered face (site/img/) is 3D Slicer's public "MRHead" sample, regenerated by tools/make_site_images.py.

Disclaimer

RadVeil is a personal, open-source project developed in the author's spare time, on personal equipment. It is not affiliated with, sponsored or endorsed by, and does not represent any current or former employer of the author; the views and code here are the author's own. Names of third-party projects (MediaPipe, SynthStrip, dlib, 3D Slicer) are used only to identify the components and data RadVeil uses and do not imply endorsement by their owners.

Generative AI tools were used in developing this project, including code, documentation and the website. All of it was reviewed by the author, who remains responsible for it.

RadVeil is provided "as is", without warranty of any kind (see the license). It is not a medical device, is not intended for diagnosis or treatment, and does not by itself make data compliant with any privacy regulation. You are responsible for validating it for your use case.

Metadata

Release files for radveil 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for radveil 0.1.0
File Size Uploaded Provenance
radveil-0.1.0.tar.gz 7.4 MB With provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for radveil 0.1.0
File
radveil-0.1.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
radveil-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
radveil-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details
radveil-0.1.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
radveil-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 47.9 MB

Release files / radveil-0.1.0.tar.gz

Download URL radveil-0.1.0.tar.gz
Size 7.4 MB
Tags Source
SHA-256 checksum
How to use checksums
7c9c702783a1fa402c5a9368bf775d526687a6d7a763cd600e636f14548f68fd
BLAKE2b-256 checksum
How to use checksums
53d6d042b672bf1ad36f4ac18559045cf2d41bbe995574b3367962f4afb9410c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / radveil-0.1.0-cp39-abi3-win_amd64.whl

Download URL radveil-0.1.0-cp39-abi3-win_amd64.whl
Size 8.1 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
f3a82d32f031595f8f100b747e7b825d9178066c713f3a12d087c404269fdc10
BLAKE2b-256 checksum
How to use checksums
e1b0b2965c49367a6d39c988513a6f33369651beba86320c9af200d8ea2418a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / radveil-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL radveil-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 8.1 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
4e415191ce23beb710ff39542d601529dfe53eef42503e830ca68004edd81752
BLAKE2b-256 checksum
How to use checksums
6df13dc23e4886657edc5833e3ad433c9df305e18380954f8ce3a94974c0f0e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / radveil-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL radveil-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 8.0 MB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
91384b5f98f5c6e05ae0c6169aa492fc85a51c46c10950e5d66cb88ca8488047
BLAKE2b-256 checksum
How to use checksums
b92fbdb4490e863177d50ebddfba38c841ecb496ade6fff4daa094ec29d6994c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / radveil-0.1.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL radveil-0.1.0-cp39-abi3-macosx_11_0_arm64.whl
Size 8.1 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d05c197aa167152f7df9811c9cbbc3e1b9d9666dc3c5fb834fdeffef6ccdf04f
BLAKE2b-256 checksum
How to use checksums
2ba1ab3f29bf17af146a3ac36b46a42cf29c732a5f593ff3d7f50a03bf31988f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / radveil-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL radveil-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl
Size 8.1 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
df2e04f37b59b2a33228970c2bc75da6ff02e0debe3cdf755bcf6c8fc11fa279
BLAKE2b-256 checksum
How to use checksums
8211c9f50c3e073e2392c03fe9cc6bd9cb459cce79bcce9495ac6b92d2cf0e60
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Security for radveil 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 6 files in this release have been uploaded with provenance metadata.

Select from 6 files

Attestation for radveil-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

6 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page