大家好,接下来会为大家开一个树莓派5和YOLO的连载专题。
内容包括四个部分:
在树莓派5上使用YOLO进行物体和动物识别-入门指南
在树莓派5上开启YOLO姿态估计识别之旅!
如何在树莓派 AIHAT+上进行YOLO目标检测?
如何在树莓派 AI HAT+上进行YOLO姿态估计?
今天是第三部分:如何在树莓派 AI HAT+上进行YOLO目标检测?
如果大家对这个专题感兴趣,记得关注树莓派开发者,这样你将会第一时间收到我们的内容更新通知。
在本指南中,我们将探讨如何使用树莓派AI HAT设置YOLO目标检测,更重要的是,学习如何在Python项目中应用它。我们将了解如何安装所需的硬件和固件,以及如何设置和使用目标检测Python管道。通过本指南,您将掌握整个设置过程,并获得我们编写的三个不同示例脚本。一个脚本在检测到特定对象时“执行某些操作”,另一个在检测到特定数量的对象时执行操作,最后一个在特定位置检测到对象时执行操作。
像我们其他大多数计算机视觉指南一样,本指南也很有趣,让我们开始吧!
目录:
所需材料
硬件组装
安装树莓派操作系统
安装AI HAT软件和Python管道
运行目标检测演示
示例代码1:目标检测
示例代码2:计数对象
示例代码3:对象定位
运行其他YOLO模型
接下来做什么?
所需材料
要跟随本指南操作,您需要:
树莓派5 - 2GB或更大内存的型号均可。
AI HAT+板 - 本指南适用于13 TOPS和26 TOPS版本。TOPS是衡量AI加速器速度的指标,因此26 TOPS版本的AI HAT+速度大约是13 TOPS版本的两倍。这意味着它可以以更高的FPS运行更复杂、更强大的模型,比13 TOPS版本更出色。
引脚扩展器(可选) - AI HAT+附带了一个树莓派引脚扩展器,但通常它们不够长,无法完全穿过HAT。如果您打算将硬件插入树莓派或以其他方式使用引脚,则需要一个这样的扩展器来访问它们。
树莓派摄像头模块 - 我们使用的是摄像头模块V3,但几乎任何官方摄像头模块都可以使用。
摄像头适配器线 - 树莓派5使用的CSI摄像头线尺寸与之前的型号不同,您的摄像头可能附带的是旧的更宽的线,因此值得仔细检查一下。摄像头模块V3肯定需要一条适配器线。您还可以选择更长的线,如300mm和500mm!
散热解决方案 - 对于树莓派5本身,我们使用的是主动散热器。虽然AI HAT+可以在没有散热器的情况下运行,但如果您长时间运行它,一个小型自粘散热片可能是一项值得的投资。一点散热措施可能大有裨益。
电源
Micro SD卡 - 至少16GB容量。
显示器和Micro-HDMI转HDMI线
鼠标和键盘
*所需物品可以直接联系我们进行购买。
硬件安装
步骤1:安装引脚扩展器

在树莓派上安装任何硬件之前,请确保已关闭电源并断开与任何电源的连接。
首先将GPIO引脚扩展器安装在树莓派的引脚上。如果您使用的是更长的引脚扩展器,请在此处使用。注意不要弯曲这些引脚,因为它们很长,很容易弯曲。
如果您在树莓派上使用散热片或散热器,现在是安装的时候了。
步骤2:安装支柱
安装随AI HAT附带的4个支架。支架附带4个长螺丝和4个短螺丝,使用哪一种都无妨。
步骤3:连接PCIe线

要将HAT上的PCIe电缆安装到树莓派上,请先抬起树莓派PCIe插槽上的棕色卡扣。将电缆插入插槽,确保其牢固且垂直地固定在插槽内。然后将卡扣推回原位以固定电缆。
注意:避免过度弯曲或扭曲此电缆,因为它可能较为脆弱。
步骤4:放置AI HAT
现在将HAT滑动到针脚延长器上,直到它平放在支架上。在此过程中请小心不要损坏PCIe电缆。
您的树莓派在HAT下方可能会露出部分GPIO接口——这是正常现象。
步骤5:安装摄像头

相机使用的连接器与PCIe连接器采用类似的卡扣式连接设计。在相机和树莓派的连接器插槽上,先抬起卡扣,将电缆插入并确保其垂直对齐,然后将连接器按下固定到位。
步骤6:拧紧螺丝

最后,用剩下的4颗螺丝将HAT固定好。如果你选择使用自粘式散热片在AI HAT上,将其放置在电路板中央的银色处理单元上。
就这样,我们完成了!
安装树莓派操作系统

首先,我们需要将树莓派操作系统安装到Micro SD卡上。使用树莓派Imager,选择树莓派5作为设备,选择Raspberry Pi OS(64位)作为操作系统,并选择您的MicroSD卡作为存储设备。
注意:将树莓派操作系统安装到MicroSD卡上将擦除卡上的所有数据。
下载操作系统并安装可能需要几分钟时间。安装完成后,将其插入树莓派并启动。您的树莓派将进行首次安装,请确保将其连接到互联网。
安装AI HAT软件和Python管道
让我们开始安装运行AI HAT所需的固件和软件。打开一个新的终端窗口,首先使用以下命令更新您的树莓派:
sudo aptupdate&&sudo aptfull-upgrade
在这些步骤中,系统可能会询问您是否确认安装某些内容,只需输入“y”并回车即可。

