如何使用 Meta 的图像分割模型 SAM 2 有效检测物体

719 阅读11分钟

了解如何利用 Meta 的新 SAM 2 模型来细分任何事物

Segment Anything Model 2 是 Meta 最新的图像分割模型,能够检测和标记图像和代码中的对象。欢迎来到雲闪世界。本文将向您展示如何下载和使用该模型,并查看该模型及其功能。使用图像分割模型令人兴奋,因为您可以立即看到模型的结果并了解其性能如何,因为分割是您的大脑擅长的任务。因此,您可以快速判断图像分割模型是否表现良好。

这是 SAM 2 应用于武士雕像的一个例子。该图展示了 SAM 2 如何有效地检测图像中的不同物体

动机

我写这篇文章的动机是我关于跟上机器学习领域最新模型的系列文章。SAM2 是 Meta 最近发布的一个模型,Meta 是一家持续生产先进开源机器学习模型的公司。本文将重点介绍 SAM2,介绍如何自己使用该模型、可以将该模型应用于哪些任务以及该模型的性能如何。该模型也是根据 Apache 2.0 许可证发布的,这意味着您可以在商业环境中自由使用该模型,在我看来,这让该模型更加令人兴奋。

实施和运行 SAM2

Meta提供了有关在本地设置 SAM2 的良好文档,但我还将在此处包括在计算机上运行 SAM 2 所需的几个步骤。

首先,您必须克隆包含代码的 Git 存储库:

git克隆https://github.com/facebookresearch/segment-anything-2.git

使用以下命令安装所需的软件包:

cd fragment-anything-2 
pip 安装 -e 。

然后,您可以使用以下命令下载模型权重:

cd检查点
./download_ckpts.sh

这将为四种不同尺寸的 SAM 2 模型安装配重。现在,有两种方法可以运行 SAM 2。

使用常规物体检测功能运行 SAM 2

这种运行 SAM 2 的方式意味着您只需输入一张图片,SAM 2 就会检测并标记图片中的不同对象。您可以在此处查看 Meta 的此方法的示例笔记本。首先,将图片加载到 numpy 数组中。在本例中, image_path变量是您计算机上本地图片的路径。

图像 = PILImage。打开(图像路径)
图像 = np.array(图像.convert(“RGB”))

然后,您可以从segment-anything-2文件夹中运行此代码。 在我的例子中,我使用的是大型模型,但如果您使用的是其他模型,请务必修改sam2_checkpoint和model_cfg变量。

从 sam2.build_sam 导入 build_sam2
从 sam2.automatic_mask_generator 导入 SAM2AutomaticMaskGenerator

设备 = torch.device(如果 torch.cuda.is_available() 则为"cuda"否则为 "cpu" ) 
sam2_checkpoint = "./checkpoints/sam2_hiera_large.pt"
 model_cfg = "sam2_hiera_l.yaml"
设备 = "cuda"如果 torch.cuda.is_available()则为 "cpu"
 sam2 = build_sam2(model_cfg、sam2_checkpoint、device=device、apply_postprocessing=False) 

mask_generator = SAM2AutomaticMaskGenerator(sam2) 
mask = mask_generator.generate(图像)

我建议在 GPU 上运行它,因为在 CPU 上处理一张图像大约需要 14 分钟。运行上述代码后,你可以使用以下命令将模型输出打印到图像上:

导入matplotlib.pyplot作为plt 

