91在线观看视频-91在线观看视频-91在线观看免费视频-91在线观看免费-欧美第二页-欧美第1页

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何在樹莓派 AI HAT+上進行YOLO目標檢測?

上海晶珩電子科技有限公司 ? 2025-07-19 08:34 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

大家好,接下來會為大家開一個樹莓派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:安裝引腳擴展器

170d00c0-6438-11f0-a486-92fbcf53809c.jpg

在樹莓派上安裝任何硬件之前,請確保已關閉電源并斷開與任何電源的連接。

首先將GPIO引腳擴展器安裝在樹莓派的引腳上。如果您使用的是更長的引腳擴展器,請在此處使用。注意不要彎曲這些引腳,因為它們很長,很容易彎曲。

如果您在樹莓派上使用散熱片或散熱器,現在是安裝的時候了。

步驟2:安裝支柱

171bf5c6-6438-11f0-a486-92fbcf53809c.jpg

安裝隨AI HAT附帶的4個支架。支架附帶4個長螺絲和4個短螺絲,使用哪一種都無妨。

步驟3:連接PCIe線

17280028-6438-11f0-a486-92fbcf53809c.jpg

要將HAT上的PCIe電纜安裝到樹莓派上,請先抬起樹莓派PCIe插槽上的棕色卡扣。將電纜插入插槽,確保其牢固且垂直地固定在插槽內。然后將卡扣推回原位以固定電纜。

注意:避免過度彎曲或扭曲此電纜,因為它可能較為脆弱。

步驟4:放置AI HAT

1736c1ee-6438-11f0-a486-92fbcf53809c.jpg

現在將HAT滑動到針腳延長器上,直到它平放在支架上。在此過程中請小心不要損壞PCIe電纜。

您的樹莓派在HAT下方可能會露出部分GPIO接口——這是正常現象。

步驟5:安裝攝像頭

1745d4cc-6438-11f0-a486-92fbcf53809c.jpg

相機使用的連接器與PCIe連接器采用類似的卡扣式連接設計。在相機和樹莓派的連接器插槽上,先抬起卡扣,將電纜插入并確保其垂直對齊,然后將連接器按下固定到位。

步驟6:擰緊螺絲

175636be-6438-11f0-a486-92fbcf53809c.jpg

最后,用剩下的4顆螺絲將HAT固定好。如果你選擇使用自粘式散熱片在AI HAT上,將其放置在電路板中央的銀色處理單元上。

就這樣,我們完成了!


安裝樹莓派操作系統

176877e8-6438-11f0-a486-92fbcf53809c.png

首先,我們需要將樹莓派操作系統安裝到Micro SD卡上。使用樹莓派Imager,選擇樹莓派5作為設備,選擇Raspberry Pi OS(64位)作為操作系統,并選擇您的MicroSD卡作為存儲設備。

注意:將樹莓派操作系統安裝到MicroSD卡上將擦除卡上的所有數據。

下載操作系統并安裝可能需要幾分鐘時間。安裝完成后,將其插入樹莓派并啟動。您的樹莓派將進行首次安裝,請確保將其連接到互聯網。

安裝AI HAT軟件和Python管道

讓我們開始安裝運行AI HAT所需的固件和軟件。打開一個新的終端窗口,首先使用以下命令更新您的樹莓派:

sudo aptupdate&&sudo aptfull-upgrade

在這些步驟中,系統可能會詢問您是否確認安裝某些內容,只需輸入“y”并回車即可。

1778b860-6438-11f0-a486-92fbcf53809c.jpg

現在使用以下命令安裝HAT固件:

sudoapt install hailo-all

此安裝過程可能需要5到10分鐘才能完成。安裝完成后,重新啟動樹莓派。如果您想成為高級用戶,可以通過在終端中輸入以下命令來重新啟動:

reboot

現在我們將安裝Hailo的Python管道軟件和示例,但什么是管道呢?