现在使用以下命令安装HAT固件:
sudoapt install hailo-all
此安装过程可能需要5到10分钟才能完成。安装完成后,重新启动树莓派。如果您想成为高级用户,可以通过在终端中输入以下命令来重新启动:
reboot
现在我们将安装Hailo的Python管道软件和示例,但什么是管道呢?
与AI HAT硬件本身进行通信极其复杂,所需的代码也相当复杂。我们将设置并安装一个目标检测管道,它只是一组代码和软件,使我们能够更轻松地与HAT进行交互。它本质上会将我们更简单、更易读的代码转换为幕后所有的复杂操作,以使HAT运行。

要安装管道及其所需的库,首先通过在终端中输入以下命令来复制它们的GitHub存储库:
gitclonehttps://github.com/hailo-ai/hailo-rpi5-examples.git
这将在树莓派的主文件夹中下载一个名为“hailo-rpi5-examples”的文件夹,这将是我们将要在其中工作的重要位置。

在安装管道之前,我们需要告诉终端通过更改目录命令从该文件夹中工作:
cdhailo-rpi5-examples
终端中带有文件位置的蓝色文本表示您已成功运行此命令。现在我们将运行shell脚本安装程序:
./install.sh
此安装过程可能需要10到20分钟,因为它还会安装我们将要使用的所有YOLO模型。
安装完成后,再次重新启动树莓派。
运行目标检测演示
让我们运行一些示例代码!在之前的步骤中,我们从Hailo下载了一些示例管道以及使用这些管道的示例Python脚本。在本教程中,我们将使用目标检测管道 - 它被称为“detection_pipeline.py”,位于hailo_rpi5-examples/basic_pipelines下。

运行这些Python脚本的最简单方法是通过终端。首先使用更改目录命令更改终端的工作位置,这与我们之前使用的命令相同:
cdhailo-rpi5-examples
安装步骤还创建了一个虚拟环境(也称为Venv)。这本质上是一个隔离的虚拟工作空间,我们可以在其中安装软件包并进行实验,而不会影响树莓派操作系统的其他部分。我们需要使用的所有软件包都已安装在此Venv中,我们可以通过在终端中输入以下命令来告诉终端进入该环境:
sourcesetup_env.sh
您可以通过查看右侧图像中括号内左侧的名称来确认您正在Venv中工作。如果您已进入Venv并且看到了更改目录命令的蓝色文本,那么您现在就可以运行Python脚本了。如果您关闭了终端或重新启动了树莓派,则需要再次运行这些命令以返回到此状态。
我们将运行名为“detection.py”的演示Python代码,该代码位于“basic_pipelines”文件夹中,因此运行此代码的命令将是:
python basic_pipelines/detection.py
您应该看到一个新窗口出现,显示人们过马路的视频,以及YOLO目标检测模型在帧中识别对象,如右侧图像所示。恭喜!您已成功在AI HAT上设置并运行了计算机视觉。

我们看到的这个视觉输出很直观。YOLO会尝试在它认为对象所在的位置周围绘制一个边界框,然后标记它识别出的对象,并用百分比来评估识别的置信度。默认的YOLO模型是在COCO数据集上训练的,该数据集仅包含81个可检测的对象。
https://gist.github.com/AruniRC/7b3dadd004da04c80198557db5da4bda
这可能看起来不多,但其中许多是日常生活中常见的广泛对象类别,如“运动球”和“瓶子”。
要以我们的摄像头作为输入视频源来运行Python代码,我们需要将其指定为一个参数或选项。我们可以通过输入以下命令来获取目标检测管道的所有可用选项列表:
python basic_pipelines/detection.py --help

