Skip to main content

protect_image()

Detect and encrypt all license plates found in a PIL image.

Signature

safelicensing.protect_image(
image: PIL.Image.Image,
seed: float = 0.5,
model = None,
model_path: str | None = None,
) -> ProtectImageResult

Parameters

ParameterTypeDefaultDescription
imagePIL.Image.ImagerequiredInput image. Any colour mode accepted; converted to RGB internally.
seedfloat0.5Chaotic encryption seed in (0.0, 1.0) exclusive. Same seed on same image always produces same encrypted output.
modelYOLO instanceNonePre-loaded YOLO model. Loads bundled best.pt when None.
model_pathstrNonePath to custom YOLOv8 .pt weights. Ignored when model is given.

Returns: ProtectImageResult

FieldTypeDescription
originalPIL.ImageUnmodified RGB input
detectedPIL.ImageCopy of input with red bounding boxes drawn around detected plates
encryptedPIL.ImageFull image with every detected plate region encrypted
bboxeslist[tuple[int, int, int, int]](x1, y1, x2, y2) bounding box per detected plate
elapsedfloatWall-clock processing time in seconds

Raises

ExceptionCondition
TypeErrorimage is not a PIL.Image.Image instance
ValueErrorseed is not strictly inside (0.0, 1.0)

Examples

Basic usage

import safelicensing as sl
from PIL import Image

model = sl.load_model()
result = sl.protect_image(Image.open("car.jpg"), seed=0.42, model=model)

result.encrypted.save("car_protected.jpg")
print(result.bboxes) # [(x1, y1, x2, y2), ...]
print(result.elapsed) # 0.35

Load model once, process many images

import safelicensing as sl
from pathlib import Path
from PIL import Image

model = sl.load_model()

for path in Path("dataset/").glob("*.jpg"):
result = sl.protect_image(Image.open(path), seed=0.5, model=model)
result.encrypted.save(f"output/{path.name}")

Custom model path

model = sl.load_model("my_custom_weights.pt")
result = sl.protect_image(image, seed=0.3, model=model)

Access all output fields

result = sl.protect_image(image, seed=0.7)

print(f"Plates detected : {len(result.bboxes)}")
print(f"Bounding boxes : {result.bboxes}")
print(f"Elapsed : {result.elapsed:.3f}s")

result.original.save("original.jpg")
result.detected.save("detected.jpg") # red boxes
result.encrypted.save("encrypted.jpg")

Validate the encryption seed

try:
result = sl.protect_image(image, seed=1.0) # raises ValueError
except ValueError as e:
print(e) # seed must be in (0.0, 1.0) exclusive, got 1.0

Notes

  • The original image is never mutated; all outputs are independent copies.
  • When no plates are detected, encrypted is identical to original and bboxes is empty.
  • The elapsed timer starts after model loading. It measures detection + encryption only.

See also: protect_video() → | load_model() →