Image Segmentation
Transformers
Safetensors
concor1
feature-extraction
vision-language-grounding
concept-correspondence
referring-expression-segmentation
phrase-grounding
open-vocabulary-segmentation
custom_code
Instructions to use UWGZQ/ConCor-1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use UWGZQ/ConCor-1 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-segmentation", model="UWGZQ/ConCor-1", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("UWGZQ/ConCor-1", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
| #!/usr/bin/env python3 | |
| # coding=utf-8 | |
| """ConCor-1 inference example: an image + its text in, correspondences out. | |
| Given an image and a paired text, ConCor-1 predicts the full set of | |
| correspondences between visually referential text spans and instance-level | |
| image segments — the text spans are *not* given as queries; the model decides | |
| which parts of the text are grounded. | |
| Usage (the bundled `example.png` with its COCONut-PanCap caption): | |
| python example_inference.py --image example.png \ | |
| --text "This image depicts a close-up of a brown bear in a natural outdoor setting. \ | |
| The background consists of lush green grass. In the foreground, a large brown bear is \ | |
| positioned centrally." | |
| # a category list works just as well as a caption | |
| python example_inference.py --image example.png --text "bear . grass . tree . person" | |
| # write a mask overlay next to the printed correspondences | |
| python example_inference.py --image example.png --text "..." --output overlay.png | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| from pathlib import Path | |
| from typing import List | |
| import numpy as np | |
| import torch | |
| from PIL import Image, ImageDraw | |
| from transformers import AutoModel, AutoProcessor | |
| # Visually distinct overlay colours. | |
| COLORS = [ | |
| (239, 64, 64), (64, 204, 64), (64, 115, 255), (255, 204, 0), (255, 115, 0), | |
| (217, 51, 217), (0, 204, 217), (153, 89, 13), (102, 255, 102), (140, 26, 255), | |
| (255, 153, 204), (0, 140, 0), (179, 179, 0), (0, 26, 153), (204, 140, 51), | |
| (128, 128, 128), (255, 0, 128), (0, 255, 140), (140, 0, 0), (0, 140, 140), | |
| ] | |
| def overlay_masks(image: Image.Image, correspondences: List[dict], alpha: float = 0.5) -> Image.Image: | |
| """Blend each correspondence's mask over the image and label it with its phrases.""" | |
| canvas = np.array(image.convert("RGB"), dtype=np.float32) | |
| for index, correspondence in enumerate(correspondences): | |
| mask = correspondence.get("mask") | |
| if mask is None or not mask.any(): | |
| continue | |
| color = np.array(COLORS[index % len(COLORS)], dtype=np.float32) | |
| canvas[mask] = (1.0 - alpha) * canvas[mask] + alpha * color | |
| overlaid = Image.fromarray(canvas.astype(np.uint8)) | |
| draw = ImageDraw.Draw(overlaid) | |
| for index, correspondence in enumerate(correspondences): | |
| mask = correspondence.get("mask") | |
| if mask is None or not mask.any(): | |
| continue | |
| rows, columns = np.nonzero(mask) | |
| label = " / ".join(correspondence["text_phrases"]) or "(no text span)" | |
| label = f"{label} {correspondence['presence_score']:.2f}" | |
| anchor = (int(columns.min()), max(int(rows.min()) - 12, 0)) | |
| draw.text(anchor, label, fill=COLORS[index % len(COLORS)]) | |
| return overlaid | |
| def main() -> None: | |
| parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) | |
| parser.add_argument("--model", default=str(Path(__file__).parent), help="model repo id or local path") | |
| parser.add_argument("--image", required=True, type=Path) | |
| parser.add_argument("--text", required=True, help="the text to ground (caption, category list, referring expression)") | |
| parser.add_argument("--output", type=Path, default=None, help="write a mask overlay here (PNG)") | |
| parser.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu") | |
| parser.add_argument( | |
| "--attn_implementation", | |
| default="flash_attention_2", | |
| choices=["flash_attention_2", "sdpa", "eager"], | |
| help="flash_attention_2 reproduces the paper's numbers exactly; sdpa needs no extra dependency", | |
| ) | |
| parser.add_argument("--presence_threshold", type=float, default=None, help="default 0.1") | |
| parser.add_argument("--text_threshold", type=float, default=None, help="default 0.45") | |
| parser.add_argument("--image_threshold", type=float, default=None, help="default 0.45") | |
| parser.add_argument("--nms_iou_threshold", type=float, default=None, help="default 0.5") | |
| args = parser.parse_args() | |
| processor = AutoProcessor.from_pretrained(args.model, trust_remote_code=True) | |
| model = AutoModel.from_pretrained( | |
| args.model, | |
| trust_remote_code=True, | |
| dtype=torch.bfloat16, | |
| attn_implementation=args.attn_implementation, | |
| ).to(args.device).eval() | |
| image = Image.open(args.image).convert("RGB") | |
| inputs = processor(images=image, text=args.text, return_tensors="pt").to(args.device) | |
| with torch.inference_mode(), torch.autocast(args.device, dtype=torch.bfloat16): | |
| outputs = model(**inputs) | |
| correspondences = processor.post_process_correspondences( | |
| outputs, | |
| text=args.text, | |
| target_sizes=[(image.height, image.width)], | |
| presence_threshold=args.presence_threshold, | |
| text_threshold=args.text_threshold, | |
| image_threshold=args.image_threshold, | |
| nms_iou_threshold=args.nms_iou_threshold, | |
| )[0] | |
| print(f"\nimage: {args.image} ({image.width}x{image.height})") | |
| print(f"text: {args.text}") | |
| print(f"\n{len(correspondences)} correspondence(s):") | |
| for correspondence in correspondences: | |
| mask = correspondence["mask"] | |
| phrases = " / ".join(correspondence["text_phrases"]) or "(no text span)" | |
| area = 100.0 * mask.mean() if mask is not None else 0.0 | |
| print( | |
| f" presence={correspondence['presence_score']:.3f} " | |
| f"bridge={correspondence['bridge_index']:3d} " | |
| f"mask={area:5.2f}% of image spans={correspondence['text_spans']} | {phrases}" | |
| ) | |
| if args.output is not None: | |
| overlay_masks(image, correspondences).save(args.output) | |
| print(f"\nwrote {args.output}") | |
| if __name__ == "__main__": | |
| main() | |