def  show_anns(anns,borders= True):
    如果 len(anns)== 0:
        返回
    sorted_anns = sorted(anns,key=(lambda x:x[ 'area' ]),reverse= Trueax = plt.gca()
    ax.set_autoscale_on(False)

    img = np.ones((sorted_anns[ 0 ][ 'segmentation' ].shape[ 0 ],sorted_anns[ 0 ][ 'segmentation' ].shape[ 1 ],4))
    img[:, :, 3 ] = 0 
    for ann in sorted_anns:
        m = ann[ 'segmentation' ] 
        color_mask = np.concatenate([np.random.random(3),[ 0.5 ]])
        img[m] = color_mask 
        if borders: 
            import cv2 
            contours, _ = cv2.findContours(m.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) 
            # 尝试平滑轮廓
            contours = [cv2.approxPolyDP(contour, epsilon= 0.01 , closed= True ) for contour in contours] 
            cv2.drawContours(img, contours, - 1 , ( 0 , 0 , 1 , 0.4 ), thicken= 1 ) 

    ax.imshow(img) 

plt.figure(figsize=( 20 , 20 )) 
plt.imshow(image) 
show_anns(masks) 
plt.axis( 'off' ) 
plt.show()

运行 SAM 2 检测特定对象

运行 SAM 2 的第二种方法是检测特定对象,这在Meta 的笔记本中进行了进一步解释。要运行这种方法,您需要输入一张图像和图像上的一个点,然后 SAM 2 将检测该点标记的对象。首先,您必须加载模型并设置您之前加载的图像。

从sam2.build_sam导入build_sam2
从sam2.sam2_image_predictor导入SAM2ImagePredictor
导入matplotlib.pyplot作为plt 

sam2_checkpoint = "./checkpoints/sam2_hiera_large.pt"
 model_cfg = "sam2_hiera_l.yaml"

 sam2_model = build_sam2(model_cfg, sam2_checkpoint, device=device) 
predictor = SAM2ImagePredictor(sam2_model) 
predictor.set_image(image)

然后,您需要一些辅助函数来选择点并绘制 SAM 2 结果:

def  show_mask(mask,ax,random_color = False,borders = True):
    如果random_color:
        color = np.concatenate[np.random.random(3),np.array([ 0.6 ])],axis = 0)
    否则:
        color = np.array[ 30 / 255,144 / 255,255 / 255,0.6 ] ) h     ,w = mask.shape [ -2 : ]     mask = mask.astype(np.uint8) mask_image = mask.reshape     (h,w,1)* color.reshape11,-1)如果borders:导入cv2轮廓, _ =         cv2.findContoursmask,cv2.RETR_EXTERNAL ,cv2.CHAIN_APPROX_NONE) # 尝试平滑轮廓        contours = [cv2.approxPolyDP(contour, epsilon= 0.01 , closed= True ) for contour in contours]         mask_image = cv2.drawContours(mask_image, contours, - 1 , ( 1 , 1 , 1 , 0.5 ), thicken= 2 )     ax.imshow(mask_image) def show_points ( coords, labels, ax, marker_size= 375 ):     pos_points = coords[labels== 1 ]     neg_points = coords[labels== 0 ]     ax.scatter(pos_points[:, 0 ], pos_points[:, 1 ], color= 'green' , marker= '*' , s=marker_size, edgecolor= '白色' , 线宽= 1.25 )     ax.scatter(neg_points[:, 0 ], neg_points[:, 1 ], color= '红色' , marker= '*' , s=marker_size, edgecolor= '白色' , 线宽= 1.25 )    def show_box ( box, ax ):     x0, y0 = box[ 0 ], box[ 1 ]     w, h = box[ 2 ] - box[ 0 ], box[ 3 ] - box[ 1 ]     ax.add_patch(plt.Rectangle((x0, y0), w, h, edgecolor= '绿色' , facecolor=(
0,0,0,0 ) ,lw = 2 ) def     show_masks (图像,遮罩,分数,point_coords = None,box_coords = None ,input_labels = None,borders = True):对于i,(mask,score)在枚举(zip(masks,scores)中):        plt.figure(figsize =(1010))        plt.imshow(图像)show_mask (mask,plt.gca(),borders =         borders)如果point_coords不是None:断言input_labels不是None             show_points(point_coords,input_labels,plt.gca())如果box_coords不是None : #boxs show_box (             box_coords,plt.gca())如果len(scores)> 1 :plt.title             (f“Mask {i + 1 },分数:{score: .3 f} “,fontsize= 18)        plt.axis('off')        plt.show()

现在您必须选择图像上的点。您可以通过更改input_point变量来更改点的位置,其中 x 坐标的增加表示点向右移动,y 坐标的增加表示点向下移动。我选择点位置的方式是通过反复试验(只需打印带有点的图像,查看点最终的位置,然后调整坐标)。

input_point = np.array([[ 1500 , 1175 ]]) 
input_label = np.array([ 1 ]) 

plt.figure(figsize=( 10 , 10 )) 
plt.imshow(图像) 
show_points(input_point, input_label, plt.gca()) 
plt.axis( 'on' ) 
plt.show()

我输入了以下图片(来自我去东京的旅行)并指向:

添加图片注释,不超过 140 字(可选)

在这种情况下,SAM 2 很好地检测到了标志,如下图所示:

添加图片注释,不超过 140 字(可选)

测试 SAM 2

定量测试 SAM 2 很困难,因为这意味着我需要手动注释大量图像,这非常耗时。相反,正如我通常在有关新机器学习模型的文章中所做的那样,我将定性测试该模型并对其性能给出我的看法。我从亚洲之行中选择了一些图像来测试该模型。对于测试,我将使用最大的 SAM 2 模型

图片 1

首先,我测试了图像 1,其中显示了一名骑在马上的武士。我将指针放在马的脖子上,希望 SAM 2 能够检测到马,甚至检测到武士。从中间的图像中可以看到,SAM 2 准确地突出显示了马,尽管马与武士之间有一点冲突。这显示了 SAM 2 遇到困难的区域,它不确定是否应该突出显示两个相连的物体。我认为,在理想情况下,SAM 2 只会突出显示马,因为指针没有标记武士。但是,SAM 2 也开始突出显示武士的一小部分,但无法突出显示整个武士,这表明 SAM 可以改进这一领域。然而,在最右边的图像上,SAM 2 将整个雕像高亮显示到近乎完美,我认为这非常令人印象深刻,尤其是因为它知道在读取雕像底部的楼梯时应该停止高亮显示,并且它还准确地标记了骑着马的武士,而 SAM 2 在中间的图中却遇到了困难。

