mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Load labels dynamically for event filters (#6896)
* Load labels dynamically to include custom events and audio, do not include attribute labels * Formatting * Fix sorting * Also filter tracked object list on camera page * isort * Don't fail before load
This commit is contained in:
parent
3d40ed5d47
commit
ece070fee1
@ -12,6 +12,16 @@ PLUS_ENV_VAR = "PLUS_API_KEY"
|
|||||||
PLUS_API_HOST = "https://api.frigate.video"
|
PLUS_API_HOST = "https://api.frigate.video"
|
||||||
BTBN_PATH = "/usr/lib/btbn-ffmpeg"
|
BTBN_PATH = "/usr/lib/btbn-ffmpeg"
|
||||||
|
|
||||||
|
# Attributes
|
||||||
|
|
||||||
|
ATTRIBUTE_LABEL_MAP = {
|
||||||
|
"person": ["face", "amazon"],
|
||||||
|
"car": ["ups", "fedex", "amazon", "license_plate"],
|
||||||
|
}
|
||||||
|
ALL_ATTRIBUTE_LABELS = [
|
||||||
|
item for sublist in ATTRIBUTE_LABEL_MAP.values() for item in sublist
|
||||||
|
]
|
||||||
|
|
||||||
# Regex Consts
|
# Regex Consts
|
||||||
|
|
||||||
REGEX_CAMERA_NAME = r"^[a-zA-Z0-9_-]+$"
|
REGEX_CAMERA_NAME = r"^[a-zA-Z0-9_-]+$"
|
||||||
|
@ -410,6 +410,24 @@ def set_sub_label(id):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/labels")
|
||||||
|
def get_labels():
|
||||||
|
camera = request.args.get("camera", type=str, default="")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if camera:
|
||||||
|
events = Event.select(Event.label).where(Event.camera == camera).distinct()
|
||||||
|
else:
|
||||||
|
events = Event.select(Event.label).distinct()
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify(
|
||||||
|
{"success": False, "message": f"Failed to get labels: {e}"}, "404"
|
||||||
|
)
|
||||||
|
|
||||||
|
labels = sorted([e.label for e in events])
|
||||||
|
return jsonify(labels)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/sub_labels")
|
@bp.route("/sub_labels")
|
||||||
def get_sub_labels():
|
def get_sub_labels():
|
||||||
split_joined = request.args.get("split_joined", type=int)
|
split_joined = request.args.get("split_joined", type=int)
|
||||||
|
@ -15,7 +15,7 @@ import numpy as np
|
|||||||
from setproctitle import setproctitle
|
from setproctitle import setproctitle
|
||||||
|
|
||||||
from frigate.config import CameraConfig, DetectConfig
|
from frigate.config import CameraConfig, DetectConfig
|
||||||
from frigate.const import CACHE_DIR
|
from frigate.const import ALL_ATTRIBUTE_LABELS, ATTRIBUTE_LABEL_MAP, CACHE_DIR
|
||||||
from frigate.detectors.detector_config import PixelFormatEnum
|
from frigate.detectors.detector_config import PixelFormatEnum
|
||||||
from frigate.log import LogPipe
|
from frigate.log import LogPipe
|
||||||
from frigate.motion import MotionDetector
|
from frigate.motion import MotionDetector
|
||||||
@ -723,14 +723,6 @@ def process_frames(
|
|||||||
stop_event,
|
stop_event,
|
||||||
exit_on_empty: bool = False,
|
exit_on_empty: bool = False,
|
||||||
):
|
):
|
||||||
# attribute labels are not tracked and are not assigned regions
|
|
||||||
attribute_label_map = {
|
|
||||||
"person": ["face", "amazon"],
|
|
||||||
"car": ["ups", "fedex", "amazon", "license_plate"],
|
|
||||||
}
|
|
||||||
all_attribute_labels = [
|
|
||||||
item for sublist in attribute_label_map.values() for item in sublist
|
|
||||||
]
|
|
||||||
fps = process_info["process_fps"]
|
fps = process_info["process_fps"]
|
||||||
detection_fps = process_info["detection_fps"]
|
detection_fps = process_info["detection_fps"]
|
||||||
current_frame_time = process_info["detection_frame"]
|
current_frame_time = process_info["detection_frame"]
|
||||||
@ -906,7 +898,7 @@ def process_frames(
|
|||||||
tracked_detections = [
|
tracked_detections = [
|
||||||
d
|
d
|
||||||
for d in consolidated_detections
|
for d in consolidated_detections
|
||||||
if d[0] not in all_attribute_labels
|
if d[0] not in ALL_ATTRIBUTE_LABELS
|
||||||
]
|
]
|
||||||
# now that we have refined our detections, we need to track objects
|
# now that we have refined our detections, we need to track objects
|
||||||
object_tracker.match_and_update(frame_time, tracked_detections)
|
object_tracker.match_and_update(frame_time, tracked_detections)
|
||||||
@ -916,7 +908,7 @@ def process_frames(
|
|||||||
|
|
||||||
# group the attribute detections based on what label they apply to
|
# group the attribute detections based on what label they apply to
|
||||||
attribute_detections = {}
|
attribute_detections = {}
|
||||||
for label, attribute_labels in attribute_label_map.items():
|
for label, attribute_labels in ATTRIBUTE_LABEL_MAP.items():
|
||||||
attribute_detections[label] = [
|
attribute_detections[label] = [
|
||||||
d for d in consolidated_detections if d[0] in attribute_labels
|
d for d in consolidated_detections if d[0] in attribute_labels
|
||||||
]
|
]
|
||||||
|
@ -22,6 +22,7 @@ const emptyObject = Object.freeze({});
|
|||||||
|
|
||||||
export default function Camera({ camera }) {
|
export default function Camera({ camera }) {
|
||||||
const { data: config } = useSWR('config');
|
const { data: config } = useSWR('config');
|
||||||
|
const { data: trackedLabels } = useSWR(['labels', { camera }]);
|
||||||
const apiHost = useApiHost();
|
const apiHost = useApiHost();
|
||||||
const [showSettings, setShowSettings] = useState(false);
|
const [showSettings, setShowSettings] = useState(false);
|
||||||
const [viewMode, setViewMode] = useState('live');
|
const [viewMode, setViewMode] = useState('live');
|
||||||
@ -121,7 +122,9 @@ export default function Camera({ camera }) {
|
|||||||
<div className="max-w-5xl">
|
<div className="max-w-5xl">
|
||||||
<video-stream
|
<video-stream
|
||||||
mode="mse"
|
mode="mse"
|
||||||
src={new URL(`${baseUrl.replace(/^http/, 'ws')}live/webrtc/api/ws?src=${cameraConfig.live.stream_name}`)}
|
src={
|
||||||
|
new URL(`${baseUrl.replace(/^http/, 'ws')}live/webrtc/api/ws?src=${cameraConfig.live.stream_name}`)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
@ -203,7 +206,7 @@ export default function Camera({ camera }) {
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Heading size="sm">Tracked objects</Heading>
|
<Heading size="sm">Tracked objects</Heading>
|
||||||
<div className="flex flex-wrap justify-start">
|
<div className="flex flex-wrap justify-start">
|
||||||
{cameraConfig.objects.track.map((objectType) => (
|
{(trackedLabels || []).map((objectType) => (
|
||||||
<Card
|
<Card
|
||||||
className="mb-4 mr-4"
|
className="mb-4 mr-4"
|
||||||
key={objectType}
|
key={objectType}
|
||||||
|
@ -106,6 +106,7 @@ export default function Events({ path, ...props }) {
|
|||||||
|
|
||||||
const { data: config } = useSWR('config');
|
const { data: config } = useSWR('config');
|
||||||
|
|
||||||
|
const { data: allLabels } = useSWR(['labels']);
|
||||||
const { data: allSubLabels } = useSWR(['sub_labels', { split_joined: 1 }]);
|
const { data: allSubLabels } = useSWR(['sub_labels', { split_joined: 1 }]);
|
||||||
|
|
||||||
const filterValues = useMemo(
|
const filterValues = useMemo(
|
||||||
@ -120,15 +121,10 @@ export default function Events({ path, ...props }) {
|
|||||||
.filter((value, i, self) => self.indexOf(value) === i),
|
.filter((value, i, self) => self.indexOf(value) === i),
|
||||||
'None',
|
'None',
|
||||||
],
|
],
|
||||||
labels: Object.values(config?.cameras || {})
|
labels: Object.values(allLabels || {}),
|
||||||
.reduce((memo, camera) => {
|
|
||||||
memo = memo.concat(camera?.objects?.track || []);
|
|
||||||
return memo;
|
|
||||||
}, config?.objects?.track || [])
|
|
||||||
.filter((value, i, self) => self.indexOf(value) === i),
|
|
||||||
sub_labels: (allSubLabels || []).length > 0 ? [...Object.values(allSubLabels), 'None'] : [],
|
sub_labels: (allSubLabels || []).length > 0 ? [...Object.values(allSubLabels), 'None'] : [],
|
||||||
}),
|
}),
|
||||||
[config, allSubLabels]
|
[config, allLabels, allSubLabels]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSave = async (e, eventId, save) => {
|
const onSave = async (e, eventId, save) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user