File size: 5,515 Bytes
12f490a
 
9ac8c85
 
12f490a
9ac8c85
 
12f490a
9ac8c85
 
 
12f490a
9ac8c85
 
12f490a
81c7aed
 
 
 
 
 
 
9ac8c85
 
 
 
 
 
 
e284c36
12f490a
81c7aed
9ac8c85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81c7aed
9ac8c85
12f490a
9ac8c85
12f490a
e284c36
 
12f490a
e284c36
 
12f490a
e284c36
 
12f490a
9ac8c85
 
 
12f490a
81c7aed
 
 
9ac8c85
 
81c7aed
 
 
 
 
9ac8c85
81c7aed
9ac8c85
81c7aed
9ac8c85
 
 
 
 
 
 
 
 
81c7aed
 
 
9ac8c85
12f490a
9ac8c85
 
 
e284c36
 
9ac8c85
 
 
81c7aed
9ac8c85
e284c36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12f490a
81c7aed
 
12f490a
9ac8c85
e284c36
9ac8c85
 
12f490a
 
 
e284c36
 
9ac8c85
 
12f490a
 
e284c36
9ac8c85
e284c36
 
9ac8c85
e284c36
 
9ac8c85
e284c36
12f490a
9ac8c85
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import gradio as gr
import torch
from ultralyticsplus import YOLO
from PIL import Image, ImageDraw, ImageFont
import os
from transformers import pipeline
import numpy as np

# Tải model YOLO (detection)
yolo_model_path = "best.pt"  # Thay đường dẫn model YOLO của bạn
yolo_model = YOLO(yolo_model_path)

# Tải pipeline classification
class_pipe = pipeline("image-classification", model="Hemg/Acne-classification")

# Mapping từ tiếng Anh sang tiếng Việt cho các lớp: Comedo, Acne, Clear
label_mapping = {
    "Comedo": "Mụn cám",
    "Acne": "Mụn trứng cá",
    "Clear": "Vùng da sạch"
}

def detect_and_classify(image, image_size, conf_thresold=0.4, iou_thresold=0.5):
    # image là đường dẫn file, đọc thành PIL
    pil_image = Image.open(image).convert("RGB")

    # Detect với YOLO
    results = yolo_model.predict(pil_image, conf=conf_thresold, iou=iou_thresold, imgsz=image_size)
    boxes = results[0].boxes
    num_boxes = len(boxes)

    # Nếu không có vùng mụn
    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 có loại mụn nào được phát hiện."

    # Chuyển boxes về array
    xyxy = boxes.xyxy.detach().cpu().numpy().astype(int)
    confidences = boxes.conf.detach().cpu().numpy()

    # Crop từng box và classify
    class_names = []
    for box in xyxy:
        x1, y1, x2, y2 = box
        crop = pil_image.crop((x1, y1, x2, y2))
        # Classification trên vùng crop
        results_class = class_pipe(crop)
        top_class = results_class[0]['label']  # tiếng Anh
        class_names.append(top_class)

    # Đá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 = "Hãy duy trì skincare đều đặn với sữa rửa mặt dịu nhẹ và dưỡng ẩm phù hợp."
    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 hiện tại."

    # Vẽ bounding box và class name lên ảnh
    draw = ImageDraw.Draw(pil_image)
    font = ImageFont.load_default()

    # Tạo chuỗi kết quả loại mụn
    acne_types_str = "Danh sách mụn phát hiện:\n"

    for i, (box, cname, conf) in enumerate(zip(xyxy, class_names, confidences), start=1):
        x1, y1, x2, y2 = box
        
        # Lấy tên tiếng việt từ mapping (nếu không có, dùng tên cũ)
        vn_name = label_mapping.get(cname, cname)

        # Vẽ box
        draw.rectangle([x1, y1, x2, y2], outline="red", width=2)
        text = f"#{i}: {cname} ({vn_name}) ({conf:.2f})"

        # Sử dụng textbbox để lấy kích thước text
        bbox = draw.textbbox((0,0), text, font=font)
        text_w = bbox[2]-bbox[0]
        text_h = bbox[3]-bbox[1]

        # Vẽ nền cho text
        draw.rectangle([x1, y1 - text_h, x1 + text_w, y1], fill="red")
        # Vẽ text
        draw.text((x1, y1 - text_h), text, fill="white", font=font)

        # Thêm vào chuỗi mô tả
        acne_types_str += f"Mụn #{i}: {cname} ({vn_name})\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 & Phân Loại Mụn
- Sử dụng YOLO để phát hiện các vùng mụn trên khuôn mặt.
- Sử dụng mô hình phân loại (Hemg/Acne-classification) để xác định loại mụn.
- Hiển thị bounding box kèm số thứ tự, tên tiếng Anh và tiếng Việt của loại mụn.
- Đánh giá tình trạng da và đưa ra khuyến nghị.
"""

custom_css = """
#component-0, #component-1, #component-2, #component-3, #component-4 {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    text-align: center;
}
#component-0 h1 {
    color: #F15B2A;
}
#component-0 h2, h3 {
    color: #333;
}
.gr-button {
    background-color: #F15B2A !important;
    color: #fff !important;
    border: none !important;
    font-weight: bold !important;
}
.gr-button:hover {
    background-color: #d94c1f !important;
}
"""

import gradio as gr

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)
]

yolo_app = gr.Interface(
    fn=detect_and_classify,
    inputs=inputs,
    outputs=outputs,
    title="YOLOv8 + Classification: Nhận Diện & Phân Loại Mụn",
    description=description_md,
    css=custom_css,
    theme="default"
)

yolo_app.launch(share=True)