Pixelate Annotator
Apply pixelation effect to detected regions for privacy protection with a distinctive blocky appearance.
Overview
The pixelate() annotator creates a blocky, mosaic-like effect on detected regions by downscaling and upscaling with nearest neighbor interpolation. Unlike Gaussian blur which creates smooth gradients, pixelation produces sharp, clearly artificial blocks - making it obvious that privacy redaction has been applied.
pf.annotators.pixelate(image, detections)
Function Signature
def pixelate( image: np.ndarray, detections: Detections, pixel_size: Optional[int] = None, padding_percent: float = 0.05) -> np.ndarray
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| image | np.ndarray | required | Input image in BGR format. Modified in-place. |
| detections | Detections | required | PixelFlow detections with bounding boxes. |
| pixel_size | int or None | None | Size of pixel blocks. Larger = blockier. None = auto. |
| padding_percent | float | 0.05 | Extra padding around detection as % of bbox size (0.0-0.5). |
Returns:np.ndarray - The input image with pixelated regions (same array, modified in-place).
Basic Usage
import cv2import pixelflow as pffrom ultralytics import YOLO# Load image and detect facesimage = cv2.imread("crowd.jpg")model = YOLO("yolov8n-face.pt")results = model.predict(image)detections = pf.from_ultralytics(results)# Pixelate all detected facesimage = pf.annotators.pixelate(image, detections)cv2.imshow("Privacy Protected", image)cv2.waitKey(0)
How It Works
The pixelation effect is created through a two-step resize process:
Original Region Downscaled Upscaled (Pixelated)┌─────────────────┐ ┌─────┐ ┌─────────────────┐│ │ │█░█░█│ │███░░░███░░░███░││ Detailed │ → │░█░█░│ → │███░░░███░░░███░││ Image │ │█░█░█│ │░░░███░░░███░░░░││ │ └─────┘ │░░░███░░░███░░░░│└─────────────────┘ (tiny size) │███░░░███░░░███░│ └─────────────────┘ (back to original size with blocky pixels)
- Downscale: Region is shrunk using linear interpolation (averages colors)
- Upscale: Tiny image is enlarged back using nearest neighbor (creates blocks)
Pixel Size Control
The pixel_size parameter controls how large each block appears. Larger values create more obvious, blockier pixelation.
| pixel_size | Effect | Use Case |
|---|---|---|
| 3-5 | Fine pixelation | Subtle, details somewhat visible |
| 8-12 | Medium pixelation | Standard privacy protection |
| 15-20 | Coarse pixelation | Strong anonymization |
| 25+ | Heavy pixelation | Extreme obscuring, few blocks visible |
# Subtle pixelation - some detail remainsimage = pf.annotators.pixelate(image, detections, pixel_size=5)# Standard pixelationimage = pf.annotators.pixelate(image, detections, pixel_size=12)# Heavy pixelation - just colored blocksimage = pf.annotators.pixelate(image, detections, pixel_size=25)
Padding Control
The padding_percent parameter expands the pixelated region beyond the bounding box, ensuring complete coverage when detections are slightly tight.
# No padding - exact bounding boximage = pf.annotators.pixelate(image, detections, padding_percent=0.0)# Default 5% paddingimage = pf.annotators.pixelate(image, detections, padding_percent=0.05)# Generous padding for complete coverageimage = pf.annotators.pixelate(image, detections, padding_percent=0.15)
Blur vs Pixelate
Both annotators provide privacy protection but with different visual styles:
| Feature | blur() | pixelate() |
|---|---|---|
| Appearance | Smooth, natural | Blocky, artificial |
| Edges | Soft gradients | Sharp block boundaries |
| Intent | Subtle, blends in | Obvious redaction |
| Style | Professional/news | Retro/gaming aesthetic |
| Performance | Slightly faster | Very fast |
Common Use Cases
Face Anonymization
face_model = YOLO("yolov8n-face.pt")results = face_model.predict(image)faces = pf.from_ultralytics(results)# Strong pixelation with extra paddingimage = pf.annotators.pixelate(image, faces, pixel_size=15, padding_percent=0.1)
Selective Pixelation
# Detect all objectsresults = model.predict(image)detections = pf.from_ultralytics(results)# Pixelate only people, show boxes on everything elsepeople = detections.filter_by_class_id([0])others = detections.filter_by_class_id([0], exclude=True)image = pf.annotators.pixelate(image, people)image = pf.annotators.box(image, others)image = pf.annotators.label(image, others)
With Labels
# Pixelate faces but show redaction labelsimage = pf.annotators.pixelate(image, faces)image = pf.annotators.box(image, faces)image = pf.annotators.label(image, faces, "[REDACTED]")
Adaptive Sizing
When pixel_size=None, the block size automatically adapts to image resolution:
| Image Resolution | Auto pixel_size |
|---|---|
| 640x480 | ~5px |
| 1280x720 | ~8px |
| 1920x1080 | ~10px |
| 3840x2160 (4K) | ~20px |
Performance
The pixelate() annotator is extremely fast due to OpenCV's optimized resize operations:
Notes
-
In-place modification: The input image is modified directly. Use
image.copy()if you need the original preserved. - Minimum pixel_size: Values below 1 are automatically clamped to 1.
- Small regions: Regions smaller than pixel_size are skipped to prevent artifacts.
- Boundary handling: Bounding boxes are automatically clipped to image boundaries.
-
Padding limits: The
padding_percentis clamped to range [0.0, 0.5].
See Also
-
blur()- Alternative privacy method using Gaussian blur -
mask()- Overlay colored masks on detections -
filter_by_class_id()- Filter detections before pixelating