NudeNix is a powerful, modular utility for NSFW content detection and censoring. It can process existing video files or capture your screen live, applying censorship effects and outputting the result to a new file or a transparent, click-through system overlay.
- NudeNet for NSFW detection
- PyQt5 for the transparent, click-through screen overlay
- PyAV for media handling and encoding
- OpenCV for image processing
- Pillow for screen capture
- NumPy for numerical operations
- ImageHash for perceptual hashing
- Real-Time Screen Censoring: Capture any monitor and apply a transparent overlay that hides NSFW content in real-time.
- Modular Architecture: Easily switch between input sources (files, screen) and output destinations (files, overlay).
- Highly Configurable: Control detection sensitivity, censor types, and per-label settings via
censor_settings.yaml. - Extensible: Add new censor effects by simply dropping a Python file into the
censors/directory.
Python 3.10+: The project is developed using Python. Download from python.org.
To use NudeNix, you can either install it directly from the source or use a pre-packaged executable.
-
Clone the Repository:
git clone https://github.com/your-username/NudeNix.git cd NudeNix -
Create a Python Virtual Environment (Recommended):
python3 -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate
-
Install Dependencies:
pip install -r requirements.txt
Simply download and extract the .zip file. No Python installation or dependency management is required on your part.
NudeNix uses a URI-based system for inputs and outputs.
General Command:
python main.py -i <INPUT_URI> -o <OUTPUT_URI> [OPTIONS]- Input (
-i):file://path/to/video.mp4: Process an existing video.screen://1: Capture monitor 1.
- Output (
-o):file://path/to/output.mp4: Save the censored result to a file.overlay://: Display censorship as a transparent system overlay.
# Live screen censoring with overlay
python main.py -i screen://1 -o overlay://
# Censoring a video file and saving to MP4
python main.py -i file://input.mp4 -o file://censored.mp4
# Recording a censored screen capture
python main.py -i screen://1 -o file://recording.mp4NudeNix includes an optional, pluggable statistics system to help analyze processing bottlenecks and optimization efficiency. To enable it, add the --performance-statistics flag to any command.
Example:
python main.py -i file://input.mp4 -o file://censored.mp4 --performance-statisticsWhen enabled, a performance report will be printed upon exit.
Censoring behavior is controlled by the censor_settings.yaml file. This YAML file defines global settings for all detection labels and allows for specific overrides per label. See censor_settings.example.yaml, is provided. You should copy censor_settings.example.yaml to censor_settings.yaml and modify it. Customize censor_settings.yaml to define your desired censoring logic and place the file
- next to your
main.pyscript (if running from source) - or next to the
NudeNixexecutable (if running a packaged version).
You can configure the nudenet model's behavior via the top-level nudenet_settings block in censor_settings.yaml.
model_path: Specifies a custom ONNX model file to load. If leftnull, Nudenet will use its default model.inference_resolution: Sets the resolution at which the model performs inference. This should match the resolution the model was trained on (e.g., 320 for320n.onnx, 640 for640m.onnx).
The clustering_settings block in censor_settings.yaml controls the merging of closely located detection boxes.
enabled: Set totrueto enable the box clustering feature.max_distance: Defines how close two boxes of the same label must be (in pixels) to be considered for merging into a single larger box.
This feature optimizes performance by avoiding redundant NSFW detection runs on consecutive frames that are visually similar. It uses image hashing to determine frame similarity.
enabled(boolean, default:true): Set tofalseto disable this optimization.algorithm(string, default:'average_hash'): Specifies the image hashing algorithm to use. Options include:'average_hash'(fastest, good for slight changes)'phash'(perceptual hash, more robust to resizing/cropping)'dhash'(difference hash, good for small shifts)'whash'(wavelet hash)
hash_threshold(integer, default:11): The maximum "Hamming distance" between two image hashes for them to be considered "similar." A lower value means stricter similarity.max_skip_frames(integer, default:5): The maximum number of consecutive frames for which detection can be skipped, even if hashes remain similar. This prevents stale detections if content subtly changes over a long period. After this many skipped frames, detection will run regardless of hash similarity.debug_overlay(boolean, default:false): Iftrue, a small circle will be drawn on the top-left corner of the video frame for debugging:- Green Circle: Detection was skipped due to hash similarity.
- Red Circle: Detection was run (either first frame or hash difference).
- Blue Circle: Detection was forced to run (
max_skip_framesreached).
This section details the censor types currently implemented and available for use in censor_settings.yaml.
- Type:
box - Description: Draws a rectangular box around the detected region. Can be configured to draw a border or fill the entire region.
- Settings:
thickness(integer, default:2): The thickness of the border in pixels. Set to-1to fill the entire box.size_percent(integer, default:100): The size of the box as a percentage of the detected bounding box (e.g.,90for 90% of the original size).color(object, default:{r: 0, g: 0, b: 255}- Red): The color of the box in RGB format. Example:{r: 0, g: 255, b: 0}for Green.display_label(boolean, default:true): Whether to display the detection label as text above the box.display_score(boolean, default:true): Whether to display the detection score as text above the box.adaptive(boolean, default:false): Reserved for future confidence-based scaling.
- Type:
pixelation - Description: Applies a pixelation (mosaic) effect to the detected region.
- Settings:
strength(integer, default:10): The block size in pixels for pixelation. A higher value means larger pixels and stronger effect.scale_with_detection_size(boolean, default:true): Iftrue, thestrengthis interpreted as a percentage of the detected region's smallest dimension, making the pixelation adaptive.sampling_mode(string, default:'accurate'): How colors are sampled for the pixel blocks.'accurate': Usescv2.INTER_AREAfor downscaling, which provides a good average color for the block.'fast': Usescv2.INTER_NEARESTfor downscaling, which samples the center pixel's color, but is less accurate.
adaptive(boolean, default:false): Iftrue, the pixel size will scale dynamically based on the detection confidence.
- Type:
blur - Description: Applies a Gaussian blur effect to the detected region.
- Settings:
kernel_size(integer, default:15): Defines the blur radius.sigma(integer, default:0): The standard deviation for Gaussian kernel.scale_with_detection_size(boolean, default:true): Iftrue, thekernel_sizeis interpreted as a percentage of the detected region's smallest dimension.adaptive(boolean, default:false): Iftrue, the blur radius will scale dynamically based on the detection confidence.
- Type:
grayscale - Description: Desaturates the detected region.
- Settings:
intensity(float, default:1.0): Strength of the grayscale effect (0.0to1.0).adaptive(boolean, default:false): Iftrue, the intensity will scale dynamically based on the detection confidence.
- Type:
blanking - Description: Fills the entire video frame with a solid color.
- Settings:
color(object, default:{r: 0, g: 0, b: 0}): The color to fill the frame with in RGB format.
Censors support an adaptive: true toggle. When enabled, the strength of the effect (e.g., pixel size, blur radius, or grayscale intensity) scales linearly based on NudeNet's confidence score.
If the score is exactly at the min_score threshold, the effect is minimal; if the score is 1.0, the effect reaches its configured maximum.
Example:
labels:
FEMALE_BREAST_EXPOSED:
min_score: 0.6
censors:
- type: pixelation
settings:
strength: 20
adaptive: true # Pixel size scales from ~1 at 0.6 confidence to 20 at 1.0 confidence.The nudenet model provides the following detection labels that can be configured for censoring:
FEMALE_GENITALIA_COVEREDFACE_FEMALEBUTTOCKS_EXPOSEDFEMALE_BREAST_EXPOSEDFEMALE_GENITALIA_EXPOSEDMALE_BREAST_EXPOSEDANUS_EXPOSEDFEET_EXPOSEDBELLY_COVEREDFEET_COVEREDARMPITS_COVEREDARMPITS_EXPOSEDFACE_MALEBELLY_EXPOSEDMALE_GENITALIA_EXPOSEDANUS_COVEREDFEMALE_BREAST_COVEREDBUTTOCKS_COVERED
Follow the User Installation steps to set up the development environment.
The modular design of the censoring system allows for easy addition of new censoring effects. To add a new censor type:
- Create a New File: In the
censors/directory, create a new Python file (e.g.,censors/my_custom_censor.py). - Define a Censor Class: Inside this file, define a class named according to the pattern
<CensorType>Censor(e.g.,MyCustomCensor). This class must have:- An
__init__(self, settings)method that takes a dictionary of settings specific to this censor type. - An
apply(self, frame_ndarray, detection, metadata)method that takes the NumPy array of the video frame, a detection object, and an environmental metadata object. - A
get_type(self) -> strmethod that returns the string type for registration.
- An
The metadata object (CensorMetadata) provided to the apply method contains context about the current detection:
metadata.label: The string label of the detection.metadata.score: The confidence score (0.0 to 1.0).metadata.min_score: The threshold configured for this label.metadata.confidence_ratio: A pre-calculated value from 0.0 (atmin_score) to 1.0 (atscore=1.0). Useful for scaling effects.metadata.frame_time: The timestamp of the current frame.
- Update
censor_settings.yaml: In yourcensor_settings.yamlfile, add your new censor type under thecensorslist forall_labelsor specific labels. Thetypekey in the YAML should match the lowercase, underscore-separated version of yourget_typemethod.
To distribute NudeNix as a standalone executable, you can use PyInstaller.
Ensure pyinstaller is installed (pip install pyinstaller). Then, navigate to your project root and run a build:
pyinstaller NudeNix.specThe dist/NudeNix directory will now contain your standalone application.
The project uses pytest for unit testing. Test files are located in the tests/ directory.
- Install pytest:
Activate your virtual environment (e.g.,
source venv/bin/activate), then:pip install pytest
- Run tests:
Activate your virtual environment (e.g.,
source venv/bin/activate), then execute:This command will discover and run all tests in thePYTHONPATH=. pytest
tests/directory.