Spaces:
Running
Running
import gradio as gr | |
import pandas as pd | |
from PIL import Image | |
# Define your sections and labels | |
SECTION_LABELS = { | |
"Oil Pore Related Issues": [ | |
"Oily Sheen", | |
"Very Large Pores (Not Red)", | |
"Whiteheads (Clogged Pores)", | |
"Blackheads (Clogged Pores)", | |
"Shinny Skin", | |
"Sebaceous Filaments (Sebum)" | |
], | |
"Acne and Blemishes": [ | |
"Pustules", | |
"Papules", | |
"Nodules", | |
"Cysts" | |
], | |
"Redness and Irritation": [ | |
"Redness", | |
"Irritation", | |
"Itching", | |
"Burning Sensation", | |
"Allergic Reactions" | |
], | |
"Dryness and Texture Issues": [ | |
"Dryness", | |
"Fine Lines / Wrinkles", | |
"Flakiness" | |
], | |
"Aging and Elasticity Issues": [ | |
"Loss of Elasticity", | |
"Sagging Skin", | |
"Wrinkle Prone Areas" | |
], | |
"Pigmentation Issues": [ | |
"Dark Spots", | |
"Uneven Skin Tone", | |
"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: | |
gr.Markdown("## Dermo Annotator") | |
file_upload = gr.File(label="Upload Images", file_count="multiple", file_types=["image"]) | |
# Create checkbox components in layout order | |
checkbox_components = [] | |
# First row: first 3 sections | |
with gr.Row(): | |
for section in list(SECTION_LABELS.keys())[:3]: | |
with gr.Column(): | |
gr.Markdown(f"### {section}") | |
for lbl in SECTION_LABELS[section]: | |
cb = gr.Checkbox(label=lbl) | |
checkbox_components.append(cb) | |
# Second row: next 3 sections | |
with gr.Row(): | |
for section in list(SECTION_LABELS.keys())[3:]: | |
with gr.Column(): | |
gr.Markdown(f"### {section}") | |
for lbl in SECTION_LABELS[section]: | |
cb = gr.Checkbox(label=lbl) | |
checkbox_components.append(cb) | |
# Image display and controls | |
with gr.Row(): | |
with gr.Column(scale=2): | |
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): | |
submit_btn = gr.Button("Submit Labels") | |
status = gr.Label() | |
csv_downloader = gr.File(label="Download labels CSV") | |
# Wire events | |
file_upload.upload( | |
fn=upload, | |
inputs=file_upload, | |
outputs=[img, caption] + checkbox_components + [file_upload] | |
) | |
prev_btn.click( | |
fn=lambda: navigate(-1), | |
outputs=[img, caption] + checkbox_components | |
) | |
next_btn.click( | |
fn=lambda: navigate(1), | |
outputs=[img, caption] + checkbox_components | |
) | |
submit_btn.click( | |
fn=submit, | |
inputs=checkbox_components, | |
outputs=[status, csv_downloader] | |
) | |
if __name__ == "__main__": | |
demo.launch(server_name="0.0.0.0", server_port=7860) |