这里有一些有用的选项可供探索,您应该找个时间尝试一下,但我们感兴趣的是使用“--input”选项更改源。在这里我们可以看到,我们可以指定一个文件或摄像头作为输入,并且我们可以使用以下命令运行带有摄像头模块的检测脚本:
python basic_pipelines/detection.py --input rpi
现在我们的代码已经运行并从摄像头中检测对象了,让我们快速了解一下幕后发生了什么,以便我们学习如何在自定义项目中应用此目标检测。这里有很多复杂的过程,有数千行代码在运行,但其中大部分都是在管道中幕后运行的。这对我们来说很幸运,因为这意味着我们只需要与“detection.py”文件交互,该文件更加简洁且易于人类阅读(我们称之为高级代码)。
让我们在Thonny中打开detection.py并探索其中发生了什么。代码首先导入所有所需的软件包和库以运行,其中两个是同一文件夹中的Python脚本,“detection_pipeline”和“hailo_rpi_common”。如果您希望修改此设置中不在detection.py中的更深层次的行为,它很可能位于这些文件中。如果您希望为项目导入任何库或软件包,请像往常一样在此处添加。
importgigi.require_version('Gst','1.0')fromgi.repositoryimportGst,GLibimportosimportnumpyasnpimportcv2importhailofromhailo_apps_infra.hailo_rpi_commonimport( get_caps_from_pad, get_numpy_from_buffer, app_callback_class,)fromhailo_apps_infra.detection_pipelineimportGStreamerDetectionApp
然后,我们在脚本顶部定义了一个类,其中嵌套了一个名为“__init__”的函数。通常在编写代码时,我们将“初始化”代码放在顶部,并且只运行一次。这个类就是放置此“初始化”代码的地方。因此,如果我们想定义一个常量变量、设置一个引脚或声明一个函数,则必须在此部分中完成。Hailo在此部分提供了一个创建变量和函数的示例:
classuser_app_callback_class(app_callback_class): def__init__(self): super().__init__() self.new_variable =42 # New variable example defnew_function(self): # New function example return"The meaning of life is: "
然后我们有一个名为“app_callback”的函数。每次AI HAT处理一帧时,此函数的内容都会运行,可以将其视为我们在代码中通常使用的while true循环。此循环中的前十几行代码对我们来说兴趣不大。它们主要是在管理管道,并在最后创建了一个名为“detections”的对象,该对象保存了来自YOLO模型的所有目标检测信息。
defapp_callback(pad, info, user_data): # Get the GstBuffer from the probe info buffer = info.get_buffer() # Check if the buffer is valid ifbufferisNone: returnGst.PadProbeReturn.OK # Using the user_data to count the number of frames user_data.increment() string_to_print =f"Frame count:{user_data.get_count()}\n" # Get the caps from the pad format, width, height = get_caps_from_pad(pad) # If the user_data.use_frame is set to True, we can get the video frame from the buffer frame =None ifuser_data.use_frameandformatisnotNoneandwidthisnotNoneandheightisnotNone: # Get video frame frame = get_numpy_from_buffer(buffer,format, width, height) # Get the detections from the buffer roi = hailo.get_roi_from_buffer(buffer) detections = roi.get_objects_typed(hailo.HAILO_DETECTION)
现在我们到了这段代码的核心部分,开始处理detections对象。在这个for循环内部是一系列步骤。对于每个检测到的对象,它首先获取其标签(名称)、边界框的坐标(围绕对象的框)和检测的置信度。这三个信息片段是您的项目所需的关键拼图,因为它们是摄像头所看到内容的输出。在此演示代码中,它检查检测到的事物是否是人,然后将计数器增加1,并统计图像中的人数(尽管它并没有对此进行任何操作)。
detection_count=0 fordetection in detections: label= detection.get_label() bbox= detection.get_bbox() confidence= detection.get_confidence() iflabel =="person": string_to_print+= f"Detection: {label} {confidence:.2f}\n" detection_count+=1
这段代码的其余部分使用openCV显示相关信息,然后将检测数据打印到shell。
ifuser_data.use_frame: #Note:using imshow will not work here, as the callback function is not running in the main thread # Let's print the detection count to the frame cv2.putText(frame, f"Detections: {detection_count}", (10,30), cv2.FONT_HERSHEY_SIMPLEX,1, (0,255,0),2) # Example of how to use the new_variable and new_function from the user_data # Let's print the new_variable and the result of the new_function to the frame cv2.putText(frame, f"{user_data.new_function()} {user_data.new_variable}", (10,60), cv2.FONT_HERSHEY_SIMPLEX,1, (0,255,0),2) # Convert the frame to BGR frame= cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) user_data.set_frame(frame) print(string_to_print) returnGst.PadProbeReturn.OK
有了这个脚本,您现在就有了开始使用AI HAT进行自己的目标检测项目的工具。对于一些创客来说,这可能已经足够了,但我们还根据detection.py编写了三个更精炼和健壮的示例代码。这些脚本旨在让您能够启动项目,同时还提供了更多关于如何根据需要修改detections.py的示例。
示例代码1:目标检测
此脚本的最终目标是在检测到特定对象时“执行某些操作”。以下是完整代码:
importgigi.require_version('Gst','1.0')fromgi.repositoryimportGst, GLibimportosimportnumpyasnpimportcv2importhailofromhailo_apps_infra.hailo_rpi_commonimport( get_caps_from_pad, get_numpy_from_buffer, app_callback_class,)fromhailo_apps_infra.detection_pipelineimportGStreamerDetectionAppfromgpiozeroimportAngularServo# Inheritance from the app_callback_classclassuser_app_callback_class(app_callback_class): def__init__(self): super().__init__()
# Initialize state variables for debouncing self.detection_counter =0 # Count consecutive frames with detections self.no_detection_counter =0 # Count consecutive frames without detections
# State tracking, is it active or not? self.is_it_active =False
self.servo = AngularServo(18, min_pulse_width=0.0006, max_pulse_width=0.0023)
defapp_callback(pad, info, user_data): # Get the GstBuffer from the probe info buffer = info.get_buffer() # Check if the buffer is valid ifbufferisNone: returnGst.PadProbeReturn.OK
# Using the user_data to count the number of frames user_data.increment()
# Get the caps from the pad format, width, height = get_caps_from_pad(pad) # If the user_data.use_frame is set to True, we can get the video frame from the buffer frame =None ifuser_data.use_frameandformatisnotNoneandwidthisnotNoneandheightisnotNone: frame = get_numpy_from_buffer(buffer,format, width, height)
# Get the detections from the buffer roi = hailo.get_roi_from_buffer(buffer) detections = roi.get_objects_typed(hailo.HAILO_DETECTION)
# Track if we've seen objects of interest this frame object_detected =False detection_string =""
# Parse the detections fordetectionindetections: label = detection.get_label() confidence = detection.get_confidence()
# Check for objects of interest with confidence threshold ifconfidence >0.4: # Adjust confidence threshold as needed iflabel =="person": object_detected =True detection_string +=f"Detection:{label}{confidence:.2f}\n" # Debouncing logic ifobject_detected: user_data.detection_counter +=1 user_data.no_detection_counter =0
# Only activate after given amount of consecutive frames with detections ifuser_data.detection_counter >=4andnotuser_data.is_it_active: # Move the Servo or do what ever you want to do user_data.servo.angle =90 # Update the is it active variable so this doesnt keep repeating user_data.is_it_active =True print("OBJECT DETECTED!") else: user_data.no_detection_counter +=1 user_data.detection_counter =0
# Only deactivate after 5 consecutive frames without detections ifuser_data.no_detection_counter >=5anduser_data.is_it_active: # Move the Servo or do what ever you want to do user_data.servo.angle =0 user_data.is_it_active =False print("Object Gone.") # Print detections if any ifdetection_string: print(detection_string, end='')
returnGst.PadProbeReturn.OKif__name__ =="__main__": # Create an instance of the user app callback class user_data = user_app_callback_class() app = GStreamerDetectionApp(app_callback, user_data) app.run()
要运行此代码,请在同一个basic_pipelines文件夹中创建一个新的Python文件。对于此示例,我们将其命名为“watcher.py”。要运行代码,命令与之前相同,但必须使用新名称:
python basic_pipelines/watcher.py --input rpi

