SAM(Segment Anything Model)是由 Meta 的研究人員團(tuán)隊(duì)創(chuàng)建和訓(xùn)練的深度學(xué)習(xí)模型。該創(chuàng)新成果發(fā)表在 2023 年 4 月 5 日發(fā)表的一篇研究論文中,它立即引起了公眾的廣泛興趣——相關(guān)的 Twitter 帖子迄今為止已累積超過 350 萬次瀏覽:
計(jì)算機(jī)視覺專業(yè)人士現(xiàn)在將注意力轉(zhuǎn)向 SAM——但為什么呢?
推薦:用 NSDT編輯器 快速搭建可編程3D場景
1、什么是SAM?
在 Segment everything 研究論文中,SAM 被稱為“基礎(chǔ)模型”。
基礎(chǔ)模型是在大量數(shù)據(jù)上訓(xùn)練的機(jī)器學(xué)習(xí)模型(通常通過自監(jiān)督或半監(jiān)督學(xué)習(xí)),其目的是在更具體的任務(wù)上使用和重新訓(xùn)練。
換句話說,SAM 是一個(gè)預(yù)訓(xùn)練模型,旨在適應(yīng)其他任務(wù)(特別是通過微調(diào))。
例如,SAM 可以重新訓(xùn)練并用于僅對數(shù)據(jù)集中的人員進(jìn)行分割。
人物分割是 SAM 可以執(zhí)行的一項(xiàng)附件任務(wù),因?yàn)樗呀?jīng)在包含此類對象的數(shù)據(jù)集上進(jìn)行了訓(xùn)練 - 但不僅如此!
2、SAM 是如何訓(xùn)練的?
SAM 在 SA-1B 數(shù)據(jù)集上進(jìn)行了訓(xùn)練,該數(shù)據(jù)集由 Meta 與 Segment Anything 研究論文并行引入。
Facebook 母公司的數(shù)據(jù)集包含超過 1100 萬張幾乎在整個(gè)地球上收集的圖像——這是開發(fā)具有泛化能力的模型的一個(gè)重要方面。
幾乎在整個(gè)地球上收集的圖像 – SA-1B 數(shù)據(jù)集
這些高質(zhì)量圖像(平均 1500×2250 像素)伴隨著與數(shù)據(jù)集標(biāo)簽相對應(yīng)的 11 億個(gè)分割掩模。
Meta 使用此數(shù)據(jù)集的目的是為AI博士創(chuàng)建細(xì)分參考。 它已獲得官方免費(fèi)許可用于研究目的。
盡管信息量很大,但值得注意的是,掩模與類別無關(guān)。 換句話說,即使SAM可以生成一個(gè)人的掩模,它也無法表明這個(gè)掩模代表一個(gè)人。
這是需要牢記的重要一點(diǎn),因?yàn)檫@意味著 SAM 必須與其他算法結(jié)合才能真正發(fā)揮作用。
讓我們仔細(xì)看看。
3、如何使用 SAM?
首先,我們需要加載 2 項(xiàng):
- segment-anything GitHub 文件夾,其中包含使用 SAM 的類和函數(shù)
- 使用 Meta 研究人員獲得的模型版本的預(yù)訓(xùn)練模型權(quán)重
!pip install git+https://github.com/facebookresearch/segment-anything.git &> /dev/null
!wget -q https://dl.fbaipublicfiles.com/segment_anything/sam_vit_h_4b8939.pth
接下來,我們創(chuàng)建 3 個(gè)全局變量:
- MODEL_TYPE:要使用的 SAM 架構(gòu)
- CHECKPOINT_PATH:包含模型權(quán)重的文件的路徑
- DEVICE:使用的處理器,“cpu”或“cuda”(如果 GPU 可用)
MODEL_TYPE = "vit_h"
CHECKPOINT_PATH = "/content/sam_vit_h_4b8939.pth"
DEVICE = "cuda" #cpu,cuda
我們現(xiàn)在可以使用 sam_model_registry 函數(shù)加載 SAM 模型,指示模型權(quán)重:
from segment_anything import sam_model_registry
sam = sam_model_registry[MODEL_TYPE](checkpoint=CHECKPOINT_PATH).to(device=DEVICE)
模型加載后,Meta 為我們提供了兩種使用選項(xiàng):
- 生成器選項(xiàng),允許你從圖像中獲取模型生成的所有掩模
- Predictor選項(xiàng),它允許我們根據(jù)提示從圖像中獲取一個(gè)或多個(gè)特定的掩模。
我們將在下面幾行中探討這兩個(gè)選項(xiàng)。
在此之前,讓我們從互聯(lián)網(wǎng)加載一張圖像,我們將在該圖像上試驗(yàn)我們的模型:
from urllib.request import urlopen
import cv2
import numpy as np
from google.colab.patches import cv2_imshow
resp = urlopen('https://images.unsplash.com/photo-1615948812700-8828458d368a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2072&q=80')
image = np.asarray(bytearray(resp.read()), dtype='uint8')
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
image = cv2.resize(image, (int(image.shape[1]/2.5), int(image.shape[0]/2.5)))
cv2_imshow(image)
我們的圖像包含幾個(gè)人、一只狗和一些汽車。
現(xiàn)在我們將使用 SAM 和 Generator 選項(xiàng)來分割該圖像。
4、生成器
在本節(jié)中,我們將使用 SAM 的生成器版本。 這將使我們能夠獲得由于模型對圖像的分析而生成的一組掩模。
讓我們初始化 SamAutomaticMaskGenerator 對象:
from segment_anything import SamAutomaticMaskGenerator
mask_generator = SamAutomaticMaskGenerator(sam)
接下來,我們使用 generate()函數(shù)啟動掩碼生成:
masks_generated = mask_generator.generate(image)
該函數(shù)為檢測到的每個(gè)對象生成一個(gè)掩碼以及其他數(shù)據(jù)。 SAM 實(shí)際上生成一組與其檢測到的對象相關(guān)的信息(以字典形式)。
5、預(yù)測結(jié)果
我們可以顯示每組信息獲得的鍵:
print(masks_generated[0].keys())
輸出:
dict_keys(['segmentation', 'area', 'bbox', 'predicted_iou', 'point_coords', 'stability_score', 'crop_box'])
結(jié)果是一組 7 條信息。 第一個(gè)“分割”表示與檢測到的對象的位置相對應(yīng)的像素:如果像素包含對象,則為 True,否則為 False。
掩碼可以顯示如下:
cv2_imshow(masks_generated[3]['segmentation'].astype(int)*255)
該集合中的其他信息對應(yīng)于以下描述:
- area:遮罩區(qū)域(以像素為單位)
- bbox:XYWH 格式的掩模邊界框
- Predicted_iou:模型預(yù)測的掩模質(zhì)量得分
- point_coords:生成此掩碼的采樣輸入點(diǎn)
- stable_score:額外的掩模質(zhì)量分?jǐn)?shù)
- Crop_box:用于生成 XYWH 格式的此蒙版的圖像裁剪
大多數(shù)從業(yè)者不會使用此信息,但對于特定情況,重要的是要知道 SAM 不僅生成掩模,而且還生成諸如此類的附加信息。
以下是為上面顯示的掩碼獲得的其余信息:
print('area :', masks_generated[3]['area'])
print('bbox :',masks_generated[3]['bbox'])
print('predicted_iou :',masks_generated[3]['predicted_iou'])
print('point_coords :',masks_generated[3]['point_coords'])
print('stability_score :',masks_generated[3]['stability_score'])
print('crop_box :',masks_generated[3]['crop_box'])
輸出:
area : 5200 bbox : [499, 284, 92, 70]
predicted_iou : 1.005275845527649
point_coords : [[582.1875, 318.546875]]
stability_score : 0.981315553188324
crop_box : [0, 0, 828, 551]
我們還可以顯示 SAM 生成的掩碼數(shù)量:
print(len(masks_generated))
輸出:
111
SAM 從我們的圖像中總共生成了 111 個(gè)掩模。
6、顯示預(yù)測
使用這篇文章介紹的 draw_masks_fromDict 函數(shù),我們可以繪制圖像上生成的所有蒙版:
segmented_image = draw_masks_fromDict(image, masks_generated)
cv2_imshow(segmented_image)
開始的圖像現(xiàn)在包含 SAM 生成的掩模。
在本節(jié)中,我們使用 SAM 的生成器版本。 這使我們能夠從圖像生成 111 個(gè)掩模。 除了掩模之外,SAM 還生成額外的檢測信息。 為了可視化模型的預(yù)測,我們最終在起始圖像上繪制了所有掩模。
因此,SAM 使我們能夠執(zhí)行圖像分割。 然而,我們可以看到生成的掩碼是無序的:沒有分類來區(qū)分不同的掩碼。 例如,人們的面具并不與單一顏色相關(guān)聯(lián)。 因此,無法對所得分段進(jìn)行排序。 這里獲得的唯一信息是對象的位置和界限。
此外,生成的掩??梢灾丿B。 事實(shí)上,SAM 可以檢測其他物體內(nèi)部的物體。 從積極的一面來看,這證明了 SAM 能夠檢測圖像中幾乎所有物體。 這意味著我們可以分割狗、汽車、人以及其他物體,例如車輪、窗戶或褲子。 因此,SAM 的生成器版本能夠分割圖像中的所有對象,甚至是重疊的對象。
7、超越生成器
但是,此功能也具有不利的一面:它增加了給定區(qū)域中的預(yù)測數(shù)量,這可能會破壞目標(biāo)的實(shí)現(xiàn)。例如,如果要檢測圖像中的人物,則同時(shí)檢測與其夾克和褲子對應(yīng)的面具無關(guān)緊要。
此外,由于SAM沒有在標(biāo)記數(shù)據(jù)上進(jìn)行訓(xùn)練,因此不可能過濾其預(yù)測以保留我們感興趣的預(yù)測。這意味著,即使我們使用 SAM 的生成器版本分割數(shù)據(jù)集中的所有圖像,也不可能輕松提取例如人的掩碼。因此,SAM 生成器分割圖像中所有對象的能力可能不適合解決某些問題。
因此,對于目標(biāo)對象檢測,不適合使用 SAM 的生成器版本。相反,我們需要使用預(yù)測器版本。此版本將使我們能夠使用 SAM 并提示指定我們的請求和要檢測的目標(biāo)對象。
8、預(yù)測器
在本部分中,我們將使用 SAM 的預(yù)測器版本。預(yù)測器版本將使我們能夠檢測目標(biāo)對象。為此,我們將發(fā)送 SAM 提示以指定我們要檢測的對象。
目前,可以通過兩種方式向 SAM 發(fā)送提示:
- 按興趣點(diǎn)
- 通過邊界框
SAM 可以將針對代表對象的圖像像素的興趣點(diǎn)(x 和 y 坐標(biāo))作為輸入。然后,由興趣點(diǎn)指定的對象將使 SAM 能夠生成與此對象關(guān)聯(lián)的掩碼。
SAM 還可以將分隔圖像中對象輪廓的邊界框作為輸入。根據(jù)這些輪廓,SAM 將生成適當(dāng)?shù)难诖a。
注意:“提示”是一個(gè)時(shí)髦的術(shù)語,在大多數(shù)情況下,用于指發(fā)送到 ChatGPT 的文本請求。但是,如 SAM 所示,提示不僅限于文本請求。它擴(kuò)展到從業(yè)者可以發(fā)送到機(jī)器學(xué)習(xí)模型的一組查詢。
需要注意的是,雖然該功能目前尚未公開,但 Meta 已通過其細(xì)分任何模型為文本請求理解提供了條件。
也就是說,對于本教程的其余部分,我們需要有一個(gè)發(fā)送到 SAM 的提示。邊界框是計(jì)算機(jī)視覺標(biāo)準(zhǔn),因此我們將使用它們。
9、使用邊界框提示
如果要繼續(xù)學(xué)習(xí)本教程,則必須首先具有與要分割的對象關(guān)聯(lián)的邊界框。
如果沒有圖像的邊界框,則可以使用 YOLO 模板在幾行代碼中輕松生成它們。
你可以了解如何使用此模板快速生成自己的邊界框。專門針對最新版本 YOLO 的教程在這里等著你。
一旦在我們的圖像上使用 YOLO,我們就會得到這樣的結(jié)果:
image_bboxes = image.copy()
boxes = np.array(results[0].to('cpu').boxes.data)
plot_bboxes(image_bboxes, boxes, score=False)
注意:結(jié)果變量是模型預(yù)測的結(jié)果。
使用 YOLO 獲得的邊界框采用以下形式:
print(boxes)
輸出:
[[ 495.96 285.65 589.8 356.48 0.89921 2]
[ 270.63 147.99 403.17 496.82 0.79781 0]
…
[ 235.32 279.23 508.93 399.63 0.3193 2]
[ 612.13 303.94 647.61 333.11 0.2854 2]]
前 4 個(gè)值表示邊界框坐標(biāo),第 5 個(gè)值表示預(yù)測邊界框的置信度分?jǐn)?shù),第 6 個(gè)值表示檢測到的類。
現(xiàn)在我們有了提示,讓我們初始化 SamPredictor 對象:
from segment_anything import SamPredictor
mask_predictor = SamPredictor(sam)
接下來,我們指定要由SAM分析的圖像:
mask_predictor.set_image(image)
從這里開始,本教程分為兩部分:
- 單個(gè)對象檢測
- 批量對象檢測
讓我們從第一個(gè)選項(xiàng)開始。
10、檢測單個(gè)對象
為了預(yù)測對象的掩碼,我們在 predict()函數(shù)中告訴 Predictor 與該對象對應(yīng)的邊界框:
mask, _, _ = mask_predictor.predict(
box=boxes[1][:-2]
)
我們以布爾數(shù)組的形式獲得一個(gè)掩碼,指示檢測到的對象的位置(如之前在字典的“分割”鍵中):如果像素包含對象,則為 True,否則為 False。
我們可以使用這篇文章中描述的 draw_mask函數(shù)在圖像上繪制此蒙版:
我們的凸顯現(xiàn)在包含 SAM 檢測到的掩碼。
多虧了給SAM的提示,我們已經(jīng)能夠獲得對象的遮罩并將其顯示在我們的圖像上。
現(xiàn)在讓我們看看如何檢測與所有邊界框?qū)?yīng)的掩碼。
11、檢測多個(gè)對象
為了對一組邊界框進(jìn)行預(yù)測,我們需要將它們收集到 PyTorch 張量中。
然后我們使用 transform.apply_boxes_torch()來更新我們的對象。
最后,我們使用 predict_torch來預(yù)測相應(yīng)的掩碼。
import torch
input_boxes = torch.tensor(boxes[:, :-2], device=mask_predictor.device)
transformed_boxes = mask_predictor.transform.apply_boxes_torch(input_boxes, image.shape[:2])
masks, _, _ = mask_predictor.predict_torch(
point_coords=None,
point_labels=None,
boxes=transformed_boxes,
multimask_output=False,
)
結(jié)果是在一維 (1, 551, 828) 上編碼的一批 13 個(gè)掩碼。
為了更好地操作這個(gè)張量,讓我們刪除第一個(gè)不相關(guān)的維度:
print(masks.shape)
masks = torch.squeeze(masks, 1)
print(masks.shape)
輸出:
torch.Size([13, 1, 551, 828])
torch.Size([13, 551, 828])
在 SAM 上游使用邊界框的優(yōu)點(diǎn)是,我們可以將每個(gè)生成的掩碼與邊界框?qū)?yīng)的標(biāo)簽相關(guān)聯(lián),從而在顯示時(shí)使用顏色來區(qū)分它們。
讓我們定義一個(gè)與 YOLO 可以預(yù)測的類關(guān)聯(lián)的顏色漸變:
COLORS = [(89, 161, 197),(67, 161, 255),(19, 222, 24),(186, 55, 2),(167, 146, 11),(190, 76, 98),(130, 172, 179),(115, 209, 128),(204, 79, 135),(136, 126, 185),(209, 213, 45),(44, 52, 10),(101, 158, 121),(179, 124, 12),(25, 33, 189),(45, 115, 11),(73, 197, 184),(62, 225, 221),(32, 46, 52),(20, 165, 16),(54, 15, 57),(12, 150, 9),(10, 46, 99),(94, 89, 46),(48, 37, 106),(42, 10, 96),(7, 164, 128),(98, 213, 120),(40, 5, 219),(54, 25, 150),(251, 74, 172),(0, 236, 196),(21, 104, 190),(226, 74, 232),(120, 67, 25),(191, 106, 197),(8, 15, 134),(21, 2, 1),(142, 63, 109),(133, 148, 146),(187, 77, 253),(155, 22, 122),(218, 130, 77),(164, 102, 79),(43, 152, 125),(185, 124, 151),(95, 159, 238),(128, 89, 85),(228, 6, 60),(6, 41, 210),(11, 1, 133),(30, 96, 58),(230, 136, 109),(126, 45, 174),(164, 63, 165),(32, 111, 29),(232, 40, 70),(55, 31, 198),(148, 211, 129),(10, 186, 211),(181, 201, 94),(55, 35, 92),(129, 140, 233),(70, 250, 116),(61, 209, 152),(216, 21, 138),(100, 0, 176),(3, 42, 70),(151, 13, 44),(216, 102, 88),(125, 216, 93),(171, 236, 47),(253, 127, 103),(205, 137, 244),(193, 137, 224),(36, 152, 214),(17, 50, 238),(154, 165, 67),(114, 129, 60),(119, 24, 48),(73, 8, 110)]
最后,我們可以使用本文中開發(fā)的 draw_masks_fromList函數(shù)來繪制我們所有的蒙版,為每個(gè)標(biāo)簽關(guān)聯(lián)一種顏色:
segmented_image = draw_masks_fromList(image, masks.to('cpu'), boxes, COLORS)
cv2_imshow(segmented_image)
我們使用提供的邊界框顯示了 YOLO 預(yù)測的所有遮罩。此外,每個(gè)蒙版都根據(jù)邊界框指示的類別進(jìn)行著色。這使得區(qū)分各種分割對象變得容易。文章來源:http://www.zghlxwxcb.cn/news/detail-705486.html
原文連接:SAM+YOLOv8簡明教程 — BimAnt文章來源地址http://www.zghlxwxcb.cn/news/detail-705486.html
到了這里,關(guān)于SAM + YOLOv8 圖像分割及對象檢測的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!