reduce grid size for contrast improvement (#6870)

This commit is contained in:
Blake Blackshear 2023-06-21 08:38:51 -05:00 committed by GitHub
parent 7c1568fcb9
commit 9e531b0b5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 63 deletions

View File

@ -1,14 +1,13 @@
import datetime import datetime
import multiprocessing as mp import multiprocessing as mp
import os import os
from statistics import mean
import cv2 import cv2
import numpy as np import numpy as np
from frigate.config import MotionConfig from frigate.config import MotionConfig
from frigate.motion.frigate_motion import FrigateMotionDetector
from frigate.motion.improved_motion import ImprovedMotionDetector from frigate.motion.improved_motion import ImprovedMotionDetector
from frigate.util import create_mask
# get info on the video # get info on the video
# cap = cv2.VideoCapture("debug/front_cam_2023_05_23_08_41__2023_05_23_08_43.mp4") # cap = cv2.VideoCapture("debug/front_cam_2023_05_23_08_41__2023_05_23_08_43.mp4")
@ -20,84 +19,85 @@ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS) fps = cap.get(cv2.CAP_PROP_FPS)
frame_shape = (height, width, 3) frame_shape = (height, width, 3)
mask = create_mask(
(height, width),
[],
)
# create the motion config # create the motion config
motion_config = MotionConfig() motion_config_1 = MotionConfig()
motion_config.mask = np.zeros((height, width), np.uint8) motion_config_1.mask = np.zeros((height, width), np.uint8)
motion_config.mask[:] = 255 motion_config_1.mask[:] = mask
motion_config.improve_contrast = 1 # motion_config_1.improve_contrast = 1
motion_config.frame_alpha = 0.02 # motion_config_1.frame_height = 150
motion_config.threshold = 40 # motion_config_1.frame_alpha = 0.02
motion_config.contour_area = 15 # motion_config_1.threshold = 30
# motion_config_1.contour_area = 10
motion_config_2 = MotionConfig()
motion_config_2.mask = np.zeros((height, width), np.uint8)
motion_config_2.mask[:] = mask
# motion_config_2.improve_contrast = 1
# motion_config_2.frame_height = 150
# motion_config_2.frame_alpha = 0.01
# motion_config_2.threshold = 20
# motion_config.contour_area = 10
save_images = True save_images = True
# create motion detectors improved_motion_detector_1 = ImprovedMotionDetector(
frigate_motion_detector = FrigateMotionDetector(
frame_shape=frame_shape, frame_shape=frame_shape,
config=motion_config, config=motion_config_1,
fps=fps, fps=fps,
improve_contrast=mp.Value("i", motion_config.improve_contrast), improve_contrast=mp.Value("i", motion_config_1.improve_contrast),
threshold=mp.Value("i", motion_config.threshold), threshold=mp.Value("i", motion_config_1.threshold),
contour_area=mp.Value("i", motion_config.contour_area), contour_area=mp.Value("i", motion_config_1.contour_area),
name="default",
clipLimit=2.0,
tileGridSize=(8, 8),
) )
frigate_motion_detector.save_images = save_images improved_motion_detector_1.save_images = save_images
improved_motion_detector = ImprovedMotionDetector( improved_motion_detector_2 = ImprovedMotionDetector(
frame_shape=frame_shape, frame_shape=frame_shape,
config=motion_config, config=motion_config_2,
fps=fps, fps=fps,
improve_contrast=mp.Value("i", motion_config.improve_contrast), improve_contrast=mp.Value("i", motion_config_2.improve_contrast),
threshold=mp.Value("i", motion_config.threshold), threshold=mp.Value("i", motion_config_2.threshold),
contour_area=mp.Value("i", motion_config.contour_area), contour_area=mp.Value("i", motion_config_2.contour_area),
name="compare",
) )
improved_motion_detector.save_images = save_images improved_motion_detector_2.save_images = save_images
# read and process frames # read and process frames
frame_times = {"frigate": [], "improved": []}
ret, frame = cap.read() ret, frame = cap.read()
frame_counter = 1 frame_counter = 1
while ret: while ret:
yuv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420) yuv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420)
start_frame = datetime.datetime.now().timestamp() start_frame = datetime.datetime.now().timestamp()
frigate_motion_detector.detect(yuv_frame) improved_motion_detector_1.detect(yuv_frame)
frame_times["frigate"].append(datetime.datetime.now().timestamp() - start_frame)
start_frame = datetime.datetime.now().timestamp() start_frame = datetime.datetime.now().timestamp()
improved_motion_detector.detect(yuv_frame) improved_motion_detector_2.detect(yuv_frame)
frame_times["improved"].append(datetime.datetime.now().timestamp() - start_frame)
frigate_frame = f"debug/frames/frigate-{frame_counter}.jpg" default_frame = f"debug/frames/default-{frame_counter}.jpg"
improved_frame = f"debug/frames/improved-{frame_counter}.jpg" compare_frame = f"debug/frames/compare-{frame_counter}.jpg"
if os.path.exists(frigate_frame) and os.path.exists(improved_frame): if os.path.exists(default_frame) and os.path.exists(compare_frame):
image_row_1 = cv2.hconcat( images = [
[ cv2.imread(default_frame),
cv2.imread(frigate_frame), cv2.imread(compare_frame),
cv2.imread(improved_frame), ]
]
)
image_row_2 = cv2.resize(
frame,
dsize=(
frigate_motion_detector.motion_frame_size[1] * 2,
frigate_motion_detector.motion_frame_size[0] * 2,
),
interpolation=cv2.INTER_LINEAR,
)
cv2.imwrite( cv2.imwrite(
f"debug/frames/all-{frame_counter}.jpg", f"debug/frames/all-{frame_counter}.jpg",
cv2.vconcat([image_row_1, image_row_2]), cv2.vconcat(images)
if frame_shape[0] > frame_shape[1]
else cv2.hconcat(images),
) )
os.unlink(frigate_frame) os.unlink(default_frame)
os.unlink(improved_frame) os.unlink(compare_frame)
frame_counter += 1 frame_counter += 1
ret, frame = cap.read() ret, frame = cap.read()
cap.release() cap.release()
print("Frigate Motion Detector")
print(f"Average frame processing time: {mean(frame_times['frigate'])*1000:.2f}ms")
print("Improved Motion Detector")
print(f"Average frame processing time: {mean(frame_times['improved'])*1000:.2f}ms")

