File size: 4,276 Bytes
eb3d3f0
1ccaea2
eb3d3f0
0983def
eb3d3f0
 
 
 
 
0983def
eb3d3f0
 
 
 
 
 
 
 
 
7e2c1f5
eb3d3f0
 
 
 
 
 
 
7e2c1f5
 
 
1ccaea2
7e2c1f5
1ccaea2
7e2c1f5
1ccaea2
7e2c1f5
0983def
 
1ccaea2
eb3d3f0
0983def
 
2306344
1ccaea2
2306344
 
 
 
 
 
 
 
 
 
 
1ccaea2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb3d3f0
0983def
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# Face Detection-Based AI Automation of Lab Tests
# Redesigned UI using Gradio Blocks + HTML Cards

import gradio as gr
import cv2
import numpy as np
import mediapipe as mp

mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5)

def estimate_heart_rate(frame, landmarks):
    h, w, _ = frame.shape
    forehead_pts = [landmarks[10], landmarks[338], landmarks[297], landmarks[332]]
    mask = np.zeros((h, w), dtype=np.uint8)
    pts = np.array([[int(pt.x * w), int(pt.y * h)] for pt in forehead_pts], np.int32)
    cv2.fillConvexPoly(mask, pts, 255)
    green_channel = cv2.split(frame)[1]
    mean_intensity = cv2.mean(green_channel, mask=mask)[0]
    heart_rate = int(60 + 30 * np.sin(mean_intensity / 255.0 * np.pi))
    return heart_rate

def estimate_spo2_rr(heart_rate):
    spo2 = min(100, max(90, 97 + (heart_rate % 5 - 2)))
    rr = int(12 + abs(heart_rate % 5 - 2))
    return spo2, rr

def get_risk_color(value, normal_range):
    low, high = normal_range
    if value < low:
        return ("πŸ”» LOW", "#FFCCCC")  # Red background
    elif value > high:
        return ("πŸ”Ί HIGH", "#FFE680")  # Yellow background
    else:
        return ("βœ… Normal", "#CCFFCC")  # Green background

def analyze_face(image):
    if image is None:
        return [], None

    frame_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    result = face_mesh.process(frame_rgb)
    if not result.multi_face_landmarks:
        return [["Face not detected", "#FFDDDD"]], None

    landmarks = result.multi_face_landmarks[0].landmark
    heart_rate = estimate_heart_rate(frame_rgb, landmarks)
    spo2, rr = estimate_spo2_rr(heart_rate)

    hb, wbc, platelets = 12.3, 6.4, 210
    iron, ferritin, tibc = 55, 45, 340
    bilirubin, creatinine = 1.5, 1.3
    tsh, cortisol = 2.5, 18
    fbs, hba1c = 120, 6.2

    def section(title, items):
        html = f'<div style="padding:10px;border:1px solid #ccc;border-radius:8px;margin-bottom:10px;background:#f8f9fa;">'
        html += f'<h4 style="margin:0 0 10px 0">{title}</h4>'
        for label, val, rng in items:
            status, bgcolor = get_risk_color(val, rng)
            html += f'<div style="padding:6px;margin-bottom:4px;background:{bgcolor};border-radius:4px;">{label}: {val} - {status}</div>'
        html += '</div>'
        return html

    cards = [
        section("🩸 Hematology", [
            ("Hemoglobin", hb, (13.5, 17.5)),
            ("WBC Count", wbc, (4.0, 11.0)),
            ("Platelets", platelets, (150, 450))
        ]),
        section("🧬 Iron & Liver Panel", [
            ("Iron", iron, (60, 170)),
            ("Ferritin", ferritin, (30, 300)),
            ("TIBC", tibc, (250, 400)),
            ("Bilirubin", bilirubin, (0.3, 1.2))
        ]),
        section("πŸ§ͺ Kidney, Thyroid & Stress", [
            ("Creatinine", creatinine, (0.6, 1.2)),
            ("TSH", tsh, (0.4, 4.0)),
            ("Cortisol", cortisol, (5, 25))
        ]),
        section("🧁 Metabolic Panel", [
            ("Fasting Blood Sugar", fbs, (70, 110)),
            ("HbA1c", hba1c, (4.0, 5.7))
        ]),
        section("❀️ Vital Signs", [
            ("SpO2", spo2, (95, 100)),
            ("Heart Rate", heart_rate, (60, 100)),
            ("Respiratory Rate", rr, (12, 20))
        ])
    ]
    return cards, frame_rgb

# Gradio App Layout (Custom UI with Cards)
demo = gr.Blocks()
with demo:
    gr.Markdown("""
    # 🧠 Face-Based Lab Test AI Report
    Upload a face photo to infer health diagnostics with AI-based visual markers.
    """)

    with gr.Row():
        with gr.Column(scale=1):
            image_input = gr.Image(type="numpy", label="πŸ“Έ Upload Face Image")
            submit_btn = gr.Button("πŸ” Analyze")
        with gr.Column(scale=2):
            result_html = gr.HTML(label="πŸ§ͺ Visual Diagnostic Cards")
            result_image = gr.Image(label="πŸ“· Face Scan Annotated")

    def format_html(cards):
        return "".join(cards)

    submit_btn.click(
        fn=analyze_face,
        inputs=image_input,
        outputs=[result_html, result_image]
    ).then(
        fn=format_html,
        inputs=None,
        outputs=result_html
    )

demo.launch()