Rename run.py to app.py

#1
by IFMedTechdemo - opened
Files changed (2) hide show
  1. app.py +141 -0
  2. run.py +0 -16
app.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ import cv2
4
+ import numpy as np
5
+ from collections import deque
6
+ import time
7
+
8
+ # Length of signal history to display (in samples)
9
+ MAX_LEN = 500
10
+
11
+ # Deques to store PPG samples and timestamps
12
+ red_signal = deque(maxlen=MAX_LEN)
13
+ green_signal = deque(maxlen=MAX_LEN)
14
+ timestamps = deque(maxlen=MAX_LEN)
15
+
16
+ def process_frame(frame, state):
17
+ """
18
+ frame: numpy array (BGR or RGB, Gradio passes RGB by default)
19
+ state: dict holding rolling signals
20
+ """
21
+ if frame is None:
22
+ return None, state["red"], state["green"], state["time"]
23
+
24
+ img = frame.copy()
25
+ h, w, _ = img.shape
26
+
27
+ # Ensure image is in RGB
28
+ # If needed, convert from BGR to RGB; Gradio webcam is usually RGB already
29
+ # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
30
+
31
+ # Define ROI: square with side = 1/5 of frame height, centered
32
+ box_size = h // 5
33
+ cx, cy = w // 2, h // 2
34
+ x1 = cx - box_size // 2
35
+ y1 = cy - box_size // 2
36
+ x2 = cx + box_size // 2
37
+ y2 = cy + box_size // 2
38
+
39
+ # Clamp to frame bounds
40
+ x1 = max(0, x1); y1 = max(0, y1)
41
+ x2 = min(w, x2); y2 = min(h, y2)
42
+
43
+ # Draw green bounding box
44
+ cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
45
+
46
+ # Extract ROI
47
+ roi = img[y1:y2, x1:x2, :]
48
+
49
+ if roi.size > 0:
50
+ # Compute mean intensity for R and G channels (assuming RGB)
51
+ # img shape: (H, W, 3) -> channels: R=0, G=1, B=2 if RGB
52
+ # If your frame is BGR, swap indices accordingly.
53
+ roi_float = roi.astype(np.float32)
54
+ red_mean = float(np.mean(roi_float[..., 0]))
55
+ green_mean = float(np.mean(roi_float[..., 1]))
56
+ else:
57
+ red_mean = 0.0
58
+ green_mean = 0.0
59
+
60
+ t = time.time()
61
+
62
+ # Update deques
63
+ state["red"].append(red_mean)
64
+ state["green"].append(green_mean)
65
+ state["time"].append(t)
66
+
67
+ # Convert to list for plotting
68
+ red_list = list(state["red"])
69
+ green_list = list(state["green"])
70
+ time_list = list(state["time"])
71
+
72
+ # Optional: normalize time to start at 0
73
+ if len(time_list) > 0:
74
+ t0 = time_list[0]
75
+ time_list = [ti - t0 for ti in time_list]
76
+
77
+ # Return:
78
+ # - processed image with box
79
+ # - data for plots (as lists)
80
+ return img, red_list, green_list, time_list
81
+
82
+
83
+ def snap(frame, state):
84
+ """
85
+ Wrapper for Gradio streaming.
86
+ Gradio passes latest frame, we update state and return:
87
+ - video frame with bounding box
88
+ - red PPG
89
+ - green PPG
90
+ """
91
+ img, red_list, green_list, time_list = process_frame(frame, state)
92
+
93
+ # Build plot data for Gradio Plot component:
94
+ # each as { "x": [...], "y": [...] }
95
+ red_plot = {
96
+ "x": time_list,
97
+ "y": red_list,
98
+ "mode": "lines",
99
+ "name": "Red PPG",
100
+ }
101
+ green_plot = {
102
+ "x": time_list,
103
+ "y": green_list,
104
+ "mode": "lines",
105
+ "name": "Green PPG",
106
+ }
107
+
108
+ # Plotly-style dict
109
+ plot_data = {
110
+ "data": [red_plot, green_plot],
111
+ "layout": {
112
+ "title": "Red & Green PPG",
113
+ "xaxis": {"title": "Time (s)"},
114
+ "yaxis": {"title": "Intensity"},
115
+ },
116
+ }
117
+
118
+ return img, plot_data, state
119
+
120
+
121
+ with gr.Blocks() as demo:
122
+ # Stateful object to store signals across frames
123
+ state = gr.State({"red": red_signal, "green": green_signal, "time": timestamps})
124
+
125
+ with gr.Row():
126
+ cam = gr.Image(
127
+ source="webcam",
128
+ streaming=True, # continuous streaming
129
+ label="Webcam with ROI",
130
+ )
131
+ plot = gr.Plot(label="PPG Signals (Red & Green)")
132
+
133
+ # When webcam streams, call snap continuously
134
+ cam.stream(
135
+ fn=snap,
136
+ inputs=[cam, state],
137
+ outputs=[cam, plot, state],
138
+ )
139
+
140
+ if __name__ == "__main__":
141
+ demo.launch()
run.py DELETED
@@ -1,16 +0,0 @@
1
-
2
- import gradio as gr
3
-
4
-
5
- def snap(image, video):
6
- return [image, video]
7
-
8
-
9
- demo = gr.Interface(
10
- snap,
11
- [gr.Image(source="webcam", tool=None), gr.Video(source="webcam")],
12
- ["image", "video"],
13
- )
14
-
15
- if __name__ == "__main__":
16
- demo.launch()