搜尋此網誌

2025年6月11日 星期三

Raspberry pi PyTorch 影像識別

緣起:


    前兩個禮拜,那個廢物鄰居被他的朋友載出門,不知去哪工作,直接不管他家的小狗,就把它一隻狗放在家中,不管它的死活。要不是我這段時間有去餵它的話,它可能真的會餓死。

    前幾天發現一個問題,那小狗會跑去我們神明廳大便,不知是不是它已經沒辨法在它家裡找到適合大便的位置,總之,這件事造成我們不小的困擾,我已經掃它大便兩次了。

    為了阻止它繼續在我們神明廳大便,我打算自製一個驅狗器。有上網查,能用超音波來趕狗子,所以想說使用 arduino 搭配紅外線感測器,再加個能發出超聲波的電子零件之類的(?,簡單做。後來仔細去查才發現,一般的蜂鳴器模組是沒辨法做到發出 25K Hz 以上的聲音,如果是想使用 HC-SR04 模組的話,聲音太小,需要加強驅動電路。好麻煩,我又不知怎麼設計電路的東西。

    後來想到,好像不一定要超聲波,用喇叭最大音量播放狗吠聲,應該也可以把那隻小狗給嚇跑。所以後來轉而使用 raspberry pi 來處理,我有 3 代的 pi,它有 3.5 mm 的孔能直接連音源線。不過,要用喇叭的話,就不能單純紅外線感測器偵測到物體時播放聲音,如果進來的是我爸媽,然後把他們嚇到,到時我就倒楣了。所以,更好的方案應該是使用 usb 網路攝影機,搭配影像識別。

    前天下午都一直在搞這東西,雖然大部份的時間都是在載套件。隔天,我看我爸用鐵網把神明廳的入口擋住,哇,老祖宗的方法果然還是快速又方便


    感覺有點白忙一場,後來想了想,還是有學到不少東西,所以想寫篇文章紀錄。


python venv:


    呼叫 gpt 幫我寫程式,它推薦我使用 pytorch 與 YOLOv5,第一步先安裝 python3-opencv,python3-pip 已經有了,所以就不安裝

sudo apt update
sudo apt install python3-opencv

    再來用 pip3 安裝 python 的 library 時碰上了點問題,收到 externally-managed-environment 的 error,跟這個有關,它會這樣做是為了避免 apt 跟 pip 之間的套件衝突。是可以暴力解,只要加個 --break-package-system 的參數就行,但我還是乖乖的學怎麼用 python 的 venv 好了。

    在 Desktop 下執行

python -m venv ./yolo5_dog_detects

    它會建立一個資料夾,進入裡頭看,裡面會有 pyvenv.cfg,還有、bin、module、lib、lib64、share,資料夾,bin 裡包含可執行檔,可以用 bin 裡的 pip3 來為此虛擬環境安裝 pip 套件,這樣它就不會報錯了。

./yolo5_dog_detects/bin/pip3 install torch torchvision
git clone https://github.com/ultralytics/yolov5
./yolo5_dog_detects/bin/pip3 install -r ./yolov5/requirements.txt

pip3 timeout:


    在安裝套件時有碰到一個問題,它會載到一半然後報 timeout error,有在這邊找到解法,pip3 install 加個 --timeout=1000 的參數就行了


    問題就出在我手機網路太慢。

程式:


    gpt 給我的初版程式長這樣

import torch
import cv2

# 載入 YOLO 模型
model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True)

# 開啟 Webcam
cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    if not ret:
        break

    # 偵測畫面
    results = model(frame)
    labels = results.pandas().xyxy[0]['name'].values

    if 'dog' in labels:
        print("狗狗出現啦!")

    # 顯示畫面
    cv2.imshow('cam', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

    這時才知道,原來 cv2 那麼好用啊,抓 webcam 的影像很簡單,用視窗顯示拍到的圖片也很簡單。程式第一次執行時,它會先載模型,等待模型載入也要一小段時間,實際跑起來後,超卡的,像在看幻燈片,目測有五秒的延遲,根本用不了啊,cpu 還會燒到 80 度。

    後來在想著怎麼改善程式,想到的解法是,先用紅外線感測器偵測,有偵測到東西後再開始拍照、解析圖像中有沒有狗子。為了讓我更方便觀察,我還有加個 LED 燈,當紅外線感測器有感應到時,讓 LED 燈微亮,當偵測到狗子時,LED 燈全亮。
    

    程式如下,要記得裝 Rpi.GPIO 套件

if __name__ == '__main__':
    import sys
    import torch
    import cv2
    import time
    import RPi.GPIO as GPIO
    
    LED_PIN = 12
    SENSOR_PIN=18
    
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(LED_PIN, GPIO.OUT)
    GPIO.setup(SENSOR_PIN, GPIO.IN)
    
    pwm=GPIO.PWM(LED_PIN, 100)
    pwm.start(0)
    
    model = torch.hub.load('ultralytics/yolov5', 'yolov5n', pretrained=True)
    cap=cv2.VideoCapture(0)
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
    while True:
        pwm.ChangeDutyCycle(0)
        time.sleep(0.2)
        if GPIO.input(SENSOR_PIN) == 1:
            pwm.ChangeDutyCycle(1)
            for i in range(0,5):
                
                ret, frame=cap.read()
                results=model(frame)
                labels = results.pandas().xyxy[0]['name'].values
    
                if 'dog' in labels:
                    pwm.ChangeDutyCycle(100)
                    print('---------------------------\n')
                    print('dog appear\n')
                    print('---------------------------\n')
                else:
                    pwm.ChangeDutyCycle(1)
        
                #cv2.imshow('cam', frame)
                #if cv2.waitKey(1) & 0xFF == ord('q'):
                #    break
    
    cap.release()
    cv2.destroyAllWindows()
    pwm.stop()
    GPIO.cleanup()

15 行 : 用 GPIO.PWM 來設定 18 腳 (需要腳位有支援PWM),頻率 100 Hz
16 行 : 開始 pwm 輸出,初始 duty cycle 為 0
20、21 行 : 為了減輕 pi 的負擔,有把圖片解析度改成 640X480
23 行: 可以呼叫 ChangeDutyCycle 來改變 duty cycle

    有先在自己房間裡測試,我用平板,放張狗的照片,然後各種前前後後四處移動,等到測試得差不多後,我開始把設備都搬到神明廳那邊,準備把東西都架設,然後找我家的薯泥來測試。那時已經下午 5 點多,我媽看我在神明廳擺那些東西,警告我說不要鬧,不然爸爸回來後看到這些會罵我,所以我就先停手了。

    還有播放 mp3 的部份沒加入,有查過,感覺可以用 vlc 的 python lib 來處理這塊,之後有機會再接著做的話再學吧。

沒有留言:

張貼留言