рд╕рд╛рдордЧреНрд░реА рдкрд░ рдЬрд╛рдПрдВ

рдХреЗ рд▓рд┐рдП рд╕рдВрджрд░реНрдн ultralytics/models/sam/predict.py

рдиреЛрдЯ

рдпрд╣ рдлрд╝рд╛рдЗрд▓ рдпрд╣рд╛рдБ рдЙрдкрд▓рдмреНрдз рд╣реИ https://github.com/ultralytics/ultralytics/рдмреВрдБрдж/рдореБрдЦреНрдп/ultralytics/рдореЙрдбрд▓/sam/predict.pyред рдпрджрд┐ рдЖрдк рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рджреЗрдЦрддреЗ рд╣реИрдВ рддреЛ рдХреГрдкрдпрд╛ рдкреБрд▓ рдЕрдиреБрд░реЛрдз рдХрд╛ рдпреЛрдЧрджрд╛рди рдХрд░рдХреЗ рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдВ ЁЯЫая╕Пред ЁЯЩП рдзрдиреНрдпрд╡рд╛рдж !



ultralytics.models.sam.predict.Predictor

рдХрд╛ рд░реВрдк: BasePredictor

рд╕реЗрдЧрдореЗрдВрдЯ рдПрдиреАрдерд┐рдВрдЧ рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рдкреНрд░реЗрдбрд┐рдХреНрдЯрд░ рдХреНрд▓рд╛рд╕ (SAM), BasePredictor рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ред

рд╡рд░реНрдЧ рдЫрд╡рд┐ рд╡рд┐рднрд╛рдЬрди рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдЕрдиреБрд░реВрдк рдореЙрдбрд▓ рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЙрдиреНрдирдд рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдФрд░ рд╢реАрдШреНрд░ рд╡рд┐рднрд╛рдЬрди рдХреНрд╖рдорддрд╛рдУрдВ рдХреЗ рд╕рд╛рде, рдпрд╣ рд▓рдЪреАрд▓реЗ рдФрд░ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдХреА рд╕реБрд╡рд┐рдзрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдореБрдЦреМрдЯрд╛ рдкреАрдврд╝реАред рдХрдХреНрд╖рд╛ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдВрдХреЗрддреЛрдВ рдЬреИрд╕реЗ рдмрд╛рдЙрдВрдбрд┐рдВрдЧ рдмреЙрдХреНрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИ, рдЕрдВрдХ, рдФрд░ рдХрдо-рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди рдорд╛рд╕реНрдХред

рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдБ:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
cfg dict

рдореЙрдбрд▓ рдФрд░ рдХрд╛рд░реНрдп-рд╕рдВрдмрдВрдзрд┐рдд рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╢рдмреНрджрдХреЛрд╢ред

overrides dict

рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдорд╛рдиреЛрдВ рд╡рд╛рд▓реЗ рд╢рдмреНрджрдХреЛрд╢.

_callbacks dict

рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдмрдврд╝рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛-рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХрд╛ рд╢рдмреНрджрдХреЛрд╢ред

args namespace

рдХрдорд╛рдВрдб-рд▓рд╛рдЗрди рддрд░реНрдХ рдпрд╛ рдЕрдиреНрдп рдкрд░рд┐рдЪрд╛рд▓рди рдЪрд░ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдирд╛рдорд╕реНрдерд╛рдиред

im Tensor

рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕реНрдб рдЗрдирдкреБрдЯ рдЫрд╡рд┐ tensor.

features Tensor

рдирд┐рд╖реНрдХрд░реНрд╖ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рдирд┐рдХрд╛рд▓реА рдЧрдИ рдЫрд╡рд┐ рд╕реБрд╡рд┐рдзрд╛рдПрдБред

prompts dict

рд╡рд┐рднрд┐рдиреНрди рд╢реАрдШреНрд░ рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рд╕рдВрдЧреНрд░рд╣, рдЬреИрд╕реЗ рдмрд╛рдЙрдВрдбрд┐рдВрдЧ рдмреЙрдХреНрд╕ рдФрд░ рдкреЙрдЗрдВрдЯреНрд╕ред

segment_all bool