此代码目前设置为在检测到人时移动伺服。一个实际应用示例是解决办公室里的一个实际问题。在我的办公桌前,我经常戴着耳机,这使得当人们从我身后进入办公室时很容易吓到我。当这段代码检测到指向我身后门的摄像头中有人时,它会旋转一个伺服,创建一个视觉警报,表明有人进来了!
让我们看看代码的一些关键部分,了解我们添加了什么以及如何根据您的需求进行定制。
我们首先导入完全相同的库,但添加了gpiozero库,其中包含我们将使用的易于使用的伺服控制。
fromgpiozeroimportAngularServo
然后在只运行一次的类中,我们创建了几个变量。有两个用于去抖动的计数器变量,以及一个用于跟踪伺服当前状态的“is_it_active”变量。我们还设置了连接到引脚18的伺服。非常重要的一点是,当我们在这一部分创建变量时,必须使用“self.”前缀。如果我们希望一个变量在app_callback()(“while true循环”)中可访问,我们需要有这个前缀。
classuser_app_callback_class(app_callback_class): def__init__(self): super().__init__() # Initialize state variables for debouncing self.detection_counter =0 # Count consecutive frames with detections self.no_detection_counter =0 # Count consecutive frames without detections # State tracking, is it active or not? self.is_it_active =False self.servo = AngularServo(18, min_pulse_width=0.0006, max_pulse_width=0.0023)
app_callback()的前半部分保持不变,因为它正在管理管道,我们不想更改它。之后,我们首先创建一个名为“object_detected”和“detection_string”的变量。由于我们是在循环内部创建它们,因此不需要“self.”前缀,但它们将在每个循环周期结束时被擦除。
# Track if we've seen objects of interest this frame object_detected =False detection_string ="" # Parse the detections fordetectionindetections: label = detection.get_label() confidence = detection.get_confidence() # Check for objects of interest with confidence threshold ifconfidence >0.4: # Adjust confidence threshold as needed iflabel =="person": object_detected =True detection_string +=f"Detection:{label}{confidence:.2f}\n"
然后我们进入for detections循环,遍历当前帧中检测到的每个对象。在这里,我们像往常一样获取标签和置信度。然后,我们将检查置信度是否大于0.4(40%),以及它是否被识别为人 - 您可以根据需要调整置信度和要检测的对象。如果它是人且置信度足够,我们将object_detected设置为true。在这一部分,我们基本上分析了摄像头看到的每个对象,并检查其中是否至少有一个人。
# Parse the detections fordetectionindetections: label = detection.get_label() confidence = detection.get_confidence() # Check for objects of interest with confidence threshold ifconfidence >0.4: # Adjust confidence threshold as needed iflabel =="person": object_detected =True detection_string +=f"Detection:{label}{confidence:.2f}\n"
接下来的这一部分真正使这段代码变得健壮。如果我们检测到了人,我们将detection_counter增加1,并将no_detection_counter重置为0,因为这个计数器是在计算我们有多少帧没有看到人。非常重要的一点是,当我们使用在类部分中声明的detection_counter时,必须使用“user_data.”前缀。因此,当我们在类部分上方创建变量时使用“self.” - 当我们想在app_callback()中使用它时,必须使用“user_data.”。
在下一行中,我们检查detection_counter是否大于4,如果是,我们移动伺服(再次注意,当我们移动伺服时,必须使用“user_data.”)。在这里,您可以放置自定义代码,以便在检测到对象时“执行某些操作”。您可以发送电子邮件、打开灯、旋转电机,任何您想要的操作!
但我们为什么要连续计算4帧后再执行操作呢?这是因为我们正在为按钮添加类似去抖动的功能。假设这段代码没有去抖动,我们用它来监视房子外面,以便在检测到狗时自动打开狗门。假设系统工作得很好,但有一天一只猫接近了门。Yolo会非常可靠地识别出它是一只猫 - 但计算机视觉并不完美。有一帧它可能会错误地将猫识别为狗,这会在我们不希望的时候打开狗门。大多数时候这不是问题,但我们在测试中发现,在某些极端情况下,这可能会成为一个相当大的问题。
这段去抖动代码通过确保YOLO连续4次检测到目标对象后再“执行某些操作”,有助于消除这个问题,您可以根据项目需求更改这个数字。
# Debouncing logic ifobject_detected: user_data.detection_counter +=1 user_data.no_detection_counter =0 # Only activate after given amount of consecutive frames with detections ifuser_data.detection_counter >=4and not user_data.is_it_active: # Move the Servo or do what ever you want to do user_data.servo.angle =90 # Update the is it active variable so this doesnt keep repeating user_data.is_it_active = True print("OBJECT DETECTED!")
我们也有相反的情况。在这个else分支中(如果我们没有检测到人),我们将detection_counter设置为0,并将no_detection_counter增加1。然后我们检查no_detection_counter是否大于5,如果是,我们将移动伺服返回。在这里,您可以放置自定义代码,以便在未检测到目标对象时“执行其他操作”。
这段代码需要在5帧内未检测到对象后才会“执行某些操作”,我们这样做的原因与之前类似。假设一只狗正走向狗门,当它走过时,YOLO在一帧中将其识别为马。这会在可怜的狗经过时关上门。因此,我们通过确保在目标对象消失前有5帧未检测到它来解决这个问题。
值得注意的是,这段去抖动代码会使代码响应速度降低,因为必须在反应前经过4或5帧。代码很可能以30fps运行,因此这大约会有1/6秒的延迟。如果您想移除这个功能,可以将这些值设置为1。
这段代码中还有一件事值得探索。在这些去抖动检查的末尾,我们还检查了我们创建的is_it_active变量:
ifuser_data.detection_counter >=4and not user_data.is_it_active:
这本质上确保了每次检测到对象时,我们只“执行一次该操作”。如果对象离开并再次返回,它将再次“执行该操作”,但只执行一次。假设我们不是移动伺服,而是在检测到人时发送电子邮件。按照当前的设置,如果检测到人,它将发送一封电子邮件,并且只有当人离开并再次返回时才会发送另一封。但是假设我们没有检查这个is_it_active变量。代码会检测到一个人,并且每次分析帧时都会发送一封电子邮件(每秒30封)。如果需要,您可以从代码中移除这部分。
示例代码2:计数对象
此脚本使用与上一段代码相同的去抖动逻辑,但除了“执行某些操作”外,我们在检测到特定数量的对象时“执行某些操作”。以下是完整代码:
importgigi.require_version('Gst','1.0')fromgi.repositoryimportGst, GLibimportosimportnumpyasnpimportcv2importhailofromhailo_apps_infra.hailo_rpi_commonimport( get_caps_from_pad, get_numpy_from_buffer, app_callback_class,)fromhailo_apps_infra.detection_pipelineimportGStreamerDetectionAppfromgpiozeroimportLEDclassuser_app_callback_class(app_callback_class): def__init__(self): super().__init__() # Configuration self.target_object ="cup" # Object type to detect
# Debouncing variables self.detection_counter =0 # Consecutive frames with exact match self.no_detection_counter =0 # Consecutive frames without match
# State tracking, is it active or not? self.is_it_active =False
self.green_led = LED(18) self.red_led = LED(14)
self.red_led.off() self.green_led.on()defapp_callback(pad, info, user_data): # Get the GstBuffer from the probe info buffer = info.get_buffer() # Check if the buffer is valid ifbufferisNone: returnGst.PadProbeReturn.OK
# Using the user_data to count the number of frames user_data.increment()
# Get the caps from the pad format, width, height = get_caps_from_pad(pad) # If the user_data.use_frame is set to True, we can get the video frame from the buffer frame =None ifuser_data.use_frameandformatisnotNoneandwidthisnotNoneandheightisnotNone: frame = get_numpy_from_buffer(buffer,format, width, height)
# Get the detections from the buffer roi = hailo.get_roi_from_buffer(buffer) detections = roi.get_objects_typed(hailo.HAILO_DETECTION)
# Count objects in this frame object_count =0 detection_string =""
# Parse the detections fordetectionindetections: label = detection.get_label() confidence = detection.get_confidence()
# Check for target objects with confidence threshold ifconfidence >0.4: iflabel == user_data.target_object: object_count +=1 detection_string +=f"{label.capitalize()}detected! Confidence:{confidence:.2f}\n"
# Debouncing logic for number of items ifobject_count >=3: user_data.detection_counter +=1 user_data.no_detection_counter =0
# Only activate after sufficient consistent frames ifuser_data.detection_counter >=4andnotuser_data.is_it_active: # Turn on red led, or do what ever else you want to do user_data.red_led.on() user_data.green_led.off()
user_data.is_it_active =True print(f"NUMBER OF OBJECTS DETECTED!") else: user_data.no_detection_counter +=1 user_data.detection_counter =0
# Only deactivate after sufficient non-matching frames ifuser_data.no_detection_counter >=5anduser_data.is_it_active: # Turn on green LED or what ever else you wish to do user_data.red_led.off() user_data.green_led.on()
user_data.is_it_active =False print(f"No longer detecting number of objects.") # Print detections if any ifdetection_string: print(f"Current{user_data.target_object}count:{object_count}") print(detection_string, end='')
returnGst.PadProbeReturn.OKif__name__ =="__main__": # Create an instance of the user app callback class user_data = user_app_callback_class() app = GStreamerDetectionApp(app_callback, user_data) app.run()
此代码目前设置为控制这个塔灯中的一对LED - 与前一个示例完全相同。此示例应用的一个实际应用是,我们将其设置为智能监控系统。树脂3D打印部件在最后固化步骤之前是有毒的,我们希望在打印时让人们远离它。因此,此设置将寻找人,如果检测到人并且他们位于打印机附近,它将打开警告灯。