View File

@ -230,7 +230,7 @@ detect:
# especially when using separate streams for detect and record. # especially when using separate streams for detect and record.
# Use this setting to make the timeline bounding boxes more closely align # Use this setting to make the timeline bounding boxes more closely align
# with the recording. The value can be positive or negative. # with the recording. The value can be positive or negative.
# TIP: Imagine there is an event clip with a person walking from left to right. # TIP: Imagine there is an event clip with a person walking from left to right.
# If the event timeline bounding box is consistently to the left of the person # If the event timeline bounding box is consistently to the left of the person
# then the value should be decreased. Similarly, if a person is walking from # then the value should be decreased. Similarly, if a person is walking from
# left to right and the bounding box is consistently ahead of the person # left to right and the bounding box is consistently ahead of the person
@ -275,7 +275,7 @@ motion:
# Optional: The threshold passed to cv2.threshold to determine if a pixel is different enough to be counted as motion. (default: shown below) # Optional: The threshold passed to cv2.threshold to determine if a pixel is different enough to be counted as motion. (default: shown below)
# Increasing this value will make motion detection less sensitive and decreasing it will make motion detection more sensitive. # Increasing this value will make motion detection less sensitive and decreasing it will make motion detection more sensitive.
# The value should be between 1 and 255. # The value should be between 1 and 255.
threshold: 40 threshold: 20
# Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection # Optional: The percentage of the image used to detect lightning or other substantial changes where motion detection
# needs to recalibrate. (default: shown below) # needs to recalibrate. (default: shown below)
# Increasing this value will make motion detection more likely to consider lightning or ir mode changes as valid motion. # Increasing this value will make motion detection more likely to consider lightning or ir mode changes as valid motion.
@ -286,19 +286,19 @@ motion:
# Increasing this value will prevent smaller areas of motion from being detected. Decreasing will # Increasing this value will prevent smaller areas of motion from being detected. Decreasing will
# make motion detection more sensitive to smaller moving objects. # make motion detection more sensitive to smaller moving objects.
# As a rule of thumb: # As a rule of thumb:
# - 15 - high sensitivity # - 10 - high sensitivity
# - 30 - medium sensitivity # - 30 - medium sensitivity
# - 50 - low sensitivity # - 50 - low sensitivity
contour_area: 15 contour_area: 10
# Optional: Alpha value passed to cv2.accumulateWeighted when averaging frames to determine the background (default: shown below) # Optional: Alpha value passed to cv2.accumulateWeighted when averaging frames to determine the background (default: shown below)
# Higher values mean the current frame impacts the average a lot, and a new object will be averaged into the background faster. # Higher values mean the current frame impacts the average a lot, and a new object will be averaged into the background faster.
# Low values will cause things like moving shadows to be detected as motion for longer. # Low values will cause things like moving shadows to be detected as motion for longer.
# https://www.geeksforgeeks.org/background-subtraction-in-an-image-using-concept-of-running-average/ # https://www.geeksforgeeks.org/background-subtraction-in-an-image-using-concept-of-running-average/
frame_alpha: 0.02 frame_alpha: 0.01
# Optional: Height of the resized motion frame (default: 50) # Optional: Height of the resized motion frame (default: 50)
# Higher values will result in more granular motion detection at the expense of higher CPU usage. # Higher values will result in more granular motion detection at the expense of higher CPU usage.
# Lower values result in less CPU, but small changes may not register as motion. # Lower values result in less CPU, but small changes may not register as motion.
frame_height: 50 frame_height: 100
# Optional: motion mask # Optional: motion mask
# NOTE: see docs for more detailed info on creating masks # NOTE: see docs for more detailed info on creating masks
mask: 0,900,1080,900,1080,1920,0,1920 mask: 0,900,1080,900,1080,1920,0,1920