рдЫрд╡рд┐ рдореЗрдВ рд╕рднреА рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЛ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╛ рдХреЗрд╡рд▓ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд▓реЛрдЧреЛрдВ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдзреНрд╡рдЬред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
class Predictor(BasePredictor):
    """
    Predictor class for the Segment Anything Model (SAM), extending BasePredictor.

    The class provides an interface for model inference tailored to image segmentation tasks.
    With advanced architecture and promptable segmentation capabilities, it facilitates flexible and real-time
    mask generation. The class is capable of working with various types of prompts such as bounding boxes,
    points, and low-resolution masks.

    Attributes:
        cfg (dict): Configuration dictionary specifying model and task-related parameters.
        overrides (dict): Dictionary containing values that override the default configuration.
        _callbacks (dict): Dictionary of user-defined callback functions to augment behavior.
        args (namespace): Namespace to hold command-line arguments or other operational variables.
        im (torch.Tensor): Preprocessed input image tensor.
        features (torch.Tensor): Extracted image features used for inference.
        prompts (dict): Collection of various prompt types, such as bounding boxes and points.
        segment_all (bool): Flag to control whether to segment all objects in the image or only specified ones.
    """

    def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
        """
        Initialize the Predictor with configuration, overrides, and callbacks.

        The method sets up the Predictor object and applies any configuration overrides or callbacks provided. It
        initializes task-specific settings for SAM, such as retina_masks being set to True for optimal results.

        Args:
            cfg (dict): Configuration dictionary.
            overrides (dict, optional): Dictionary of values to override default configuration.
            _callbacks (dict, optional): Dictionary of callback functions to customize behavior.
        """
        if overrides is None:
            overrides = {}
        overrides.update(dict(task="segment", mode="predict", imgsz=1024))
        super().__init__(cfg, overrides, _callbacks)
        self.args.retina_masks = True
        self.im = None
        self.features = None
        self.prompts = {}
        self.segment_all = False

    def preprocess(self, im):
        """
        Preprocess the input image for model inference.

        The method prepares the input image by applying transformations and normalization.
        It supports both torch.Tensor and list of np.ndarray as input formats.

        Args:
            im (torch.Tensor | List[np.ndarray]): BCHW tensor format or list of HWC numpy arrays.

        Returns:
            (torch.Tensor): The preprocessed image tensor.
        """
        if self.im is not None:
            return self.im
        not_tensor = not isinstance(im, torch.Tensor)
        if not_tensor:
            im = np.stack(self.pre_transform(im))
            im = im[..., ::-1].transpose((0, 3, 1, 2))
            im = np.ascontiguousarray(im)
            im = torch.from_numpy(im)

        im = im.to(self.device)
        im = im.half() if self.model.fp16 else im.float()
        if not_tensor:
            im = (im - self.mean) / self.std
        return im

    def pre_transform(self, im):
        """
        Perform initial transformations on the input image for preprocessing.

        The method applies transformations such as resizing to prepare the image for further preprocessing.
        Currently, batched inference is not supported; hence the list length should be 1.

        Args:
            im (List[np.ndarray]): List containing images in HWC numpy array format.

        Returns:
            (List[np.ndarray]): List of transformed images.
        """
        assert len(im) == 1, "SAM model does not currently support batched inference"
        letterbox = LetterBox(self.args.imgsz, auto=False, center=False)
        return [letterbox(image=x) for x in im]

    def inference(self, im, bboxes=None, points=None, labels=None, masks=None, multimask_output=False, *args, **kwargs):
        """
        Perform image segmentation inference based on the given input cues, using the currently loaded image. This
        method leverages SAM's (Segment Anything Model) architecture consisting of image encoder, prompt encoder, and
        mask decoder for real-time and promptable segmentation tasks.

        Args:
            im (torch.Tensor): The preprocessed input image in tensor format, with shape (N, C, H, W).
            bboxes (np.ndarray | List, optional): Bounding boxes with shape (N, 4), in XYXY format.
            points (np.ndarray | List, optional): Points indicating object locations with shape (N, 2), in pixels.
            labels (np.ndarray | List, optional): Labels for point prompts, shape (N, ). 1 = foreground, 0 = background.
            masks (np.ndarray, optional): Low-resolution masks from previous predictions shape (N,H,W). For SAM H=W=256.
            multimask_output (bool, optional): Flag to return multiple masks. Helpful for ambiguous prompts.

        Returns:
            (tuple): Contains the following three elements.
                - np.ndarray: The output masks in shape CxHxW, where C is the number of generated masks.
                - np.ndarray: An array of length C containing quality scores predicted by the model for each mask.
                - np.ndarray: Low-resolution logits of shape CxHxW for subsequent inference, where H=W=256.
        """
        # Override prompts if any stored in self.prompts
        bboxes = self.prompts.pop("bboxes", bboxes)
        points = self.prompts.pop("points", points)
        masks = self.prompts.pop("masks", masks)

        if all(i is None for i in [bboxes, points, masks]):
            return self.generate(im, *args, **kwargs)

        return self.prompt_inference(im, bboxes, points, labels, masks, multimask_output)

    def prompt_inference(self, im, bboxes=None, points=None, labels=None, masks=None, multimask_output=False):
        """
        Internal function for image segmentation inference based on cues like bounding boxes, points, and masks.
        Leverages SAM's specialized architecture for prompt-based, real-time segmentation.

        Args:
            im (torch.Tensor): The preprocessed input image in tensor format, with shape (N, C, H, W).
            bboxes (np.ndarray | List, optional): Bounding boxes with shape (N, 4), in XYXY format.
            points (np.ndarray | List, optional): Points indicating object locations with shape (N, 2), in pixels.
            labels (np.ndarray | List, optional): Labels for point prompts, shape (N, ). 1 = foreground, 0 = background.
            masks (np.ndarray, optional): Low-resolution masks from previous predictions shape (N,H,W). For SAM H=W=256.
            multimask_output (bool, optional): Flag to return multiple masks. Helpful for ambiguous prompts.

        Returns:
            (tuple): Contains the following three elements.
                - np.ndarray: The output masks in shape CxHxW, where C is the number of generated masks.
                - np.ndarray: An array of length C containing quality scores predicted by the model for each mask.
                - np.ndarray: Low-resolution logits of shape CxHxW for subsequent inference, where H=W=256.
        """
        features = self.model.image_encoder(im) if self.features is None else self.features

        src_shape, dst_shape = self.batch[1][0].shape[:2], im.shape[2:]
        r = 1.0 if self.segment_all else min(dst_shape[0] / src_shape[0], dst_shape[1] / src_shape[1])
        # Transform input prompts
        if points is not None:
            points = torch.as_tensor(points, dtype=torch.float32, device=self.device)
            points = points[None] if points.ndim == 1 else points
            # Assuming labels are all positive if users don't pass labels.
            if labels is None:
                labels = np.ones(points.shape[0])
            labels = torch.as_tensor(labels, dtype=torch.int32, device=self.device)
            points *= r
            # (N, 2) --> (N, 1, 2), (N, ) --> (N, 1)
            points, labels = points[:, None, :], labels[:, None]
        if bboxes is not None:
            bboxes = torch.as_tensor(bboxes, dtype=torch.float32, device=self.device)
            bboxes = bboxes[None] if bboxes.ndim == 1 else bboxes
            bboxes *= r
        if masks is not None:
            masks = torch.as_tensor(masks, dtype=torch.float32, device=self.device).unsqueeze(1)

        points = (points, labels) if points is not None else None
        # Embed prompts
        sparse_embeddings, dense_embeddings = self.model.prompt_encoder(points=points, boxes=bboxes, masks=masks)

        # Predict masks
        pred_masks, pred_scores = self.model.mask_decoder(
            image_embeddings=features,
            image_pe=self.model.prompt_encoder.get_dense_pe(),
            sparse_prompt_embeddings=sparse_embeddings,
            dense_prompt_embeddings=dense_embeddings,
            multimask_output=multimask_output,
        )

        # (N, d, H, W) --> (N*d, H, W), (N, d) --> (N*d, )
        # `d` could be 1 or 3 depends on `multimask_output`.
        return pred_masks.flatten(0, 1), pred_scores.flatten(0, 1)

    def generate(
        self,
        im,
        crop_n_layers=0,
        crop_overlap_ratio=512 / 1500,
        crop_downscale_factor=1,
        point_grids=None,
        points_stride=32,
        points_batch_size=64,
        conf_thres=0.88,
        stability_score_thresh=0.95,
        stability_score_offset=0.95,
        crop_nms_thresh=0.7,
    ):
        """
        Perform image segmentation using the Segment Anything Model (SAM).

        This function segments an entire image into constituent parts by leveraging SAM's advanced architecture
        and real-time performance capabilities. It can optionally work on image crops for finer segmentation.

        Args:
            im (torch.Tensor): Input tensor representing the preprocessed image with dimensions (N, C, H, W).
            crop_n_layers (int): Specifies the number of layers for additional mask predictions on image crops.
                                 Each layer produces 2**i_layer number of image crops.
            crop_overlap_ratio (float): Determines the overlap between crops. Scaled down in subsequent layers.
            crop_downscale_factor (int): Scaling factor for the number of sampled points-per-side in each layer.
            point_grids (list[np.ndarray], optional): Custom grids for point sampling normalized to [0,1].
                                                      Used in the nth crop layer.
            points_stride (int, optional): Number of points to sample along each side of the image.
                                           Exclusive with 'point_grids'.
            points_batch_size (int): Batch size for the number of points processed simultaneously.
            conf_thres (float): Confidence threshold [0,1] for filtering based on the model's mask quality prediction.
            stability_score_thresh (float): Stability threshold [0,1] for mask filtering based on mask stability.
            stability_score_offset (float): Offset value for calculating stability score.
            crop_nms_thresh (float): IoU cutoff for NMS to remove duplicate masks between crops.

        Returns:
            (tuple): A tuple containing segmented masks, confidence scores, and bounding boxes.
        """
        import torchvision  # scope for faster 'import ultralytics'

        self.segment_all = True
        ih, iw = im.shape[2:]
        crop_regions, layer_idxs = generate_crop_boxes((ih, iw), crop_n_layers, crop_overlap_ratio)
        if point_grids is None:
            point_grids = build_all_layer_point_grids(points_stride, crop_n_layers, crop_downscale_factor)
        pred_masks, pred_scores, pred_bboxes, region_areas = [], [], [], []
        for crop_region, layer_idx in zip(crop_regions, layer_idxs):
            x1, y1, x2, y2 = crop_region
            w, h = x2 - x1, y2 - y1
            area = torch.tensor(w * h, device=im.device)
            points_scale = np.array([[w, h]])  # w, h
            # Crop image and interpolate to input size
            crop_im = F.interpolate(im[..., y1:y2, x1:x2], (ih, iw), mode="bilinear", align_corners=False)
            # (num_points, 2)
            points_for_image = point_grids[layer_idx] * points_scale
            crop_masks, crop_scores, crop_bboxes = [], [], []
            for (points,) in batch_iterator(points_batch_size, points_for_image):
                pred_mask, pred_score = self.prompt_inference(crop_im, points=points, multimask_output=True)
                # Interpolate predicted masks to input size
                pred_mask = F.interpolate(pred_mask[None], (h, w), mode="bilinear", align_corners=False)[0]
                idx = pred_score > conf_thres
                pred_mask, pred_score = pred_mask[idx], pred_score[idx]

                stability_score = calculate_stability_score(
                    pred_mask, self.model.mask_threshold, stability_score_offset
                )
                idx = stability_score > stability_score_thresh
                pred_mask, pred_score = pred_mask[idx], pred_score[idx]
                # Bool type is much more memory-efficient.
                pred_mask = pred_mask > self.model.mask_threshold
                # (N, 4)
                pred_bbox = batched_mask_to_box(pred_mask).float()
                keep_mask = ~is_box_near_crop_edge(pred_bbox, crop_region, [0, 0, iw, ih])
                if not torch.all(keep_mask):
                    pred_bbox, pred_mask, pred_score = pred_bbox[keep_mask], pred_mask[keep_mask], pred_score[keep_mask]

                crop_masks.append(pred_mask)
                crop_bboxes.append(pred_bbox)
                crop_scores.append(pred_score)

            # Do nms within this crop
            crop_masks = torch.cat(crop_masks)
            crop_bboxes = torch.cat(crop_bboxes)
            crop_scores = torch.cat(crop_scores)
            keep = torchvision.ops.nms(crop_bboxes, crop_scores, self.args.iou)  # NMS
            crop_bboxes = uncrop_boxes_xyxy(crop_bboxes[keep], crop_region)
            crop_masks = uncrop_masks(crop_masks[keep], crop_region, ih, iw)
            crop_scores = crop_scores[keep]

            pred_masks.append(crop_masks)
            pred_bboxes.append(crop_bboxes)
            pred_scores.append(crop_scores)
            region_areas.append(area.expand(len(crop_masks)))

        pred_masks = torch.cat(pred_masks)
        pred_bboxes = torch.cat(pred_bboxes)
        pred_scores = torch.cat(pred_scores)
        region_areas = torch.cat(region_areas)

        # Remove duplicate masks between crops
        if len(crop_regions) > 1:
            scores = 1 / region_areas
            keep = torchvision.ops.nms(pred_bboxes, scores, crop_nms_thresh)
            pred_masks, pred_bboxes, pred_scores = pred_masks[keep], pred_bboxes[keep], pred_scores[keep]

        return pred_masks, pred_scores, pred_bboxes

    def setup_model(self, model, verbose=True):
        """
        Initializes the Segment Anything Model (SAM) for inference.

        This method sets up the SAM model by allocating it to the appropriate device and initializing the necessary
        parameters for image normalization and other Ultralytics compatibility settings.

        Args:
            model (torch.nn.Module): A pre-trained SAM model. If None, a model will be built based on configuration.
            verbose (bool): If True, prints selected device information.

        Attributes:
            model (torch.nn.Module): The SAM model allocated to the chosen device for inference.
            device (torch.device): The device to which the model and tensors are allocated.
            mean (torch.Tensor): The mean values for image normalization.
            std (torch.Tensor): The standard deviation values for image normalization.
        """
        device = select_device(self.args.device, verbose=verbose)
        if model is None:
            model = build_sam(self.args.model)
        model.eval()
        self.model = model.to(device)
        self.device = device
        self.mean = torch.tensor([123.675, 116.28, 103.53]).view(-1, 1, 1).to(device)
        self.std = torch.tensor([58.395, 57.12, 57.375]).view(-1, 1, 1).to(device)

        # Ultralytics compatibility settings
        self.model.pt = False
        self.model.triton = False
        self.model.stride = 32
        self.model.fp16 = False
        self.done_warmup = True

    def postprocess(self, preds, img, orig_imgs):
        """
        Post-processes SAM's inference outputs to generate object detection masks and bounding boxes.

        The method scales masks and boxes to the original image size and applies a threshold to the mask predictions.
        The SAM model uses advanced architecture and promptable segmentation tasks to achieve real-time performance.

        Args:
            preds (tuple): The output from SAM model inference, containing masks, scores, and optional bounding boxes.
            img (torch.Tensor): The processed input image tensor.
            orig_imgs (list | torch.Tensor): The original, unprocessed images.

        Returns:
            (list): List of Results objects containing detection masks, bounding boxes, and other metadata.
        """
        # (N, 1, H, W), (N, 1)
        pred_masks, pred_scores = preds[:2]
        pred_bboxes = preds[2] if self.segment_all else None
        names = dict(enumerate(str(i) for i in range(len(pred_masks))))

        if not isinstance(orig_imgs, list):  # input images are a torch.Tensor, not a list
            orig_imgs = ops.convert_torch2numpy_batch(orig_imgs)

        results = []
        for i, masks in enumerate([pred_masks]):
            orig_img = orig_imgs[i]
            if pred_bboxes is not None:
                pred_bboxes = ops.scale_boxes(img.shape[2:], pred_bboxes.float(), orig_img.shape, padding=False)
                cls = torch.arange(len(pred_masks), dtype=torch.int32, device=pred_masks.device)
                pred_bboxes = torch.cat([pred_bboxes, pred_scores[:, None], cls[:, None]], dim=-1)

            masks = ops.scale_masks(masks[None].float(), orig_img.shape[:2], padding=False)[0]
            masks = masks > self.model.mask_threshold  # to bool
            img_path = self.batch[0][i]
            results.append(Results(orig_img, path=img_path, names=names, masks=masks, boxes=pred_bboxes))
        # Reset segment-all mode.
        self.segment_all = False
        return results

    def setup_source(self, source):
        """
        Sets up the data source for inference.

        This method configures the data source from which images will be fetched for inference. The source could be a
        directory, a video file, or other types of image data sources.

        Args:
            source (str | Path): The path to the image data source for inference.
        """
        if source is not None:
            super().setup_source(source)

    def set_image(self, image):
        """
        Preprocesses and sets a single image for inference.

        This function sets up the model if not already initialized, configures the data source to the specified image,
        and preprocesses the image for feature extraction. Only one image can be set at a time.

        Args:
            image (str | np.ndarray): Image file path as a string, or a np.ndarray image read by cv2.

        Raises:
            AssertionError: If more than one image is set.
        """
        if self.model is None:
            model = build_sam(self.args.model)
            self.setup_model(model)
        self.setup_source(image)
        assert len(self.dataset) == 1, "`set_image` only supports setting one image!"
        for batch in self.dataset:
            im = self.preprocess(batch[1])
            self.features = self.model.image_encoder(im)
            self.im = im
            break

    def set_prompts(self, prompts):
        """Set prompts in advance."""
        self.prompts = prompts

    def reset_image(self):
        """Resets the image and its features to None."""
        self.im = None
        self.features = None

    @staticmethod
    def remove_small_regions(masks, min_area=0, nms_thresh=0.7):
        """
        Perform post-processing on segmentation masks generated by the Segment Anything Model (SAM). Specifically, this
        function removes small disconnected regions and holes from the input masks, and then performs Non-Maximum
        Suppression (NMS) to eliminate any newly created duplicate boxes.

        Args:
            masks (torch.Tensor): A tensor containing the masks to be processed. Shape should be (N, H, W), where N is
                                  the number of masks, H is height, and W is width.
            min_area (int): The minimum area below which disconnected regions and holes will be removed. Defaults to 0.
            nms_thresh (float): The IoU threshold for the NMS algorithm. Defaults to 0.7.

        Returns:
            (tuple([torch.Tensor, List[int]])):
                - new_masks (torch.Tensor): The processed masks with small regions removed. Shape is (N, H, W).
                - keep (List[int]): The indices of the remaining masks post-NMS, which can be used to filter the boxes.
        """
        import torchvision  # scope for faster 'import ultralytics'

        if len(masks) == 0:
            return masks

        # Filter small disconnected regions and holes
        new_masks = []
        scores = []
        for mask in masks:
            mask = mask.cpu().numpy().astype(np.uint8)
            mask, changed = remove_small_regions(mask, min_area, mode="holes")
            unchanged = not changed
            mask, changed = remove_small_regions(mask, min_area, mode="islands")
            unchanged = unchanged and not changed

            new_masks.append(torch.as_tensor(mask).unsqueeze(0))
            # Give score=0 to changed masks and 1 to unchanged masks so NMS prefers masks not needing postprocessing
            scores.append(float(unchanged))

        # Recalculate boxes and remove any new duplicates
        new_masks = torch.cat(new_masks, dim=0)
        boxes = batched_mask_to_box(new_masks)
        keep = torchvision.ops.nms(boxes.float(), torch.as_tensor(scores), nms_thresh)

        return new_masks[keep].to(device=masks.device, dtype=masks.dtype), keep