这段代码在很大程度上与之前的示例代码相似,但有一些添加。首先,我们从gpiozero库中导入LED,这是向GPIO引脚发送数字信号的最简单方法。
fromgpiozeroimportLED
然后在类部分中,我们创建了一个要计数的目标对象的变量,在此示例中我们将其设置为杯子 - 再次根据您的需要进行更改。然后我们有与上次相同的计数变量。但在此部分中,我们设置了LED并初始化红色为关闭状态,绿色为开启状态。注意我们仍然必须使用“self.”前缀。
classuser_app_callback_class(app_callback_class): def__init__(self): super().__init__() # Configuration self.target_object ="cup" # Object type to detect # Debouncing variables self.detection_counter =0 # Consecutive frames with exact match self.no_detection_counter =0 # Consecutive frames without match # State tracking, is it active or not? self.is_it_active =False self.green_led = LED(18) self.red_led = LED(14) self.red_led.off() self.green_led.on()
我们的代码在很大程度上是相同的,直到我们到达检测循环。在这里,对于每个置信度高于0.4且标记为我们目标对象的对象,我们将计数器增加1。
# Check for target objects with confidence threshold ifconfidence >0.4: iflabel == user_data.target_object: object_count+=1 detection_string+= f"{label.capitalize()} detected! Confidence: {confidence:.2f}\n"
然后,如果有等于或多于3个这样的对象,我们增加检测计数器并运行与之前相同的去抖动代码,并将根据相同的逻辑控制LED。
# Debouncing logic for number of items ifobject_count >=3: user_data.detection_counter +=1 user_data.no_detection_counter =0 # Only activate after sufficient consistent frames ifuser_data.detection_counter >=4and not user_data.is_it_active: # Turn on red led, or do what ever else you want to do user_data.red_led.on() user_data.green_led.off() user_data.is_it_active = True print(f"NUMBER OF OBJECTS DETECTED!") else: user_data.no_detection_counter +=1 user_data.detection_counter =0 # Only deactivate after sufficient non-matching frames ifuser_data.no_detection_counter >=5and user_data.is_it_active: # Turn on green LED or what ever else you wish to do user_data.red_led.off() user_data.green_led.on() user_data.is_it_active = False print(f"No longer detecting number of objects.")
示例代码3:对象定位
此脚本使用与前一段代码相同的去抖动逻辑,但在这里我们跟踪被检测对象的中心,如果它移动到指定位置,我们“执行某些操作”。以下是完整代码:
importgigi.require_version('Gst','1.0')fromgi.repositoryimportGst, GLibimportosimportnumpyasnpimportcv2importhailofromhailo_apps_infra.hailo_rpi_commonimport( get_caps_from_pad, get_numpy_from_buffer, app_callback_class,)fromhailo_apps_infra.detection_pipelineimportGStreamerDetectionAppfromgpiozeroimportLEDclassuser_app_callback_class(app_callback_class): def__init__(self): super().__init__() # Configuration self.target_object ="person" # Object type to detect
# Target zone configuration (normalized coordinates 0-1) self.zone_x_min =0.4 # Left boundary of target zone self.zone_x_max =0.6 # Right boundary of target zone self.zone_y_min =0.3 # Top boundary of target zone self.zone_y_max =0.7 # Bottom boundary of target zone
# Debouncing variables self.in_zone_frames =0 # Consecutive frames with object in zone self.out_zone_frames =0 # Consecutive frames without object in zone
# State tracking self.is_it_active =False self.green_led = LED(18) self.red_led = LED(14)
self.red_led.off() self.green_led.on()
defapp_callback(pad, info, user_data): # Get the GstBuffer from the probe info buffer = info.get_buffer() ifbufferisNone: returnGst.PadProbeReturn.OK
user_data.increment()
# Get the caps from the pad format, width, height = get_caps_from_pad(pad) frame =None ifuser_data.use_frameandformatisnotNoneandwidthisnotNoneandheightisnotNone: frame = get_numpy_from_buffer(buffer,format, width, height)
# Get the detections from the buffer roi = hailo.get_roi_from_buffer(buffer) detections = roi.get_objects_typed(hailo.HAILO_DETECTION)
object_in_zone =False detection_string =""
# Parse the detections fordetectionindetections: label = detection.get_label() confidence = detection.get_confidence()
ifconfidence >0.4andlabel == user_data.target_object: # Get bounding box coordinates bbox = detection.get_bbox()
# Call the coordinate methods x_min = bbox.xmin() y_min = bbox.ymin() box_width = bbox.width() box_height = bbox.height()
# Calculate max coordinates x_max = x_min + box_width y_max = y_min + box_height
# Calculate center point (these are normalized 0-1) center_x = x_min + (box_width /2) center_y = (y_min + (box_height /2) -0.22) *1.83 # Debug print for coordinates detection_string += (f"{label.capitalize()}detected!\n" f"Position: center=({center_x:.2f},{center_y:.2f})\n" f"Bounds: xmin={x_min:.2f}, ymin={y_min:.2f}, xmax={x_max:.2f}, ymax={y_max:.2f}\n" f"Confidence:{confidence:.2f}\n")
# Check if object's center is in the target zone if(user_data.zone_x_min <= center_x <= user_data.zone_x_max and (user_data.zone_y_min - 0.22) * 1.83 <= center_y <= (user_data.zone_y_max - 0.22) * 1.83): object_in_zone = True detection_string += f"Object is in target zone!\n"
# Debouncing logic for zone detection ifobject_in_zone: user_data.in_zone_frames +=1 user_data.out_zone_frames =0
ifuser_data.in_zone_frames >=4andnotuser_data.is_it_active: # Turn on red led, or do what ever else you want to do user_data.red_led.on() user_data.green_led.off()
user_data.is_it_active =True print(f"{user_data.target_object.capitalize()}detected in target zone - Servo activated!") else: user_data.out_zone_frames +=1 user_data.in_zone_frames =0
ifuser_data.out_zone_frames >=5anduser_data.is_it_active: user_data.red_led.off() user_data.green_led.on()
user_data.is_it_active =False print(f"No{user_data.target_object}in target zone - Servo deactivated!") # Print detections if any ifdetection_string: print(detection_string, end='')
returnGst.PadProbeReturn.OKif__name__ =="__main__": user_data = user_app_callback_class() app = GStreamerDetectionApp(app_callback, user_data) app.run()
此代码目前设置为控制这个塔灯中的一对LED。另一个实际问题的解决方案 - 每次我起身拿饮料时,经常会带回一个新杯子,它们开始挤满我的桌子。这段代码将检测我的桌子上是否有3个或更多杯子,如果有,将打开红灯。如果杯子少于3个,它将打开绿灯。

