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

5a36c95786aa4cd588f03deab37ba08d.png

 

目录
概述:
所需组件
树莓派相机连接
什么是均方误差 (MSE) 和 Canny 边缘检测方法?
均方误差 (MSE)
Canny边缘检测方法
Raspberry Pi 设置、库和依赖项安装
使用 OpenCV 进行边缘检测和运动传感的 Raspberry Pi Python 代码
Python代码
代码说明
边缘检测和运动传感的测试和结果
结论

 

 概述:

该项目是关于在Raspberry Pi 4上使用 OpenCV 进行边缘检测运动传感

OpenCV中,边缘检测运动传感图像处理和计算机视觉的支柱。通过图像处理,边缘检测等技术可以细化视觉数据,突出显示特征以改进图像输出。相比之下,计算机视觉中的运动传感是关于解释的;它通过分析图像序列来辨别和理解运动,从而更深入地了解视觉数据。

 

661164cf9eafa5040da55e5d8ca5c896.jpeg

在这个项目中,我们将在Raspberry Pi 4上使用OpenCV来处理视频帧。对于边缘检测,我们将在帧的灰度版本上使用Canny 边缘检测方法。为了识别运动,我们将计算连续灰度帧之间的均方误差(MSE)MSE的显着变化表明运动。此设置提供了视频源中边缘和潜在运动的实时视觉表示。

所需组件:

01665bde745b49a3aa927baada5faf32.png

 

树莓派相机连接

Raspberry Pi 相机是由 Raspberry Pi 基金会开发的外围设备,可与其系列 Raspberry Pi 单板计算机一起使用。相机模块提供了一种向 Raspberry Pi 项目添加视频/照片功能的方法。

对于这个项目,我们可以使用5 兆像素的Raspberry Pi 相机。

 

1942239fab4eb8f395a5570d1d1b56d5.png

只需使用相机连接器将相机模块连接到 Raspberry Pi 4 板即可。

 

c5ce52b92dfb235017065c0c81f539c7.jpeg

要使用相机,您需要先启用相机模块。sudo raspi-config通过在终端中键入内容来打开 Raspberry Pi 配置工具。导航至Interfacing Options>Camera并启用它。

什么是均方误差 (MSE) 和 Canny 边缘检测方法?

该项目使用Canny 边缘检测方法进行边缘检测,并使用均方误差 (MSE) 算法进行运动检测。这些步骤共同使 Canny 算法能够稳健地检测图像中的边缘。

均方误差 (MSE)

MSE是衡量两个图像或信号之间差异的常用指标。它计算两个信号或图像的对应值之间的平均平方差。

 

be07c6c1574ebd3aa9756864bd2cc5f8.png

MSE表明两者密切相关,而高 MSE表明存在显着差异。从数学上来说,对于两个图像IJ,MSE 由下式给出:

 

94a082c70768758f414a920146119a70.jpeg

其中mn是图像的尺寸。

Canny边缘检测方法

Canny方法是一种多步骤算法,旨在检测图像中的各种边缘

 

2312a93420fa56a756ccca75cd5a0479.jpeg

关键阶段包括:

  • 降噪:使用高斯滤波器对图像进行平滑处理以消除噪声。
  • 梯度计算:计算每个像素的梯度大小和方向,突出显示潜在的边缘。
  • 非极大值抑制:此步骤通过确保边缘方向上的梯度幅值最大来细化潜在边缘,从而减少边缘的厚度。
  • 双阈值:区分强边缘、弱边缘和非边缘,确保真正的边缘清晰。
  • 通过滞后进行边缘跟踪:根据弱边缘与强边缘的连接性,弱边缘会被丢弃或提升为强边缘。

Raspberry Pi 设置、库和依赖项安装

边缘检测运动传感以及代码中存在的其他图像处理任务需要OpenCV 。因此您需要先安装OpenCV。请按照以下指南在您的系统中安装 OpenCV

《如何在 Raspberry Pi 4 上安装和设置 OpenCV》

下一步是安装picamera因此使用pip安装它。

 

 
 

pip3 install picamera

设置部分现已完成。我们可以使用 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 个窗口,如下所示。

 

4cf4a519f0e9a67bb6ef871e6e2dd7d6.jpeg

第一个窗口将显示原始图像。第二个窗口将显示转换后的灰度图像。在第三个窗口中,将显示补偿后的图像,看起来更加清晰。第四张图像显示了边缘检测

Thonny Shell 将显示每秒估计的帧数

 

5f9c6613275969d922271fd690d1191b.png

它还将显示运动检测状态。这意味着每当物体移动或帧发生变化时,“检测到运动”就会显示在Thonny Shell上。

结论

使用 Raspberry Pi 和 OpenCV 进行边缘检测和运动传感项目是在实时场景中使用OpenCV集成多种图像处理技术的综合演示。它捕获视频帧,通过光照补偿对其进行增强,使用Canny 边缘检测来检测边缘,并通过均方误差方法监视帧间变化以检测运动

此外,它还实时显示处理后的图像并计算每秒帧数以衡量性能。这种技术组合不仅展示了OpenCV 的强大功能和灵活性,还为更先进的监视或监控系统奠定了基础,这些系统可以在不同的照明条件下有效运行并检测运动。