__init__(cfg=DEFAULT_CFG, overrides=None, _callbacks=None)

рдкреНрд░реЗрдбрд┐рдХреНрдЯрд░ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди, рдУрд╡рд░рд░рд╛рдЗрдб рдФрд░ рдХреЙрд▓рдмреИрдХ рдХреЗ рд╕рд╛рде рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░реЗрдВред

рд╡рд┐рдзрд┐ рдкреНрд░реЗрдбрд┐рдХреНрдЯрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реЗрдЯ рдХрд░рддреА рд╣реИ рдФрд░ рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП рдХрд┐рд╕реА рднреА рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдУрд╡рд░рд░рд╛рдЗрдб рдпрд╛ рдХреЙрд▓рдмреИрдХ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреА рд╣реИред рдпрд╣ рдХреЗ рд▓рд┐рдП рдХрд╛рд░реНрдп-рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдкреНрд░рд╛рд░рдВрдн рдХрд░рддрд╛ рд╣реИ SAM, рдЬреИрд╕реЗ рдХрд┐ рдЗрд╖реНрдЯрддрдо рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЗ рд▓рд┐рдП retina_masks True рдкрд░ рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
cfg dict

рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╢рдмреНрджрдХреЛрд╢ред

DEFAULT_CFG
overrides dict

рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдорд╛рдиреЛрдВ рдХрд╛ рд╢рдмреНрджрдХреЛрд╢ред

None
_callbacks dict

рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЙрд▓рдмреИрдХ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдХрд╛ рд╢рдмреНрджрдХреЛрд╢ред

None
рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):
    """
    Initialize the Predictor with configuration, overrides, and callbacks.

    The method sets up the Predictor object and applies any configuration overrides or callbacks provided. It
    initializes task-specific settings for SAM, such as retina_masks being set to True for optimal results.

    Args:
        cfg (dict): Configuration dictionary.
        overrides (dict, optional): Dictionary of values to override default configuration.
        _callbacks (dict, optional): Dictionary of callback functions to customize behavior.
    """
    if overrides is None:
        overrides = {}
    overrides.update(dict(task="segment", mode="predict", imgsz=1024))
    super().__init__(cfg, overrides, _callbacks)
    self.args.retina_masks = True
    self.im = None
    self.features = None
    self.prompts = {}
    self.segment_all = False

generate(im, crop_n_layers=0, crop_overlap_ratio=512 / 1500, crop_downscale_factor=1, point_grids=None, points_stride=32, points_batch_size=64, conf_thres=0.88, stability_score_thresh=0.95, stability_score_offset=0.95, crop_nms_thresh=0.7)

рд╕реЗрдЧрдореЗрдВрдЯ рдПрдиреАрдерд┐рдВрдЧ рдореЙрдбрд▓ (SAM).

рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рд▓реАрд╡рд░реЗрдЬ рджреНрд╡рд╛рд░рд╛ рдПрдХ рд╕рдВрдкреВрд░реНрдг рдЫрд╡рд┐ рдХреЛ рдШрдЯрдХ рднрд╛рдЧреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рддрд╛ рд╣реИ SAMрдЙрдиреНрдирдд рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдФрд░ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдкреНрд░рджрд░реНрд╢рди рдХреНрд╖рдорддрд╛рдУрдВред рдпрд╣ рд╡реИрдХрд▓реНрдкрд┐рдХ рд░реВрдк рд╕реЗ рдмреЗрд╣рддрд░ рд╡рд┐рднрд╛рдЬрди рдХреЗ рд▓рд┐рдП рдЫрд╡рд┐ рдлрд╕рд▓реЛрдВ рдкрд░ рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ.

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
im Tensor

рдирд┐рд╡реЗрд╢ tensor рдЖрдпрд╛рдореЛрдВ (рдПрди, рд╕реА, рдПрдЪ, рдбрдмреНрд▓реНрдпреВ) рдХреЗ рд╕рд╛рде рдкреВрд░реНрд╡рд╕рдВрд╕рд╛рдзрд┐рдд рдЫрд╡рд┐ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рдирд╛ред