我们从与之前相同的类设置部分开始,但添加了一些额外的变量以在图像上绘制一个框,该框具有最小和最大的x和y值。如果对象位于此框内,我们将“执行某些操作”。该框由小数定义,x轴上0为图像左侧,1.0为右侧,0.5为中间。y轴从0(顶部)到1.0(底部)。以下是可以绘制的两个框的示例,您可以更改这些x和y最小和最大变量以设置自定义检测框。
detection_counter变量也已更改为in_zone_frames和out_zone_frames。这只是名称更改,使用方式完全相同。
classuser_app_callback_class(app_callback_class): def__init__(self): super().__init__() # Configuration self.target_object ="person" # Object type to detect # Target zone configuration (normalized coordinates 0-1) self.zone_x_min =0.4 # Left boundary of target zone self.zone_x_max =0.6 # Right boundary of target zone self.zone_y_min =0.3 # Top boundary of target zone self.zone_y_max =0.7 # Bottom boundary of target zone # Debouncing variables self.in_zone_frames =0 # Consecutive frames with object in zone self.out_zone_frames =0 # Consecutive frames without object in zone # State tracking self.is_it_active =False self.green_led = LED(18) self.red_led = LED(14) self.red_led.off() self.green_led.on()

其余代码几乎相同,但在我们的检测循环中,如果标签是target_object且置信度高于0.4,我们从YOLO获取边界框,找到其中心,然后检查其是否在我们的最小和最大x和y值内。如果是,则我们将object_in_zone设置为true,并运行与前两个代码片段完全相同的去抖动逻辑。
ifconfidence >0.4andlabel == user_data.target_object: # Get bounding box coordinates bbox = detection.get_bbox() # Call the coordinate methods x_min = bbox.xmin() y_min = bbox.ymin() box_width = bbox.width() box_height = bbox.height() # Calculate max coordinates x_max = x_min + box_width y_max = y_min + box_height # Calculate center point (these are normalized 0-1) center_x = x_min + (box_width /2) center_y = (y_min + (box_height /2) -0.22) *1.83 # Debug print for coordinates detection_string += (f"{label.capitalize()}detected!\n" f"Position: center=({center_x:.2f},{center_y:.2f})\n" f"Bounds: xmin={x_min:.2f}, ymin={y_min:.2f}, xmax={x_max:.2f}, ymax={y_max:.2f}\n" f"Confidence:{confidence:.2f}\n") # Check if object's center is in the target zone if(user_data.zone_x_min <= center_x <= user_data.zone_x_max and (user_data.zone_y_min - 0.22) * 1.83 <= center_y <= (user_data.zone_y_max - 0.22) * 1.83): object_in_zone = True detection_string += f"Object is in target zone!\n"
运行其他YOLO模型
我们为何要选择其他模型呢?实际上,YOLO在不同版本和模型尺寸上有许多变体。较新的YOLO模型通常功能更强大,且处理需求更低。未来,你或许能在这里找到YOLO11以及其他新模型,但选择其他模型的主要原因在于更改模型尺寸。YOLO有5种尺寸——纳米级、小型、中型、大型和超大型。模型越大,其处理能力越强、精度越高、检测距离越远,但会牺牲帧率(FPS)。默认情况下,13 TOPS的设备将运行小型模型,26 TOPS的设备将运行中型模型,这两种情况下都能实现流畅的30 FPS。
AI HAT+可以运行多种神经网络模型,但有一个前提条件——必须先将模型转换为HEF格式,并且需要针对特定型号的扩展板进行转换(为13 TOPS扩展板转换的模型可能在26 TOPS扩展板上表现不佳)。将模型转换为HEF格式需要遵循一定流程,Hailo公司提供了相关指南,但请注意,这是一个相当复杂的过程。
https://github.com/hailo-ai/hailo-rpi5-examples/blob/main/doc/retraining-example.md
而且,这可能是一个极其漫长的过程,即使配备了最高端的GPU,也可能需要数小时,而使用低端GPU甚至CPU进行转换,则可能需要数天或数周时间。
不过,幸运的是,我们可以从互联网上获取预转换的模型,其中最好的来源之一就是Hailo的模型库。该库提供了适用于13 TOPS(Hailo-8)和26 TOPS(Hailo-8L)扩展板的模型集合。虽然可以使用多种模型,但我们将重点关注YOLO系列,因为我们发现该流程更有可能与它们兼容。
要运行模型,只需下载其编译版本,该版本应位于表格的最右侧(你可能需要向右滚动才能看到)。请仔细检查下载的是“.hef”格式的文件。下载完成后,将其拖放到“hailo-rpi5-examples”文件夹中的“resources”文件夹内,与其他YOLO模型放在一起。在我们的示例中,我们下载了名为“yolov8l.hef”的大型模型。
如果模型已放入文件夹中,你可以通过在运行命令中添加该模型作为选项来运行它,此时需要使用模型名称。例如,我们的命令如下:
python basic_pipelines/detection.py --input rpi --hef resources/yolov8l.hef
如果你获得了其他已转换为HEF格式的YOLO模型,操作流程也是一样的。
接下来该做什么?
现在,我们已经设置好了树莓派和AI HAT,并使用了一些示例代码运行了目标检测功能,这些代码可以用于你的项目中。现在,唯一剩下的就是弄清楚如何实现你项目中想要完成的“某件事”。我们提供了一些关于树莓派的一般指南,帮助你入门,例如,如何使用继电器控制直流电机和步进电机、伺服电机,甚至电磁阀(你可以使用继电器控制几乎任何东西)。
使用树莓派和继电器控制电磁阀:
https://core-electronics.com.au/guides/raspberry-pi/control-servo-raspberry-pi/
原文地址:
https://core-electronics.com.au/guides/raspberry-pi/yolo-object-detection-on-the-raspberry-pi-ai-hat-writing-custom-python/#KBNAKNI
- 随机文章
- 热门文章
- 热评文章
- 中亚国家商务合作对接会在浙江慈溪举行,中亚国家商务合作对接会在浙江慈溪举行
- “内蒙古文学重点作品创作工程”入选作品改稿会举办,“内蒙古文学重点作品创作工程”入选作品改稿会举办
- 多地高温天气持续 “桑拿天”来了如何应对?专家提醒,多地高温天气持续 “桑拿天”来了如何应对?专家提醒
- 福建建宁:竹“宝藏”激活经济增长,福建建宁:竹“宝藏”激活经济增长
- 民进2025年会史工作主题年工作中期推进会暨现场会在杭州举行,民进2025年会史工作主题年工作中期推进会暨现场会在杭州举行
- 西藏林芝市森林消防支队组织开展车辆安全教育,西藏林芝市森林消防支队组织开展车辆安全教育
- 上海:政府多种探索协同发展银发经济,上海:政府多种探索协同发展银发经济
- 傅莎:碳中和产业投资空间广阔,傅莎:碳中和产业投资空间广阔
- 近百名榕台师生福州开启公益写作采风,近百名榕台师生福州开启公益写作采风
- 全球首个!中国科研团队实现离子液体法再生纤维素纤维规模化生产,全球首个!中国科研团队实现离子液体法再生纤维素纤维规模化生产
- 江苏省扬州市网络代表人士联谊会成立,江苏省扬州市网络代表人士联谊会成立
- 中越民众边境共庆京族传统盛典“哈节”,中越民众边境共庆京族传统盛典“哈节”
- 1北方稀土跌0.52% 机构净卖出4.01亿元
- 2整流桥GBJ2002和GBJ3002,有什么区别?
- 3与作者面对面丨英飞凌IPAC直播间即将亮相PCIM Asia 2025
- 4东周时期贵族饮食考古发现:女性食源多样肉食明显低于男性,东周时期贵族饮食考古发现:女性食源多样肉食明显低于男性
- 52025CJ直击:骁龙是如何从游戏芯到全能王的?
- 6浙江宁波机场口岸上半年出入境外籍旅客同比增长87%,浙江宁波机场口岸上半年出入境外籍旅客同比增长87%
- 7钙钛矿助力Micro-LED发展:从材料突破到显示应用
- 8入选沙利文白皮书行业标杆!华宝新能全场景家庭绿电解决方案亮相AIA 25 Expo
- 9机构关注高端装备股,开启“反内卷”新一轮上涨行情
- 10能源组态数据大屏管理平台有什么功能?
- 11南平市文旅经济发展大会召开 全力打造世界级旅游目的地,南平市文旅经济发展大会召开 全力打造世界级旅游目的地
- 12800余位浙江衢州籍海内外人士聚家乡 共促开放发展
- 1安乃达(603350):首次公开发行部分限售股上市流通
- 2数字化工厂-注塑机数据采集、边缘计算
- 3白银站稳32:多重利好共振下的反弹能否持续?
- 4韩国总统李在明涉华表态:将尽快改善韩中关系,韩国总统李在明涉华表态:将尽快改善韩中关系
- 5金证股份(600446):金证股份第八届董事会2025年第六次会议决议
- 6ST盛屯股东户数下降6.18%,户均持股19.61万元
- 7EBC金融集团外汇行情播报|欧股仍然承压 奢侈品不香了
- 8光储充一体化构建绿色能源与智能交通的交汇点
- 9奥飞数据拟募资不超17.5亿元建设云计算产业园
- 10慧能泰推出零外围A+C快充芯片HUSB382D
- 11一季度超七成混基正收益 鹏华碳中和主题混合涨60%
- 12江西首座“光储充放检调”一体超级充电示范站投运,江西首座“光储充放检调”一体超级充电示范站投运








