7
7
Fork
You've already forked TF-CCTV
3

Add some documentation on using models in Frigate #102

Merged
Curid merged 2 commits from csanders/TF-CCTV:frigate into master 2025年07月03日 21:27:20 +02:00
Contributor
Copy link
No description provided.
Owner
Copy link

Since we're moving away from mobiledet models it's important that the Frigate documentation includes instructions for how to patch Frigate so it can use our new yolo models.

frigate 0.14.1

diff --git a/frigate/detectors/plugins/cpu_tfl.py b/frigate/detectors/plugins/cpu_tfl.py
index 8a54363e..b7c6343a 100644
--- a/frigate/detectors/plugins/cpu_tfl.py
+++ b/frigate/detectors/plugins/cpu_tfl.py
@@ -38,9 +38,58 @@ class CpuTfl(DetectionApi):
 self.tensor_output_details = self.interpreter.get_output_details()
 
 def detect_raw(self, tensor_input):
+ scale, zero_point = self.tensor_input_details[0]["quantization"]
+ tensor_input = (
+ (tensor_input - scale * zero_point * 255) * (1.0 / (scale * 255))
+ ).astype(self.tensor_input_details[0]["dtype"])
+
 self.interpreter.set_tensor(self.tensor_input_details[0]["index"], tensor_input)
 self.interpreter.invoke()
 
+ scale, zero_point = self.tensor_output_details[0]["quantization"]
+ tensor_output = self.interpreter.get_tensor(
+ self.tensor_output_details[0]["index"]
+ )
+ tensor_output = (tensor_output.astype(np.float32) - zero_point) * scale
+ model_input_shape = self.tensor_input_details[0]["shape"]
+
+ tensor_output[:, [0, 2]] *= model_input_shape[2]
+ tensor_output[:, [1, 3]] *= model_input_shape[1]
+ model_box_count = tensor_output.shape[2]
+ probs = tensor_output[0, 4:, :]
+ all_ids = np.argmax(probs, axis=0)
+ all_confidences = probs.T[np.arange(model_box_count), all_ids]
+ all_boxes = tensor_output[0, 0:4, :].T
+ mask = all_confidences > 0.5
+ class_ids = all_ids[mask]
+ confidences = all_confidences[mask]
+ cx, cy, w, h = all_boxes[mask].T
+
+ if model_input_shape[3] == 3:
+ scale_y, scale_x = 1 / model_input_shape[1], 1 / model_input_shape[2]
+ else:
+ scale_y, scale_x = 1 / model_input_shape[2], 1 / model_input_shape[3]
+ detections = np.stack(
+ (
+ class_ids,
+ confidences,
+ scale_y * (cy - h / 2),
+ scale_x * (cx - w / 2),
+ scale_y * (cy + h / 2),
+ scale_x * (cx + w / 2),
+ ),
+ axis=1,
+ )
+ if detections.shape[0] > 20:
+ boxes = np.stack((cx - w / 2, cy - h / 2, w, h), axis=1)
+ indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.5)
+ detections = detections[indexes]
+ if detections.shape[0] > 20:
+ detections = detections[np.argpartition(detections[:, 1], -20)[-20:]]
+ detections = detections.copy()
+ detections.resize((20, 6))
+ return detections
+
 boxes = self.interpreter.tensor(self.tensor_output_details[0]["index"])()[0]
 class_ids = self.interpreter.tensor(self.tensor_output_details[1]["index"])()[0]
 scores = self.interpreter.tensor(self.tensor_output_details[2]["index"])()[0]
diff --git a/frigate/detectors/plugins/edgetpu_tfl.py b/frigate/detectors/plugins/edgetpu_tfl.py
index c320bd89..ee3678e2 100644
--- a/frigate/detectors/plugins/edgetpu_tfl.py
+++ b/frigate/detectors/plugins/edgetpu_tfl.py
@@ -57,9 +57,58 @@ class EdgeTpuTfl(DetectionApi):
 self.model_type = detector_config.model.model_type
 
 def detect_raw(self, tensor_input):
+ scale, zero_point = self.tensor_input_details[0]["quantization"]
+ tensor_input = (
+ (tensor_input - scale * zero_point * 255) * (1.0 / (scale * 255))
+ ).astype(self.tensor_input_details[0]["dtype"])
+
 self.interpreter.set_tensor(self.tensor_input_details[0]["index"], tensor_input)
 self.interpreter.invoke()
 