рдЖрд╡рд╢реНрдпрдХ
crop_n_layers int

рдЫрд╡рд┐ рдлрд╕рд▓реЛрдВ рдкрд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдореБрдЦреМрдЯрд╛ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдкрд░рддреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддрд╛ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рдкрд░рдд 2 ** i_layer рдЫрд╡рд┐ рдлрд╕рд▓реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХрд╛ рдЙрддреНрдкрд╛рджрди рдХрд░рддреА рд╣реИред

0
crop_overlap_ratio float

рдлрд╕рд▓реЛрдВ рдХреЗ рдмреАрдЪ рдУрд╡рд░рд▓реИрдк рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИред рдмрд╛рдж рдХреА рдкрд░рддреЛрдВ рдореЗрдВ рдиреАрдЪреЗ рдЧрд┐рд░рд╛рдпрд╛ рдЧрдпрд╛ред

512 / 1500
crop_downscale_factor int

рдкреНрд░рддреНрдпреЗрдХ рдкрд░рдд рдореЗрдВ рдирдореВрдирд╛ рдЕрдВрдХ рдкреНрд░рддрд┐ рдкрдХреНрд╖ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд▓рд┐рдП рд╕реНрдХреЗрд▓рд┐рдВрдЧ рдХрд╛рд░рдХ.

1
point_grids list[ndarray]

рдмрд┐рдВрджреБ рдирдореВрдирд╛рдХрд░рдг рдХреЗ рд▓рд┐рдП рдХрд╕реНрдЯрдо рдЧреНрд░рд┐рдб [0,1] рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рд╣реИрдВред nth рдлрд╕рд▓ рдкрд░рдд рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

None
points_stride int

рдЫрд╡рд┐ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдкрдХреНрд╖ рдХреЗ рд╕рд╛рде рдирдореВрдирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдВрдХ рдХреА рд╕рдВрдЦреНрдпрд╛. 'point_grids' рдХреЗ рд╕рд╛рде рд╡рд┐рд╢реЗрд╖ред

32
points_batch_size int

рдПрдХ рд╕рд╛рде рд╕рдВрд╕рд╛рдзрд┐рдд рдЕрдВрдХреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд▓рд┐рдП рдмреИрдЪ рдЖрдХрд╛рд░ред

64
conf_thres float

рдореЙрдбрд▓ рдХреА рдореБрдЦреМрдЯрд╛ рдЧреБрдгрд╡рддреНрддрд╛ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЖрддреНрдорд╡рд┐рд╢реНрд╡рд╛рд╕ рд╕реАрдорд╛ [0,1]ред

0.88
stability_score_thresh float

рд╕реНрдерд┐рд░рддрд╛ рд╕реАрдорд╛ [0,1] рдорд╛рд╕реНрдХ рд╕реНрдерд┐рд░рддрд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдорд╛рд╕реНрдХ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдПред

0.95
stability_score_offset float

рд╕реНрдерд┐рд░рддрд╛ рд╕реНрдХреЛрд░ рдХреА рдЧрдгрдирд╛ рдХреЗ рд▓рд┐рдП рдСрдлрд╕реЗрдЯ рдореВрд▓реНрдпред

0.95
crop_nms_thresh float

рдлрд╕рд▓реЛрдВ рдХреЗ рдмреАрдЪ рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдорд╛рд╕реНрдХ рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдирдПрдордПрд╕ рдХреЗ рд▓рд┐рдП IoU рдХрдЯрдСрдлред

0.7

рджреЗрддрд╛:

рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
tuple

рдПрдХ рдЯрдкрд▓ рдЬрд┐рд╕рдореЗрдВ рдЦрдВрдбрд┐рдд рдорд╛рд╕реНрдХ, рдЖрддреНрдорд╡рд┐рд╢реНрд╡рд╛рд╕ рд╕реНрдХреЛрд░ рдФрд░ рдмрд╛рдЙрдВрдбрд┐рдВрдЧ рдмреЙрдХреНрд╕ рд╣реЛрддреЗ рд╣реИрдВред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def generate(
    self,
    im,
    crop_n_layers=0,
    crop_overlap_ratio=512 / 1500,
    crop_downscale_factor=1,
    point_grids=None,
    points_stride=32,
    points_batch_size=64,
    conf_thres=0.88,
    stability_score_thresh=0.95,
    stability_score_offset=0.95,
    crop_nms_thresh=0.7,
):
    """
    Perform image segmentation using the Segment Anything Model (SAM).

    This function segments an entire image into constituent parts by leveraging SAM's advanced architecture
    and real-time performance capabilities. It can optionally work on image crops for finer segmentation.

    Args:
        im (torch.Tensor): Input tensor representing the preprocessed image with dimensions (N, C, H, W).
        crop_n_layers (int): Specifies the number of layers for additional mask predictions on image crops.
                             Each layer produces 2**i_layer number of image crops.
        crop_overlap_ratio (float): Determines the overlap between crops. Scaled down in subsequent layers.
        crop_downscale_factor (int): Scaling factor for the number of sampled points-per-side in each layer.
        point_grids (list[np.ndarray], optional): Custom grids for point sampling normalized to [0,1].
                                                  Used in the nth crop layer.
        points_stride (int, optional): Number of points to sample along each side of the image.
                                       Exclusive with 'point_grids'.
        points_batch_size (int): Batch size for the number of points processed simultaneously.
        conf_thres (float): Confidence threshold [0,1] for filtering based on the model's mask quality prediction.
        stability_score_thresh (float): Stability threshold [0,1] for mask filtering based on mask stability.
        stability_score_offset (float): Offset value for calculating stability score.
        crop_nms_thresh (float): IoU cutoff for NMS to remove duplicate masks between crops.

    Returns:
        (tuple): A tuple containing segmented masks, confidence scores, and bounding boxes.
    """
    import torchvision  # scope for faster 'import ultralytics'

    self.segment_all = True
    ih, iw = im.shape[2:]
    crop_regions, layer_idxs = generate_crop_boxes((ih, iw), crop_n_layers, crop_overlap_ratio)
    if point_grids is None:
        point_grids = build_all_layer_point_grids(points_stride, crop_n_layers, crop_downscale_factor)
    pred_masks, pred_scores, pred_bboxes, region_areas = [], [], [], []
    for crop_region, layer_idx in zip(crop_regions, layer_idxs):
        x1, y1, x2, y2 = crop_region
        w, h = x2 - x1, y2 - y1
        area = torch.tensor(w * h, device=im.device)
        points_scale = np.array([[w, h]])  # w, h
        # Crop image and interpolate to input size
        crop_im = F.interpolate(im[..., y1:y2, x1:x2], (ih, iw), mode="bilinear", align_corners=False)
        # (num_points, 2)
        points_for_image = point_grids[layer_idx] * points_scale
        crop_masks, crop_scores, crop_bboxes = [], [], []
        for (points,) in batch_iterator(points_batch_size, points_for_image):
            pred_mask, pred_score = self.prompt_inference(crop_im, points=points, multimask_output=True)
            # Interpolate predicted masks to input size
            pred_mask = F.interpolate(pred_mask[None], (h, w), mode="bilinear", align_corners=False)[0]
            idx = pred_score > conf_thres
            pred_mask, pred_score = pred_mask[idx], pred_score[idx]

            stability_score = calculate_stability_score(
                pred_mask, self.model.mask_threshold, stability_score_offset
            )
            idx = stability_score > stability_score_thresh
            pred_mask, pred_score = pred_mask[idx], pred_score[idx]
            # Bool type is much more memory-efficient.
            pred_mask = pred_mask > self.model.mask_threshold
            # (N, 4)
            pred_bbox = batched_mask_to_box(pred_mask).float()
            keep_mask = ~is_box_near_crop_edge(pred_bbox, crop_region, [0, 0, iw, ih])
            if not torch.all(keep_mask):
                pred_bbox, pred_mask, pred_score = pred_bbox[keep_mask], pred_mask[keep_mask], pred_score[keep_mask]

            crop_masks.append(pred_mask)
            crop_bboxes.append(pred_bbox)
            crop_scores.append(pred_score)

        # Do nms within this crop
        crop_masks = torch.cat(crop_masks)
        crop_bboxes = torch.cat(crop_bboxes)
        crop_scores = torch.cat(crop_scores)
        keep = torchvision.ops.nms(crop_bboxes, crop_scores, self.args.iou)  # NMS
        crop_bboxes = uncrop_boxes_xyxy(crop_bboxes[keep], crop_region)
        crop_masks = uncrop_masks(crop_masks[keep], crop_region, ih, iw)
        crop_scores = crop_scores[keep]

        pred_masks.append(crop_masks)
        pred_bboxes.append(crop_bboxes)
        pred_scores.append(crop_scores)
        region_areas.append(area.expand(len(crop_masks)))

    pred_masks = torch.cat(pred_masks)
    pred_bboxes = torch.cat(pred_bboxes)
    pred_scores = torch.cat(pred_scores)
    region_areas = torch.cat(region_areas)

    # Remove duplicate masks between crops
    if len(crop_regions) > 1:
        scores = 1 / region_areas
        keep = torchvision.ops.nms(pred_bboxes, scores, crop_nms_thresh)
        pred_masks, pred_bboxes, pred_scores = pred_masks[keep], pred_bboxes[keep], pred_scores[keep]

    return pred_masks, pred_scores, pred_bboxes

