move width/height/fps under detect and make required

also resizes the output from ffmpeg to specified size
This commit is contained in:
Blake Blackshear 2021-08-14 14:18:35 -05:00
parent 0ccf543ec1
commit f3a1c1de0a
7 changed files with 175 additions and 95 deletions

View File

@ -32,9 +32,10 @@ cameras:
roles:
- clips
- record
width: 1280
height: 720
fps: 5
detect:
width: 1280
height: 720
fps: 5
```
## Masks & Zones
@ -280,14 +281,20 @@ cameras:
# Optional: camera specific output args (default: inherit)
output_args:
# Required: width of the frame for the input with the detect role
width: 1280
# Required: height of the frame for the input with the detect role
height: 720
# Optional: desired fps for your camera for the input with the detect role
# NOTE: Recommended value of 5. Ideally, try and reduce your FPS on the camera.
# Frigate will attempt to autodetect if not specified.
fps: 5
# Required: Camera level detect settings
detect:
# Required: width of the frame for the input with the detect role
width: 1280
# Required: height of the frame for the input with the detect role
height: 720
# Required: desired fps for your camera for the input with the detect role
# NOTE: Recommended value of 5. Ideally, try and reduce your FPS on the camera.
fps: 5
# Optional: enables detection for the camera (default: True)
# This value can be set via MQTT and will be updated in startup based on retained value
enabled: True
# Optional: Number of frames without a detection before frigate considers an object to be gone. (default: 5x the frame rate)
max_disappeared: 25
# Optional: camera level motion config
motion:
@ -319,14 +326,6 @@ cameras:
max_area: 100000
threshold: 0.7
# Optional: Camera level detect settings
detect:
# Optional: enables detection for the camera (default: True)
# This value can be set via MQTT and will be updated in startup based on retained value
enabled: True
# Optional: Number of frames without a detection before frigate considers an object to be gone. (default: 5x the frame rate)
max_disappeared: 25
# Optional: save clips configuration
clips:
# Required: enables clips for the camera (default: shown below)

View File

@ -20,9 +20,10 @@ cameras:
roles:
- detect
- rtmp
width: 1280
height: 720
fps: 5
detect:
width: 1280
height: 720
fps: 5
```
## Required
@ -76,9 +77,10 @@ cameras:
roles:
- detect
- rtmp
width: 1280
height: 720
fps: 5
detect:
width: 1280
height: 720
fps: 5
```
## Optional

View File

@ -151,6 +151,9 @@ class RuntimeMotionConfig(MotionConfig):
class DetectConfig(BaseModel):
height: int = Field(title="Height of the stream for the detect role.")
width: int = Field(title="Width of the stream for the detect role.")
fps: int = Field(title="Number of frames per second to process through detection.")
enabled: bool = Field(default=True, title="Detection Enabled.")
max_disappeared: Optional[int] = Field(
title="Maximum number of frames the object can dissapear before detection ends."
@ -435,11 +438,6 @@ class CameraLiveConfig(BaseModel):
class CameraConfig(BaseModel):
name: Optional[str] = Field(title="Camera name.")
ffmpeg: CameraFfmpegConfig = Field(title="FFmpeg configuration for the camera.")
height: int = Field(title="Height of the stream for the detect role.")
width: int = Field(title="Width of the stream for the detect role.")
fps: Optional[int] = Field(
title="Number of frames per second to process through Frigate."
)
best_image_timeout: int = Field(
default=60,
title="How long to wait for the image with the highest confidence score.",
@ -465,7 +463,7 @@ class CameraConfig(BaseModel):
default_factory=ObjectConfig, title="Object configuration."
)
motion: Optional[MotionConfig] = Field(title="Motion detection configuration.")
detect: Optional[DetectConfig] = Field(title="Object detection configuration.")
detect: DetectConfig = Field(title="Object detection configuration.")
timestamp_style: TimestampStyleConfig = Field(
default_factory=TimestampStyleConfig, title="Timestamp style configuration."
)
@ -483,11 +481,11 @@ class CameraConfig(BaseModel):
@property
def frame_shape(self) -> Tuple[int, int]:
return self.height, self.width
return self.detect.height, self.detect.width
@property
def frame_shape_yuv(self) -> Tuple[int, int]:
return self.height * 3 // 2, self.width
return self.detect.height * 3 // 2, self.detect.width
@property
def ffmpeg_cmds(self) -> List[Dict[str, List[str]]]:
@ -508,9 +506,17 @@ class CameraConfig(BaseModel):
if isinstance(self.ffmpeg.output_args.detect, list)
else self.ffmpeg.output_args.detect.split(" ")
)
ffmpeg_output_args = detect_args + ffmpeg_output_args + ["pipe:"]
if self.fps:
ffmpeg_output_args = ["-r", str(self.fps)] + ffmpeg_output_args
ffmpeg_output_args = (
[
"-r",
str(self.detect.fps),
"-s",
f"{self.detect.width}x{self.detect.height}",
]
+ detect_args
+ ffmpeg_output_args
+ ["pipe:"]
)
if "rtmp" in ffmpeg_input.roles and self.rtmp.enabled:
rtmp_args = (
self.ffmpeg.output_args.rtmp
@ -735,12 +741,9 @@ class FrigateConfig(BaseModel):
)
# Default detect configuration
max_disappeared = (camera_config.fps or 5) * 5
if camera_config.detect:
if camera_config.detect.max_disappeared is None:
camera_config.detect.max_disappeared = max_disappeared
else:
camera_config.detect = DetectConfig(max_disappeared=max_disappeared)
max_disappeared = camera_config.detect.fps * 5
if camera_config.detect.max_disappeared is None:
camera_config.detect.max_disappeared = max_disappeared
# Default live configuration
if camera_config.live is None:

View File

@ -18,8 +18,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -42,8 +45,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -60,8 +66,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -82,8 +91,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
"objects": {"track": ["cat"]},
}
},
@ -105,8 +117,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -130,8 +145,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -152,8 +170,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
"objects": {
"track": ["person", "dog"],
"filters": {"dog": {"threshold": 0.7}},
@ -179,8 +200,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
"objects": {
"mask": "0,0,1,1,0,1",
"filters": {"dog": {"mask": "1,1,1,1,1,1"}},
@ -210,8 +234,11 @@ class TestConfig(unittest.TestCase):
},
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -233,8 +260,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
"objects": {
"track": ["person", "dog"],
"filters": {"dog": {"threshold": 0.7}},
@ -260,8 +290,11 @@ class TestConfig(unittest.TestCase):
],
"input_args": ["-re"],
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
"objects": {
"track": ["person", "dog"],
"filters": {"dog": {"threshold": 0.7}},
@ -292,8 +325,11 @@ class TestConfig(unittest.TestCase):
],
"input_args": "test3",
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
"objects": {
"track": ["person", "dog"],
"filters": {"dog": {"threshold": 0.7}},
@ -321,8 +357,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -344,8 +383,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video2", "roles": ["detect"]},
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -362,8 +404,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
"zones": {"back": {"coordinates": "1,1,1,1,1,1"}},
}
},
@ -381,8 +426,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
"zones": {"test": {"coordinates": "1,1,1,1,1,1"}},
}
},
@ -408,8 +456,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/video", "roles": ["detect"]}
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
"clips": {"enabled": True},
}
},
@ -436,8 +487,11 @@ class TestConfig(unittest.TestCase):
{"path": "rtsp://10.0.0.1:554/record", "roles": ["record"]},
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -463,9 +517,12 @@ class TestConfig(unittest.TestCase):
},
]
},
"height": 1080,
"width": 1920,
"detect": {"enabled": True},
"detect": {
"enabled": True,
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -490,8 +547,11 @@ class TestConfig(unittest.TestCase):
},
]
},
"height": 480,
"width": 640,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -516,8 +576,11 @@ class TestConfig(unittest.TestCase):
},
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -543,8 +606,11 @@ class TestConfig(unittest.TestCase):
},
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -569,8 +635,11 @@ class TestConfig(unittest.TestCase):
},
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}
@ -596,8 +665,11 @@ class TestConfig(unittest.TestCase):
},
]
},
"height": 1080,
"width": 1920,
"detect": {
"height": 1080,
"width": 1920,
"fps": 5,
},
}
},
}

View File

@ -12,7 +12,8 @@ export default function CameraImage({ camera, onload, searchParams = '', stretch
const canvasRef = useRef(null);
const [{ width: availableWidth }] = useResizeObserver(containerRef);
const { name, width, height } = config.cameras[camera];
const { name } = config.cameras[camera];
const { width, height } = config.cameras[camera].detect;
const aspectRatio = width / height;
const scaledHeight = useMemo(() => {

View File

@ -7,7 +7,7 @@ import { render, screen } from '@testing-library/preact';
describe('CameraImage', () => {
beforeEach(() => {
jest.spyOn(Api, 'useConfig').mockImplementation(() => {
return { data: { cameras: { front: { name: 'front', width: 1280, height: 720 } } } };
return { data: { cameras: { front: { name: 'front', detect: { width: 1280, height: 720 } } } } };
});
jest.spyOn(Api, 'useApiHost').mockReturnValue('http://base-url.local:5000');
jest.spyOn(Hooks, 'useResizeObserver').mockImplementation(() => [{ width: 0 }]);

View File

@ -15,13 +15,16 @@ export default function CameraMasks({ camera, url }) {
const cameraConfig = config.cameras[camera];
const {
width,
height,
motion: { mask: motionMask },
objects: { filters: objectFilters },
zones,
} = cameraConfig;
const {
width,
height,
} = cameraConfig.detect;
const [{ width: scaledWidth }] = useResizeObserver(imageRef);
const imageScale = scaledWidth / width;