+ scale, zero_point = self.tensor_output_details[0]["quantization"]
+ tensor_output = self.interpreter.get_tensor(
+ self.tensor_output_details[0]["index"]
+ )
+ tensor_output = (tensor_output.astype(np.float32) - zero_point) * scale
+ model_input_shape = self.tensor_input_details[0]["shape"]
+
+ tensor_output[:, [0, 2]] *= model_input_shape[2]
+ tensor_output[:, [1, 3]] *= model_input_shape[1]
+ model_box_count = tensor_output.shape[2]
+ probs = tensor_output[0, 4:, :]
+ all_ids = np.argmax(probs, axis=0)
+ all_confidences = probs.T[np.arange(model_box_count), all_ids]
+ all_boxes = tensor_output[0, 0:4, :].T
+ mask = all_confidences > 0.5
+ class_ids = all_ids[mask]
+ confidences = all_confidences[mask]
+ cx, cy, w, h = all_boxes[mask].T
+
+ if model_input_shape[3] == 3:
+ scale_y, scale_x = 1 / model_input_shape[1], 1 / model_input_shape[2]
+ else:
+ scale_y, scale_x = 1 / model_input_shape[2], 1 / model_input_shape[3]
+ detections = np.stack(
+ (
+ class_ids,
+ confidences,
+ scale_y * (cy - h / 2),
+ scale_x * (cx - w / 2),
+ scale_y * (cy + h / 2),
+ scale_x * (cx + w / 2),
+ ),
+ axis=1,
+ )
+ if detections.shape[0] > 20:
+ boxes = np.stack((cx - w / 2, cy - h / 2, w, h), axis=1)
+ indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.5)
+ detections = detections[indexes]
+ if detections.shape[0] > 20:
+ detections = detections[np.argpartition(detections[:, 1], -20)[-20:]]
+ detections = detections.copy()
+ detections.resize((20, 6))
+ return detections
+
 boxes = self.interpreter.tensor(self.tensor_output_details[0]["index"])()[0]
 class_ids = self.interpreter.tensor(self.tensor_output_details[1]["index"])()[0]
 scores = self.interpreter.tensor(self.tensor_output_details[2]["index"])()[0]
