File size: 2,321 Bytes
efabbbd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt
import tempfile
import cv2
from scipy.signal import find_peaks, butter, filtfilt

def extract_ppg_signal(video_file):
    cap = cv2.VideoCapture(video_file)
    ppg_signal = []
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        ppg_signal.append(np.mean(cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)))
    cap.release()
    return np.array(ppg_signal)

def process_ppg_signal(ppg_signal, fs=30):
    nyquist = 0.5 * fs
    b, a = butter(1, [0.5 / nyquist, 3.0 / nyquist], btype='band')
    return filtfilt(b, a, ppg_signal)

def detect_hrv(video_file):
    filtered_signal = process_ppg_signal(extract_ppg_signal(video_file))
    peaks, _ = find_peaks(filtered_signal, distance=15)  # 30 fps / 2.5
    rr_intervals = np.diff(peaks) / 30
    heart_rate = 60 / rr_intervals.mean()
    hrv = np.std(rr_intervals)
    
    plt.figure(figsize=(10, 4))
    time = np.arange(len(filtered_signal)) / 30
    plt.plot(time, filtered_signal, label='Filtered PPG Signal')
    plt.plot(time[peaks], filtered_signal[peaks], 'ro', label='Detected Peaks')
    plt.title('Heart Rate Variability over Time')
    plt.xlabel('Time (s)')
    plt.ylabel('PPG Signal Intensity')
    plt.legend()
    plt.tight_layout()
    with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as temp_file:
        plt.savefig(temp_file.name)
    plt.close()
    
    return f"{hrv:.2f} ms", f"{heart_rate:.2f} BPM", temp_file.name

def create_hrv_tab():
    with gr.Row():
        with gr.Column(scale=2):
            input_video = gr.Video(label="Input Video")
            with gr.Row():
                clear_btn = gr.Button("Clear", scale=1)
                submit_btn = gr.Button("Analyze", scale=1, elem_classes="submit")
        with gr.Column(scale=1):
            output_hrv = gr.Label(label="HRV Value")
            output_hr = gr.Label(label="Average Heart Rate")
            output_plot = gr.Image(label="HRV Plot")
    
    submit_btn.click(detect_hrv, inputs=[input_video], outputs=[output_hrv, output_hr, output_plot], queue=True)
    clear_btn.click(lambda: (None, None, None, None), outputs=[input_video, output_hrv, output_hr, output_plot], queue=True)
    gr.Examples(["./assets/videos/fitness.mp4"], [input_video])