问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

基于计算机视觉的呼吸频率检测方法

创作时间:
作者:
@小白创作中心

基于计算机视觉的呼吸频率检测方法

引用
CSDN
1.
https://blog.csdn.net/weixin_40277125/article/details/143366791

本文介绍了一种基于计算机视觉的呼吸频率检测方法,通过从视频中提取帧并定义ROI区域,计算ROI中的运动幅度,进而检测呼吸频率。文章提供了完整的Python代码实现,包括视频读取、灰度转换、ROI提取、运动幅度计算、数据平滑、峰值检测等关键步骤,并展示了具体的结果图像。

基本流程

  1. 从视频中提取帧并定义ROI区域
  2. 计算ROI中的运动幅度
  3. 基于运动幅度检测呼吸频率

代码实现

import cv2
import numpy as np
from scipy.ndimage import gaussian_filter1d
from scipy.signal import find_peaks
import matplotlib.pyplot as plt

def preprocess_and_detect_motion(video_path, initial_roi=(676, 485, 296, 315)):
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        raise ValueError("无法打开视频文件,请检查路径是否正确")
    
    fps = cap.get(cv2.CAP_PROP_FPS)
    if fps is None or fps <= 0:
        raise ValueError("无法获取视频的帧率,请检查视频文件")
    ret, frame = cap.read()
    if not ret:
        raise ValueError("无法读取视频帧,请检查视频文件")
    # 初始化 ROI
    x_start, y_start, width, height = initial_roi
    movements = []
    prev_roi_frame = None
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        
        # 转换为灰度图像并提取 ROI 区域
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        roi_frame = gray[y_start:y_start+height, x_start:x_start+width]
        
        if prev_roi_frame is not None:
            # 确保 ROI 大小匹配
            if prev_roi_frame.shape == roi_frame.shape:
                diff = cv2.absdiff(prev_roi_frame, roi_frame)
                movement = np.mean(diff)
                movements.append(movement)
        
        prev_roi_frame = roi_frame
    cap.release()
    return movements, fps

def calculate_breathing_rate(movements, fps):
    if len(movements) == 0:
        return 0
    
    # 平滑数据
    smooth_movements = gaussian_filter1d(movements, sigma=1)
    peaks, _ = find_peaks(smooth_movements, distance=fps / 3)
    breath_rate = len(peaks) / (len(smooth_movements) / fps / 60)
    
    # 可视化
    time_axis = np.arange(len(smooth_movements)) / fps
    plt.plot(time_axis, smooth_movements, label='Smoothed Movement')
    plt.plot(time_axis[peaks], smooth_movements[peaks], "x", label='Breaths Detected')
    plt.title("Breathing Movement over Time")
    plt.xlabel("Time (s)")
    plt.ylabel("Smoothed Movement Amplitude")
    plt.legend()
    plt.show()
    
    return breath_rate

def main():
    video_path = 'Sow_fast_breathing.mp4'
    initial_roi = (676, 485, 296, 315)   # 替换为适当的ROI区域(x_start, y_start, width, height)
    
    movements, fps = preprocess_and_detect_motion(video_path, initial_roi)
    
    if movements:
        breath_rate = calculate_breathing_rate(movements, fps)
        print(f"Estimated Breathing Rate: {breath_rate:.2f} breaths per minute")
    else:
        print("未检测到任何运动")

if __name__ == "__main__":
    main()

参数调整

可以调整sigmadistance参数以优化峰值检测效果。例如,将sigma设置为0.5,将distance设置为fps/4可以检测到更多的峰值。

手动选择ROI区域

可以使用以下代码手动选择ROI区域:

import cv2

video_path = 'Sow_fast_breathing.mp4'
cap = cv2.VideoCapture(video_path)
ret, frame = cap.read()
if ret:
    roi = cv2.selectROI("Select ROI", frame, fromCenter=False, showCrosshair=True)
    cv2.destroyAllWindows()
    print("Selected ROI:", roi)  # 输出格式为 (x, y, width, height)
cap.release()

结果展示

以下是检测结果的可视化图像:

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号