Since we're moving away from mobiledet models it's important that the Frigate documentation includes instructions for how to patch Frigate so it can use our new yolo models. frigate 0.14.1 ``` diff diff --git a/frigate/detectors/plugins/cpu_tfl.py b/frigate/detectors/plugins/cpu_tfl.py index 8a54363e..b7c6343a 100644 --- a/frigate/detectors/plugins/cpu_tfl.py +++ b/frigate/detectors/plugins/cpu_tfl.py @@ -38,9 +38,58 @@ class CpuTfl(DetectionApi): self.tensor_output_details = self.interpreter.get_output_details() def detect_raw(self, tensor_input): + scale, zero_point = self.tensor_input_details[0]["quantization"] + tensor_input = ( + (tensor_input - scale * zero_point * 255) * (1.0 / (scale * 255)) + ).astype(self.tensor_input_details[0]["dtype"]) + self.interpreter.set_tensor(self.tensor_input_details[0]["index"], tensor_input) self.interpreter.invoke() + scale, zero_point = self.tensor_output_details[0]["quantization"] + tensor_output = self.interpreter.get_tensor( + self.tensor_output_details[0]["index"] + ) + tensor_output = (tensor_output.astype(np.float32) - zero_point) * scale + model_input_shape = self.tensor_input_details[0]["shape"] + + tensor_output[:, [0, 2]] *= model_input_shape[2] + tensor_output[:, [1, 3]] *= model_input_shape[1] + model_box_count = tensor_output.shape[2] + probs = tensor_output[0, 4:, :] + all_ids = np.argmax(probs, axis=0) + all_confidences = probs.T[np.arange(model_box_count), all_ids] + all_boxes = tensor_output[0, 0:4, :].T + mask = all_confidences > 0.5 + class_ids = all_ids[mask] + confidences = all_confidences[mask] + cx, cy, w, h = all_boxes[mask].T + + if model_input_shape[3] == 3: + scale_y, scale_x = 1 / model_input_shape[1], 1 / model_input_shape[2] + else: + scale_y, scale_x = 1 / model_input_shape[2], 1 / model_input_shape[3] + detections = np.stack( + ( + class_ids, + confidences, + scale_y * (cy - h / 2), + scale_x * (cx - w / 2), + scale_y * (cy + h / 2), + scale_x * (cx + w / 2), + ), + axis=1, + ) + if detections.shape[0] > 20: + boxes = np.stack((cx - w / 2, cy - h / 2, w, h), axis=1) + indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.5) + detections = detections[indexes] + if detections.shape[0] > 20: + detections = detections[np.argpartition(detections[:, 1], -20)[-20:]] + detections = detections.copy() + detections.resize((20, 6)) + return detections + boxes = self.interpreter.tensor(self.tensor_output_details[0]["index"])()[0] class_ids = self.interpreter.tensor(self.tensor_output_details[1]["index"])()[0] scores = self.interpreter.tensor(self.tensor_output_details[2]["index"])()[0] diff --git a/frigate/detectors/plugins/edgetpu_tfl.py b/frigate/detectors/plugins/edgetpu_tfl.py index c320bd89..ee3678e2 100644 --- a/frigate/detectors/plugins/edgetpu_tfl.py +++ b/frigate/detectors/plugins/edgetpu_tfl.py @@ -57,9 +57,58 @@ class EdgeTpuTfl(DetectionApi): self.model_type = detector_config.model.model_type def detect_raw(self, tensor_input): + scale, zero_point = self.tensor_input_details[0]["quantization"] + tensor_input = ( + (tensor_input - scale * zero_point * 255) * (1.0 / (scale * 255)) + ).astype(self.tensor_input_details[0]["dtype"]) + self.interpreter.set_tensor(self.tensor_input_details[0]["index"], tensor_input) self.interpreter.invoke() + scale, zero_point = self.tensor_output_details[0]["quantization"] + tensor_output = self.interpreter.get_tensor( + self.tensor_output_details[0]["index"] + ) + tensor_output = (tensor_output.astype(np.float32) - zero_point) * scale + model_input_shape = self.tensor_input_details[0]["shape"] + + tensor_output[:, [0, 2]] *= model_input_shape[2] + tensor_output[:, [1, 3]] *= model_input_shape[1] + model_box_count = tensor_output.shape[2] + probs = tensor_output[0, 4:, :] + all_ids = np.argmax(probs, axis=0) + all_confidences = probs.T[np.arange(model_box_count), all_ids] + all_boxes = tensor_output[0, 0:4, :].T + mask = all_confidences > 0.5 + class_ids = all_ids[mask] + confidences = all_confidences[mask] + cx, cy, w, h = all_boxes[mask].T + + if model_input_shape[3] == 3: + scale_y, scale_x = 1 / model_input_shape[1], 1 / model_input_shape[2] + else: + scale_y, scale_x = 1 / model_input_shape[2], 1 / model_input_shape[3] + detections = np.stack( + ( + class_ids, + confidences, + scale_y * (cy - h / 2), + scale_x * (cx - w / 2), + scale_y * (cy + h / 2), + scale_x * (cx + w / 2), + ), + axis=1, + ) + if detections.shape[0] > 20: + boxes = np.stack((cx - w / 2, cy - h / 2, w, h), axis=1) + indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.5) + detections = detections[indexes] + if detections.shape[0] > 20: + detections = detections[np.argpartition(detections[:, 1], -20)[-20:]] + detections = detections.copy() + detections.resize((20, 6)) + return detections + boxes = self.interpreter.tensor(self.tensor_output_details[0]["index"])()[0] class_ids = self.interpreter.tensor(self.tensor_output_details[1]["index"])()[0] scores = self.interpreter.tensor(self.tensor_output_details[2]["index"])()[0] ```
Owner
Copy link

@harryqt would you like to review the instructions before we merge them? rendered

@harryqt would you like to review the instructions before we merge them? [rendered](https://codeberg.org/Curid/TF-CCTV/src/commit/8407a3a114084751146397eeba02e9b99212c861/docs/frigate.md)
First-time contributor
Copy link

Everything is good, except import cv2 statement is missing.

Everything is good, except `import cv2` statement is missing.
Author
Contributor
Copy link

It was missing in the original but it's in the diff: 8407a3a114/docs/frigate-yolo-support-v0.15.1.diff

Lines 8 and 78, unless you're talking about somewhere else?

It was missing in the original but it's in the diff: https://codeberg.org/Curid/TF-CCTV/src/commit/8407a3a114084751146397eeba02e9b99212c861/docs/frigate-yolo-support-v0.15.1.diff Lines 8 and 78, unless you're talking about somewhere else?
First-time contributor
Copy link

All good 👍

All good 👍
Sign in to join this conversation.
No reviewers
Labels
Clear labels
No items
No labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Curid/TF-CCTV!102
Reference in a new issue
Curid/TF-CCTV
No description provided.
Delete branch "csanders/TF-CCTV:frigate"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?