inference(im, bboxes=None, points=None, labels=None, masks=None, multimask_output=False, *args, **kwargs)

рд╡рд░реНрддрдорд╛рди рдореЗрдВ рднрд░реА рд╣реБрдИ рдЫрд╡рд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рджрд┐рдП рдЧрдП рдЗрдирдкреБрдЯ рд╕рдВрдХреЗрддреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЫрд╡рд┐ рд╡рд┐рднрд╛рдЬрди рдЕрдиреБрдорд╛рди рдХрд░реЗрдВред рдпрд╣рди рд╡рд┐рдзрд┐ рдХрд╛ рд▓рд╛рдн рдЙрдард╛рддрд╛ рд╣реИ SAM(рд╕реЗрдЧрдореЗрдВрдЯ рдПрдиреАрдерд┐рдВрдЧ рдореЙрдбрд▓) рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдЬрд┐рд╕рдореЗрдВ рдЗрдореЗрдЬ рдПрдирдХреЛрдбрд░, рдкреНрд░реЙрдореНрдкреНрдЯ рдПрдирдХреЛрдбрд░ рдФрд░ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдФрд░ рд╢реАрдШреНрд░ рд╡рд┐рднрд╛рдЬрди рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдорд╛рд╕реНрдХ рдбрд┐рдХреЛрдбрд░ред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
im Tensor

рдореЗрдВ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕реНрдб рдЗрдирдкреБрдЯ рдЫрд╡рд┐ tensor рдкреНрд░рд╛рд░реВрдк, рдЖрдХрд╛рд░ рдХреЗ рд╕рд╛рде (рдПрди, рд╕реА, рдПрдЪ, рдбрдмреНрд▓реНрдпреВ)ред

рдЖрд╡рд╢реНрдпрдХ
bboxes ndarray | List

рдЖрдХрд╛рд░ (N, 4) рдХреЗ рд╕рд╛рде рдмрд╛рдЙрдВрдбрд┐рдВрдЧ рдмреЙрдХреНрд╕, XYXY рдкреНрд░рд╛рд░реВрдк рдореЗрдВред

None
points ndarray | List

рдкрд┐рдХреНрд╕реЗрд▓ рдореЗрдВ рдЖрдХреГрддрд┐ (N, 2) рдХреЗ рд╕рд╛рде рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдерд╛рдиреЛрдВ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдмрд┐рдВрджреБ.

None
labels ndarray | List

рдмрд┐рдВрджреБ рд╕рдВрдХреЗрддреЛрдВ рдХреЗ рд▓рд┐рдП рд▓реЗрдмрд▓, рдЖрдХрд╛рд░ (рдПрди, )ред 1 = рдЕрдЧреНрд░рднреВрдорд┐, 0 = рдкреГрд╖реНрдарднреВрдорд┐ред

None
masks ndarray

рдкрд┐рдЫрд▓реЗ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпреЛрдВ рдХреЗ рдЖрдХрд╛рд░ рд╕реЗ рдХрдо-рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди рдорд╛рд╕реНрдХ (рдПрди, рдПрдЪ, рдбрдмреНрд▓реНрдпреВ)ред рдХреЗ рд▓рд┐рдП SAM рдПрдЪ = рдбрдмреНрд▓реНрдпреВ = 256ред

None
multimask_output bool

рдПрдХрд╛рдзрд┐рдХ рдорд╛рд╕реНрдХ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдзреНрд╡рдЬред рдЕрд╕реНрдкрд╖реНрдЯ рд╕рдВрдХреЗрддреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рд╣рд╛рдпрдХред

False

рджреЗрддрд╛:

рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
tuple

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддреАрди рддрддреНрд╡ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред - np.ndarray: рдЖрдХрд╛рд░ CxHxW рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯ рдорд╛рд╕реНрдХ, рдЬрд╣рд╛рдВ C рдЙрддреНрдкрдиреНрди рдорд╛рд╕реНрдХ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╣реИред - np.ndarray: рд▓рдВрдмрд╛рдИ рд╕реА рдХреА рдПрдХ рд╕рд░рдгреА рдЬрд┐рд╕рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдорд╛рд╕реНрдХ рдХреЗ рд▓рд┐рдП рдореЙрдбрд▓ рджреНрд╡рд╛рд░рд╛ рдЕрдиреБрдорд╛рдирд┐рдд рдЧреБрдгрд╡рддреНрддрд╛ рд╕реНрдХреЛрд░ рд╣реЛрддреЗ рд╣реИрдВред - np.ndarray: рдмрд╛рдж рдХреЗ рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдЖрдХрд╛рд░ CxHxW рдХреЗ рдХрдо-рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди рд▓реЙрдЧ, рдЬрд╣рд╛рдВ H=W=256ред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def inference(self, im, bboxes=None, points=None, labels=None, masks=None, multimask_output=False, *args, **kwargs):
    """
    Perform image segmentation inference based on the given input cues, using the currently loaded image. This
    method leverages SAM's (Segment Anything Model) architecture consisting of image encoder, prompt encoder, and
    mask decoder for real-time and promptable segmentation tasks.

    Args:
        im (torch.Tensor): The preprocessed input image in tensor format, with shape (N, C, H, W).
        bboxes (np.ndarray | List, optional): Bounding boxes with shape (N, 4), in XYXY format.
        points (np.ndarray | List, optional): Points indicating object locations with shape (N, 2), in pixels.
        labels (np.ndarray | List, optional): Labels for point prompts, shape (N, ). 1 = foreground, 0 = background.
        masks (np.ndarray, optional): Low-resolution masks from previous predictions shape (N,H,W). For SAM H=W=256.
        multimask_output (bool, optional): Flag to return multiple masks. Helpful for ambiguous prompts.

    Returns:
        (tuple): Contains the following three elements.
            - np.ndarray: The output masks in shape CxHxW, where C is the number of generated masks.
            - np.ndarray: An array of length C containing quality scores predicted by the model for each mask.
            - np.ndarray: Low-resolution logits of shape CxHxW for subsequent inference, where H=W=256.
    """
    # Override prompts if any stored in self.prompts
    bboxes = self.prompts.pop("bboxes", bboxes)
    points = self.prompts.pop("points", points)
    masks = self.prompts.pop("masks", masks)

    if all(i is None for i in [bboxes, points, masks]):
        return self.generate(im, *args, **kwargs)

    return self.prompt_inference(im, bboxes, points, labels, masks, multimask_output)

postprocess(preds, img, orig_imgs)

рдкреЛрд╕реНрдЯ-рдкреНрд░рдХреНрд░рд┐рдпрд╛рдПрдВ SAMрдСрдмреНрдЬреЗрдХреНрдЯ рдбрд┐рдЯреЗрдХреНрд╢рди рдорд╛рд╕реНрдХ рдФрд░ рдмрд╛рдЙрдВрдбрд┐рдВрдЧ рдмреЙрдХреНрд╕ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдорд╛рди рдЖрдЙрдЯрдкреБрдЯ рдХрд░рддрд╛ рд╣реИред

рд╡рд┐рдзрд┐ рдорд╛рд╕реНрдХ рдФрд░ рдмрдХреНрд╕реЗ рдХреЛ рдореВрд▓ рдЫрд╡рд┐ рдЖрдХрд╛рд░ рдореЗрдВ рдорд╛рдкрддреА рд╣реИ рдФрд░ рдореБрдЦреМрдЯрд╛ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реАрдорд╛ рд▓рд╛рдЧреВ рдХрд░рддреА рд╣реИред рд╡рд╣реА SAM рдореЙрдбрд▓ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдиреНрдирдд рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдФрд░ рд╢реАрдШреНрд░ рд╡рд┐рднрд╛рдЬрди рдХрд╛рд░реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
preds tuple

рд╕реЗ рдЖрдЙрдЯрдкреБрдЯ SAM рдореЙрдбрд▓ рдЕрдиреБрдорд╛рди, рдЬрд┐рд╕рдореЗрдВ рдорд╛рд╕реНрдХ, рд╕реНрдХреЛрд░ рдФрд░ рд╡реИрдХрд▓реНрдкрд┐рдХ рдмрд╛рдЙрдВрдбрд┐рдВрдЧ рдмреЙрдХреНрд╕ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред

рдЖрд╡рд╢реНрдпрдХ
img Tensor

рд╕рдВрд╕рд╛рдзрд┐рдд рдЗрдирдкреБрдЯ рдЫрд╡рд┐ tensor.

рдЖрд╡рд╢реНрдпрдХ
orig_imgs list | Tensor

рдореВрд▓, рдЕрд╕рдВрд╕рд╛рдзрд┐рдд рдЪрд┐рддреНрд░ред

рдЖрд╡рд╢реНрдпрдХ

рджреЗрддрд╛:

рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
list