與AI HAT硬件本身進行通信極其復雜,所需的代碼也相當復雜。我們將設置并安裝一個目標檢測管道,它只是一組代碼和軟件,使我們能夠更輕松地與HAT進行交互。它本質上會將我們更簡單、更易讀的代碼轉換為幕后所有的復雜操作,以使HAT運行。

17894504-6438-11f0-a486-92fbcf53809c.jpg

要安裝管道及其所需的庫,首先通過在終端中輸入以下命令來復制它們的GitHub存儲庫:

gitclonehttps://github.com/hailo-ai/hailo-rpi5-examples.git

這將在樹莓派的主文件夾中下載一個名為“hailo-rpi5-examples”的文件夾,這將是我們將要在其中工作的重要位置。

1793184a-6438-11f0-a486-92fbcf53809c.jpg

在安裝管道之前,我們需要告訴終端通過更改目錄命令從該文件夾中工作:

cdhailo-rpi5-examples

終端中帶有文件位置的藍色文本表示您已成功運行此命令。現在我們將運行shell腳本安裝程序:

./install.sh

此安裝過程可能需要10到20分鐘,因為它還會安裝我們將要使用的所有YOLO模型。

安裝完成后,再次重新啟動樹莓派。


運行目標檢測演示

讓我們運行一些示例代碼!在之前的步驟中,我們從Hailo下載了一些示例管道以及使用這些管道的示例Python腳本。在本教程中,我們將使用目標檢測管道 - 它被稱為“detection_pipeline.py”,位于hailo_rpi5-examples/basic_pipelines下。

17a1df60-6438-11f0-a486-92fbcf53809c.jpg

運行這些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上設置并運行了計算機視覺。

17aea16e-6438-11f0-a486-92fbcf53809c.jpg

我們看到的這個視覺輸出很直觀。YOLO會嘗試在它認為對象所在的位置周圍繪制一個邊界框,然后標記它識別出的對象,并用百分比來評估識別的置信度。默認的YOLO模型是在COCO數據集上訓練的,該數據集僅包含81個可檢測的對象。

https://gist.github.com/AruniRC/7b3dadd004da04c80198557db5da4bda

這可能看起來不多,但其中許多是日常生活中常見的廣泛對象類別,如“運動球”和“瓶子”。

要以我們的攝像頭作為輸入視頻源來運行Python代碼,我們需要將其指定為一個參數或選項。我們可以通過輸入以下命令來獲取目標檢測管道的所有可用選項列表:

python basic_pipelines/detection.py --help

17c2d652-6438-11f0-a486-92fbcf53809c.jpg

這里有一些有用的選項可供探索,您應該找個時間嘗試一下,但我們感興趣的是使用“--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

17cf6174-6438-11f0-a486-92fbcf53809c.jpg

此代碼目前設置為在檢測到人時移動伺服。一個實際應用示例是解決辦公室里的一個實際問題。在我的辦公桌前,我經常戴著耳機,這使得當人們從我身后進入辦公室時很容易嚇到我。當這段代碼檢測到指向我身后門的攝像頭中有人時,它會旋轉一個伺服,創建一個視覺警報,表明有人進來了!

讓我們看看代碼的一些關鍵部分,了解我們添加了什么以及如何根據您的需求進行定制。

我們首先導入完全相同的庫,但添加了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打印部件在最后固化步驟之前是有毒的,我們希望在打印時讓人們遠離它。因此,此設置將尋找人,如果檢測到人并且他們位于打印機附近,它將打開警告燈。

17dfd680-6438-11f0-a486-92fbcf53809c.jpg

這段代碼在很大程度上與之前的示例代碼相似,但有一些添加。首先,我們從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個,它將打開綠燈。

17ed8c1c-6438-11f0-a486-92fbcf53809c.jpg

我們從與之前相同的類設置部分開始,但添加了一些額外的變量以在圖像上繪制一個框,該框具有最小和最大的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()

17fa00aa-6438-11f0-a486-92fbcf53809c.jpg

