這篇部落客要講述了如何通過OriginBot來看護寶寶,當寶寶的臉不在攝像頭的範圍之内時,發送消息到釘釘群組,通知家人及時檢視。
前言
我在上個月有了寶寶,為了友善照看寶寶,就買了一個帶有寶寶看護功能的攝像頭,但是産品做的不怎麼樣,最重要的臉部遮擋功能用不了,後來就退貨了。退貨後就萌生了自己用OriginBot做一個類似功能的想法,于是就有了這篇部落格~
功能流程圖(架構圖)
具體的流程或者說架構如下:
其實整體也不複雜,OriginBot上有一個MIPI攝像頭,然後利用地平線TogetheROS.Bot的人體檢測和跟蹤來實時檢測攝像頭中有沒有臉部,如果沒有臉部,就向後端發送一條資料,然後後端會向釘釘群組發消息告訴家人。釘釘群組裡面需要事先建立一個webhook。
下面會分為人體檢測、判斷有無臉部、後端操作三個部分來記錄。
人體檢測
這一部分用的是地平線TogetheROS.Bot現成的功能,啟動OriginBot之後,在指令行中運作如下指令:
# 配置tros.b環境
source /opt/tros/setup.bash
# 從tros.b的安裝路徑中拷貝出運作示例需要的配置檔案。
cp -r /opt/tros/lib/mono2d_body_detection/config/ .
# 配置MIPI攝像頭
export CAM_TYPE=mipi
# 啟動launch檔案
ros2 launch mono2d_body_detection mono2d_body_detection.launch.py
此時可以通過http://IP:8000檢視檢測效果,這個子產品檢測了人體、人頭、人臉、人手檢測框、檢測框類型和目标跟蹤ID以及人體關鍵點等,我隻取其中的人臉部分,當然了,以後也可以增加如人體檢測等。
上面的指令運作之後,在OriginBot上執行ros2 topic list,應該會有一個topic叫做hobot_mono2d_body_detection, 這個就是我們需要的,我們會訂閱這個話題,然後分析其中發送資料來判斷有沒有臉部
判斷攝像頭中有沒有臉部
按照TogetheROS.Bot的文檔說明,hobot_mono2d_body_detection的消息類型是ai_msgs.msg.PerceptionTargets, 具體如下:
# 感覺結果
# 消息頭
std_msgs/Header header
# 感覺結果的處理幀率
# fps val is invalid if fps is less than 0
int16 fps
# 性能統計資訊,比如記錄每個模型推理的耗時
Perf[] perfs
# 感覺目标集合
Target[] targets
# 消失目标集合
Target[] disappeared_targets
其中的disappeared_targets是我們關注的重點,如果face出現在disappeared_targets中,就說明之前是有臉部的,但是現在沒有了,這個時候就要向後端發出資料進一步處理。
我為了判斷有無臉部,寫了一個Node,代碼如下:
import rclpy
from rclpy.node import Node
from ai_msgs.msg import PerceptionTargets
from cv_bridge import CvBridge
import time
from api_connection import APIConnection
BabyMonitorMapping = {
# 這裡的k-v要根據後端Django中的值來确定
"face": "看不到臉",
"body": "不在攝像頭範圍内",
}
class FaceDetectionListener(Node):
""" 檢測寶寶的臉是不是在攝像頭中 """
def __init__(self):
super().__init__("face_detection")
self.bridge = CvBridge()
self.subscription = self.create_subscription(
PerceptionTargets, "hobot_mono2d_body_detection", self.listener_callback, 10
)
self.conn = APIConnection()
self.timer = time.time()
self.counter = 0
def listener_callback(self, msg):
targets = msg.targets
disappeared_targets = msg.disappeared_targets
targets_list = []
disappeared_targets_list = []
if disappeared_targets:
for item in disappeared_targets:
disappeared_targets_list.append(item.rois[0].type)
if targets:
for item in targets:
targets_list.append(item.rois[0].type)
print(f"檢測到的對象如下:{targets_list}")
print(f"消失的對象如下:{disappeared_targets_list}")
if disappeared_targets_list:
self.sending_notification(disappeared_targets_list)
def sending_notification(self, disappeared_targets_list):
for item in disappeared_targets_list:
if BabyMonitorMapping.get(item):
event = BabyMonitorMapping.get(item)
if self.counter == 0:
# 這裡baby的ID是模拟的,應該去資料庫中查
data = {"event": event, "baby": "6b56979a-b2b9-11ee-920d-f12e14f97477"}
self.conn.post_data(item=data, api="api/monitor/face-detection/")
self.counter += 1
self.timer = time.time()
else:
if time.time() - self.timer >= 60.0:
# 60秒不重複發消釘釘消息
data = {"event": event, "baby": "6b56979a-b2b9-11ee-920d-f12e14f97477"}
self.conn.post_data(item=data, api="api/monitor/face-detection/")
self.timer = time.time()
self.counter += 1
def main(args=None):
rclpy.init(args=args)
try:
face_detection_listener = FaceDetectionListener()
rclpy.spin(face_detection_listener)
except KeyboardInterrupt:
print("終止運作")
finally:
face_detection_listener.destroy_node()
rclpy.shutdown()
if __name__ == "__main__":
main()
代碼整體不難,但還是做幾點必要的說明:
1. BabyMonitorMapping
這個字典的作用是把TogetheROS.Bot裡面的字段跟後端的字段做一個映射關系,友善後面使用
點選OriginBot家庭助理計劃之寶寶看護助手 - 古月居可檢視全文