mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-18 17:14:26 +03:00
GenAI: enable blurring detected faces if desired
This commit is contained in:
parent
00371546a3
commit
6a05e791c8
@ -174,12 +174,15 @@ genai:
|
|||||||
object_prompts:
|
object_prompts:
|
||||||
person: "Examine the main person in these images. What are they doing and what might their actions suggest about their intent (e.g., approaching a door, leaving an area, standing still)? Do not describe the surroundings or static details."
|
person: "Examine the main person in these images. What are they doing and what might their actions suggest about their intent (e.g., approaching a door, leaving an area, standing still)? Do not describe the surroundings or static details."
|
||||||
car: "Observe the primary vehicle in these images. Focus on its movement, direction, or purpose (e.g., parking, approaching, circling). If it's a delivery vehicle, mention the company."
|
car: "Observe the primary vehicle in these images. Focus on its movement, direction, or purpose (e.g., parking, approaching, circling). If it's a delivery vehicle, mention the company."
|
||||||
|
blur_faces: False
|
||||||
```
|
```
|
||||||
|
|
||||||
Prompts can also be overriden at the camera level to provide a more detailed prompt to the model about your specific camera, if you desire. By default, descriptions will be generated for all tracked objects and all zones. But you can also optionally specify `objects` and `required_zones` to only generate descriptions for certain tracked objects or zones.
|
Prompts can also be overriden at the camera level to provide a more detailed prompt to the model about your specific camera, if you desire. By default, descriptions will be generated for all tracked objects and all zones. But you can also optionally specify `objects` and `required_zones` to only generate descriptions for certain tracked objects or zones.
|
||||||
|
|
||||||
Optionally, you can generate the description using a snapshot (if enabled) by setting `use_snapshot` to `True`. By default, this is set to `False`, which sends the uncompressed images from the `detect` stream collected over the object's lifetime to the model. Once the object lifecycle ends, only a single compressed and cropped thumbnail is saved with the tracked object. Using a snapshot might be useful when you want to _regenerate_ a tracked object's description as it will provide the AI with a higher-quality image (typically downscaled by the AI itself) than the cropped/compressed thumbnail. Using a snapshot otherwise has a trade-off in that only a single image is sent to your provider, which will limit the model's ability to determine object movement or direction.
|
Optionally, you can generate the description using a snapshot (if enabled) by setting `use_snapshot` to `True`. By default, this is set to `False`, which sends the uncompressed images from the `detect` stream collected over the object's lifetime to the model. Once the object lifecycle ends, only a single compressed and cropped thumbnail is saved with the tracked object. Using a snapshot might be useful when you want to _regenerate_ a tracked object's description as it will provide the AI with a higher-quality image (typically downscaled by the AI itself) than the cropped/compressed thumbnail. Using a snapshot otherwise has a trade-off in that only a single image is sent to your provider, which will limit the model's ability to determine object movement or direction.
|
||||||
|
|
||||||
|
If required for privacy purposes, Frigate can use OpenCV to attempt to detect faces in an image and blur them before sending to the provider. You can enable this by setting `blur_faces` to `True`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
cameras:
|
cameras:
|
||||||
front_door:
|
front_door:
|
||||||
|
|||||||
@ -543,6 +543,8 @@ genai:
|
|||||||
# Format: {label}: {prompt}
|
# Format: {label}: {prompt}
|
||||||
object_prompts:
|
object_prompts:
|
||||||
person: "My special person prompt."
|
person: "My special person prompt."
|
||||||
|
# Optional: Attempt to detect faces in the image and blur for privacy before sending to provider (default: shown below)
|
||||||
|
blur_faces: False
|
||||||
|
|
||||||
# Optional: Restream configuration
|
# Optional: Restream configuration
|
||||||
# Uses https://github.com/AlexxIT/go2rtc (v1.9.2)
|
# Uses https://github.com/AlexxIT/go2rtc (v1.9.2)
|
||||||
|
|||||||
@ -68,3 +68,6 @@ class GenAIConfig(FrigateBaseModel):
|
|||||||
provider: GenAIProviderEnum = Field(
|
provider: GenAIProviderEnum = Field(
|
||||||
default=GenAIProviderEnum.openai, title="GenAI provider."
|
default=GenAIProviderEnum.openai, title="GenAI provider."
|
||||||
)
|
)
|
||||||
|
blur_faces: bool = Field(
|
||||||
|
default=False, title="Blur faces if detected in the image."
|
||||||
|
)
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import logging
|
|||||||
import os
|
import os
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
from playhouse.shortcuts import model_to_dict
|
from playhouse.shortcuts import model_to_dict
|
||||||
|
|
||||||
from frigate.config import CameraConfig, FrigateConfig, GenAIConfig, GenAIProviderEnum
|
from frigate.config import CameraConfig, FrigateConfig, GenAIConfig, GenAIProviderEnum
|
||||||
@ -33,6 +35,14 @@ class GenAIClient:
|
|||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.provider = self._init_provider()
|
self.provider = self._init_provider()
|
||||||
|
|
||||||
|
if self.genai_config.blur_faces:
|
||||||
|
self.face_cascade_classifier = cv2.CascadeClassifier(
|
||||||
|
cv2.data.haarcascades + "/haarcascade_frontalface_alt.xml"
|
||||||
|
)
|
||||||
|
self.face_profile_cascade_classifier = cv2.CascadeClassifier(
|
||||||
|
cv2.data.haarcascades + "/haarcascade_profileface.xml"
|
||||||
|
)
|
||||||
|
|
||||||
def generate_description(
|
def generate_description(
|
||||||
self,
|
self,
|
||||||
camera_config: CameraConfig,
|
camera_config: CameraConfig,
|
||||||
@ -44,6 +54,8 @@ class GenAIClient:
|
|||||||
event.label,
|
event.label,
|
||||||
camera_config.genai.prompt,
|
camera_config.genai.prompt,
|
||||||
).format(**model_to_dict(event))
|
).format(**model_to_dict(event))
|
||||||
|
if self.genai_config.blur_faces:
|
||||||
|
self.blur_faces(thumbnails)
|
||||||
logger.debug(f"Sending images to genai provider with prompt: {prompt}")
|
logger.debug(f"Sending images to genai provider with prompt: {prompt}")
|
||||||
return self._send(prompt, thumbnails)
|
return self._send(prompt, thumbnails)
|
||||||
|
|
||||||
@ -55,6 +67,30 @@ class GenAIClient:
|
|||||||
"""Submit a request to the provider."""
|
"""Submit a request to the provider."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def blur_faces(self, thumbnails: list[bytes]):
|
||||||
|
for thumb in thumbnails:
|
||||||
|
image = cv2.imdecode(np.frombuffer(thumb, dtype=np.int8), cv2.IMREAD_COLOR)
|
||||||
|
|
||||||
|
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
face_data = self.face_cascade_classifier.detectMultiScale(
|
||||||
|
image=gray, scaleFactor=1.1, minNeighbors=2, minSize=(25, 25)
|
||||||
|
)
|
||||||
|
|
||||||
|
face_profile_data = self.face_profile_cascade_classifier.detectMultiScale(
|
||||||
|
image=gray, scaleFactor=1.1, minNeighbors=2, minSize=(25, 25)
|
||||||
|
)
|
||||||
|
|
||||||
|
for x, y, w, h in face_data:
|
||||||
|
roi = image[y : y + h, x : x + w]
|
||||||
|
roi = cv2.GaussianBlur(roi, (23, 23), 30)
|
||||||
|
image[y : y + h, x : x + w] = roi
|
||||||
|
|
||||||
|
for x, y, w, h in face_profile_data:
|
||||||
|
roi = image[y : y + h, x : x + w]
|
||||||
|
roi = cv2.GaussianBlur(roi, (23, 23), 30)
|
||||||
|
image[y : y + h, x : x + w] = roi
|
||||||
|
|
||||||
|
|
||||||
def get_genai_client(config: FrigateConfig) -> Optional[GenAIClient]:
|
def get_genai_client(config: FrigateConfig) -> Optional[GenAIClient]:
|
||||||
"""Get the GenAI client."""
|
"""Get the GenAI client."""
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user