LX Anonymizer is a comprehensive toolkit for de-identifying endoscopy frames and medical reports. It combines advanced OCR pipelines, spaCy-based NER, heuristic sanitizers, and report-specific rules to redact or pseudonymize sensitive information while preserving clinical context.
Specialized for medical report anonymization with support for:
Designed for real-time video frame anonymization featuring:
LX Anonymizer will return a sensitive meta compliant dict when running either of the main client functions above.
de_core_news_sm model for German NER. Source installs with uv
use the locked model wheel; other runtime environments may need an explicit
install.The repository exposes flake packages and can be consumed directly from another
project's devenv.yaml:
inputs:
lx-anonymizer:
url: github:wg-lux/lx-anonymizer
After adding the input, reference the package through your own devenv.nix or
flake outputs. You do not need to commit or publish local result or
result-app symlinks for this to work.
pip install lx-anonymizer
The base package installs the public API, CLI, PDF/image processing, detector training, spaCy-based metadata extraction, and PyTesseract fallback OCR. Install extras only when you need the corresponding hardware or development feature set:
pip install "lx-anonymizer[dev]" # local development tooling
pip install "lx-anonymizer[cpu]" # CPU PyTorch wheel selection
pip install "lx-anonymizer[gpu]" # CUDA PyTorch wheel selection
git clone https://github.com/wg-lux/lx-anonymizer.git
cd lx-anonymizer
uv sync --extra dev --extra cpu # development + CPU PyTorch stack
uv sync --extra gpu # CUDA 12.8 PyTorch-dependent features
The cpu and gpu extras are mutually exclusive in uv. The CPU extra routes
torch, torchaudio, and torchvision to PyTorch's CPU wheel index; the GPU
extra routes them to PyTorch's CUDA 12.8 wheel index and adds
onnxruntime-gpu.
direnv allow
nix develop
This loads GPU, OCR, and tooling dependencies declared in devenv.nix.
PyPI releases now use a split artifact strategy:
maturin and include the Rust extensionpyproject.toml with python -m build --sdistFor a local source-package sanity check:
uv build --sdist
uv run python scripts/audit_distribution.py dist/*.tar.gz
If you build the local wheel on a non-manylinux host (for example Nix), pass the desired compatibility target explicitly:
make pypi-wheel PYPI_COMPATIBILITY=manylinux_2_34
CI uses maturin --manylinux auto via PyO3/maturin-action to produce the
published Linux wheels.
The published Python package is the complete baseline install path. Only hardware-specific PyTorch wheel selection and development/build tools remain in extras; type stubs and test tools stay outside the runtime dependency set.
The repository also contains an optional Rust extension used for local and Nix
packaging. The Python code loads it opportunistically through
lx_anonymizer._native and falls back to pure Python implementations when the
native module is unavailable or only partially implemented.
PyPI wheels built by CI now include this extension. Pure-Python fallback still exists for environments that install from source without a compiled native module.
Local prebuilt extension files, generated reports, study data, and cache files are excluded from PyPI artifacts. CI audits each wheel and sdist before upload.
The flake exports multiple package variants, including the base CLI package and a native-enabled package:
nix build .#lx-anonymizer
nix build .#lx-anonymizer-with-native
Those commands create local ./result symlinks for inspection on your machine.
They are build outputs, not repository contents, and should remain uncommitted.
uv build --sdist and uv run python scripts/audit_distribution.py dist/*.tar.gz to validate the source distribution locally.maturin.nix build .#lx-anonymizer or nix build .#lx-anonymizer-with-native to validate flake packaging.result or result-app.The intended release path is now:
vX.Y.Z to trigger the production publish workflow.The release workflow publishes:
maturinpython -m build --sdistSettings are loaded from environment variables and an optional .env file. See
SETTINGS.md for a quick overview and example configuration.
The default German spaCy model is de_core_news_sm. On first use, LX Anonymizer
loads the model if it is installed and otherwise downloads it with the same
Python interpreter that is running the application. To pre-install it, run:
python -m spacy download de_core_news_sm
Clinical/strict deployments fail loudly when the configured model is missing.
Automatic download is enabled by default. Set
LX_ANONYMIZER_SPACY_AUTO_DOWNLOAD=0 or SPACY_AUTO_DOWNLOAD=False to disable
network installation. Outside clinical/strict profiles, disabling it permits
the degraded blank fallback.
Start a compatible LLM server exposing either an OpenAI-compatible API or Ollama:
# Default local Gemma 4 setup used for OCR and text recognition
bash scripts/provision_ollama_gemma4.sh
# In a devenv shell, the equivalent task is:
devenv tasks run ollama:provision-gemma4
# Alternative high-throughput setup
vllm serve Qwen/Qwen3.5-9B --port 8000
Caution: This is only recommended on devices with sufficient gpu capabilities
The EAST detector now downloads on first use, not on import. TrOCR and other optional OCR assets download only when those paths are exercised. For air-gapped deployments, pre-seed the required model files before running the relevant pipeline steps.
Install the package, then use lx-anonymizer --help as the single command
index. Every workflow has its own help page:
# List all image, report, evaluation, dataset, export, and training commands
lx-anonymizer --help
# Show options for one workflow without importing or running the pipeline
lx-anonymizer report --help
lx-anonymizer evaluate-midi-b --help
# Process a single image or PDF
lx-anonymizer image frame.png
# Use a custom EAST model and device profile
lx-anonymizer image frame.png \
--east /models/frozen_east_text_detection.pb \
--device olympus_cv_1500
# Return validation metadata in addition to the output path
lx-anonymizer image report.pdf --validation
# The historical spelling remains available
lx-anonymizer -i frame.png
The report command validates the source snapshot and writes one unpublished PDF candidate to an attempt-owned directory. Its standard output is one JSON object, which can be consumed directly by shell tooling.
lx-anonymizer report report.pdf \
--output-directory ./attempt-output \
--no-llm
# Optional extraction modes and a caller-supplied attempt identity
lx-anonymizer report report.pdf \
--output-directory ./attempt-output \
--attempt-id 12345678-1234-5678-1234-567812345678 \
--ensemble \
--llm
The output directory may be new or existing, but the generated attempt artifact
must not already exist. A new UUID is generated when --attempt-id is omitted.
The previously separate console scripts are also available as subcommands:
lx-anonymizer evaluate-midi-b --help
lx-anonymizer export-dicom --help
lx-anonymizer generate-phi-data --help
lx-anonymizer generate-endoscopy-stickers --help
lx-anonymizer generate-midi-b-phi-data --help
lx-anonymizer generate-radphi-data --help
lx-anonymizer train-phi --help
The historical lx-anonymizer-evaluate-midi-b,
lx-anonymizer-export-dicom, lx-anonymizer-generate-*, and
lx-anonymizer-train-phi executables remain as compatibility aliases.
python -m lx_anonymizer.cli provides the same command interface.
Video import is deliberately not exposed as a standalone production shell
workflow. endoreg-db owns durable attempts, leases, encrypted staging,
validation, and publication; it creates one FrameCleaner per attempt and uses
the Python API described below.
The three central strands use the same shape: construct a typed request, then
call processor.process(request) to receive a typed result with an
artifact_path. The historical main(...), clean_video(...), and
process_report(...) methods remain compatibility wrappers.
from pathlib import Path
from lx_anonymizer import ImageAnonymizer
from lx_anonymizer.processing_contracts import ImageAnonymizationRequest
attempt_directory = Path("/path/to/image-attempt")
attempt_directory.mkdir(parents=True)
result = ImageAnonymizer().process(
ImageAnonymizationRequest(
source_path=Path("/path/to/image.png"),
output_directory=attempt_directory,
)
)
print(result.artifact_path, result.metadata)
import hashlib
from pathlib import Path
from uuid import uuid4
from lx_anonymizer import ReportReader
from lx_anonymizer.report_contracts import (
ReportAnonymizationOptions,
ReportAnonymizationRequest,
)
source_path = Path("/path/to/report.pdf")
source_bytes = source_path.read_bytes()
attempt_directory = Path("/path/to/attempt")
attempt_directory.mkdir(parents=True)
request = ReportAnonymizationRequest(
attempt_id=uuid4(),
source_path=source_path,
source_sha256=hashlib.sha256(source_bytes).hexdigest(),
source_size_bytes=len(source_bytes),
output_directory=attempt_directory,
options=ReportAnonymizationOptions(use_ensemble=True, use_llm=True),
)
reader = ReportReader(locale="de_DE")
result = reader.process(request)
print(result.artifact_path, result.artifact_sha256)
# Advanced processing with region cropping
original, anonymized, meta, cropped_regions, anonymized_pdf = reader.process_report_with_cropping(
pdf_path="/path/to/report.pdf",
crop_output_dir="/path/to/cropped_regions",
crop_sensitive_regions=True,
use_llm=True
)
ReportReader is the canonical report-oriented entry point for immutable PDF
snapshots.
ReportReader(...) constructor:
report_root_path: optional base path for report assets.locale: Faker locale for pseudonymized replacements.employee_first_names / employee_last_names: optional replacement pools.flags: optional parsing markers merged with DEFAULT_SETTINGS["flags"].text_date_format: output format used for anonymized date text.process(...) (and its compatibility alias process_report(...)) accepts one strictly validated
ReportAnonymizationRequest. The caller supplies the immutable source identity,
an attempt-owned output directory, and processing options. The method always
creates and validates an anonymized PDF without choosing a canonical publication
path.
It returns a frozen ReportAnonymizationResult containing original and
anonymized text, typed sensitive metadata, the attempt-local artifact path,
artifact size and SHA-256, structural PDF validation, and anonymizer provenance.
process_report_with_cropping(...) is a separate diagnostic helper with:
crop_output_dir: where cropped sensitive regions are written.crop_sensitive_regions: enable or disable crop extraction.anonymization_output_dir: output directory for the crop-based anonymized PDF.process_report_with_cropping(...) returns:
original_textanonymized_textreport_metacropped_regions_info: mapping of cropped sensitive regions.anonymized_pdf_path: Path | Nonefrom fractions import Fraction
from pathlib import Path
from lx_anonymizer.frame_cleaner import FrameCleaner
from lx_anonymizer.processing_contracts import VideoAnonymizationRequest
result = FrameCleaner(use_llm=True).process(
VideoAnonymizationRequest(
source_path=Path("endoscopy.mp4"),
output_path=Path("attempt/candidate.mp4"),
source_frame_rate=Fraction(25, 1),
endoscope_image_roi={"x": 550, "y": 0, "width": 1350, "height": 1080},
endoscope_data_roi_nested={
"patient_info": {"x": 10, "y": 10, "width": 300, "height": 50}
},
technique="mask_overlay",
)
)
print(result.artifact_path, result.metadata)
FrameCleaner is the video-oriented entry point for endoscopy footage and
frame-level overlays.
FrameCleaner(...) constructor:
use_llm: enables provider-backed batch metadata enrichment when available.use_minicpm and minicpm_config: reserved for optional OCR backends.clean_video(...) parameters:
video_path: input video file.endoscope_image_roi: flat ROI dict for the visible endoscope image, typically with x, y, width, height.endoscope_data_roi_nested: nested ROI mapping for text-bearing overlay regions such as patient info blocks.output_path: optional explicit output path.technique: one of mask_overlay, remove_frames, or extract_only.device: device profile name, defaulting to olympus_cv_1500.clean_video(...) behavior by technique:
mask_overlay: preserves the timeline and overlays masks onto sensitive regions.remove_frames: drops sensitive frames and rewrites the stream.extract_only: does metadata extraction without producing a masked/removal-focused anonymization pass.clean_video(...) returns:
output_video_path: resulting video path. With extract_only, this is still the path chosen for the run.sensitive_meta: accumulated metadata dictionary extracted from sampled frames.Training is included in the standard installation. Its typed result creates the checksum-pinned runtime configuration accepted by every strand:
from pathlib import Path
from lx_anonymizer import ImageAnonymizer, ReportReader
from lx_anonymizer.frame_cleaner import FrameCleaner
from lx_anonymizer.text_detection.phi_region_detector import CustomPhiRegionDetector
from lx_anonymizer.text_detection.phi_region_detector_training import (
PhiRegionDetectorTrainingConfig,
train_phi_region_detector,
)
training = train_phi_region_detector(
PhiRegionDetectorTrainingConfig(
dataset_yaml=Path("datasets/phi/data.yaml"),
output_dir=Path("runs/phi"),
)
)
detector = CustomPhiRegionDetector(training.detector_config(required=True))
image_processor = ImageAnonymizer(region_detector=detector)
video_processor = FrameCleaner(region_detector=detector)
report_processor = ReportReader(region_detector=detector)
ROI guidance:
endoscope_image_roi for the main picture area that may need masking.endoscope_data_roi_nested for device-specific overlay fields.x, y, width, height directly is the least ambiguous form.See tests/test_report_reader_init.py and tests/test_frame_cleaner.py for concrete usage patterns.
-c copy for maximum speedBy default, outputs live in ~/etc/lx-anonymizer/{data,temp}. Adjust them in
lx_anonymizer/setup/directory_setup.py.
Clean temp regularly to avoid large intermediate artefacts.
uv run flake8 for linting and formattinguv run pytest -m "not gpu"uv run pytest -m gpu (requires CUDA-capable hardware)uv run pytest tests/test_cli_integration.pyuv run pytest tests/test_frame_cleaner.py--log-level DEBUG for detailed timing informationuv run python -m build --sdist for local sdist validation; GitHub Actions builds release wheelsscripts/run_checks.sh for comprehensive local testingexample_anonymize_pdf.py for end-to-end testing scenariosSee CONTRIBUTING.md for contribution guidelines, testing instructions, and communication channels.
Released under the MIT License.
Questions? Email lux@coloreg.de .
Python
96.8%
Nix
1.9%
Rust
1.0%
LX Anonymizer is a comprehensive toolkit for de-identifying endoscopy frames and medical reports. It combines advanced OCR pipelines, spaCy-based NER, heuristic sanitizers, and report-specific rules to redact or pseudonymize sensitive information while preserving clinical context.
Specialized for medical report anonymization with support for:
Designed for real-time video frame anonymization featuring:
LX Anonymizer will return a sensitive meta compliant dict when running either of the main client functions above.
de_core_news_sm model for German NER. Source installs with uv
use the locked model wheel; other runtime environments may need an explicit
install.The repository exposes flake packages and can be consumed directly from another
project's devenv.yaml:
inputs:
lx-anonymizer:
url: github:wg-lux/lx-anonymizer
After adding the input, reference the package through your own devenv.nix or
flake outputs. You do not need to commit or publish local result or
result-app symlinks for this to work.
pip install lx-anonymizer
The base package installs the public API, CLI, PDF/image processing, detector training, spaCy-based metadata extraction, and PyTesseract fallback OCR. Install extras only when you need the corresponding hardware or development feature set:
pip install "lx-anonymizer[dev]" # local development tooling
pip install "lx-anonymizer[cpu]" # CPU PyTorch wheel selection
pip install "lx-anonymizer[gpu]" # CUDA PyTorch wheel selection
git clone https://github.com/wg-lux/lx-anonymizer.git
cd lx-anonymizer
uv sync --extra dev --extra cpu # development + CPU PyTorch stack
uv sync --extra gpu # CUDA 12.8 PyTorch-dependent features
The cpu and gpu extras are mutually exclusive in uv. The CPU extra routes
torch, torchaudio, and torchvision to PyTorch's CPU wheel index; the GPU
extra routes them to PyTorch's CUDA 12.8 wheel index and adds
onnxruntime-gpu.
direnv allow
nix develop
This loads GPU, OCR, and tooling dependencies declared in devenv.nix.
PyPI releases now use a split artifact strategy:
maturin and include the Rust extensionpyproject.toml with python -m build --sdistFor a local source-package sanity check:
uv build --sdist
uv run python scripts/audit_distribution.py dist/*.tar.gz
If you build the local wheel on a non-manylinux host (for example Nix), pass the desired compatibility target explicitly:
make pypi-wheel PYPI_COMPATIBILITY=manylinux_2_34
CI uses maturin --manylinux auto via PyO3/maturin-action to produce the
published Linux wheels.
The published Python package is the complete baseline install path. Only hardware-specific PyTorch wheel selection and development/build tools remain in extras; type stubs and test tools stay outside the runtime dependency set.
The repository also contains an optional Rust extension used for local and Nix
packaging. The Python code loads it opportunistically through
lx_anonymizer._native and falls back to pure Python implementations when the
native module is unavailable or only partially implemented.
PyPI wheels built by CI now include this extension. Pure-Python fallback still exists for environments that install from source without a compiled native module.
Local prebuilt extension files, generated reports, study data, and cache files are excluded from PyPI artifacts. CI audits each wheel and sdist before upload.
The flake exports multiple package variants, including the base CLI package and a native-enabled package:
nix build .#lx-anonymizer
nix build .#lx-anonymizer-with-native
Those commands create local ./result symlinks for inspection on your machine.
They are build outputs, not repository contents, and should remain uncommitted.
uv build --sdist and uv run python scripts/audit_distribution.py dist/*.tar.gz to validate the source distribution locally.maturin.nix build .#lx-anonymizer or nix build .#lx-anonymizer-with-native to validate flake packaging.result or result-app.The intended release path is now:
vX.Y.Z to trigger the production publish workflow.The release workflow publishes:
maturinpython -m build --sdistSettings are loaded from environment variables and an optional .env file. See
SETTINGS.md for a quick overview and example configuration.
The default German spaCy model is de_core_news_sm. On first use, LX Anonymizer
loads the model if it is installed and otherwise downloads it with the same
Python interpreter that is running the application. To pre-install it, run:
python -m spacy download de_core_news_sm
Clinical/strict deployments fail loudly when the configured model is missing.
Automatic download is enabled by default. Set
LX_ANONYMIZER_SPACY_AUTO_DOWNLOAD=0 or SPACY_AUTO_DOWNLOAD=False to disable
network installation. Outside clinical/strict profiles, disabling it permits
the degraded blank fallback.
Start a compatible LLM server exposing either an OpenAI-compatible API or Ollama:
# Default local Gemma 4 setup used for OCR and text recognition
bash scripts/provision_ollama_gemma4.sh
# In a devenv shell, the equivalent task is:
devenv tasks run ollama:provision-gemma4
# Alternative high-throughput setup
vllm serve Qwen/Qwen3.5-9B --port 8000
Caution: This is only recommended on devices with sufficient gpu capabilities
The EAST detector now downloads on first use, not on import. TrOCR and other optional OCR assets download only when those paths are exercised. For air-gapped deployments, pre-seed the required model files before running the relevant pipeline steps.
Install the package, then use lx-anonymizer --help as the single command
index. Every workflow has its own help page:
# List all image, report, evaluation, dataset, export, and training commands
lx-anonymizer --help
# Show options for one workflow without importing or running the pipeline
lx-anonymizer report --help
lx-anonymizer evaluate-midi-b --help
# Process a single image or PDF
lx-anonymizer image frame.png
# Use a custom EAST model and device profile
lx-anonymizer image frame.png \
--east /models/frozen_east_text_detection.pb \
--device olympus_cv_1500
# Return validation metadata in addition to the output path
lx-anonymizer image report.pdf --validation
# The historical spelling remains available
lx-anonymizer -i frame.png
The report command validates the source snapshot and writes one unpublished PDF candidate to an attempt-owned directory. Its standard output is one JSON object, which can be consumed directly by shell tooling.
lx-anonymizer report report.pdf \
--output-directory ./attempt-output \
--no-llm
# Optional extraction modes and a caller-supplied attempt identity
lx-anonymizer report report.pdf \
--output-directory ./attempt-output \
--attempt-id 12345678-1234-5678-1234-567812345678 \
--ensemble \
--llm
The output directory may be new or existing, but the generated attempt artifact
must not already exist. A new UUID is generated when --attempt-id is omitted.
The previously separate console scripts are also available as subcommands:
lx-anonymizer evaluate-midi-b --help
lx-anonymizer export-dicom --help
lx-anonymizer generate-phi-data --help
lx-anonymizer generate-endoscopy-stickers --help
lx-anonymizer generate-midi-b-phi-data --help
lx-anonymizer generate-radphi-data --help
lx-anonymizer train-phi --help
The historical lx-anonymizer-evaluate-midi-b,
lx-anonymizer-export-dicom, lx-anonymizer-generate-*, and
lx-anonymizer-train-phi executables remain as compatibility aliases.
python -m lx_anonymizer.cli provides the same command interface.
Video import is deliberately not exposed as a standalone production shell
workflow. endoreg-db owns durable attempts, leases, encrypted staging,
validation, and publication; it creates one FrameCleaner per attempt and uses
the Python API described below.
The three central strands use the same shape: construct a typed request, then
call processor.process(request) to receive a typed result with an
artifact_path. The historical main(...), clean_video(...), and
process_report(...) methods remain compatibility wrappers.
from pathlib import Path
from lx_anonymizer import ImageAnonymizer
from lx_anonymizer.processing_contracts import ImageAnonymizationRequest
attempt_directory = Path("/path/to/image-attempt")
attempt_directory.mkdir(parents=True)
result = ImageAnonymizer().process(
ImageAnonymizationRequest(
source_path=Path("/path/to/image.png"),
output_directory=attempt_directory,
)
)
print(result.artifact_path, result.metadata)
import hashlib
from pathlib import Path
from uuid import uuid4
from lx_anonymizer import ReportReader
from lx_anonymizer.report_contracts import (
ReportAnonymizationOptions,
ReportAnonymizationRequest,
)
source_path = Path("/path/to/report.pdf")
source_bytes = source_path.read_bytes()
attempt_directory = Path("/path/to/attempt")
attempt_directory.mkdir(parents=True)
request = ReportAnonymizationRequest(
attempt_id=uuid4(),
source_path=source_path,
source_sha256=hashlib.sha256(source_bytes).hexdigest(),
source_size_bytes=len(source_bytes),
output_directory=attempt_directory,
options=ReportAnonymizationOptions(use_ensemble=True, use_llm=True),
)
reader = ReportReader(locale="de_DE")
result = reader.process(request)
print(result.artifact_path, result.artifact_sha256)
# Advanced processing with region cropping
original, anonymized, meta, cropped_regions, anonymized_pdf = reader.process_report_with_cropping(
pdf_path="/path/to/report.pdf",
crop_output_dir="/path/to/cropped_regions",
crop_sensitive_regions=True,
use_llm=True
)
ReportReader is the canonical report-oriented entry point for immutable PDF
snapshots.
ReportReader(...) constructor:
report_root_path: optional base path for report assets.locale: Faker locale for pseudonymized replacements.employee_first_names / employee_last_names: optional replacement pools.flags: optional parsing markers merged with DEFAULT_SETTINGS["flags"].text_date_format: output format used for anonymized date text.process(...) (and its compatibility alias process_report(...)) accepts one strictly validated
ReportAnonymizationRequest. The caller supplies the immutable source identity,
an attempt-owned output directory, and processing options. The method always
creates and validates an anonymized PDF without choosing a canonical publication
path.
It returns a frozen ReportAnonymizationResult containing original and
anonymized text, typed sensitive metadata, the attempt-local artifact path,
artifact size and SHA-256, structural PDF validation, and anonymizer provenance.
process_report_with_cropping(...) is a separate diagnostic helper with:
crop_output_dir: where cropped sensitive regions are written.crop_sensitive_regions: enable or disable crop extraction.anonymization_output_dir: output directory for the crop-based anonymized PDF.process_report_with_cropping(...) returns:
original_textanonymized_textreport_metacropped_regions_info: mapping of cropped sensitive regions.anonymized_pdf_path: Path | Nonefrom fractions import Fraction
from pathlib import Path
from lx_anonymizer.frame_cleaner import FrameCleaner
from lx_anonymizer.processing_contracts import VideoAnonymizationRequest
result = FrameCleaner(use_llm=True).process(
VideoAnonymizationRequest(
source_path=Path("endoscopy.mp4"),
output_path=Path("attempt/candidate.mp4"),
source_frame_rate=Fraction(25, 1),
endoscope_image_roi={"x": 550, "y": 0, "width": 1350, "height": 1080},
endoscope_data_roi_nested={
"patient_info": {"x": 10, "y": 10, "width": 300, "height": 50}
},
technique="mask_overlay",
)
)
print(result.artifact_path, result.metadata)
FrameCleaner is the video-oriented entry point for endoscopy footage and
frame-level overlays.
FrameCleaner(...) constructor:
use_llm: enables provider-backed batch metadata enrichment when available.use_minicpm and minicpm_config: reserved for optional OCR backends.clean_video(...) parameters:
video_path: input video file.endoscope_image_roi: flat ROI dict for the visible endoscope image, typically with x, y, width, height.endoscope_data_roi_nested: nested ROI mapping for text-bearing overlay regions such as patient info blocks.output_path: optional explicit output path.technique: one of mask_overlay, remove_frames, or extract_only.device: device profile name, defaulting to olympus_cv_1500.clean_video(...) behavior by technique:
mask_overlay: preserves the timeline and overlays masks onto sensitive regions.remove_frames: drops sensitive frames and rewrites the stream.extract_only: does metadata extraction without producing a masked/removal-focused anonymization pass.clean_video(...) returns:
output_video_path: resulting video path. With extract_only, this is still the path chosen for the run.sensitive_meta: accumulated metadata dictionary extracted from sampled frames.Training is included in the standard installation. Its typed result creates the checksum-pinned runtime configuration accepted by every strand:
from pathlib import Path
from lx_anonymizer import ImageAnonymizer, ReportReader
from lx_anonymizer.frame_cleaner import FrameCleaner
from lx_anonymizer.text_detection.phi_region_detector import CustomPhiRegionDetector
from lx_anonymizer.text_detection.phi_region_detector_training import (
PhiRegionDetectorTrainingConfig,
train_phi_region_detector,
)
training = train_phi_region_detector(
PhiRegionDetectorTrainingConfig(
dataset_yaml=Path("datasets/phi/data.yaml"),
output_dir=Path("runs/phi"),
)
)
detector = CustomPhiRegionDetector(training.detector_config(required=True))
image_processor = ImageAnonymizer(region_detector=detector)
video_processor = FrameCleaner(region_detector=detector)
report_processor = ReportReader(region_detector=detector)
ROI guidance:
endoscope_image_roi for the main picture area that may need masking.endoscope_data_roi_nested for device-specific overlay fields.x, y, width, height directly is the least ambiguous form.See tests/test_report_reader_init.py and tests/test_frame_cleaner.py for concrete usage patterns.
-c copy for maximum speedBy default, outputs live in ~/etc/lx-anonymizer/{data,temp}. Adjust them in
lx_anonymizer/setup/directory_setup.py.
Clean temp regularly to avoid large intermediate artefacts.
uv run flake8 for linting and formattinguv run pytest -m "not gpu"uv run pytest -m gpu (requires CUDA-capable hardware)uv run pytest tests/test_cli_integration.pyuv run pytest tests/test_frame_cleaner.py--log-level DEBUG for detailed timing informationuv run python -m build --sdist for local sdist validation; GitHub Actions builds release wheelsscripts/run_checks.sh for comprehensive local testingexample_anonymize_pdf.py for end-to-end testing scenariosSee CONTRIBUTING.md for contribution guidelines, testing instructions, and communication channels.
Released under the MIT License.
Questions? Email lux@coloreg.de .
Python
96.8%
Nix
1.9%
Rust
1.0%