File size: 5,116 Bytes
12f490a
 
9ac8c85
 
12f490a
9ac8c85
 
12f490a
9ac8c85
 
 
12f490a
9ac8c85
 
12f490a
9ac8c85
 
 
 
 
 
 
e284c36
12f490a
9ac8c85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12f490a
9ac8c85
12f490a
e284c36
 
12f490a
e284c36
 
12f490a
e284c36
 
12f490a
9ac8c85
 
 
12f490a
9ac8c85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12f490a
9ac8c85
 
 
 
 
 
12f490a
9ac8c85
e284c36
 
9ac8c85
 
 
 
 
e284c36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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")

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, trả về kết quả
    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']
        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()

    for i, (box, cname, conf) in enumerate(zip(xyxy, class_names, confidences), start=1):
        x1, y1, x2, y2 = box
        draw.rectangle([x1, y1, x2, y2], outline="red", width=2)
        text = f"#{i}: {cname} ({conf:.2f})"

        # Dùng textbbox để xác định 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)

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

    # Liệt kê loại mụn theo số thứ tự
    acne_types_str = "Danh sách mụn phát hiện:\n"
    for i, cname in enumerate(class_names, start=1):
        acne_types_str += f"Mụn #{i}: {cname}\n"

    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ự và loại mụn tương ứng.
- Đá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;
}
"""

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)