Jetson 15 OpenCV 运动检测
来自Waveshare Wiki
OpenCV 运动检测
本章教程使用 OpenCV 来检测画面中的变化,你可以为变化多少设置一个阈值,更改阈值,可以更改运动检测的敏感度。
本章节需要前置章节的基础。
准备工作
由于产品开机默认会自动运行主程序,主程序会占用摄像头资源,这种情况下是不能使用本教程的,需要结束主程序或禁止主程序自动运行后再重新启动机器人。
这里需要注意的是,由于机器人主程序中使用了多线程且由 crontab 配置开机自动运行,所以常规的 sudo killall python 的方法通常是不起作用的,所以我们这里介绍禁用主程序自动运行的方法。
如果你已经禁用了机器人主程序的开机自动运行,则不需要执行下面的结束主程序章节。
结束主程序
1. 点击上方本页面选项卡旁边的 “+”号,会打开一个新的名为 Launcher 的选项卡。
2. 点击 Other 内的 Terminal,打开终端窗口。
3. 在终端窗口内输入 bash 后按回车。
4. 现在你可以使用 Bash Shell 来控制机器人了。
5. 输入命令: sudo killall -9 python
例程
以下代码块可以直接运行:
1. 选中下面的代码块
2. 按 Shift + Enter 运行代码块
3. 观看实时视频窗口
4. 按 STOP 关闭实时视频,释放摄像头资源
如果运行时不能看到摄像头实时画面
- 需要点击上方的 Kernel - Shut down all kernels
- 关闭本章节选项卡,再次打开
- 点击 STOP 释放摄像头资源后重新运行代码块
- 重启设备
注意事项
如果使用CSI摄像头则需要注释`frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)`这一句。
本章节的特性
你需要更改一些参数来调增 OpenCV 对画面中变化检测的阈值(灵敏度)`threshold`,这个阈值越低,OpenCV 对画面的变化越敏感。
运行
运行代码块是,你可以看到摄像头的实时画面,可以在画面前挥手,本例程会自动将出现变化的部分使用绿色的方框圈起来。
import cv2
import numpy as np
from IPython.display import display, Image
import ipywidgets as widgets
import threading
threshold = 2000 # 动态检测面积阈值
# ============================
# 创建停止按钮
# ============================
stopButton = widgets.ToggleButton(
value=False,
description='Stop',
disabled=False,
button_style='danger',
tooltip='Description',
icon='square'
)
# ============================
# 视频流 + 动态检测
# ============================
def view(button):
# 打开 USB 摄像头
camera = cv2.VideoCapture(-1)
camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
display_handle = display(None, display_id=True)
avg = None # 用于背景平均
while True:
ret, frame = camera.read()
if not ret:
continue
# BGR → 灰度 → 高斯模糊
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
# 初始化背景
if avg is None:
avg = gray.copy().astype("float")
continue
# 更新背景
cv2.accumulateWeighted(gray, avg, 0.5)
# 当前帧 vs 背景
frameDelta = cv2.absdiff(gray, cv2.convertScaleAbs(avg))
# 阈值化 + 膨胀
thresh = cv2.threshold(frameDelta, 5, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=2)
# 不用 imutils,直接用 OpenCV
contours, _ = cv2.findContours(
thresh.copy(),
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE
)
# 画矩形框
for c in contours:
if cv2.contourArea(c) < threshold:
continue
(mov_x, mov_y, mov_w, mov_h) = cv2.boundingRect(c)
cv2.rectangle(frame,
(mov_x, mov_y),
(mov_x + mov_w, mov_y + mov_h),
(128, 255, 0), 1)
# 显示画面
_, jpg = cv2.imencode('.jpeg', frame)
display_handle.update(Image(data=jpg.tobytes()))
# 点击停止按钮
if stopButton.value:
camera.release()
display_handle.update(None)
return
# ============================
# 显示按钮 + 启动线程
# ============================
display(stopButton)
thread = threading.Thread(target=view, args=(stopButton,))
thread.start()