Waseem771 commited on
Commit
d0e82c7
·
verified ·
1 Parent(s): 1379cc7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -43
app.py CHANGED
@@ -21,17 +21,20 @@ def calculate_hrv(peaks):
21
  def estimate_respiratory_rate(signal_buffer, fps=30):
22
  respiration_peaks, _ = find_peaks(signal_buffer, distance=fps * 2)
23
  if len(respiration_peaks) > 1:
24
- return len(respiration_peaks) * 60.0 / (len(signal_buffer) / fps)
 
25
  return None
26
 
27
  def estimate_spo2(signal_buffer):
28
  green_channel = signal_buffer[:, 1]
29
  red_channel = signal_buffer[:, 2]
30
- return 100 - 5 * (np.mean(red_channel) / np.mean(green_channel))
 
31
 
32
- def get_heart_rate_from_video(video):
33
  face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
34
- cap = cv2.VideoCapture(video)
 
35
  buffer_size = 256
36
  bpm_list = []
37
  color_buffer = []
@@ -42,62 +45,81 @@ def get_heart_rate_from_video(video):
42
  ret, frame = cap.read()
43
  if not ret:
44
  break
 
45
  forehead = extract_forehead_region(frame, face_cascade)
46
  if forehead is not None:
47
  face_detected = True
48
  avg_color = np.mean(forehead, axis=(0, 1))
49
  color_buffer.append(avg_color)
 
50
  if len(color_buffer) >= buffer_size:
51
  color_buffer = np.array(color_buffer)
52
  green_channel = color_buffer[:, 1]
53
  green_channel = green_channel - np.mean(green_channel)
54
  signal_buffer.append(green_channel)
55
  peaks, _ = find_peaks(green_channel, distance=15)
 
56
  if len(peaks) > 1:
57
- avg_interval = np.mean(np.diff(peaks))
 
58
  avg_interval_sec = avg_interval / 30.0
59
  bpm = 60.0 / avg_interval_sec
60
  bpm_list.append(bpm)
61
  hrv = calculate_hrv(peaks)
 
62
  color_buffer = []
63
 
64
  cap.release()
65
 
66
  if not face_detected:
67
- return {"Error": "No face detected or unsupported video format."}, None
68
 
69
  results = {}
 
70
  if bpm_list:
71
  avg_bpm = np.mean(bpm_list)
72
  adjusted_bpm = avg_bpm - 15
73
  results['Heart Rate'] = f"{adjusted_bpm:.2f} BPM"
74
  else:
75
- results['Heart Rate'] = "Not detected"
76
 
77
- systolic_bp = 120 + 0.5 * (avg_bpm - 60)
78
- diastolic_bp = 80 + 0.3 * (avg_bpm - 60)
79
- results['Blood Pressure'] = f"{systolic_bp:.2f}/{diastolic_bp:.2f} mmHg"
80
- body_temperature = 36.5 if avg_bpm <= 100 else 37.0 + 0.1 * (avg_bpm - 100)
 
 
 
 
 
 
 
81
  results['Body Temperature'] = f"{body_temperature:.2f} °C"
82
 
83
  if signal_buffer:
84
  respiration_signal = np.concatenate(signal_buffer)
85
- resp_rate = estimate_respiratory_rate(respiration_signal)
86
- results['Respiratory Rate'] = (
87
- f"{resp_rate:.2f} breaths/min" if resp_rate else "Not detected"
88
- )
89
-
90
- if color_buffer != []:
91
- spo2_estimation = estimate_spo2(np.array(color_buffer))
92
- results['SpO2'] = f"{spo2_estimation:.2f}%"
93
-
94
- if adjusted_bpm < 60:
95
- results['Fatigue/Alertness'] = "Possible fatigue detected."
96
- elif adjusted_bpm > 100:
97
- results['Fatigue/Alertness'] = "Possible alertness or stress."
98
- else:
99
- results['Fatigue/Alertness'] = "Normal state detected."
100
 
 
 
 
 
 
 
 
 
 
101
  if signal_buffer:
102
  plt.figure(figsize=(12, 6))
103
  signal_array = np.concatenate(signal_buffer)
@@ -106,30 +128,34 @@ def get_heart_rate_from_video(video):
106
  plt.ylabel('Signal Intensity')
107
  plt.title('Green Channel Signal from Forehead')
108
  plt.legend()
109
- plt.savefig("signal_plot.png")
 
110
  plt.close()
111
- return results, "signal_plot.png"
112
 
113
- return results, None
114
 
115
- def process_video(video):
116
- return get_heart_rate_from_video(video)
117
 
118
- objective = "Objective: AI-powered health app that estimates vital signs using face video.\n"
119
- team_members = (
120
- "Team:\n"
121
- "- Irfan Jamshed (ID#2697) - engr.irfan@must.edu.pk\n"
122
- "- Adnan Munir (ID#2031) - adnanmunir41@yahoo.com\n"
123
- "- Muhammad Hannan Rauf (ID#2421) - hananrauf1@gmail.com\n"
124
- "- Waseem Hassan (ID#2807) - engr.waseem77@gmail.com\n"
125
- "- Dua Javed (ID#647) - duaajaved321@gmail.com\n"
126
- )
 
127
 
128
  iface = gr.Interface(
129
  fn=process_video,
130
- inputs=gr.Video(label="Upload Facial Video"),
131
- outputs=[gr.JSON(label="Vital Signs"), gr.Image(label="Signal Plot")],
132
- title="HeartSense: Video-Based Health Monitoring",
 
 
 
133
  description=objective + team_members
134
  )
135
 
 
21
  def estimate_respiratory_rate(signal_buffer, fps=30):
22
  respiration_peaks, _ = find_peaks(signal_buffer, distance=fps * 2)
