I was working on the following code, which was functioning correctly:
import gi
import gc
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GLib
import os
import argparse
import numpy as np
import setproctitle
import cv2
import time
from datetime import datetime
from collections import defaultdict
import math
import hailo
from hailo_common_funcs import get_numpy_from_buffer, disable_qos
from hailo_rpi_common import get_default_parser, QUEUE, get_caps_from_pad, GStreamerApp, app_callback_class
# Configuración global
CONFIDENCE_THRESHOLD = 0.75
VALID_CLASSES = {'car', 'bus', 'truck', 'person', 'bicycle', 'motorcycle'}
OUTPUT_DIR = "detected_images"
os.makedirs(OUTPUT_DIR, exist_ok=True)
class TrackedObject:
def __init__(self, label, position, timestamp, confidence):
self.label = label
self.position = position # (x, y)
self.last_seen = timestamp
self.confidence = confidence
self.trajectory = [position]
self.saved = False
def update(self, position, timestamp, confidence):
self.position = position
self.last_seen = timestamp
self.confidence = max(self.confidence, confidence)
self.trajectory.append(position)
if len(self.trajectory) > 10: # Mantener solo los últimos 10 puntos
self.trajectory.pop(0)
def get_velocity(self):
if len(self.trajectory) < 2:
return (0, 0)
pos1 = self.trajectory[-2]
pos2 = self.trajectory[-1]
return (pos2[0] - pos1[0], pos2[1] - pos1[1])
class UserAppCallbackClass(app_callback_class):
def __init__(self):
super().__init__()
self.tracked_objects = {}
self.object_count = defaultdict(int)
self.crossing_line = {
'start': (400, 600),
'end': (1000, 600),
'color': (0, 0, 255),
'thickness': 3
}
self.detection_zone = {
'top': 500,
'bottom': 700,
'min_size': 50,
'max_size': 400
}
self.cooldown_time = 2.0
self.use_frame = True
self.position_threshold = 50 # Distancia mínima para considerar objetos diferentes
self.cleanup_interval = 5.0 # Tiempo en segundos para limpiar objetos antiguos
def cleanup_old_objects(self, current_time):
objects_to_remove = []
for obj_id, tracked_obj in self.tracked_objects.items():
time_diff = (current_time - tracked_obj.last_seen).total_seconds()
if time_diff > self.cleanup_interval:
objects_to_remove.append(obj_id)
for obj_id in objects_to_remove:
del self.tracked_objects[obj_id]
def get_object_id(self, label, position, current_time):
# Buscar objeto existente cercano
for obj_id, tracked_obj in self.tracked_objects.items():
if tracked_obj.label != label:
continue
# Calcular distancia euclidiana
dx = tracked_obj.position[0] - position[0]
dy = tracked_obj.position[1] - position[1]
distance = math.sqrt(dx*dx + dy*dy)
time_diff = (current_time - tracked_obj.last_seen).total_seconds()
if distance < self.position_threshold and time_diff < self.cooldown_time:
return obj_id
# Si no se encuentra un objeto cercano, crear nuevo ID
return f"{label}_{position[0]}_{position[1]}_{current_time.strftime('%H%M%S%f')}"
def check_line_crossing(point, line_config, detection_zone):
if point[1] < detection_zone['top'] or point[1] > detection_zone['bottom']:
return False
v1x = line_config['end'][0] - line_config['start'][0]
v1y = line_config['end'][1] - line_config['start'][1]
v2x = point[0] - line_config['start'][0]
v2y = point[1] - line_config['start'][1]
return (v1x * v2y - v1y * v2x) < 0
def app_callback(pad, info, user_data):
buffer = info.get_buffer()
if buffer is None:
return Gst.PadProbeReturn.OK
format, width, height = get_caps_from_pad(pad)
if not all([format, width, height]):
return Gst.PadProbeReturn.OK
frame = get_numpy_from_buffer(buffer, format, width, height)
display_frame = frame.copy()
current_time = datetime.now()
# Limpiar objetos antiguos periódicamente
user_data.cleanup_old_objects(current_time)
try:
roi = hailo.get_roi_from_buffer(buffer)
detections = roi.get_objects_typed(hailo.HAILO_DETECTION)
for detection in detections:
confidence = detection.get_confidence()
label = detection.get_label()
if label in VALID_CLASSES and confidence >= CONFIDENCE_THRESHOLD:
bbox = detection.get_bbox()
x, y, w, h = [
int(v) for v in (
bbox.xmin() * width,
bbox.ymin() * height,
bbox.width() * width,
bbox.height() * height,
)
]
if w < user_data.detection_zone['min_size'] or h < user_data.detection_zone['min_size'] or \
w > user_data.detection_zone['max_size'] or h > user_data.detection_zone['max_size']:
continue
center_bottom = (int(x + w/2), int(y + h))
if check_line_crossing(center_bottom, user_data.crossing_line, user_data.detection_zone):
obj_id = user_data.get_object_id(label, center_bottom, current_time)
if obj_id not in user_data.tracked_objects:
user_data.tracked_objects[obj_id] = TrackedObject(label, center_bottom, current_time, confidence)
user_data.object_count[label] += 1
else:
tracked_obj = user_data.tracked_objects[obj_id]
tracked_obj.update(center_bottom, current_time, confidence)
if not tracked_obj.saved:
tracked_obj.saved = True
# Guardar imagen
if 0 <= x < width and 0 <= y < height:
margin = 100
x1 = max(0, x - margin)
y1 = max(0, y - margin)
x2 = min(width, x + w + margin)
y2 = min(height, y + h + margin)
cropped_image = frame[y1:y2, x1:x2].copy()
if cropped_image.shape[0] > 0 and cropped_image.shape[1] > 0:
if cropped_image.shape[0] < 480:
scale_factor = 480 / cropped_image.shape[0]
new_width = int(cropped_image.shape[1] * scale_factor)
cropped_image = cv2.resize(cropped_image, (new_width, 480))
# Añadir información al nombre del archivo
filename = os.path.join(
OUTPUT_DIR,
f"{label}_{confidence:.2f}_{current_time.strftime('%Y%m%d_%H%M%S')}.jpg"
)
cv2.imwrite(filename, cv2.cvtColor(cropped_image, cv2.COLOR_RGB2BGR))
# Dibujar información en el frame
cv2.circle(display_frame, center_bottom, 5, (0, 255, 0), -1)
cv2.putText(display_frame, f"{label} #{user_data.object_count[label]}",
(x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# Dibujar línea de cruce y zonas
cv2.line(display_frame,
user_data.crossing_line['start'],
user_data.crossing_line['end'],
user_data.crossing_line['color'],
user_data.crossing_line['thickness'])
cv2.line(display_frame,
(user_data.crossing_line['start'][0], user_data.detection_zone['top']),
(user_data.crossing_line['end'][0], user_data.detection_zone['top']),
(0, 255, 0), 1)
cv2.line(display_frame,
(user_data.crossing_line['start'][0], user_data.detection_zone['bottom']),
(user_data.crossing_line['end'][0], user_data.detection_zone['bottom']),
(0, 255, 0), 1)
user_data.set_frame(display_frame)
except Exception as e:
print(f"Error in app_callback: {e}")
return Gst.PadProbeReturn.OK
class GStreamerYOLOv8App(GStreamerApp):
def __init__(self, args, user_data):
super().__init__(args, user_data)
self.batch_size = 1
self.network_width = 640
self.network_height = 640
self.network_format = "RGB"
self.source_type = "rpi"
# Configuración de umbral
self.nms_score_threshold = 0.3
self.nms_iou_threshold = 0.45
self.thresholds_str = f"nms-score-threshold={self.nms_score_threshold} nms-iou-threshold={self.nms_iou_threshold} output-format-type=HAILO_FORMAT_TYPE_FLOAT32"
# Ruta al modelo YOLOv8
self.hef_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'hailomodel/yolov8s_h8l.hef'
)
self.default_postprocess_so = os.path.join(self.postprocess_dir, 'libyolo_hailortpp_post.so')
self.app_callback = app_callback
setproctitle.setproctitle("YOLOv8 Detection App")
self.create_pipeline()
def get_pipeline_string(self):
source_element = ""
if self.source_type == "rpi":
source_element = f"libcamerasrc name=src_0 auto-focus-mode=2 ! "
source_element += f"video/x-raw, format={self.network_format}, width=1536, height=864 ! "
source_element += QUEUE("queue_src_scale")
source_element += f"videoscale ! "
source_element += f"video/x-raw, format={self.network_format}, width={self.network_width}, height={self.network_height}, framerate=30/1 ! "
elif self.source_type == "usb":
source_element = f"v4l2src device={self.video_source} name=src_0 ! "
source_element += f"video/x-raw, width=640, height=480, framerate=30/1 ! "
elif self.source_type == "file":
source_element = f"filesrc location={self.video_source} name=src_0 ! "
source_element += QUEUE("queue_dec264")
source_element += f" qtdemux ! h264parse ! avdec_h264 max-threads=2 ! "
source_element += f" video/x-raw,format=I420 ! "
pipeline_string = "hailomuxer name=hmux "
pipeline_string += source_element
pipeline_string += "tee name=t ! "
pipeline_string += QUEUE("bypass_queue", max_size_buffers=20) + "hmux.sink_0 "
pipeline_string += "t. ! " + QUEUE("queue_hailonet")
pipeline_string += "videoconvert n-threads=3 ! "
pipeline_string += f"hailonet hef-path={self.hef_path} batch-size={self.batch_size} {self.thresholds_str} force-writable=true ! "
pipeline_string += QUEUE("queue_hailofilter")
pipeline_string += f"hailofilter so-path={self.default_postprocess_so} qos=false ! "
pipeline_string += QUEUE("queue_hmuc") + " hmux.sink_1 "
pipeline_string += "hmux. ! " + QUEUE("queue_hailo_python")
pipeline_string += QUEUE("queue_user_callback")
pipeline_string += f"identity name=identity_callback ! "
pipeline_string += QUEUE("queue_hailooverlay")
pipeline_string += f"hailooverlay ! "
pipeline_string += QUEUE("queue_videoconvert")
pipeline_string += f"videoconvert n-threads=3 qos=false ! "
pipeline_string += QUEUE("queue_hailo_display")
pipeline_string += f"fpsdisplaysink video-sink={self.video_sink} name=hailo_display sync={self.sync} text-overlay={self.options_menu.show_fps} signal-fps-measurements=true "
return pipeline_string
if __name__ == "__main__":
parser = get_default_parser()
args = parser.parse_args()
user_data = UserAppCallbackClass()
app = GStreamerYOLOv8App(args, user_data)
app.run()
I was working with Hailo version 4.19, but I accidentally performed an update that installed version 4.20. After upgrading to version 4.20, my code started failing because it could not import some Hailo dependencies used in my script. I reviewed the issue, performed the necessary validations, and updated multiple components, but the issue persisted.
Later, I attempted to downgrade to version 4.19, but the driver remained at 4.20. I gave up on both upgrading and downgrading and decided to standardize everything to version 4.20.
** Current Error**
Now, when I run the following command:
hailortcli fw-control identify
I get the following output:
Executing on device: 0000:01:00.0
Identifying board
Control Protocol Version: 2
Firmware Version: 4.20.0 (release,app,extended context switch buffer)
Logger Version: 0
Board Name: Hailo-8
Device Architecture: HAILO8L
Serial Number: HLDDLBB242501236
Part Number: HM21LB1C2LAE
Product Name: HAILO-8L AI ACC M.2 B+M KEY MODULE EXT TMP
[HailoRT] [error] Ioctl HAILO_READ_NOTIFICATION failed with 22. Read dmesg log for more info
Additional Issue: Running My Code on Hailo 4.20
When I try to execute my code, I receive the following errors:
0:00:00.070670192 3869803 0x5555aaf722d0 WARN v4l2codecs-h265dec gstv4l2codech265dec.c:1684:gst_v4l2_codec_h265_dec_register: Not registering H265 decoder since it produces no supp orted format
0:00:00.274744385 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:570:gst_parse_element_make: no element "hailomuxer"
0:00:00.436070430 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:623:gst_parse_element_make: no property "auto-focus-mode" in element "libcamerasrc"
0:00:00.443760462 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:1262:priv_gst_parse_yyparse: link has no source [sink=@0x1c1321c0]
0:00:00.451671382 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:570:gst_parse_element_make: no element "hailofilter"
0:00:00.451734234 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:1262:priv_gst_parse_yyparse: link has no sink [source=@0x1c132ac0]
0:00:00.451828585 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:1262:priv_gst_parse_yyparse: link has no source [sink=@0x1c132dc0]
0:00:00.452157344 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:570:gst_parse_element_make: no element "hailooverlay"
0:00:00.452182029 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:1262:priv_gst_parse_yyparse: link has no sink [source=@0x1c1336c0]
0:00:00.452227992 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:1262:priv_gst_parse_yyparse: link has no source [sink=@0x1c1339c0]
0:00:00.468526849 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:1615:priv_gst_parse_launch: No sink-element named "(null)" - omitting link
0:00:01.094927717 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:1615:priv_gst_parse_launch: No sink-element named "(null)" - omitting link
0:00:01.094966847 3869562 0x1bdfd830 ERROR GST_PIPELINE gst/parse/grammar.y:1601:priv_gst_parse_launch: No src-element named "hmux" - omitting link
gst_parse_error: no element "hailomuxer" (1)
hailomuxer name=hmux libcamerasrc name=src_0 auto-focus-mode=2 ! video/x-raw, format=RGB, width=1536, height=864 ! queue name=queue_src_scale max-size-buffers=3 max-size-bytes=0 max-siz e-time=0 ! videoscale ! video/x-raw, format=RGB, width=640, height=640, framerate=30/1 ! tee name=t ! queue name=bypass_queue max-size-buffers=20 max-size-bytes=0 max-size-time=0 ! hmux .sink_0 t. ! queue name=queue_hailonet max-size-buffers=3 max-size-bytes=0 max-size-time=0 ! videoconvert n-threads=3 ! hailonet hef-path=/home/jhsbeltr/Downloads/proyecto_yolo8/hailomo del/yolov8s_h8l.hef batch-size=1 nms-score-threshold=0.3 nms-iou-threshold=0.45 output-format-type=HAILO_FORMAT_TYPE_FLOAT32 force-writable=true ! queue name=queue_hailofilter max-size- buffers=3 max-size-bytes=0 max-size-time=0 ! hailofilter so-path=/usr/lib/hailo-post-processes/libyolo_hailortpp_post.so qos=false ! queue name=queue_hmuc max-size-buffers=3 max-size-by tes=0 max-size-time=0 ! hmux.sink_1 hmux. ! queue name=queue_hailo_python max-size-buffers=3 max-size-bytes=0 max-size-time=0 ! queue name=queue_user_callback max-size-buffers=3 max-si ze-bytes=0 max-size-time=0 ! identity name=identity_callback ! queue name=queue_hailooverlay max-size-buffers=3 max-size-bytes=0 max-size-time=0 ! hailooverlay ! queue name=queue_videoc onvert max-size-buffers=3 max-size-bytes=0 max-size-time=0 ! videoconvert n-threads=3 qos=false ! queue name=queue_hailo_display max-size-buffers=3 max-size-bytes=0 max-size-time=0 ! fp sdisplaysink video-sink=xvimagesink name=hailo_display sync=false text-overlay=False signal-fps-measurements=true
** What I Need Help With:**
- Resolving the
HAILO_READ_NOTIFICATION
error shown when runninghailortcli fw-control identify
. - Understanding how to make my existing code (which worked on version 4.19) run on version 4.20. The main issues seem to be:
- Missing
hailomuxer
,hailofilter
, andhailooverlay
elements in GStreamer. - Issues with
libcamerasrc
properties likeauto-focus-mode
. - Parsing and linking errors in the GStreamer pipeline.
Any guidance on how to fix these errors and adapt my code to Hailo 4.20 would be greatly appreciated.