其余代碼幾乎相同,但在我們的檢測循環中,如果標簽是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

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • AI
    AI
    +關注

    關注

    88

    文章

    35194

    瀏覽量

    280258
  • 目標檢測
    +關注

    關注

    0

    文章

    227

    瀏覽量

    16028
  • 樹莓派
    +關注

    關注

    121

    文章

    2016

    瀏覽量

    107512
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    完整指南:如何使用樹莓5、Hailo AI HatYOLO、Docker進行自定義數據集訓練?

    今天,我將展示如何使用令人印象深刻的HailoAIHat在樹莓5上訓練、編譯和部署自定義模型。注意:文章內的鏈接可能需要科學上網。HailoAIHat根據你的設置,在樹莓5的CPU
    的頭像 發表于 06-28 08:23 ?1306次閱讀
    完整指南:如何使用<b class='flag-5'>樹莓</b><b class='flag-5'>派</b>5、Hailo <b class='flag-5'>AI</b> <b class='flag-5'>Hat</b>、<b class='flag-5'>YOLO</b>、Docker<b class='flag-5'>進行</b>自定義數據集訓練?

    MCC推出用于樹莓的MCC 118電壓測量HAT模塊

    HAT)提供8通道模擬電壓輸入,基于樹莓的數據采集/數據記錄系統。每張MCC 118最大采樣率為100kS/s,可以進行單電壓點和電壓波形采集。最多可在單塊
    發表于 08-30 10:28

    MCC基于樹莓HAT模塊

    ),數模轉換器(DAC)或條件數字輸入和輸出(DIO)。但是,可以通過USB端口或支持SPI和I2C的GPIO的40-pin接頭擴展這些功能。直接和樹莓GPIO進行堆棧式連接的設備稱為HAT
    發表于 09-05 11:45

    樹莓MCC118

    on Top),用于市場上最流行的單板計算機樹莓(Raspberry Pi)HAT是種附加板,帶有40W GPIO(通用輸入/輸出)連接器,符合Raspberry PiHAT規范。MCC 118
    發表于 01-21 09:22

    【POE HAT擴展板試用連載】樹莓3B+電路板POE供電應用

    項目名稱:樹莓3B+電路板POE供電應用試用計劃:申請理由本人嵌入式領域有十余年的開發經驗,去年購買了一塊樹莓3B+的電路板用來設計一款廚余垃圾處理機器的控制器,計劃利用這塊擴展板
    發表于 01-09 11:49

    樹莓ReSpeaker 2 Mics Pi HAT電路原理圖免費下載

    本文檔的主要內容詳細介紹的是樹莓ReSpeaker 2 Mics Pi HAT電路原理圖免費下載。
    發表于 06-16 14:22 ?0次下載

    樹莓ReSpeaker 2 Mics Pi HAT的PCB圖免費下載

    本文檔的主要內容詳細介紹的是樹莓ReSpeaker 2 Mics Pi HAT的PCB圖免費下載。
    發表于 06-16 08:00 ?0次下載
    <b class='flag-5'>樹莓</b><b class='flag-5'>派</b>ReSpeaker 2 Mics Pi <b class='flag-5'>HAT</b>的PCB圖免費下載

    目標檢測YOLO的重要性!

    YOLO是什么? 它是One-stage目標檢測的代表,整個框架非常簡單。與RCNN算法不一樣,是以不同方式處理對象檢測YOLO算法的最
    的頭像 發表于 06-10 15:45 ?4458次閱讀

    樹莓新推AI HAT+:26 TOPS高性能版本震撼登場

     在成功推出樹莓AI套件與AI攝像頭后,樹莓再次擴大其A
    的頭像 發表于 11-07 13:44 ?1335次閱讀

    樹莓派上部署YOLOv5進行動物目標檢測的完整流程

    卓越的性能。本文將詳細介紹如何在性能更強的計算機上訓練YOLOv5模型,并將訓練好的模型部署到樹莓4B上,通過樹莓的攝像頭
    的頭像 發表于 11-11 10:38 ?3744次閱讀
    在<b class='flag-5'>樹莓</b>派上部署YOLOv5<b class='flag-5'>進行</b>動物<b class='flag-5'>目標</b><b class='flag-5'>檢測</b>的完整流程

    如何將 M.2 HAT+ 與 Raspberry Pi 5 一起使用?

    邊緣連接器。您可以連接任何使用2230或2242尺寸的設備。M.2HAT+最大可提供3A的電源輸出。M.2HAT+使用了樹莓HAT+規范
    的頭像 發表于 03-25 09:48 ?307次閱讀
    如何將 M.2 <b class='flag-5'>HAT+</b> 與 Raspberry Pi 5 一起使用?

    樹莓分類器:用樹莓識別不同型號的樹莓

    在本教程系列的第一部分中,您將學習如何使用樹莓AI攝像頭來檢測不同的樹莓型號。本系列由Dav
    的頭像 發表于 06-13 16:39 ?427次閱讀
    <b class='flag-5'>樹莓</b><b class='flag-5'>派</b>分類器:用<b class='flag-5'>樹莓</b><b class='flag-5'>派</b>識別不同型號的<b class='flag-5'>樹莓</b><b class='flag-5'>派</b>!

    樹莓5上使用YOLO進行物體和動物識別-入門指南

    大家好,接下來會為大家開一個樹莓5和YOLO的專題。內容包括四個部分:在樹莓5上使用YOLO
    的頭像 發表于 07-17 17:16 ?169次閱讀
    在<b class='flag-5'>樹莓</b><b class='flag-5'>派</b>5上使用<b class='flag-5'>YOLO</b><b class='flag-5'>進行</b>物體和動物識別-入門指南

    樹莓5上開啟YOLO姿態估計識別之旅!

    大家好,接下來會為大家開一個樹莓5和YOLO的連載文章。內容包括四個部分:在樹莓5上使用YOLO
    的頭像 發表于 07-18 15:31 ?124次閱讀
    在<b class='flag-5'>樹莓</b><b class='flag-5'>派</b>5上開啟<b class='flag-5'>YOLO</b>姿態估計識別之旅!

    何在樹莓 AI HAT+上進行YOLO姿態估計?

    YOLO目標檢測?如何在樹莓AIHAT+上進行
    的頭像 發表于 07-20 20:34 ?29次閱讀
    如<b class='flag-5'>何在</b><b class='flag-5'>樹莓</b><b class='flag-5'>派</b> <b class='flag-5'>AI</b> <b class='flag-5'>HAT+</b><b class='flag-5'>上進行</b><b class='flag-5'>YOLO</b>姿態估計?
    主站蜘蛛池模板: 男女交性无遮挡免费视频 | 亚洲免费不卡 | 色综合天天综合网国产成人网 | 日本国产高清色www视频在线 | 国模精品视频一区二区三区 | 五月天天色 | 午夜影院在线观看 | 久久夜色tv网站免费影院 | 大黄一级片 | 69中国xxxxxxxx18| 欧美一级色视频 | 黄色成人在线网站 | 伊人亚洲综合网成人 | 狠狠色伊人亚洲综合第8页 狠狠色依依成人婷婷九月 狠狠色影院 | 中国一级特黄视频 | 日本一区二区三区视频在线 | 国产精品一级香蕉一区 | 国产精品欧美激情在线播放 | 日本一区二区三区四区视频 | 夜夜狠狠操 | 天天操天天射天天爽 | 色播四房间 | 免费一级欧美片在线观免看 | 色播在线 | 四虎影院免费网址 | 色视频一区 | 49pao强力免费打造在线高清 | 亚洲资源在线视频 | 末满18以下勿进色禁网站 | 爱爱小视频免费 | 天堂8在线天堂资源在线 | 色综合天天操 | 亚洲免费福利视频 | 国产在线观看黄色 | 米奇777色狠狠8888影视 | 乱子伦xxxx厨房 | 国内在线观看精品免费视频 | 亚洲综合五月天婷 | 精品xxxxxbbbb欧美中文 | 国产一级做a爰大片免费久久 | 成人sese|