23
  if len(respiration_peaks) > 1:
24
+ respiratory_rate = len(respiration_peaks) * 60.0 / (len(signal_buffer) / fps)
25
+ return respiratory_rate
26
  return None
27
 
28
  def estimate_spo2(signal_buffer):
29
  green_channel = signal_buffer[:, 1]
30
  red_channel = signal_buffer[:, 2]
31
+ spo2_estimation = 100 - 5 * (np.mean(red_channel) / np.mean(green_channel))
32
+ return spo2_estimation
33
 
34
+ def get_heart_rate_from_video(video_path):
35
  face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
36
+ cap = cv2.VideoCapture(video_path)
37
+
38
  buffer_size = 256
39
  bpm_list = []
40
  color_buffer = []
 
45
  ret, frame = cap.read()
46
  if not ret:
47
  break
48
+
49
  forehead = extract_forehead_region(frame, face_cascade)
50
  if forehead is not None:
51
  face_detected = True
52
  avg_color = np.mean(forehead, axis=(0, 1))
53
  color_buffer.append(avg_color)
54
+
55
  if len(color_buffer) >= buffer_size:
56
  color_buffer = np.array(color_buffer)
57
  green_channel = color_buffer[:, 1]
58
  green_channel = green_channel - np.mean(green_channel)
59
  signal_buffer.append(green_channel)
60
  peaks, _ = find_peaks(green_channel, distance=15)
61
+
62
  if len(peaks) > 1:
63
+ peak_intervals = np.diff(peaks)
64
+ avg_interval = np.mean(peak_intervals)
65
  avg_interval_sec = avg_interval / 30.0
66
  bpm = 60.0 / avg_interval_sec
67
  bpm_list.append(bpm)
68
  hrv = calculate_hrv(peaks)
69
+
70
  color_buffer = []
71
 
72
  cap.release()
73
 
74
  if not face_detected:
75
+ return {"Error": "No face detected or unsupported video."}, None
76
 
77
  results = {}
78
+
79
  if bpm_list:
80
  avg_bpm = np.mean(bpm_list)
81
  adjusted_bpm = avg_bpm - 15
82
  results['Heart Rate'] = f"{adjusted_bpm:.2f} BPM"
83
  else:
84
+ results['Heart Rate'] = "No heart rate detected."
85
 
86
+ if bpm_list:
87
+ systolic_bp = 120 + 0.5 * (avg_bpm - 60)
88
+ diastolic_bp = 80 + 0.3 * (avg_bpm - 60)
89
+ results['Blood Pressure'] = f"{systolic_bp:.2f}/{diastolic_bp:.2f} mmHg"
90
+ else:
91
+ results['Blood Pressure'] = "Unavailable"
92
+
93
+ if bpm_list and avg_bpm > 100:
94
+ body_temperature = 37.0 + 0.1 * (avg_bpm - 100)
95
+ else:
96
+ body_temperature = 36.5
97
  results['Body Temperature'] = f"{body_temperature:.2f} °C"
98
 
99
  if signal_buffer:
100
  respiration_signal = np.concatenate(signal_buffer)
101
+ respiratory_rate = estimate_respiratory_rate(respiration_signal)
102
+ if respiratory_rate:
103
+ results['Respiratory Rate'] = f"{respiratory_rate:.2f} breaths/min"
104
+ else:
105
+ results['Respiratory Rate'] = "Unable to estimate"
106
+
107
+ if color_buffer:
108
+ try:
109
+ spo2_estimation = estimate_spo2(np.array(color_buffer))
110
+ results['SpO2'] = f"{spo2_estimation:.2f}%"
111
+ except:
112
+ results['SpO2'] = "Error estimating SpO2"
 
 
 
113
 
114
+ if bpm_list:
115
+ if adjusted_bpm < 60:
116
+ results['Fatigue/Alertness'] = "Possible fatigue detected."
117
+ elif adjusted_bpm > 100:
118
+ results['Fatigue/Alertness'] = "Possible alertness or stress detected."
119
+ else:
120
+ results['Fatigue/Alertness'] = "Normal state detected."
121
+
122
+ plot_path = None
123
  if signal_buffer:
124
  plt.figure(figsize=(12, 6))
125
  signal_array = np.concatenate(signal_buffer)
 
128
  plt.ylabel('Signal Intensity')
129
  plt.title('Green Channel Signal from Forehead')
130
  plt.legend()
131
+ plot_path = "signal_plot.png"
132
+ plt.savefig(plot_path)
133
  plt.close()
 
134
 
135
+ return results, plot_path
136
 
137
+ def process_video(video_path):
138
+ return get_heart_rate_from_video(video_path)
139
 
140
+ # Gradio interface
141
+ objective = "Objective: To develop a Gradio-based application that estimates vital signs using facial video.\n\n"
142
+ team_members = """
143
+ Team Members:
144
+ - Irfan Jamshed (ID#2697) - engr.irfan@must.edu.pk
145
+ - Adnan Munir (ID#2031) - adnanmunir41@yahoo.com
146
+ - Muhammad Hannan Rauf (ID#2421) - hananrauf1@gmail.com
147
+ - Waseem Hassan (ID#2807) - engr.waseem77@gmail.com
148
+ - Dua Javed (ID#647) - duaajaved321@gmail.com
149
+ """
150
 
151
  iface = gr.Interface(
152
  fn=process_video,
153
+ inputs=gr.Video(label="Upload Video", type="filepath", format="mp4"),
154
+ outputs=[
155
+ gr.JSON(label="Vital Signs"),
156
+ gr.Image(label="Signal Plot")
157
+ ],
158
+ title="HeartSense: AI-Based Health Monitoring from Facial Video",
159
  description=objective + team_members
160
  )
161