Views
No views yet
1# Copyright 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
5# http://www.apache.org/licenses/LICENSE-2.0
6# Unless required by applicable law or agreed to in writing, software
7# distributed under the License is distributed on an "AS IS" BASIS,
8# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9# See the License for the specific language governing permissions and
10# limitations under the License.
11# SPDX-License-Identifier: Apache-2.0
12
13import torch
14import numpy as np
15from PIL import Image
16from transformers import SamModel, SamProcessor, AutoModel
17import cv2
18import requests
19from io import BytesIO
20
21
22def apply_sam(image, input_points=None, input_boxes=None, input_labels=None):
23 inputs = sam_processor(image, input_points=input_points, input_boxes=input_boxes,
24 input_labels=input_labels, return_tensors="pt").to(device)
25
26 with torch.no_grad():
27 outputs = sam_model(**inputs)
28
29 masks = sam_processor.image_processor.post_process_masks(
30 outputs.pred_masks.cpu(),
31 inputs["original_sizes"].cpu(),
32 inputs["reshaped_input_sizes"].cpu()
33 )[0][0]
34 scores = outputs.iou_scores[0, 0]
35
36 mask_selection_index = scores.argmax()
37 mask_np = masks[mask_selection_index].numpy()
38 return mask_np
39
40
41def add_contour(img, mask, input_points=None, input_boxes=None):
42 img = img.copy()
43 mask = mask.astype(np.uint8) * 255
44 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
45 cv2.drawContours(img, contours, -1, (1.0, 1.0, 1.0), thickness=6)
46
47 if input_points is not None:
48 for points in input_points:
49 for x, y in points:
50 cv2.circle(img, (int(x), int(y)), radius=10, color=(1.0, 0.0, 0.0), thickness=-1)
51 cv2.circle(img, (int(x), int(y)), radius=10, color=(1.0, 1.0, 1.0), thickness=2)
52
53 if input_boxes is not None:
54 for box_batch in input_boxes:
55 for box in box_batch:
56 x1, y1, x2, y2 = map(int, box)
57 cv2.rectangle(img, (x1, y1), (x2, y2), color=(1.0, 1.0, 1.0), thickness=4)
58 cv2.rectangle(img, (x1, y1), (x2, y2), color=(1.0, 0.0, 0.0), thickness=2)
59
60 return img
61
62def print_streaming(text):
63 print(text, end="", flush=True)
64
65if __name__ == '__main__':
66 # Download the image via HTTP
67 image_url = 'https://github.com/NVlabs/describe-anything/blob/main/images/1.jpg?raw=true'
68 response = requests.get(image_url)
69 img = Image.open(BytesIO(response.content)).convert('RGB')
70
71 device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
72 sam_model = SamModel.from_pretrained("facebook/sam-vit-huge").to(device)
73 sam_processor = SamProcessor.from_pretrained("facebook/sam-vit-huge")
74 image_size = img.size # (width, height)
75
76 # Initialize DAM model once
77 model = AutoModel.from_pretrained(
78 'nvidia/DAM-3B-Self-Contained',
79 trust_remote_code=True,
80 torch_dtype='torch.float16'
81 ).to(device)
82 dam = model.init_dam(conv_mode='v1', prompt_mode='full+focal_crop')
83
84 # Define two runs: one with points, one with box
85 runs = [
86 {
87 'use_box': False,
88 'points': [[1172, 812], [1572, 800]],
89 'output_image_path': 'output_visualization_points.png'
90 },
91 {
92 'use_box': True,
93 'box': [800, 500, 1800, 1000],
94 'output_image_path': 'output_visualization_box.png'
95 }
96 ]
97
98 for run in runs:
99 if run['use_box']:
100 # Prepare box input
101 coords = run['box']
102 input_boxes = [[coords]]
103 print(f"Running inference with input_boxes: {input_boxes}")
104 mask_np = apply_sam(img, input_boxes=input_boxes)
105 vis_points = None
106 vis_boxes = input_boxes
107 else:
108 # Prepare point input
109 pts = run['points']
110 input_points = [pts]
111 input_labels = [[1] * len(pts)]
112 print(f"Running inference with input_points: {input_points}")
113 mask_np = apply_sam(img, input_points=input_points, input_labels=input_labels)
114 vis_points = input_points
115 vis_boxes = None
116
117 # Convert mask and describe
118 mask = Image.fromarray((mask_np * 255).astype(np.uint8))
119 print("Description:")
120 for token in dam.get_description(
121 img,
122 mask,
123 '<image>\nDescribe the masked region in detail.',
124 streaming=True,
125 temperature=0.2,
126 top_p=0.5,
127 num_beams=1,
128 max_new_tokens=512
129 ):
130 print_streaming(token)
131 print() # newline
132
133 # Save visualization with contour
134 img_np = np.asarray(img).astype(float) / 255.0
135 img_with_contour_np = add_contour(img_np, mask_np,
136 input_points=vis_points,
137 input_boxes=vis_boxes)
138 img_with_contour_pil = Image.fromarray((img_with_contour_np * 255.0).astype(np.uint8))
139 img_with_contour_pil.save(run['output_image_path'])
140 print(f"Output image with contour saved as {run['output_image_path']}")@article{lian2025describe,
title={Describe Anything: Detailed Localized Image and Video Captioning},
author={Long Lian and Yifan Ding and Yunhao Ge and Sifei Liu and Hanzi Mao and Boyi Li and Marco Pavone and Ming-Yu Liu and Trevor Darrell and Adam Yala and Yin Cui},
journal={arXiv preprint arXiv:2504.16072},
year={2025}
}