SuriRaja commited on
Commit
7e2c1f5
·
verified ·
1 Parent(s): e5ac99c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +125 -25
app.py CHANGED
@@ -1,16 +1,14 @@
1
  # Face Detection-Based AI Automation of Lab Tests
2
- # Gradio App with OpenCV + MediaPipe + rPPG Integration for Hugging Face Spaces
3
 
4
  import gradio as gr
5
  import cv2
6
  import numpy as np
7
  import mediapipe as mp
8
 
9
- # Setup Mediapipe Face Mesh
10
  mp_face_mesh = mp.solutions.face_mesh
11
  face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5)
12
 
13
- # Function to calculate mean green intensity (simplified rPPG)
14
  def estimate_heart_rate(frame, landmarks):
15
  h, w, _ = frame.shape
16
  forehead_pts = [landmarks[10], landmarks[338], landmarks[297], landmarks[332]]
@@ -19,19 +17,56 @@ def estimate_heart_rate(frame, landmarks):
19
  cv2.fillConvexPoly(mask, pts, 255)
20
  green_channel = cv2.split(frame)[1]
21
  mean_intensity = cv2.mean(green_channel, mask=mask)[0]
22
- heart_rate = int(60 + 30 * np.sin(mean_intensity / 255.0 * np.pi)) # Simulated
23
  return heart_rate
24
 
25
- # Estimate SpO2 and Respiratory Rate (simulated based on heart rate)
26
  def estimate_spo2_rr(heart_rate):
27
  spo2 = min(100, max(90, 97 + (heart_rate % 5 - 2)))
28
  rr = int(12 + abs(heart_rate % 5 - 2))
29
  return spo2, rr
30
 
31
- # Main analysis function
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  def analyze_face(image):
33
  if image is None:
34
- return {"error": "No image provided"}, None
35
 
36
  frame_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
37
  result = face_mesh.process(frame_rgb)
@@ -41,25 +76,90 @@ def analyze_face(image):
41
  heart_rate = estimate_heart_rate(frame_rgb, landmarks)
42
  spo2, rr = estimate_spo2_rr(heart_rate)
43
 
