File size: 5,030 Bytes
12f490a
 
9ac8c85
 
 
e82b84e
 
12f490a
9ac8c85
e82b84e
9ac8c85
12f490a
e82b84e
 
 
12f490a
e82b84e
 
 
 
 
 
 
 
 
81c7aed
 
e82b84e
 
9ac8c85
 
e82b84e
 
9ac8c85
e284c36
12f490a
9ac8c85
 
 
e82b84e
9ac8c85
e82b84e
9ac8c85
 
 
e82b84e
9ac8c85
 
12f490a
e82b84e
 
 
9ac8c85
e82b84e
81c7aed
e82b84e
 
 
 
 
 
 
 
 
 
 
9ac8c85
e82b84e
 
9ac8c85
 
 
 
e82b84e
9ac8c85
 
 
e82b84e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81c7aed
9ac8c85
12f490a
9ac8c85
 
 
e284c36
 
e82b84e
 
 
 
e284c36
12f490a
 
9ac8c85
e284c36
9ac8c85
 
12f490a
 
 
e284c36
 
9ac8c85
 
12f490a
 
e82b84e
9ac8c85
e284c36
 
e82b84e
 
e284c36
12f490a
e82b84e
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
125
126
127
128
129
130
131
132
import gradio as gr
import torch
from ultralyticsplus import YOLO
from PIL import Image, ImageDraw, ImageFont
import numpy as np
from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing.image import img_to_array

# Tải model YOLO (detection)
yolo_model_path = "best.pt"
yolo_model = YOLO(yolo_model_path)

# Tải model classification (.h5)
classification_model_path = "classification.h5"
class_model = load_model(classification_model_path)

# Danh sách lớp theo thứ tự model classification
class_labels = ['Acne', 'Comedones', 'Papule', 'Pustule']

# Ánh xạ tiếng Anh -> tiếng Việt
class_mapping = {
    'Acne': 'Mụn trứng cá',
    'Comedones': 'Mụn cám',
    'Papule': 'Mụn sẩn',
    'Pustule': 'Mụn mủ'
}

def detect_and_classify(image, image_size, conf_threshold=0.4, iou_threshold=0.5):
    # image là đường dẫn file
    pil_image = Image.open(image).convert("RGB")

    # Detect vùng mụn với YOLO
    results = yolo_model.predict(pil_image, conf=conf_threshold, iou=iou_threshold, imgsz=image_size)
    boxes = results[0].boxes
    num_boxes = len(boxes)

    if num_boxes == 0:
        severity = "Tốt"
        recommendation = "Làn da bạn khá ổn! Tiếp tục duy trì thói quen chăm sóc da."
        return image, f"Tình trạng mụn: {severity}", recommendation, "Không phát hiện mụn."

    # Lấy toạ độ bounding box
    xyxy = boxes.xyxy.detach().cpu().numpy().astype(int)
    confidences = boxes.conf.detach().cpu().numpy()

    # Chuẩn bị vẽ
    draw = ImageDraw.Draw(pil_image)
    font = ImageFont.load_default()

    # Classification từng box
    classified_results = []
    for i, box in enumerate(xyxy, start=1):
        x1, y1, x2, y2 = box
        crop = pil_image.crop((x1, y1, x2, y2))

        # Tiền xử lý crop để đưa vào classification model
        crop_resized = crop.resize((224, 224))
        img_arr = img_to_array(crop_resized) / 255.0
        img_arr = np.expand_dims(img_arr, axis=0)

        # Dự đoán loại mụn
        pred = class_model.predict(img_arr)
        class_idx = np.argmax(pred)
        class_name_en = class_labels[class_idx]
        class_name_vn = class_mapping.get(class_name_en, class_name_en)  # Lấy tên tiếng Việt
        conf = confidences[i-1]

        # Vẽ box và label
        text = f"#{i}: {class_name_en} ({class_name_vn}) ({conf:.2f})"
        bbox = draw.textbbox((0,0), text, font=font)
        text_w = bbox[2]-bbox[0]
        text_h = bbox[3]-bbox[1]

        draw.rectangle([x1, y1, x2, y2], outline="red", width=2)
        draw.rectangle([x1, y1 - text_h, x1 + text_w, y1], fill="red")
        draw.text((x1, y1 - text_h), text, fill="white", font=font)

        classified_results.append((i, class_name_en, class_name_vn))

    # Đánh giá tình trạng dựa trên số lượng mụn
    if num_boxes > 10:
        severity = "Nặng"
        recommendation = "Bạn nên đến gặp bác sĩ da liễu và sử dụng liệu trình trị mụn chuyên sâu."
    elif 5 <= num_boxes <= 10:
        severity = "Trung bình"
        recommendation = "Duy trì skincare đều đặn với sữa rửa mặt dịu nhẹ và dưỡng ẩm."
    else:
        severity = "Tốt"
        recommendation = "Làn da bạn khá ổn! Tiếp tục duy trì thói quen chăm sóc da."

    # Liệt kê loại mụn
    acne_types_str = "Danh sách mụn phát hiện:\n"
    for idx, cname_en, cname_vn in classified_results:
        acne_types_str += f"Mụn #{idx}: {cname_en} ({cname_vn})\n"

    # Lưu ảnh kết quả
    predicted_image_save_path = "predicted_image.jpg"
    pil_image.save(predicted_image_save_path)

    return predicted_image_save_path, f"Tình trạng mụn: {severity}", recommendation, acne_types_str

description_md = """
## Ứng dụng Nhận Diện (YOLO) & Phân Loại Mụn (Classification.h5)
1. Dùng YOLO để phát hiện vùng mụn trên khuôn mặt.
2. Dùng model classification (h5) để phân loại loại mụn.
3. Hiển thị kết quả lên ảnh cùng tình trạng da và gợi ý, kèm tên tiếng Anh và tiếng Việt của loại mụn.
"""

inputs = [
    gr.Image(type="filepath", label="Ảnh Khuôn Mặt"),
    gr.Slider(minimum=320, maximum=1280, step=32, value=640, label="Kích thước ảnh (Image Size)"),
    gr.Slider(minimum=0, maximum=1, step=0.05, value=0.4, label="Ngưỡng Confidence"),
    gr.Slider(minimum=0, maximum=1, step=0.05, value=0.5, label="Ngưỡng IOU")
]

outputs = [
    gr.Image(type="filepath", label="Ảnh Sau Khi Xử Lý"),
    gr.Textbox(label="Tình Trạng Mụn", interactive=False),
    gr.Textbox(label="Khuyến Nghị", interactive=False),
    gr.Textbox(label="Loại Mụn Phát Hiện", interactive=False)
]

app = gr.Interface(
    fn=detect_and_classify,
    inputs=inputs,
    outputs=outputs,
    title="YOLO + Classification (H5) Mụn Tiếng Việt",
    description=description_md
)

app.launch(share=True)