View File

@ -187,7 +187,7 @@ class RecordConfig(FrigateBaseModel):
class MotionConfig(FrigateBaseModel): class MotionConfig(FrigateBaseModel):
threshold: int = Field( threshold: int = Field(
default=30, default=20,
title="Motion detection threshold (1-255).", title="Motion detection threshold (1-255).",
ge=1, ge=1,
le=255, le=255,
@ -198,7 +198,7 @@ class MotionConfig(FrigateBaseModel):
improve_contrast: bool = Field(default=True, title="Improve Contrast") improve_contrast: bool = Field(default=True, title="Improve Contrast")
contour_area: Optional[int] = Field(default=10, title="Contour Area") contour_area: Optional[int] = Field(default=10, title="Contour Area")
delta_alpha: float = Field(default=0.2, title="Delta Alpha") delta_alpha: float = Field(default=0.2, title="Delta Alpha")
frame_alpha: float = Field(default=0.02, title="Frame Alpha") frame_alpha: float = Field(default=0.01, title="Frame Alpha")
frame_height: Optional[int] = Field(default=100, title="Frame Height") frame_height: Optional[int] = Field(default=100, title="Frame Height")
mask: Union[str, List[str]] = Field( mask: Union[str, List[str]] = Field(
default="", title="Coordinates polygon for the motion mask." default="", title="Coordinates polygon for the motion mask."

View File

@ -15,7 +15,11 @@ class ImprovedMotionDetector(MotionDetector):
improve_contrast, improve_contrast,
threshold, threshold,
contour_area, contour_area,
clipLimit=2.0,
tileGridSize=(2, 2),
name="improved",
): ):
self.name = name
self.config = config self.config = config
self.frame_shape = frame_shape self.frame_shape = frame_shape
self.resize_factor = frame_shape[0] / config.frame_height self.resize_factor = frame_shape[0] / config.frame_height
@ -38,7 +42,7 @@ class ImprovedMotionDetector(MotionDetector):
self.improve_contrast = improve_contrast self.improve_contrast = improve_contrast
self.threshold = threshold self.threshold = threshold
self.contour_area = contour_area self.contour_area = contour_area
self.clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) self.clahe = cv2.createCLAHE(clipLimit=clipLimit, tileGridSize=tileGridSize)
def detect(self, frame): def detect(self, frame):
motion_boxes = [] motion_boxes = []
@ -52,12 +56,21 @@ class ImprovedMotionDetector(MotionDetector):
interpolation=cv2.INTER_LINEAR, interpolation=cv2.INTER_LINEAR,
) )
if self.save_images:
resized_saved = resized_frame.copy()
resized_frame = cv2.GaussianBlur(resized_frame, (3, 3), cv2.BORDER_DEFAULT) resized_frame = cv2.GaussianBlur(resized_frame, (3, 3), cv2.BORDER_DEFAULT)
if self.save_images:
blurred_saved = resized_frame.copy()
# Improve contrast # Improve contrast
if self.improve_contrast.value: if self.improve_contrast.value:
resized_frame = self.clahe.apply(resized_frame) resized_frame = self.clahe.apply(resized_frame)
if self.save_images:
contrasted_saved = resized_frame.copy()
# mask frame # mask frame
resized_frame[self.mask] = [255] resized_frame[self.mask] = [255]
@ -119,8 +132,19 @@ class ImprovedMotionDetector(MotionDetector):
(0, 0, 255), (0, 0, 255),
2, 2,
) )
frames = [
cv2.cvtColor(resized_saved, cv2.COLOR_GRAY2BGR),
cv2.cvtColor(blurred_saved, cv2.COLOR_GRAY2BGR),
cv2.cvtColor(contrasted_saved, cv2.COLOR_GRAY2BGR),
cv2.cvtColor(frameDelta, cv2.COLOR_GRAY2BGR),
cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR),
thresh_dilated,
]
cv2.imwrite( cv2.imwrite(
f"debug/frames/improved-{self.frame_counter}.jpg", thresh_dilated f"debug/frames/{self.name}-{self.frame_counter}.jpg",
cv2.hconcat(frames)
if self.frame_shape[0] > self.frame_shape[1]
else cv2.vconcat(frames),
) )
if len(motion_boxes) > 0: if len(motion_boxes) > 0: