GroundingSAM / app.py
pc4work's picture
Update app.py
479d204 verified
Raw
History Blame Contribute Delete
3.78 kB
import spaces
import gradio as gr
import numpy as np
import torch
from transformers import (
AutoModelForZeroShotObjectDetection,
AutoProcessor,
SamModel,
SamProcessor,
)
CUDA_DEVICE = "cuda"
SAM_MODEL_ID = "facebook/sam-vit-base"
GROUNDING_DINO_MODEL_ID = "IDEA-Research/grounding-dino-base"
# ZeroGPU enables CUDA emulation during startup, so models should be moved to
# CUDA at module scope. Importing `spaces` before `torch` is important.
sam_model = SamModel.from_pretrained(SAM_MODEL_ID).to(CUDA_DEVICE).eval()
sam_processor = SamProcessor.from_pretrained(SAM_MODEL_ID)
dino_processor = AutoProcessor.from_pretrained(GROUNDING_DINO_MODEL_ID)
dino_model = (
AutoModelForZeroShotObjectDetection.from_pretrained(GROUNDING_DINO_MODEL_ID)
.to(CUDA_DEVICE)
.eval()
)
def infer_dino(image: np.ndarray, text_queries: list[str], score_threshold: float):
query_text = ". ".join(text_queries) + "."
height, width = image.shape[:2]
inputs = dino_processor(
images=image,
text=query_text,
return_tensors="pt",
).to(CUDA_DEVICE)
with torch.inference_mode():
outputs = dino_model(**inputs)
return dino_processor.post_process_grounded_object_detection(
outputs=outputs,
input_ids=inputs.input_ids,
threshold=score_threshold,
text_threshold=score_threshold,
target_sizes=[(height, width)],
)[0]
@spaces.GPU(duration=120)
def query_image(image: np.ndarray, text_queries: str, dino_threshold: float):
if image is None:
raise gr.Error("Please upload an image.")
queries = [query.strip() for query in text_queries.split(",") if query.strip()]
if not queries:
raise gr.Error("Please enter at least one candidate label.")
detections = infer_dino(image, queries, dino_threshold)
boxes = detections["boxes"].detach().cpu()
labels = detections.get("text_labels", detections.get("labels", []))
if len(boxes) == 0:
return image, []
# Process every detected box in one SAM forward pass.
sam_inputs = sam_processor(
images=image,
input_boxes=[boxes.tolist()],
return_tensors="pt",
).to(CUDA_DEVICE)
with torch.inference_mode():
sam_outputs = sam_model(**sam_inputs, multimask_output=True)
masks = sam_processor.image_processor.post_process_masks(
sam_outputs.pred_masks.detach().cpu(),
sam_inputs["original_sizes"].detach().cpu(),
sam_inputs["reshaped_input_sizes"].detach().cpu(),
)[0]
iou_scores = sam_outputs.iou_scores.detach().cpu()[0]
best_mask_indices = iou_scores.argmax(dim=-1)
annotations = []
for detection_index, label in enumerate(labels):
best_mask_index = int(best_mask_indices[detection_index])
mask = masks[detection_index, best_mask_index].numpy().astype(bool)
annotations.append((mask, str(label)))
return image, annotations
description = """
This Space combines Grounding DINO for open-vocabulary object detection with
SAM for text-prompted image segmentation. Enter comma-separated labels such as
`cat, dog, sidewalk, crosswalk`.
"""
demo = gr.Interface(
fn=query_image,
inputs=[
gr.Image(type="numpy", label="Image Input"),
gr.Textbox(
label="Candidate Labels",
placeholder="cat, dog, sidewalk, crosswalk",
),
gr.Slider(
minimum=0.0,
maximum=1.0,
value=0.25,
step=0.01,
label="Grounding DINO Confidence Threshold",
),
],
outputs=gr.AnnotatedImage(label="Segmentation Result"),
title="Grounding DINO + SAM Zero-shot Segmentation",
description=description,
)
if __name__ == "__main__":
demo.launch()