File size: 3,919 Bytes
3834351 4768cde dd1d7f5 a32df56 4c1c4a7 3834351 49abd9f 7c80781 3c8af25 7c80781 3c8af25 49abd9f 4768cde 3834351 e768711 4768cde 49abd9f 4768cde e768711 3c8af25 5f6c42c e768711 3c8af25 e768711 5f6c42c 3834351 9226311 d807150 e768711 d807150 e768711 5f6c42c 3c8af25 e768711 d807150 49abd9f 5f6c42c 3834351 dd1d7f5 |
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 |
import gradio as gr
import tempfile
from pathlib import Path
from wrapper import run_pipeline_on_image
import numpy as np
from PIL import Image
from itertools import product
def show_preview(image):
"""Render uploaded image faithfully, including 16-bit/single-channel inputs.
- RGB/RGBA: show as-is (strip alpha)
- 16-bit or single-channel: min-max (or 1-99%ile) normalize to 8-bit for display
"""
if image is None:
return None
try:
arr = np.array(image)
# RGBA → RGB
if arr.ndim == 3 and arr.shape[2] == 4:
return image.convert("RGB")
# RGB → as-is
if arr.ndim == 3 and arr.shape[2] == 3:
return image
# Single-channel or higher bit-depth
if arr.ndim == 2 or (arr.ndim == 3 and arr.shape[2] == 1):
if arr.ndim == 3:
arr = arr[..., 0]
a = np.nan_to_num(arr.astype(np.float64), nan=0.0, posinf=0.0, neginf=0.0)
# Robust contrast stretch
vmin = np.percentile(a, 1.0)
vmax = np.percentile(a, 99.0)
if not np.isfinite(vmin) or not np.isfinite(vmax) or vmax <= vmin:
vmin, vmax = float(np.min(a)), float(np.max(a))
denom = max(vmax - vmin, 1e-6)
vis = np.clip((a - vmin) / denom, 0.0, 1.0) * 255.0
vis8 = vis.astype(np.uint8)
return Image.fromarray(vis8, mode='L')
# Fallback
return image.convert("RGB")
except Exception:
return image
def process(image):
if image is None:
return None, None, [], ""
with tempfile.TemporaryDirectory() as tmpdir:
# Save PIL image preserving original format
ext = image.format.lower() if image.format else 'png'
img_path = Path(tmpdir) / f"input.{ext}"
image.save(img_path)
outputs = run_pipeline_on_image(str(img_path), tmpdir, save_artifacts=True)
# Assemble displays
def load_pil(path_str):
try:
if not path_str:
return None
im = Image.open(path_str)
im = im.convert('RGB')
# Copy to memory so it survives after tmpdir is removed
copied = im.copy()
im.close()
return copied
except Exception:
return None
overlay = load_pil(outputs.get('Overlay'))
mask = load_pil(outputs.get('Mask'))
composite = load_pil(outputs.get('Composite'))
order = ['NDVI', 'ARI', 'GNDVI']
gallery_items = [load_pil(outputs[k]) for k in order if k in outputs]
stats_text = outputs.get('StatsText', '')
return composite, overlay, mask, gallery_items, stats_text
with gr.Blocks() as demo:
gr.Markdown("# 🌿 Sorghum Plant Analysis Demo")
gr.Markdown("Upload a sorghum plant image to analyze vegetation indices, segmentation overlay, and stats.")
with gr.Row():
with gr.Column():
inp = gr.Image(type="pil", label="Upload Image")
run = gr.Button("Run Pipeline", variant="primary")
with gr.Column():
preview = gr.Image(type="pil", label="Uploaded Image Preview", interactive=False)
with gr.Row():
composite_img = gr.Image(type="pil", label="Composite (Segmentation Input)", interactive=False)
overlay_img = gr.Image(type="pil", label="Segmentation Overlay", interactive=False)
mask_img = gr.Image(type="pil", label="Mask", interactive=False)
gallery = gr.Gallery(label="Vegetation Indices", columns=3, height="auto")
stats = gr.Textbox(label="Statistics", lines=4)
# Update preview when image is uploaded
inp.change(fn=show_preview, inputs=inp, outputs=preview)
run.click(process, inputs=inp, outputs=[composite_img, overlay_img, mask_img, gallery, stats])
if __name__ == "__main__":
demo.launch() |