? 前情提要
家里養了三只貓咪,其中一只布偶貓經常出入廁所。但因為平時忙于學業,沒法時刻關注牠的行為。我知道貓咪的如廁頻率和時長與健康狀況密切相關,頻繁如廁可能是泌尿問題,停留過久也可能是便秘或不適。為了更科學地了解牠的如廁習慣,我計劃搭建一個基于視頻監控和AI識別的系統,自動識別貓咪進出廁所的行為,記錄如廁時間和停留時長,并區分不同貓咪。這樣即使我不在家,也能掌握貓咪的健康狀態,更安心地照顧它們。
已完成工作:
?貓咪如廁檢測與分類識別系統系列【一】 功能需求分析及貓咪分類特征提取
?貓咪如廁檢測與分類識別系統系列【二】多圖上傳及貓咪分類特征提取更新
計劃工作:
? 貓咪管理功能:已完成貓咪照片上傳與名稱登記模塊。
? 多圖上傳與分類特征提取:已支持批量上傳貓咪圖像并自動更新個體特征庫。
🔄 目標檢測與事件識別集成(YOLOv11):功能開發中,正在實現貓咪行為自動識別。
? 檢測區域繪制功能:待開發,計劃支持用戶自定義如廁檢測區域。
? 事件行為記錄模塊:待完善,將實現如廁進出時間、停留時長等事件記錄功能。
? 檢測結果推流展示:待更新,計劃支持算法結果實時推流。
? 整體運行結果推流整合:待更新,計劃集成檢測圖像與系統狀態為統一視頻流輸出。
————————————————
本次將繼續制作 實時檢測模塊:
使用 YOLOv11 檢測攝像頭畫面中的貓、判斷是否進入指定區域,并調用分類模塊識別是哪只貓 🐱📹
? 功能目標:
- 打開攝像頭實時讀取畫面
- 用 YOLOv11 檢測貓目標(設定類名為
'cat'
) - 判斷貓是否進入你定義的“如廁區域”(矩形區域)
- 如果貓在區域內 → 裁剪貓圖 → 提特征 → 分類
- 在畫面中顯示識別結果,并記錄狀態變化(進入/離開)
🧱 YOLOv11 + 分類實時檢測代碼(main.py
簡版)
import cv2
import time
import numpy as np
from recognizer.embedder import CatEmbedder
from recognizer.database import CatDatabase
from recognizer.matcher import CatMatcher
from ultralytics import YOLO # 假設你用的是YOLOv8/11格式# 初始化
model = YOLO("yolov11_cat.pt") # 替換為你的模型路徑
embedder = CatEmbedder()
db = CatDatabase()
matcher = CatMatcher(db)# 區域設定(可以做成畫圖交互)
TOILET_REGION = (100, 100, 400, 400) # (x1, y1, x2, y2)# 狀態跟蹤
cat_present = False
entry_time = None# 啟動攝像頭
cap = cv2.VideoCapture(0)while True:ret, frame = cap.read()if not ret:break# 畫如廁區域x1, y1, x2, y2 = TOILET_REGIONcv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 255), 2)# YOLOv11 推理results = model.predict(frame, verbose=False)boxes = results[0].boxesdetected = Falsecat_name = "Unknown"for box in boxes:cls = int(box.cls[0])conf = float(box.conf[0])if cls != 0: # 類別為貓(根據你的模型調整)continuexmin, ymin, xmax, ymax = map(int, box.xyxy[0])cx, cy = (xmin + xmax) // 2, (ymin + ymax) // 2# 判斷貓是否在如廁區域if x1 < cx < x2 and y1 < cy < y2:detected = Truecat_crop = frame[ymin:ymax, xmin:xmax]# 保存臨時圖片 + 識別貓tmp_path = "tmp.jpg"cv2.imwrite(tmp_path, cat_crop)vec = embedder.extract(tmp_path)cat_name = matcher.match(vec)# 顯示識別名cv2.putText(frame, f"{cat_name}", (xmin, ymin - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 200, 0), 2)cv2.rectangle(frame, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2)# 狀態變化記錄if detected and not cat_present:entry_time = time.time()print(f"🐱 {cat_name} 進入區域")cv2.imwrite(f"records/{cat_name}_enter_{int(entry_time)}.jpg", frame)if not detected and cat_present:exit_time = time.time()duration = round(exit_time - entry_time, 2)print(f"🚪 {cat_name} 離開區域,用時 {duration} 秒")cv2.imwrite(f"records/{cat_name}_leave_{int(exit_time)}.jpg", frame)cat_present = detectedcv2.imshow("Cat Monitor", frame)if cv2.waitKey(1) == 27: # ESC 退出breakcap.release()
cv2.destroyAllWindows()
📦 依賴庫列表:
-
ultralytics
(YOLOv8/11) -
torch
,opencv-python
,Pillow
-
scikit-learn
(用于相似度計算)
? 下一步工作:
-
用 Flask 做個記錄頁面,展示:
-
每次進入/離開的貓咪、時間、如廁時長
-
保存的截圖
-
-
加入狀態日志系統(寫入 SQLite)
? 讀取視頻流:
可以通過 OpenCV 直接讀取 RTSP 流的視頻畫面,替換掉 cv2.VideoCapture(0)
這一行。
? RTSP 攝像頭接入方式
假設你的攝像頭地址是:
rtsp://192.168.0.102:554/stream1
常見格式有以下幾種(具體看你的攝像頭廠商手冊):
格式類型 | 示例 URL |
---|---|
無用戶名密碼 | rtsp://192.168.0.102:554/stream1 |
有用戶名密碼 | rtsp://admin:password@192.168.0.102:554/stream1 |
如果你不確定 RTSP 路徑,可以用 VLC 打開地址測試能否連接。
? 替換代碼中的攝像頭源
# 本地攝像頭寫法
# cap = cv2.VideoCapture(0)# 替換為 RTSP 攝像頭:
cap = cv2.VideoCapture("rtsp://192.168.0.102:554/stream1")
也可以設置超時時間(推薦):
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
?? 注意事項:
-
防火墻:確保你的電腦和攝像頭在同一局域網,且攝像頭開放了 RTSP 服務。
-
穩定性:RTSP 會有卡頓或斷流情況,建議加重連邏輯(稍后我們可以加)。
-
幀率延遲:默認 RTSP 有延遲,可嘗試減少緩沖提高實時性。
? 示例(完整替換一行即可)
cap = cv2.VideoCapture("rtsp://192.168.0.102:554/stream1")
模型使用:
現在沒有收集足夠多的貓咪圖片,就先使用 YOLOv11 COCO 官方權重(基于 YOLOv8 推理架構),但是只想檢測 cat 類別(class id = 15)。我們有兩個解決方案:
? 方案一:在推理結果中篩選 cat
類別
這是最簡單的方法,無需重新訓練模型,只在代碼里過濾掉非貓類目標。
? 修改你的檢測代碼:
results = model.predict(frame, verbose=False)
boxes = results[0].boxesfor box in boxes:cls = int(box.cls[0])conf = float(box.conf[0])if cls != 15: # COCO 中 cat 是類別15continue# 保留 cat 類的后續邏輯...
你也可以打印類別名驗證一下:
from ultralytics.utils import ops
print(ops.ANCHOR_ORDER) # 也可以用 model.names[cls] 打印類別名
? 方案二:導出只含貓的 YOLOv11 模型(可選,后續更新)
如果你未來希望模型體積更小、推理更快:
-
用 COCO 數據集中只包含 cat 的部分訓練模型(或 fine-tune)。
-
自定義 data.yaml:
names: ['cat']
nc: 1
- 訓練模型:
yolo detect train data=cat.yaml model=yolov11.pt epochs=50 imgsz=640
然后就能得到一個“只識別貓”的輕量化模型了。
網絡攝像頭檢測推理錯誤
[h264 @ 00000218ddca2b00] error while decoding MB 94 41, bytestream -5
表示 OpenCV(底層用 ffmpeg)在解析 RTSP 攝像頭的視頻流時,遇到了 H.264 視頻幀解碼錯誤。這種問題在使用 RTSP 攝像頭時很常見,通常是由以下原因引起的:
? 常見原因分析:
1. 網絡不穩定 / 丟幀
-
RTSP 是實時流協議,稍有波動就可能導致數據不完整。
-
解碼器(H.264)收到了不完整的數據,無法正確解碼宏塊(Macroblock)。
2. 攝像頭編碼質量太低 / 不兼容
- 某些低端攝像頭輸出的 RTSP H.264 數據流存在兼容問題。
3. 緩沖區設置不當(OpenCV 默認大延遲)
- OpenCV 默認有較大的緩沖,容易產生過時幀或卡頓,進而出錯。
? 解決方案
? 方法 1:設置 OpenCV 緩沖區為 1(強烈推薦及采用)
cap = cv2.VideoCapture("rtsp://192.168.0.102:554/stream1")
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
? 方法 2:改用 ffmpeg
直接拉流更穩定(通過 subprocess
或 imageio
)
如果 OpenCV 解碼不穩定,可以嘗試用 ffmpeg
拉流 + pipe 給 Python 處理。
? 方法 3:嘗試切換 RTSP 子碼流(sub stream)
大多數攝像頭有主碼流(1080p)和子碼流(D1 / CIF):
-
主碼流可能過大、丟幀嚴重
-
可嘗試地址類似:
rtsp://192.168.0.102:554/sub rtsp://192.168.0.102:554/live/ch0_1 ← 子碼流
? 方法 4:嘗試加參數或禁用 HW 加速(ffmpeg flags)
可通過設置更強容錯的方式讀取(但這需要更底層控制)。
🧪 調試策略
import cv2rtsp_url = "rtsp://192.168.0.102:554/stream1"
cap = cv2.VideoCapture(rtsp_url)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)if not cap.isOpened():print("? 無法連接攝像頭")exit()while True:ret, frame = cap.read()if not ret:print("? 幀讀取失敗,跳過")continuecv2.imshow("RTSP", frame)if cv2.waitKey(1) == 27:break
? 總結建議:
方式 | 說明 |
---|---|
set(CAP_PROP_BUFFERSIZE, 1) | ? 首選,緩解延遲和丟幀問題 |
檢查 RTSP 子碼流地址 | 可大幅提升兼容性 |
嘗試更穩定解碼方式(如 GStreamer) | 高級穩定需求下可選 |
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
可以先加上上述代碼試試是否緩解問題。如果問題仍然頻繁,我們可以換 ffmpeg
或 GStreamer
拉流方式,我也可以幫你整合好。
窗口尺寸調整:
好的,如果用 OpenCV
的 cv2.imshow()
來顯示攝像頭窗口,可以通過 縮放幀的尺寸 來控制窗口大小。
? 方法:縮放圖像再顯示
在你顯示前加一行縮放代碼,比如縮放為 640x480:
# 假設 frame 是讀取的圖像
resized_frame = cv2.resize(frame, (640, 480)) # 你也可以用 (960, 720) 或其他分辨率
cv2.imshow("Cat Monitor", resized_frame)
? 推薦方式(根據原圖比例縮小)
如果你想“等比例縮放”,比如縮小為原來的 0.5 倍:
scale = 0.5
h, w = frame.shape[:2]
resized_frame = cv2.resize(frame, (int(w * scale), int(h * scale)))
cv2.imshow("Cat Monitor", resized_frame)
? 如果你想讓窗口是“可拉伸的”
還可以配合 cv2.namedWindow
控制窗口樣式:
cv2.namedWindow("Cat Monitor", cv2.WINDOW_NORMAL)
cv2.resizeWindow("Cat Monitor", 640, 480)
這允許你手動調整窗口大小。
? 已完成模塊回顧
模塊 | 狀態 | 說明 |
---|---|---|
貓咪錄入 | ? | 支持多張貓臉圖批量上傳、特征提取和保存 |
貓咪識別 | ? | 最近鄰相似度匹配分類 |
YOLOv11 + 攝像頭 | ? | 實時檢測貓是否進入區域并識別是哪只貓 |
區域判斷 | ? | 判斷貓是否進入指定如廁區域 |
RTSP 支持 | ? | 已支持 RTSP 攝像頭接入(192.168.0.102) |
窗口縮放 | ? | 圖像縮放顯示已支持 |
? 運行說明
cd cat_monitor/web
python app.py
- 瀏覽器訪問:
http://127.0.0.1:5000/
? 已完成模塊回顧
模塊 | 狀態 | 說明 |
---|---|---|
貓咪錄入 | ? | 支持多張貓臉圖批量上傳、特征提取和保存 |
貓咪識別 | ? | 最近鄰相似度匹配分類 |
YOLOv11 + 攝像頭 | ? | 實時檢測貓是否進入區域并識別是哪只貓 |
區域判斷 | ? | 判斷貓是否進入指定如廁區域 |
RTSP 支持 | ? | 已支持 RTSP 攝像頭接入(192.168.0.102) |
窗口縮放 | ? | 圖像縮放顯示已支持 |