44
- report = {
45
- "Hemoglobin": "12.3 g/dL (Estimated)",
46
- "SpO2": f"{spo2}%",
47
- "Heart Rate": f"{heart_rate} bpm",
48
- "Blood Pressure": "Low",
49
- "Respiratory Rate": f"{rr} breaths/min",
50
- "Risk Flags": ["Anemia Mild", "Hydration Low"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  }
52
- return report, frame_rgb
53
  else:
54
- return {"error": "Face not detected"}, None
55
-
56
- # Launch UI
57
- demo = gr.Interface(
58
- fn=analyze_face,
59
- inputs=gr.Image(type="numpy", label="Upload a Face Image"),
60
- outputs=[gr.JSON(label="AI Diagnostic Report"), gr.Image(label="Annotated Image")],
61
- title="Face-Based AI Lab Test Automation",
62
- description="Upload a face image to estimate basic vital signs and lab test indicators using AI-based visual inference."
63
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
  demo.launch()
 
1
  # Face Detection-Based AI Automation of Lab Tests
2
+ # Gradio App with Mobile-Responsive UI and Risk-Level Coloring
3
 
4
  import gradio as gr
5
  import cv2
6
  import numpy as np
7
  import mediapipe as mp
8
 
 
9
  mp_face_mesh = mp.solutions.face_mesh
10
  face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5)
11
 
 
12
  def estimate_heart_rate(frame, landmarks):
13
  h, w, _ = frame.shape
14
  forehead_pts = [landmarks[10], landmarks[338], landmarks[297], landmarks[332]]
 
17
  cv2.fillConvexPoly(mask, pts, 255)
18
  green_channel = cv2.split(frame)[1]
19
  mean_intensity = cv2.mean(green_channel, mask=mask)[0]
20
+ heart_rate = int(60 + 30 * np.sin(mean_intensity / 255.0 * np.pi))
21
  return heart_rate
22
 
 
23
  def estimate_spo2_rr(heart_rate):
24
  spo2 = min(100, max(90, 97 + (heart_rate % 5 - 2)))
25
  rr = int(12 + abs(heart_rate % 5 - 2))
26
  return spo2, rr
27
 
28
+ def get_risk_color(value, normal_range):
29
+ low, high = normal_range
30
+ if value < low:
31
+ return "🔻 LOW"
32
+ elif value > high:
33
+ return "🔺 HIGH"
34
+ else:
35
+ return "✅ Normal"
36
+
37
+ def generate_flags_extended(params):
38
+ hb, wbc, platelets, iron, ferritin, tibc, bilirubin, creatinine, tsh, cortisol, fbs, hba1c = params
39
+ flags = []
40
+ if hb < 13.5:
41
+ flags.append("Hemoglobin Low - Possible Anemia")
42
+ if wbc < 4.0 or wbc > 11.0:
43
+ flags.append("Abnormal WBC Count - Possible Infection")
44
+ if platelets < 150:
45
+ flags.append("Platelet Drop Risk - Bruising Possible")
46
+ if iron < 60:
47
+ flags.append("Iron Deficiency Detected")
48
+ if ferritin < 30:
49
+ flags.append("Low Ferritin - Iron Store Low")
50
+ if tibc > 400:
51
+ flags.append("High TIBC - Iron Absorption Issue")
52
+ if bilirubin > 1.2:
53
+ flags.append("Jaundice Detected - Elevated Bilirubin")
54
+ if creatinine > 1.2:
55
+ flags.append("Kidney Function Concern - High Creatinine")
56
+ if tsh < 0.4 or tsh > 4.0:
57
+ flags.append("Thyroid Imbalance - Check TSH")
58
+ if cortisol < 5 or cortisol > 25:
59
+ flags.append("Stress Hormone Abnormality - Cortisol")
60
+ if fbs > 110:
61
+ flags.append("High Fasting Blood Sugar")
62
+ if hba1c > 5.7:
63
+ flags.append("Elevated HbA1c - Diabetes Risk")
64
+ flags.append("Mood / Stress analysis requires separate behavioral model")
65
+ return flags
66
+
67
  def analyze_face(image):
68
  if image is None:
69
+ return {}, None
70
 
71
  frame_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
72
  result = face_mesh.process(frame_rgb)
 
76
  heart_rate = estimate_heart_rate(frame_rgb, landmarks)
77
  spo2, rr = estimate_spo2_rr(heart_rate)
78
 
79
+ hb, wbc, platelets = 12.3, 6.4, 210
80
+ iron, ferritin, tibc = 55, 45, 340
81
+ bilirubin, creatinine = 1.5, 1.3
82
+ tsh, cortisol = 2.5, 18
83
+ fbs, hba1c = 120, 6.2
84
+
85
+ flags = generate_flags_extended([hb, wbc, platelets, iron, ferritin, tibc, bilirubin, creatinine, tsh, cortisol, fbs, hba1c])
86
+
87
+ sections = {
88
+ "🩸 Hematology": [
89
+ f"Hemoglobin (Hb): {hb} g/dL - {get_risk_color(hb, (13.5, 17.5))}",
90
+ f"WBC Count: {wbc} x10^3/uL - {get_risk_color(wbc, (4.0, 11.0))}",
91
+ f"Platelet Count: {platelets} x10^3/uL - {get_risk_color(platelets, (150, 450))}"
92
+ ],
93
+ "🧬 Iron & Liver Panel": [
94
+ f"Iron: {iron} µg/dL - {get_risk_color(iron, (60, 170))}",
95
+ f"Ferritin: {ferritin} ng/mL - {get_risk_color(ferritin, (30, 300))}",
96
+ f"TIBC: {tibc} µg/dL - {get_risk_color(tibc, (250, 400))}",
97
+ f"Bilirubin: {bilirubin} mg/dL - {get_risk_color(bilirubin, (0.3, 1.2))}"
98
+ ],
99
+ "🧪 Kidney, Thyroid & Stress": [
100
+ f"Creatinine: {creatinine} mg/dL - {get_risk_color(creatinine, (0.6, 1.2))}",
101
+ f"TSH: {tsh} µIU/mL - {get_risk_color(tsh, (0.4, 4.0))}",
102
+ f"Cortisol: {cortisol} µg/dL - {get_risk_color(cortisol, (5, 25))}"
103
+ ],
104
+ "🧁 Metabolic Panel": [
105
+ f"Fasting Blood Sugar: {fbs} mg/dL - {get_risk_color(fbs, (70, 110))}",
106
+ f"HbA1c: {hba1c}% - {get_risk_color(hba1c, (4.0, 5.7))}"
107
+ ],
108
+ "❤️ Vital Signs": [
109
+ f"SpO2: {spo2}% - {get_risk_color(spo2, (95, 100))}",
110
+ f"Heart Rate: {heart_rate} bpm - {get_risk_color(heart_rate, (60, 100))}",
111
+ f"Respiratory Rate: {rr} breaths/min - {get_risk_color(rr, (12, 20))}",
112
+ "Blood Pressure: Low (simulated)"
113
+ ],
114
+ "⚠️ Risk Flags": flags
115
  }
116
+ return sections, frame_rgb
117
  else:
118
+ return {"⚠️ Error": ["Face not detected"]}, None
119
+
120
+ # Mobile-optimized UI with styled labels
121
+ demo = gr.Blocks(css="""
122
+ @media only screen and (max-width: 768px) {
123
+ .gr-block.gr-column { width: 100% !important; }
124
+ }
125
+ """)
126
+ with demo:
127
+ gr.Markdown("""
128
+ # 🧠 Face-Based AI Lab Test Inference
129
+ Upload a clear face image to simulate categorized lab reports with visual grouping.
130
+ """)
131
+
132
+ with gr.Row():
133
+ with gr.Column(scale=1):
134
+ image_input = gr.Image(type="numpy", label="📸 Upload a Face Image")
135
+ submit_btn = gr.Button("🔍 Analyze Now")
136
+ with gr.Column(scale=2):
137
+ accordion_output = gr.Accordion("📂 Diagnostic Summary", open=True)
138
+ with accordion_output:
139
+ result_html = gr.HighlightedText(label="📊 Grouped Report", combine_adjacent=True)
140
+ result_image = gr.Image(label="🧍 Annotated Face Scan")
141
+
142
+ def format_report(sections):
143
+ lines = []
144
+ for title, values in sections.items():
145
+ lines.append((f"{title}",))
146
+ for item in values:
147
+ lines.append((f" - {item}",))
148
+ return lines
149
+
150
+ submit_btn.click(
151
+ fn=analyze_face,
152
+ inputs=image_input,
153
+ outputs=[result_html, result_image],
154
+ preprocess=False,
155
+ postprocess=False,
156
+ _js="(data) => [data]"
157
+ ).then(
158
+ fn=format_report,
159
+ inputs=None,
160
+ outputs=result_html
161
+ )
162
+
163
+ gr.Markdown("---\n✅ Optimized for Mobile · Risk Indicators: 🔻 Low, 🔺 High, ✅ Normal")
164
 
165
  demo.launch()