Blur Annotator
Apply Gaussian blur to detected regions for privacy protection.
Overview
The blur() annotator applies Gaussian blur to detected regions, creating a natural-looking privacy filter. This is commonly used to obscure faces, license plates, or other sensitive information while preserving the rest of the image. The blur strength automatically adapts to image resolution.
pf.annotators.blur(image, detections)
Function Signature
def blur( image: np.ndarray, detections: Detections, kernel_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. |
| kernel_size | int or None | None | Blur kernel size in pixels (must be odd). 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 blurred 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") # Face detection modelresults = model.predict(image)detections = pf.from_ultralytics(results)# Blur all detected facesimage = pf.annotators.blur(image, detections)cv2.imshow("Privacy Protected", image)cv2.waitKey(0)
Blur Strength
The kernel_size parameter controls blur intensity. Larger values create stronger blur. The value must be odd (if even, it's automatically incremented).
| kernel_size | Effect | Use Case |
|---|---|---|
| 7-11 | Light blur | Subtle privacy, details still visible |
| 15-21 | Medium blur | Standard privacy protection |
| 25-35 | Strong blur | Complete anonymization |
| 51+ | Heavy blur | Extreme obscuring |
# Light blur - face shape still recognizableimage = pf.annotators.blur(image, detections, kernel_size=9)# Medium blur - good for general privacyimage = pf.annotators.blur(image, detections, kernel_size=21)# Strong blur - complete anonymizationimage = pf.annotators.blur(image, detections, kernel_size=51)
Padding Control
The padding_percent parameter expands the blur region beyond the bounding box. This helps ensure complete coverage when detections are slightly tight.
# No padding - blur exactly the bounding boximage = pf.annotators.blur(image, detections, padding_percent=0.0)# Default 5% paddingimage = pf.annotators.blur(image, detections, padding_percent=0.05)# 15% padding for better coverageimage = pf.annotators.blur(image, detections, padding_percent=0.15)# Maximum 50% paddingimage = pf.annotators.blur(image, detections, padding_percent=0.5)
padding_percent=0.0 padding_percent=0.15┌─────────────┐ ┌─────────────────┐│ Detection │ │ ┌─────────┐ ││ (bbox) │ │ │Detection│ ││ │ │ │ (bbox) │ │└─────────────┘ │ └─────────┘ │ ↑ └─────────────────┘ Exact fit ↑ Extra coverage
Common Use Cases
Face Anonymization (GDPR Compliance)
# Detect and blur faces for privacy complianceface_model = YOLO("yolov8n-face.pt")results = face_model.predict(image)faces = pf.from_ultralytics(results)# Strong blur with padding for complete anonymizationimage = pf.annotators.blur(image, faces, kernel_size=31, padding_percent=0.1)
License Plate Blurring
# Detect and blur license platesplate_model = YOLO("license_plate.pt")results = plate_model.predict(image)plates = pf.from_ultralytics(results)image = pf.annotators.blur(image, plates, kernel_size=25)
Selective Blurring with Filters
# Detect all objectsmodel = YOLO("yolo11n.pt")results = model.predict(image)detections = pf.from_ultralytics(results)# Only blur people (class_id=0 in COCO)people = detections.filter_by_class_id([0])image = pf.annotators.blur(image, people)# Draw boxes on non-blurred objectsother_objects = detections.filter_by_class_id([0], exclude=True)image = pf.annotators.box(image, other_objects)
Video Privacy Processing
import pixelflow as pffrom ultralytics import YOLOface_model = YOLO("yolov8n-face.pt")media = pf.Media("security_footage.mp4")for frame in media.frames: results = face_model.predict(frame, verbose=False) faces = pf.from_ultralytics(results) # Blur faces in each frame frame = pf.annotators.blur(frame, faces, kernel_size=25) pf.write_frame("anonymized_output.mp4", frame, media.info)
Combined with Other Annotators
# Blur faces but show detection boxes and labelsimage = pf.annotators.blur(image, faces) # Apply blur firstimage = pf.annotators.box(image, faces) # Then draw box on topimage = pf.annotators.label(image, faces, "[REDACTED]")
Adaptive Sizing
When kernel_size=None, the blur strength automatically adapts to image resolution:
| Image Resolution | Auto kernel_size |
|---|---|
| 640x480 | ~7px |
| 1280x720 | ~11px |
| 1920x1080 | ~15px |
| 3840x2160 (4K) | ~30px |
Notes
-
In-place modification: The input image is modified directly. Use
image.copy()if you need the original preserved. - Odd kernel size: Gaussian blur requires odd kernel sizes. Even values are automatically incremented.
- Minimum region size: Regions smaller than the kernel size are skipped to prevent errors.
- Boundary handling: Bounding boxes are automatically clipped to image boundaries.
-
Padding limits: The
padding_percentis clamped to range [0.0, 0.5]. - Performance: Uses OpenCV's optimized Gaussian blur for real-time video processing.
See Also
-
pixelate()- Alternative privacy method using pixelation effect -
mask()- Overlay colored masks on detections -
filter_by_class_id()- Filter detections before blurring