这是我去日本旅行时拍摄的一张令人印象深刻的武士雕像的照片。我用一根指针标记了雕像上的马,在中间的图片中,你可以看到 SAM 2 突出显示了用指针标记的马和武士。在左边的图片中,SAM 2 试图突出显示整个雕像,包括脚,它做得非常好,只有几个地方没有突出显示。

我还要求 SAM 2 突出显示图像中的所有不同物体。总体而言,我认为 SAM 2 表现不错,尽管它在某些方面肯定可以改进。不过,我认为 SAM 2 犯的大多数错误都是可以理解的。例如,对于最右边的建筑物,SAM 2 将建筑物顶部标记为紫色,而建筑物的其余部分则标记为绿色。完美的图像分割模型应该能够将整个建筑物标记为相同的颜色,但如果您查看原始图像(上图最左边的图像),您会发现建筑物顶部是不同的颜色,这可能解释了为什么 SAM 2 会这样进行分割。

添加图片注释,不超过 140 字(可选)

图片 2

这是一张更难分割的图像,因为图像中几乎没有清晰的物体是 SAM 2 能够检测到的。在最左边的图像中,我标记了一个区域(具体来说是一片稻田;在下面的完整图像中更容易看到),而 SAM 2 能够在中间和最右边的图像中有效地突出显示该区域。这张图片对 SAM 2 提出了一个有趣的挑战,因为这些物体比上面的武士图像小得多。我认为这表明 SAM 2 在特写图像和许多较小物体的缩小图像上都表现良好。

添加图片注释,不超过 140 字(可选)

在下图中,SAM 2 被要求检测图像中的所有物体。总体而言,其表现不错。SAM 2 可以很好地检测一些物体,包括一些田野和云。然而,图像的很大一部分根本没有被分割,这表明 SAM 2 在本例中更注重精度而不是召回率。这意味着 SAM 2 必须非常确定图像中的某个物体是物体,然后才能真正突出显示它。这会导致图像中的许多物体会被分割忽略,同时也有一个好处,即突出显示的物体更有可能是正确的。

上图显示的是山谷的全尺寸图像。在这种情况下,SAM 2 被要求找到图像中的所有物体,并且图像的很大一部分未被突出显示。对于 SAM 2 决定突出显示的物体,它表现得相当好。还应该提到的是,这是一张很难应用分割的图像,因为它是从很远的地方拍摄的,这意味着许多物体会很小。此外,图像中的物体不如武

图片 3

在我看来,与上图相比,这幅图像更容易进行图像分割,因为图像中的物体更清晰。在最左边的图像中,我用指针标记了其中一座山丘,在中间的图像中,你可以看到 SAM 2 有效地突出了这座山丘。在最右边的图像中,你还可以看到 SAM 2 在标记另一座山丘方面表现良好。总的来说,我认为 SAM 2 在这幅图像上的表现非常好。

这张图片展示了越南的一些山丘。SAM 2 被提示突出显示最左侧图片中的山丘,您可以在中间图片中看到它有效地做到了这一点。在最右侧图片中,SAM 2 在同时突出显示两座山丘时也表现良好。

在下图中,SAM 2 被提示突出显示图像中的所有物体,它做得很好,突出显示了图像中显示的许多山丘。它还有效地突出显示了图像右下角的道路(以紫色突出显示)。如前所述,SAM 2 仍然难以检测图像中的所有物体,但我认为这是可以接受的,因为有些山丘不是明显的物体,因此很难分割。

添加图片注释,不超过 140 字(可选)

结论

本文向您展示了如何在本地实现和运行 SAM 2 来分割图像。此外,我还在不同的图像上对该模型进行了定性测试,以查看其性能如何。我认为这些测试的主要结论是 SAM 2 在大多数任务上都表现得非常好。然而,它的表现并不像SAM 2 GitHub 页面上的图像所显示的那样好。然而,该模型也有一些可以改进的地方。一个是图像中通常有很多 SAM 2 无法检测到的物体,而它本应该检测到这些物体。此外,在某些情况下,SAM 2 很难正确标记物体,例如当您看到武士图像时。然而,这是一个小问题,在我测试的所有图像中并不普遍。总的来说,SAM 2 是一个超酷的模型,我推荐它用于图像分割。

感谢关注雲闪世界。(Aws解决方案架构师vs开发人员&GCP解决方案架构师vs开发人员)

订阅频道(t.me/awsgoogvps_…) TG交流群(t.me/awsgoogvpsHost)