树莓派项目:在树莓派上使用 OpenCV 进行边缘检测和运动传感

目录
概述:
所需组件
树莓派相机连接
什么是均方误差 (MSE) 和 Canny 边缘检测方法?
均方误差 (MSE)
Canny边缘检测方法
Raspberry Pi 设置、库和依赖项安装
使用 OpenCV 进行边缘检测和运动传感的 Raspberry Pi Python 代码
Python代码
代码说明
边缘检测和运动传感的测试和结果
结论
概述:
该项目是关于在Raspberry Pi 4上使用 OpenCV 进行边缘检测和运动传感。
在OpenCV中,边缘检测和运动传感是图像处理和计算机视觉的支柱。通过图像处理,边缘检测等技术可以细化视觉数据,突出显示特征以改进图像输出。相比之下,计算机视觉中的运动传感是关于解释的;它通过分析图像序列来辨别和理解运动,从而更深入地了解视觉数据。
在这个项目中,我们将在Raspberry Pi 4上使用OpenCV来处理视频帧。对于边缘检测,我们将在帧的灰度版本上使用Canny 边缘检测方法。为了识别运动,我们将计算连续灰度帧之间的均方误差(MSE);MSE的显着变化表明运动。此设置提供了视频源中边缘和潜在运动的实时视觉表示。
所需组件:

树莓派相机连接
Raspberry Pi 相机是由 Raspberry Pi 基金会开发的外围设备,可与其系列 Raspberry Pi 单板计算机一起使用。相机模块提供了一种向 Raspberry Pi 项目添加视频/照片功能的方法。
对于这个项目,我们可以使用5 兆像素的Raspberry Pi 相机。
只需使用相机连接器将相机模块连接到 Raspberry Pi 4 板即可。
要使用相机,您需要先启用相机模块。sudo raspi-config通过在终端中键入内容来打开 Raspberry Pi 配置工具。导航至Interfacing Options>Camera并启用它。
什么是均方误差 (MSE) 和 Canny 边缘检测方法?
该项目使用Canny 边缘检测方法进行边缘检测,并使用均方误差 (MSE) 算法进行运动检测。这些步骤共同使 Canny 算法能够稳健地检测图像中的边缘。
均方误差 (MSE)
MSE是衡量两个图像或信号之间差异的常用指标。它计算两个信号或图像的对应值之间的平均平方差。
低MSE表明两者密切相关,而高 MSE表明存在显着差异。从数学上来说,对于两个图像I和J,MSE 由下式给出:
其中m和n是图像的尺寸。
Canny边缘检测方法
Canny方法是一种多步骤算法,旨在检测图像中的各种边缘。
关键阶段包括:
- 降噪:使用高斯滤波器对图像进行平滑处理以消除噪声。
- 梯度计算:计算每个像素的梯度大小和方向,突出显示潜在的边缘。
- 非极大值抑制:此步骤通过确保边缘方向上的梯度幅值最大来细化潜在边缘,从而减少边缘的厚度。
- 双阈值:区分强边缘、弱边缘和非边缘,确保真正的边缘清晰。
- 通过滞后进行边缘跟踪:根据弱边缘与强边缘的连接性,弱边缘会被丢弃或提升为强边缘。
Raspberry Pi 设置、库和依赖项安装
边缘检测和运动传感以及代码中存在的其他图像处理任务需要OpenCV 。因此您需要先安装OpenCV。请按照以下指南在您的系统中安装 OpenCV:
《如何在 Raspberry Pi 4 上安装和设置 OpenCV》
下一步是安装picamera。因此使用pip安装它。
|
设置部分现已完成。我们可以使用 Raspberry Pi 和 OpenCV 进行边缘检测和运动传感项目。
使用 OpenCV 进行边缘检测和运动传感的 Raspberry Pi Python 代码
现在让我们开发一个Python 代码,帮助OpenCV 库和Raspberry Pi 相机进行边缘检测和运动传感。
Python代码
打开Thonny IDE并将以下代码粘贴到 Thonny 编辑器中。将此文件以名称“ Motion_detection.py ”保存到任意位置。
这是完整的 Python 代码。
import cv2
import time
import numpy as np
CAMERA_DEVICE_ID = 0
IMAGE_WIDTH = 320
IMAGE_HEIGHT = 240
MOTION_BLUR = True
cnt_frame = 0
fps = 0
def mse(image_a, image_b):
err = np.sum((image_a.astype("float") - image_b.astype("float")) ** 2)
err /= float(image_a.shape[0] * image_a.shape[1])
return err
def lighting_compensation(frame):
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
return cv2.equalizeHist(gray)
if __name__ == "__main__":
try:
cap = cv2.VideoCapture(CAMERA_DEVICE_ID)
cap.set(3, IMAGE_WIDTH)
cap.set(4, IMAGE_HEIGHT)
while True:
start_time = time.time()
_, frame_raw = cap.read()
if MOTION_BLUR:
frame = cv2.GaussianBlur(frame_raw, (3,3),0)
else:
frame = frame_raw
compensated_frame = lighting_compensation(frame)
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(frame_gray, 100, 200)
if cnt_frame > 0:
if mse(frame_gray, frame_gray_p) > 100:
print('Frame{0}: Motion Detected using MSE!'.format(cnt_frame))
cv2.imshow('Original', frame)
cv2.imshow('Compensated', compensated_frame)
cv2.imshow('Gray', frame_gray)
cv2.imshow('Edge', edges)
end_time = time.time()
seconds = end_time - start_time
fps = 1.0 / seconds
print("Estimated fps:{0:0.1f}".format(fps));
cnt_frame += 1
frame_gray_p = frame_gray
if cv2.waitKey(1) == 27:
break
except Exception as e:
print(e)
finally:
cv2.destroyAllWindows()
cap.release()
代码说明
让我们通过逐节分析来更深入地了解代码。
|
1
2
3
4
5
6
7
8
|
import cv2
import time
import numpy as np
CAMERA_DEVICE_ID = 0
IMAGE_WIDTH = 320
IMAGE_HEIGHT = 240
MOTION_BLUR = True
|
本节导入必要的库并设置一些基本配置常量。我们正在设置相机设备、分辨率,并决定是否要使用运动模糊。
|
1
2
|
def mse(image_a, image_b):
...
|
该函数计算两个图像之间的均方误差。稍后使用它通过检查差异来确定连续帧之间是否存在任何运动。
|
1
2
|
def lighting_compensation(frame):
...
|
此功能旨在提高在不同照明条件下拍摄的图像质量。它均衡灰度图像的直方图,增强其整体可视性。
|
1
2
3
4
5
|
if __name__ == "__main__":
try:
cap = cv2.VideoCapture(CAMERA_DEVICE_ID)
cap.set(3, IMAGE_WIDTH)
cap.set(4, IMAGE_HEIGHT)
|
这部分初始化主要执行。它设置从定义的相机设备进行视频捕获并设置视频分辨率。
|
1
2
3
4
5
6
7
|
while True:
start_time = time.time()
_, frame_raw = cap.read()
...
compensated_frame = lighting_compensation(frame)
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(frame_gray, 100, 200)
|
在循环内,对于每一帧,它都会捕获该帧,选择性地应用高斯模糊,执行照明补偿,将帧转换为灰度,然后检测边缘。
|
1
2
3
|
if cnt_frame > 0:
if mse(frame_gray, frame_gray_p) > 100:
print('Frame{0}: Motion Detected using MSE!'.format(cnt_frame))
|
这部分代码通过使用 MSE 将当前灰度帧与前一个灰度帧进行比较来检查运动。如果 MSE 高于 100,则表示检测到运动。
|
1
2
3
4
5
6
|
cv2.imshow('Original', frame)
...
end_time = time.time()
seconds = end_time - start_time
fps = 1.0 / seconds
print("Estimated fps:{0:0.1f}".format(fps));
|
显示已处理的帧,并计算并打印处理的 FPS(每秒帧数)。
|
1
2
3
4
5
6
|
if cv2.waitKey(1) == 27:
break
...
finally:
cv2.destroyAllWindows()
cap.release()
|
如果按下“Esc”键(ASCII 值为 27),循环就会中断。最后,无论主循环如何退出,代码都会确保 OpenCV 窗口关闭并释放资源。
边缘检测和运动传感的测试和结果
现在我们需要使用 Raspberry Pi OpenCV 运行边缘检测和运动传感代码。
运行代码后,将打开 4 个窗口,如下所示。
第一个窗口将显示原始图像。第二个窗口将显示转换后的灰度图像。在第三个窗口中,将显示补偿后的图像,看起来更加清晰。第四张图像显示了边缘检测。
Thonny Shell 将显示每秒估计的帧数。
它还将显示运动检测状态。这意味着每当物体移动或帧发生变化时,“检测到运动”就会显示在Thonny Shell上。
结论
使用 Raspberry Pi 和 OpenCV 进行边缘检测和运动传感项目是在实时场景中使用OpenCV集成多种图像处理技术的综合演示。它捕获视频帧,通过光照补偿对其进行增强,使用Canny 边缘检测来检测边缘,并通过均方误差方法监视帧间变化以检测运动。
此外,它还实时显示处理后的图像并计算每秒帧数以衡量性能。这种技术组合不仅展示了OpenCV 的强大功能和灵活性,还为更先进的监视或监控系统奠定了基础,这些系统可以在不同的照明条件下有效运行并检测运动。