рдбрд┐рдЯреЗрдХреНрд╢рди рдорд╛рд╕реНрдХ, рдмрд╛рдЙрдВрдбрд┐рдВрдЧ рдмреЙрдХреНрд╕ рдФрд░ рдЕрдиреНрдп рдореЗрдЯрд╛рдбреЗрдЯрд╛ рд╡рд╛рд▓реЗ рдкрд░рд┐рдгрд╛рдо рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреА рд╕реВрдЪреАред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def postprocess(self, preds, img, orig_imgs):
    """
    Post-processes SAM's inference outputs to generate object detection masks and bounding boxes.

    The method scales masks and boxes to the original image size and applies a threshold to the mask predictions.
    The SAM model uses advanced architecture and promptable segmentation tasks to achieve real-time performance.

    Args:
        preds (tuple): The output from SAM model inference, containing masks, scores, and optional bounding boxes.
        img (torch.Tensor): The processed input image tensor.
        orig_imgs (list | torch.Tensor): The original, unprocessed images.

    Returns:
        (list): List of Results objects containing detection masks, bounding boxes, and other metadata.
    """
    # (N, 1, H, W), (N, 1)
    pred_masks, pred_scores = preds[:2]
    pred_bboxes = preds[2] if self.segment_all else None
    names = dict(enumerate(str(i) for i in range(len(pred_masks))))

    if not isinstance(orig_imgs, list):  # input images are a torch.Tensor, not a list
        orig_imgs = ops.convert_torch2numpy_batch(orig_imgs)

    results = []
    for i, masks in enumerate([pred_masks]):
        orig_img = orig_imgs[i]
        if pred_bboxes is not None:
            pred_bboxes = ops.scale_boxes(img.shape[2:], pred_bboxes.float(), orig_img.shape, padding=False)
            cls = torch.arange(len(pred_masks), dtype=torch.int32, device=pred_masks.device)
            pred_bboxes = torch.cat([pred_bboxes, pred_scores[:, None], cls[:, None]], dim=-1)

        masks = ops.scale_masks(masks[None].float(), orig_img.shape[:2], padding=False)[0]
        masks = masks > self.model.mask_threshold  # to bool
        img_path = self.batch[0][i]
        results.append(Results(orig_img, path=img_path, names=names, masks=masks, boxes=pred_bboxes))
    # Reset segment-all mode.
    self.segment_all = False
    return results

pre_transform(im)

рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЗрдирдкреБрдЯ рдЗрдореЗрдЬ рдкрд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░реЗрдВред

рд╡рд┐рдзрд┐ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреА рд╣реИ рдЬреИрд╕реЗ рдХрд┐ рдЖрдЧреЗ рдХреЗ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП рдЫрд╡рд┐ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдХрд╛рд░ рдмрджрд▓рдирд╛ред рд╡рд░реНрддрдорд╛рди рдореЗрдВ, рдмреИрдЪ рдХрд┐рдП рдЧрдП рдЕрдиреБрдорд╛рди рд╕рдорд░реНрдерд┐рдд рдирд╣реАрдВ рд╣реИрдВ; рдЗрд╕рд▓рд┐рдП рд╕реВрдЪреА рдХреА рд▓рдВрдмрд╛рдИ 1 рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
im List[ndarray]

HWC numpy рд╕рд░рдгреА рдкреНрд░рд╛рд░реВрдк рдореЗрдВ рдЫрд╡рд┐рдпреЛрдВ рд╡рд╛рд▓реА рд╕реВрдЪреАред

рдЖрд╡рд╢реНрдпрдХ

рджреЗрддрд╛:

рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
List[ndarray]

рд░реВрдкрд╛рдВрддрд░рд┐рдд рдЫрд╡рд┐рдпреЛрдВ рдХреА рд╕реВрдЪреАред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def pre_transform(self, im):
    """
    Perform initial transformations on the input image for preprocessing.

    The method applies transformations such as resizing to prepare the image for further preprocessing.
    Currently, batched inference is not supported; hence the list length should be 1.

    Args:
        im (List[np.ndarray]): List containing images in HWC numpy array format.

    Returns:
        (List[np.ndarray]): List of transformed images.
    """
    assert len(im) == 1, "SAM model does not currently support batched inference"
    letterbox = LetterBox(self.args.imgsz, auto=False, center=False)
    return [letterbox(image=x) for x in im]

preprocess(im)

рдореЙрдбрд▓ рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдЗрдирдкреБрдЯ рдЫрд╡рд┐ рдХреЛ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕ рдХрд░реЗрдВред

рд╡рд┐рдзрд┐ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдФрд░ рд╕рд╛рдорд╛рдиреНрдпреАрдХрд░рдг рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдХреЗ рдЗрдирдкреБрдЯ рдЫрд╡рд┐ рддреИрдпрд╛рд░ рдХрд░рддреА рд╣реИред рдпрд╣ рджреЛрдиреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ torch.Tensor рдФрд░ рдЗрдирдкреБрдЯ рдкреНрд░рд╛рд░реВрдкреЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ np.ndarray рдХреА рд╕реВрдЪреАред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
im Tensor | List[ndarray]

рдмреАрд╕реАрдПрдЪрдбрдмреНрд▓реНрдпреВ tensor рдкреНрд░рд╛рд░реВрдк рдпрд╛ HWC numpy рд╕рд░рдгрд┐рдпреЛрдВ рдХреА рд╕реВрдЪреАред

рдЖрд╡рд╢реНрдпрдХ

рджреЗрддрд╛:

рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
Tensor

рдкреВрд░реНрд╡рд╕рдВрд╕рд╛рдзрд┐рдд рдЫрд╡рд┐ tensor.

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def preprocess(self, im):
    """
    Preprocess the input image for model inference.

    The method prepares the input image by applying transformations and normalization.
    It supports both torch.Tensor and list of np.ndarray as input formats.

    Args:
        im (torch.Tensor | List[np.ndarray]): BCHW tensor format or list of HWC numpy arrays.

    Returns:
        (torch.Tensor): The preprocessed image tensor.
    """
    if self.im is not None:
        return self.im
    not_tensor = not isinstance(im, torch.Tensor)
    if not_tensor:
        im = np.stack(self.pre_transform(im))
        im = im[..., ::-1].transpose((0, 3, 1, 2))
        im = np.ascontiguousarray(im)
        im = torch.from_numpy(im)

    im = im.to(self.device)
    im = im.half() if self.model.fp16 else im.float()
    if not_tensor:
        im = (im - self.mean) / self.std
    return im

prompt_inference(im, bboxes=None, points=None, labels=None, masks=None, multimask_output=False)

рдмрд╛рдЙрдВрдбрд┐рдВрдЧ рдмреЙрдХреНрд╕, рдкреЙрдЗрдВрдЯреНрд╕ рдФрд░ рдорд╛рд╕реНрдХ рдЬреИрд╕реЗ рд╕рдВрдХреЗрддреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЫрд╡рд┐ рд╡рд┐рднрд╛рдЬрди рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдЖрдВрддрд░рд┐рдХ рдХрд╛рд░реНрдпред рдлрд╝рд╛рдпрджрд╛ рдЙрдард╛рдирд╛ SAMрд╢реАрдШреНрд░-рдЖрдзрд╛рд░рд┐рдд, рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рд╡рд┐рднрд╛рдЬрди рдХреЗ рд▓рд┐рдП рд╡рд┐рд╢реЗрд╖ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
im Tensor

рдореЗрдВ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕реНрдб рдЗрдирдкреБрдЯ рдЫрд╡рд┐ tensor рдкреНрд░рд╛рд░реВрдк, рдЖрдХрд╛рд░ рдХреЗ рд╕рд╛рде (рдПрди, рд╕реА, рдПрдЪ, рдбрдмреНрд▓реНрдпреВ)ред

рдЖрд╡рд╢реНрдпрдХ
bboxes ndarray | List

рдЖрдХрд╛рд░ (N, 4) рдХреЗ рд╕рд╛рде рдмрд╛рдЙрдВрдбрд┐рдВрдЧ рдмреЙрдХреНрд╕, XYXY рдкреНрд░рд╛рд░реВрдк рдореЗрдВред

None
points ndarray | List

рдкрд┐рдХреНрд╕реЗрд▓ рдореЗрдВ рдЖрдХреГрддрд┐ (N, 2) рдХреЗ рд╕рд╛рде рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрдерд╛рдиреЛрдВ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдмрд┐рдВрджреБ.

None
labels ndarray | List

рдмрд┐рдВрджреБ рд╕рдВрдХреЗрддреЛрдВ рдХреЗ рд▓рд┐рдП рд▓реЗрдмрд▓, рдЖрдХрд╛рд░ (рдПрди, )ред 1 = рдЕрдЧреНрд░рднреВрдорд┐, 0 = рдкреГрд╖реНрдарднреВрдорд┐ред

None
masks ndarray

рдкрд┐рдЫрд▓реЗ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгрд┐рдпреЛрдВ рдХреЗ рдЖрдХрд╛рд░ рд╕реЗ рдХрдо-рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди рдорд╛рд╕реНрдХ (рдПрди, рдПрдЪ, рдбрдмреНрд▓реНрдпреВ)ред рдХреЗ рд▓рд┐рдП SAM рдПрдЪ = рдбрдмреНрд▓реНрдпреВ = 256ред

None
multimask_output bool

рдПрдХрд╛рдзрд┐рдХ рдорд╛рд╕реНрдХ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдзреНрд╡рдЬред рдЕрд╕реНрдкрд╖реНрдЯ рд╕рдВрдХреЗрддреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рд╣рд╛рдпрдХред

False

рджреЗрддрд╛:

рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
tuple

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рддреАрди рддрддреНрд╡ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред - np.ndarray: рдЖрдХрд╛рд░ CxHxW рдореЗрдВ рдЖрдЙрдЯрдкреБрдЯ рдорд╛рд╕реНрдХ, рдЬрд╣рд╛рдВ C рдЙрддреНрдкрдиреНрди рдорд╛рд╕реНрдХ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╣реИред - np.ndarray: рд▓рдВрдмрд╛рдИ рд╕реА рдХреА рдПрдХ рд╕рд░рдгреА рдЬрд┐рд╕рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдорд╛рд╕реНрдХ рдХреЗ рд▓рд┐рдП рдореЙрдбрд▓ рджреНрд╡рд╛рд░рд╛ рдЕрдиреБрдорд╛рдирд┐рдд рдЧреБрдгрд╡рддреНрддрд╛ рд╕реНрдХреЛрд░ рд╣реЛрддреЗ рд╣реИрдВред - np.ndarray: рдмрд╛рдж рдХреЗ рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдЖрдХрд╛рд░ CxHxW рдХреЗ рдХрдо-рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди рд▓реЙрдЧ, рдЬрд╣рд╛рдВ H=W=256ред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def prompt_inference(self, im, bboxes=None, points=None, labels=None, masks=None, multimask_output=False):
    """
    Internal function for image segmentation inference based on cues like bounding boxes, points, and masks.
    Leverages SAM's specialized architecture for prompt-based, real-time segmentation.

    Args:
        im (torch.Tensor): The preprocessed input image in tensor format, with shape (N, C, H, W).
        bboxes (np.ndarray | List, optional): Bounding boxes with shape (N, 4), in XYXY format.
        points (np.ndarray | List, optional): Points indicating object locations with shape (N, 2), in pixels.
        labels (np.ndarray | List, optional): Labels for point prompts, shape (N, ). 1 = foreground, 0 = background.
        masks (np.ndarray, optional): Low-resolution masks from previous predictions shape (N,H,W). For SAM H=W=256.
        multimask_output (bool, optional): Flag to return multiple masks. Helpful for ambiguous prompts.

    Returns:
        (tuple): Contains the following three elements.
            - np.ndarray: The output masks in shape CxHxW, where C is the number of generated masks.
            - np.ndarray: An array of length C containing quality scores predicted by the model for each mask.
            - np.ndarray: Low-resolution logits of shape CxHxW for subsequent inference, where H=W=256.
    """
    features = self.model.image_encoder(im) if self.features is None else self.features

    src_shape, dst_shape = self.batch[1][0].shape[:2], im.shape[2:]
    r = 1.0 if self.segment_all else min(dst_shape[0] / src_shape[0], dst_shape[1] / src_shape[1])
    # Transform input prompts
    if points is not None:
        points = torch.as_tensor(points, dtype=torch.float32, device=self.device)
        points = points[None] if points.ndim == 1 else points
        # Assuming labels are all positive if users don't pass labels.
        if labels is None:
            labels = np.ones(points.shape[0])
        labels = torch.as_tensor(labels, dtype=torch.int32, device=self.device)
        points *= r
        # (N, 2) --> (N, 1, 2), (N, ) --> (N, 1)
        points, labels = points[:, None, :], labels[:, None]
    if bboxes is not None:
        bboxes = torch.as_tensor(bboxes, dtype=torch.float32, device=self.device)
        bboxes = bboxes[None] if bboxes.ndim == 1 else bboxes
        bboxes *= r
    if masks is not None:
        masks = torch.as_tensor(masks, dtype=torch.float32, device=self.device).unsqueeze(1)

    points = (points, labels) if points is not None else None
    # Embed prompts
    sparse_embeddings, dense_embeddings = self.model.prompt_encoder(points=points, boxes=bboxes, masks=masks)

    # Predict masks
    pred_masks, pred_scores = self.model.mask_decoder(
        image_embeddings=features,
        image_pe=self.model.prompt_encoder.get_dense_pe(),
        sparse_prompt_embeddings=sparse_embeddings,
        dense_prompt_embeddings=dense_embeddings,
        multimask_output=multimask_output,
    )

    # (N, d, H, W) --> (N*d, H, W), (N, d) --> (N*d, )
    # `d` could be 1 or 3 depends on `multimask_output`.
    return pred_masks.flatten(0, 1), pred_scores.flatten(0, 1)

remove_small_regions(masks, min_area=0, nms_thresh=0.7) staticmethod

рд╕реЗрдЧрдореЗрдВрдЯ рдПрдиреАрдерд┐рдВрдЧ рдореЙрдбрд▓ рджреНрд╡рд╛рд░рд╛ рдЙрддреНрдкрдиреНрди рд╕реЗрдЧрдореЗрдВрдЯреЗрд╢рди рдорд╛рд╕реНрдХ рдкрд░ рдкреЛрд╕реНрдЯ-рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХрд░реЗрдВ (SAM). рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдЗрдирдкреБрдЯ рдорд╛рд╕реНрдХ рд╕реЗ рдЫреЛрдЯреЗ рдбрд┐рд╕реНрдХрдиреЗрдХреНрдЯ рдХрд┐рдП рдЧрдП рдХреНрд╖реЗрддреНрд░реЛрдВ рдФрд░ рдЫреЗрджреЛрдВ рдХреЛ рд╣рдЯрд╛ рджреЗрддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдЧреИрд░-рдЕрдзрд┐рдХрддрдо рдкреНрд░рджрд░реНрд╢рди рдХрд░рддрд╛ рд╣реИ рджрдорди (рдПрдирдПрдордПрд╕) рдХрд┐рд╕реА рднреА рдирдП рдмрдирд╛рдП рдЧрдП рдбреБрдкреНрд▓рд┐рдХреЗрдЯ рдмреЙрдХреНрд╕ рдХреЛ рдЦрддреНрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
masks Tensor

рдПрдХ tensor рдЬрд┐рд╕рдореЗрдВ рдорд╛рд╕реНрдХ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рд╣реИред рдЖрдХрд╛рд░ (N, H, W) рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬрд╣рд╛рдБ N рд╣реИ рдорд╛рд╕реНрдХ рдХреА рд╕рдВрдЦреНрдпрд╛, рдПрдЪ рдКрдВрдЪрд╛рдИ рд╣реИ, рдФрд░ рдбрдмреНрд▓реНрдпреВ рдЪреМрдбрд╝рд╛рдИ рд╣реИред

рдЖрд╡рд╢реНрдпрдХ
min_area int

рдиреНрдпреВрдирддрдо рдХреНрд╖реЗрддреНрд░ рдЬрд┐рд╕рдХреЗ рдиреАрдЪреЗ рдбрд┐рд╕реНрдХрдиреЗрдХреНрдЯ рдХрд┐рдП рдЧрдП рдХреНрд╖реЗрддреНрд░реЛрдВ рдФрд░ рдЫреЗрджреЛрдВ рдХреЛ рд╣рдЯрд╛ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред 0 рдХреЗ рд▓рд┐рдП рдбрд┐рдлрд╝реЙрд▓реНрдЯред

0
nms_thresh float

NMS рдПрд▓реНрдЧреЛрд░рд┐рдердо рдХреЗ рд▓рд┐рдП IoU рдереНрд░реЗрд╢реЛрд▓реНрдбред 0.7 рдХреЗ рд▓рд┐рдП рдбрд┐рдлрд╝реЙрд▓реНрдЯред

0.7

рджреЗрддрд╛:

рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
tuple([Tensor, List[int]])
  • new_masks (torch.Tensor): рдЫреЛрдЯреЗ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд╕рд╛рде рд╕рдВрд╕рд╛рдзрд┐рдд рдорд╛рд╕реНрдХ рд╣рдЯрд╛ рджрд┐рдП рдЧрдПред рдЖрдХрд╛рд░ (рдПрди, рдПрдЪ, рдбрдмреНрд▓реНрдпреВ) рд╣реИред
  • рд░рдЦреЗрдВ (рд╕реВрдЪреА [int]): рдПрдирдПрдордПрд╕ рдХреЗ рдмрд╛рдж рд╢реЗрд╖ рдорд╛рд╕реНрдХ рдХреЗ рд╕реВрдЪрдХрд╛рдВрдХ, рдЬрд┐рдирдХрд╛ рдЙрдкрдпреЛрдЧ рдмрдХреНрд╕реЗ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
