File size: 6,330 Bytes
85e4b4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fde64cd
 
 
233bda6
fde64cd
 
85e4b4a
 
 
 
 
 
 
 
bd9fe6e
85e4b4a
 
bd9fe6e
fde64cd
85e4b4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3de602a
85e4b4a
3de602a
85e4b4a
 
 
 
 
 
 
 
 
 
3de602a
 
 
 
85e4b4a
 
 
 
 
 
3de602a
 
 
 
 
 
 
85e4b4a
 
 
 
 
 
 
 
 
 
 
 
19f2fac
85e4b4a
 
 
 
 
19f2fac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85e4b4a
19f2fac
85e4b4a
 
 
 
 
19f2fac
85e4b4a
 
3de602a
85e4b4a
19f2fac
 
85e4b4a
 
 
 
 
 
 
19f2fac
85e4b4a
 
 
 
19f2fac
85e4b4a
 
 
 
19f2fac
85e4b4a
3de602a
85e4b4a
 
 
19f2fac
 
3de602a
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import gradio as gr
import pandas as pd
from PIL import Image

# Define your sections and labels
SECTION_LABELS = {
    "Oil Pore Related Issues": [
        "Very Large Pores (Not Red)",
        "Whiteheads (Clogged Pores)",
        "Blackheads (Clogged Pores)",
        "Shinny Skin",
        "Sebaceous Filaments (Sebum)"
    ],
    "Acne and Blemishes": [
        "Pustules",
        "Papules",
        "Nodules",
        "Cysts",
        "Rosacea",
        "Telangiectasia",
        "Milia",
        "Scars",
        "Ice Berg Scars",
    ],
    "Redness and Irritation": [
        "Redness",
        "Irritation",
    ],
    "Dryness and Texture Issues": [
        "Dryness",
        "Fine Lines / Wrinkles",
        "Skin Flakes"
    ],
    "Aging and Elasticity Issues": [
        "Loose Skin",
        "Deep Wrinkles"
    ],
    "Pigmentation Issues": [
        "Dark Spots",
        "Melasma",
        "Freckles"
    ]
}

# Flattened labels list
ALL_LABELS = [label for labels in SECTION_LABELS.values() for label in labels]

# Global state
images = []
current_index = 0
results = []
annotations = {}

# Core functions

def display_image(idx):
    if images:
        img = Image.open(images[idx])
        fname = images[idx].split('/')[-1]
        tick = ' ✅' if idx in annotations else ''
        caption = f"{fname} ({idx+1}/{len(images)}){tick}"
        states = annotations.get(idx, [False] * len(ALL_LABELS))
        return [img, caption] + states
    return [None, "No images uploaded"] + [False] * len(ALL_LABELS)


def navigate(delta):
    global current_index
    current_index = (current_index + delta) % len(images)
    return display_image(current_index)


def submit(*selections):
    if not images:
        # Return status and no file
        return "No image to label", None

    # Save selections
    annotations[current_index] = list(selections)
    fname = images[current_index].split('/')[-1]
    chosen = [lbl for lbl, sel in zip(ALL_LABELS, selections) if sel]
    global results
    results = [r for r in results if r['image'] != fname]
    results.append({'image': fname, 'labels': ', '.join(chosen)})

    # Write CSV
    df = pd.DataFrame(results)
    df.to_csv('image_labels.csv', index=False)

    # Return status message and CSV path
    return "Labels saved!", 'image_labels.csv'


def upload(files):
    global images, current_index, results, annotations
    images = [f.name if hasattr(f, 'name') else f for f in files]
    current_index = 0
    results = []
    annotations = {}
    outputs = display_image(0)
    # hide uploader after upload
    return outputs + [gr.update(visible=False)]

with gr.Blocks() as demo: # You can add a theme here, e.g., theme=gr.themes.Soft()
    gr.Markdown("## Dermo Annotator")
    file_upload = gr.File(label="Upload Images", file_count="multiple", file_types=["image"])

    checkbox_components = []

    # Define the sections for each column explicitly based on "new.png"
    column1_sections = ["Oil Pore Related Issues", "Dryness and Texture Issues"]
    column2_sections = ["Acne and Blemishes"]
    column3_sections = ["Redness and Irritation", "Pigmentation Issues", "Aging and Elasticity Issues"]

    with gr.Row(): # Main row to hold the three columns
        # Column 1
        with gr.Column():
            for section_name in column1_sections:
                if section_name in SECTION_LABELS:
                    with gr.Group(): # Using Group for a card-like feel
                        gr.Markdown(f"### {section_name}")
                        for lbl in SECTION_LABELS[section_name]:
                            cb = gr.Checkbox(label=lbl)
                            checkbox_components.append(cb)
        
        # Column 2
        with gr.Column():
            for section_name in column2_sections:
                if section_name in SECTION_LABELS:
                    with gr.Group(): # Using Group for a card-like feel
                        gr.Markdown(f"### {section_name}")
                        for lbl in SECTION_LABELS[section_name]:
                            cb = gr.Checkbox(label=lbl)
                            checkbox_components.append(cb)

        # Column 3
        with gr.Column():
            for section_name in column3_sections:
                if section_name in SECTION_LABELS:
                    with gr.Group(): # Using Group for a card-like feel
                        gr.Markdown(f"### {section_name}")
                        for lbl in SECTION_LABELS[section_name]:
                            cb = gr.Checkbox(label=lbl)
                            checkbox_components.append(cb)

    # Image display and controls (no change to this part from your original code)
    with gr.Row():
        with gr.Column(scale=2): # Make image column potentially wider
            img = gr.Image(label="Image")
            caption = gr.Label(value="No images uploaded")
            with gr.Row():
                prev_btn = gr.Button("⬅️ Previous")
                next_btn = gr.Button("Next ➡️")
        with gr.Column(scale=1): # Make controls column narrower
            submit_btn = gr.Button("Submit Labels")
            status = gr.Label()
            csv_downloader = gr.File(label="Download labels CSV")

    # Wire events (ensure checkbox_components is correctly populated)
    # (This part of your code for wiring events remains the same)
    file_upload.upload(
        fn=upload,
        inputs=file_upload,
        outputs=[img, caption] + checkbox_components + [file_upload]
    )

    prev_btn.click(
        fn=lambda: navigate(-1), # Ensure navigate uses global current_index and images
        outputs=[img, caption] + checkbox_components
    )

    next_btn.click(
        fn=lambda: navigate(1), # Ensure navigate uses global current_index and images
        outputs=[img, caption] + checkbox_components
    )

    submit_btn.click(
        fn=submit, # Ensure submit uses global current_index, images, results, annotations
        inputs=checkbox_components,
        outputs=[status, csv_downloader]
    )

if __name__ == "__main__":
    # Make sure your SECTION_LABELS, ALL_LABELS, and functions (upload, display_image, navigate, submit)
    # are defined before this demo block or are accessible in the global scope.
    demo.launch(server_name="0.0.0.0", server_port=7860)