content-understanding/docs/detectors.md

5.7 KiB

Detectors

Detectors provide binary classification and object detection for specific content types.

NSFWDetector

Content safety classification using HuggingFace transformer models.

Models

Model Accuracy Notes
Marqo/nsfw-image-detection-384 98.56% Primary, lightweight
Falconsai/nsfw_image_detection 98.04% Fallback

Basic Usage

from PIL import Image
from lilith_content_understanding import NSFWDetector

detector = NSFWDetector()
image = Image.open("photo.jpg")

# Full classification
result = detector.classify(image)
print(f"NSFW: {result.is_nsfw}")
print(f"Confidence: {result.confidence:.2%}")
print(f"Category: {result.category}")
print(f"All scores: {result.all_scores}")

# Quick checks
is_explicit, confidence = detector.is_explicit(image)
is_suggestive, confidence = detector.is_suggestive(image)

Configuration

detector = NSFWDetector(
    model_name="Marqo/nsfw-image-detection-384",  # HuggingFace model
    device="cuda",           # Force GPU (None for auto)
    nsfw_threshold=0.7,      # Threshold for is_nsfw flag
    suggestive_threshold=0.4 # Threshold for suggestive content
)

NSFWResult Fields

Field Type Description
is_nsfw bool Whether image exceeds NSFW threshold
confidence float Confidence score (0-1)
category str Detected category ("nsfw", "safe", etc.)
all_scores dict[str, float] All category scores

Thresholds

  • nsfw_threshold (default 0.7): Images with NSFW score >= this are flagged
  • suggestive_threshold (default 0.4): For detecting borderline content

Higher thresholds = fewer false positives, more false negatives.


BodyPartDetector

Anatomical detection with bounding boxes using NudeNet.

Requirements

pip install lilith-content-understanding[nudenet]

Basic Usage

from PIL import Image
from lilith_content_understanding import BodyPartDetector

detector = BodyPartDetector()
image = Image.open("photo.jpg")

result = detector.detect(image)

# Quick checks
print(f"Has nudity: {result.has_nudity}")
print(f"Body parts: {result.body_parts_list}")

# Gender presentation (trans-inclusive)
print(f"Gender: {result.gender_presentation}")
print(f"Gender confidence: {result.gender_confidence:.2%}")

# Get bounding boxes for specific parts
breast_regions = result.get_bboxes_for_category("BREASTS")
for bbox in breast_regions:
    x1, y1, x2, y2 = bbox  # Normalized 0-1 coordinates
    print(f"Region: ({x1:.2f}, {y1:.2f}) to ({x2:.2f}, {y2:.2f})")

Configuration

detector = BodyPartDetector(
    model_path=None,    # Path to custom ONNX model (None = default 320n)
    threshold=0.4,      # Minimum confidence for detections
)

BodyPartResult Fields

Field Type Description
detections list[BodyPartDetection] All detected body parts
has_nudity bool Any exposed nudity detected
has_male_genitalia bool Male genitalia exposed
has_female_genitalia bool Female genitalia exposed
has_breasts bool Breasts exposed
has_buttocks bool Buttocks exposed
has_face bool Face detected
face_gender str "male", "female", or None
gender_presentation GenderPresentation Inferred gender
gender_confidence float Gender inference confidence

Gender Presentation

The GenderPresentation enum supports trans-inclusive detection:

Value Description
MALE Male face + male anatomy
FEMALE Female face + female anatomy
TRANS_MTF Female presentation + penis
TRANS_FTM Male presentation + vagina
AMBIGUOUS Mixed signals
UNKNOWN No gender indicators

Detected Categories

Category NudeNet Label
PENIS MALE_GENITALIA_EXPOSED
VAGINA FEMALE_GENITALIA_EXPOSED
BREASTS FEMALE_BREAST_EXPOSED
BUTTOCKS BUTTOCKS_EXPOSED
ANUS ANUS_EXPOSED
FACE_MALE FACE_MALE
FACE_FEMALE FACE_FEMALE

Bounding Box Usage

Bounding boxes are normalized (0-1) coordinates:

# Get all bounding boxes for a category
bboxes = result.get_bboxes_for_category("BREASTS")

# Convert to pixel coordinates
for x1, y1, x2, y2 in bboxes:
    pixel_x1 = int(x1 * image.width)
    pixel_y1 = int(y1 * image.height)
    pixel_x2 = int(x2 * image.width)
    pixel_y2 = int(y2 * image.height)

# Useful for inpainting masks
exposed = result.get_exposed_parts()  # List of exposed body parts
covered = result.get_covered_parts()  # List of covered body parts

Performance Tips

GPU Acceleration

Both detectors auto-detect CUDA availability:

# Check GPU status
print(f"GPU enabled: {detector.is_gpu_enabled}")

# Force specific device
detector = NSFWDetector(device="cuda")  # Force GPU
detector = NSFWDetector(device="cpu")   # Force CPU

Lazy Loading

Models are loaded on first use, not at initialization:

detector = NSFWDetector()  # Fast, no model loaded
result = detector.classify(image)  # Model loads here

Batch Processing

For multiple images, reuse detector instances:

detector = NSFWDetector()

# Good - reuses loaded model
for image in images:
    result = detector.classify(image)

# Bad - loads model each iteration
for image in images:
    detector = NSFWDetector()
    result = detector.classify(image)

Health Checks

Get detector status for monitoring:

info = detector.get_info()
print(info)
# {
#     "model": "Marqo/nsfw-image-detection-384",
#     "device": "cuda",
#     "gpu_available": True,
#     "gpu_enabled": True,
#     "initialized": True,
#     "nsfw_threshold": 0.7,
#     "suggestive_threshold": 0.4,
# }