@staticmethod
def remove_small_regions(masks, min_area=0, nms_thresh=0.7):
    """
    Perform post-processing on segmentation masks generated by the Segment Anything Model (SAM). Specifically, this
    function removes small disconnected regions and holes from the input masks, and then performs Non-Maximum
    Suppression (NMS) to eliminate any newly created duplicate boxes.

    Args:
        masks (torch.Tensor): A tensor containing the masks to be processed. Shape should be (N, H, W), where N is
                              the number of masks, H is height, and W is width.
        min_area (int): The minimum area below which disconnected regions and holes will be removed. Defaults to 0.
        nms_thresh (float): The IoU threshold for the NMS algorithm. Defaults to 0.7.

    Returns:
        (tuple([torch.Tensor, List[int]])):
            - new_masks (torch.Tensor): The processed masks with small regions removed. Shape is (N, H, W).
            - keep (List[int]): The indices of the remaining masks post-NMS, which can be used to filter the boxes.
    """
    import torchvision  # scope for faster 'import ultralytics'

    if len(masks) == 0:
        return masks

    # Filter small disconnected regions and holes
    new_masks = []
    scores = []
    for mask in masks:
        mask = mask.cpu().numpy().astype(np.uint8)
        mask, changed = remove_small_regions(mask, min_area, mode="holes")
        unchanged = not changed
        mask, changed = remove_small_regions(mask, min_area, mode="islands")
        unchanged = unchanged and not changed

        new_masks.append(torch.as_tensor(mask).unsqueeze(0))
        # Give score=0 to changed masks and 1 to unchanged masks so NMS prefers masks not needing postprocessing
        scores.append(float(unchanged))

    # Recalculate boxes and remove any new duplicates
    new_masks = torch.cat(new_masks, dim=0)
    boxes = batched_mask_to_box(new_masks)
    keep = torchvision.ops.nms(boxes.float(), torch.as_tensor(scores), nms_thresh)

    return new_masks[keep].to(device=masks.device, dtype=masks.dtype), keep

reset_image()

рдЫрд╡рд┐ рдФрд░ рдЙрд╕рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рдХреЛрдИ рдирд╣реАрдВ рдкрд░ рд░реАрд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def reset_image(self):
    """Resets the image and its features to None."""
    self.im = None
    self.features = None

set_image(image)

рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдПрдХрд▓ рдЫрд╡рд┐ рдХреЛ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕ рдФрд░ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИред

рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдореЙрдбрд▓ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ рдпрджрд┐ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкреНрд░рд╛рд░рдВрдн рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рддреЛ рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЫрд╡рд┐ рдореЗрдВ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдлреАрдЪрд░ рдирд┐рд╖реНрдХрд░реНрд╖рдг рдХреЗ рд▓рд┐рдП рдЫрд╡рд┐ рдХреЛ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕ рдХрд░рддрд╛ рд╣реИред рдПрдХ рд╕рдордп рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рдЫрд╡рд┐ рд╕реЗрдЯ рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
image str | ndarray

рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд░реВрдк рдореЗрдВ рдЫрд╡рд┐ рдлрд╝рд╛рдЗрд▓ рдкрде, рдпрд╛ cv2 рджреНрд╡рд╛рд░рд╛ рдкрдврд╝реА рдЧрдИ np.ndarray рдЫрд╡рд┐ред

рдЖрд╡рд╢реНрдпрдХ

рдЙрдард╛рддреА:

рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
AssertionError

рдпрджрд┐ рдПрдХ рд╕реЗ рдЕрдзрд┐рдХ рдЫрд╡рд┐ рд╕реЗрдЯ рд╣реИред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def set_image(self, image):
    """
    Preprocesses and sets a single image for inference.

    This function sets up the model if not already initialized, configures the data source to the specified image,
    and preprocesses the image for feature extraction. Only one image can be set at a time.

    Args:
        image (str | np.ndarray): Image file path as a string, or a np.ndarray image read by cv2.

    Raises:
        AssertionError: If more than one image is set.
    """
    if self.model is None:
        model = build_sam(self.args.model)
        self.setup_model(model)
    self.setup_source(image)
    assert len(self.dataset) == 1, "`set_image` only supports setting one image!"
    for batch in self.dataset:
        im = self.preprocess(batch[1])
        self.features = self.model.image_encoder(im)
        self.im = im
        break

set_prompts(prompts)

рдкрд╣рд▓реЗ рд╕реЗ рд╕рдВрдХреЗрдд рд╕реЗрдЯ рдХрд░реЗрдВред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def set_prompts(self, prompts):
    """Set prompts in advance."""
    self.prompts = prompts

setup_model(model, verbose=True)

рд╕реЗрдЧрдореЗрдВрдЯ рдПрдиреАрдерд┐рдВрдЧ рдореЙрдбрд▓ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддрд╛ рд╣реИ (SAM) рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдПред

рдпрд╣ рд╡рд┐рдзрд┐ рд╕реЗрдЯ рдХрд░рддреА рд╣реИ SAM рдореЙрдбрд▓ рдХреЛ рдЙрдкрдпреБрдХреНрдд рдбрд┐рд╡рд╛рдЗрд╕ рдкрд░ рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдХреЗ рдФрд░ рдЖрд╡рд╢реНрдпрдХ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рдХреЗ рдЫрд╡рд┐ рд╕рд╛рдорд╛рдиреНрдпреАрдХрд░рдг рдФрд░ рдЕрдиреНрдп рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ Ultralytics рд╕рдВрдЧрддрддрд╛ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
model Module

рдПрдХ рдкреВрд░реНрд╡ рдкреНрд░рд╢рд┐рдХреНрд╖рд┐рдд SAM рдХреЛ рдЧрдврд╝рдирд╛ред рдпрджрд┐ рдХреЛрдИ рдирд╣реАрдВ, рддреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ рдореЙрдбрд▓ рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред

рдЖрд╡рд╢реНрдпрдХ
verbose bool

рдпрджрд┐ рд╕рд╣реА рд╣реИ, рддреЛ рдЪрдпрдирд┐рдд рдбрд┐рд╡рд╛рдЗрд╕ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд┐рдВрдЯ рдХрд░рддрд╛ рд╣реИред

True

рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдБ:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо
model Module

рд╡рд╣реА SAM рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдЪреБрдиреЗ рдЧрдП рдбрд┐рд╡рд╛рдЗрд╕ рдХреЛ рдЖрд╡рдВрдЯрд┐рдд рдореЙрдбрд▓ред

device device

рд╡рд╣ рдЙрдкрдХрд░рдг рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдореЙрдбрд▓ рдФрд░ рдЯреЗрдВрд╕рд░ рдЖрд╡рдВрдЯрд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред

mean Tensor

рдЫрд╡рд┐ рд╕рд╛рдорд╛рдиреНрдпреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдФрд╕рдд рдореВрд▓реНрдпред

std Tensor

рдЫрд╡рд┐ рд╕рд╛рдорд╛рдиреНрдпреАрдХрд░рдг рдХреЗ рд▓рд┐рдП рдорд╛рдирдХ рд╡рд┐рдЪрд▓рди рдорд╛рдиред

рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def setup_model(self, model, verbose=True):
    """
    Initializes the Segment Anything Model (SAM) for inference.

    This method sets up the SAM model by allocating it to the appropriate device and initializing the necessary
    parameters for image normalization and other Ultralytics compatibility settings.

    Args:
        model (torch.nn.Module): A pre-trained SAM model. If None, a model will be built based on configuration.
        verbose (bool): If True, prints selected device information.

    Attributes:
        model (torch.nn.Module): The SAM model allocated to the chosen device for inference.
        device (torch.device): The device to which the model and tensors are allocated.
        mean (torch.Tensor): The mean values for image normalization.
        std (torch.Tensor): The standard deviation values for image normalization.
    """
    device = select_device(self.args.device, verbose=verbose)
    if model is None:
        model = build_sam(self.args.model)
    model.eval()
    self.model = model.to(device)
    self.device = device
    self.mean = torch.tensor([123.675, 116.28, 103.53]).view(-1, 1, 1).to(device)
    self.std = torch.tensor([58.395, 57.12, 57.375]).view(-1, 1, 1).to(device)

    # Ultralytics compatibility settings
    self.model.pt = False
    self.model.triton = False
    self.model.stride = 32
    self.model.fp16 = False
    self.done_warmup = True

setup_source(source)

рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ.

рдпрд╣ рд╡рд┐рдзрд┐ рдЙрд╕ рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддреА рд╣реИ рдЬрд┐рд╕рд╕реЗ рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдЪрд┐рддреНрд░ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдП рдЬрд╛рдПрдВрдЧреЗред рд╕реНрд░реЛрдд рдПрдХ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛, рдПрдХ рд╡реАрдбрд┐рдпреЛ рдлрд╝рд╛рдЗрд▓, рдпрд╛ рдЕрдиреНрдп рдкреНрд░рдХрд╛рд░ рдХреЗ рдЫрд╡рд┐ рдбреЗрдЯрд╛ рд╕реНрд░реЛрддред

рдкреИрд░рд╛рдореАрдЯрд░:

рдирд╛рдо рдкреНрд░рдХрд╛рд░ рдпрд╛ рдХрд╝рд┐рд╕реНтАНрдо рдЪреВрдХ
source str | Path

рдЕрдиреБрдорд╛рди рдХреЗ рд▓рд┐рдП рдЫрд╡рд┐ рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рдХрд╛ рдкрде.

рдЖрд╡рд╢реНрдпрдХ
рдореЗрдВ рд╕реНрд░реЛрдд рдХреЛрдб ultralytics/models/sam/predict.py
def setup_source(self, source):
    """
    Sets up the data source for inference.

    This method configures the data source from which images will be fetched for inference. The source could be a
    directory, a video file, or other types of image data sources.

    Args:
        source (str | Path): The path to the image data source for inference.
    """
    if source is not None:
        super().setup_source(source)





2023-11-12 рдмрдирд╛рдпрд╛ рдЧрдпрд╛, рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ 2024-05-08
рд▓реЗрдЦрдХ: рдмреБрд░рд╣рд╛рди-рдХреНрдпреВ (1), рдЧреНрд▓реЗрди-рдЬреЛрдЪрд░ (3)