👉 點擊關注不迷路
👉 點擊關注不迷路
👉 點擊關注不迷路
文章大綱
- 1. __init__.py
- 2. model.py
- 3. predict.py
- 4. utils.py
- 5. val.py


FastSAM 是一種目標檢測和圖像分割模型
,Ultralytics 是一個在計算機視覺領域廣泛使用的庫,用于各種深度學習模型的訓練、推理和評估等任務。- ultralytics-cfg-models-fastsam 這個路徑下可能包含了 FastSAM 模型的配置文件,這些配置文件用于
定義模型的結構、超參數(如學習率、批次大小、訓練輪數等)
以及數據預處理和后處理的方式等。 - 同時,該路徑也可能包含已經訓練好的 FastSAM 模型權重文件,以便在進行推理或進一步微調時使用。
通過這些配置和模型文件,用戶可以方便地使用 Ultralytics 庫來加載 FastSAM 模型,進行圖像分割任務
,例如對輸入的圖像進行目標檢測和分割,識別出圖像中的不同物體并為其生成相應的分割掩碼。- 此外,也可以基于這些配置和模型文件進行模型的訓練和優化,以適應不同的數據集和應用場景。
1. init.py
-
from .model import FastSAM # 從當前目錄的model模塊中導入FastSAM類from .predict import FastSAMPredictor # 從當前目錄的predict模塊中導入FastSAMPredictor類from .val import FastSAMValidator # 從當前目錄的val模塊中導入FastSAMValidator類# 定義模塊的公共接口,即可以通過from module import *導入的名稱列表 __all__ = "FastSAMPredictor", "FastSAM", "FastSAMValidator"
2. model.py
- FastSAM 即 Fast Segment Anything Model
- 一種
高效的圖像分割模型,依托于 Ultralytics 的開發生態,在多領域展現出獨特價值
- 模型架構與原理: 它可能基于 Transformer 架構,通過對圖像特征的深度挖掘,實現對各類物體的精準分割。
在處理復雜場景圖像時,能有效捕捉物體的邊緣和細節信息,以較低的計算成本快速生成高質量的分割結果
。
- 模型架構與原理: 它可能基于 Transformer 架構,通過對圖像特征的深度挖掘,實現對各類物體的精準分割。
- 功能特點
- 快速處理: 相比傳統的圖像分割模型,
FastSAM 在保證分割精度的同時,大幅提升了處理速度。在實時性要求較高的場景,如自動駕駛的道路場景分割、直播內容的實時物體分割等
,能快速處理圖像或視頻流,滿足實時性需求。 - 多模態提示支持: 支持
多種提示方式進行分割,如邊界框(bounding boxes)、點(points)、標簽(labels)和文本(texts)
。用戶可根據具體需求,靈活選擇提示信息,引導模型對特定目標進行分割。 - 通用性強: 可應用于多種圖像分割任務,
包括但不限于實例分割、語義分割和全景分割。
無論是自然場景圖像、醫學影像,還是工業檢測圖像,都能展現出良好的分割性能。
- 快速處理: 相比傳統的圖像分割模型,
- 應用場景
- 計算機視覺研究: 為研究人員提供了一個高效的圖像分割工具,可用于探索新的分割算法、驗證研究思路。在新型神經網絡架構的研究中,利用 FastSAM 快速獲取分割結果,評估架構的有效性。
- 自動駕駛: 用于
識別道路上的車輛、行人、交通標志等目標,為自動駕駛汽車的決策提供關鍵信息
。通過實時分割道路場景圖像,幫助車輛準確感知周圍環境,實現安全行駛。 - 醫學影像分析: 在醫學領域,能輔助醫生對醫學影像(如 X 光、CT、MRI 等)進行分析。
幫助醫生快速分割出病變組織、器官等感興趣區域
,提高診斷效率和準確性。 - 工業檢測: 在工業生產中,對產品表面缺陷進行檢測時,可
分割出缺陷區域,判斷產品是否合格
。對電子芯片、機械零部件等進行質量檢測,及時發現生產過程中的問題。
-
from pathlib import Path # 導入 Path 類,用于處理文件路徑from ultralytics.engine.model import Model # 從 ultralytics 引擎模塊導入 Model 基類from .predict import FastSAMPredictor # 從當前包中導入 FastSAMPredictor 類,用于進行預測操作from .val import FastSAMValidator # 從當前包中導入 FastSAMValidator 類,用于進行驗證操作class FastSAM(Model):"""FastSAM model interface for segment anything tasks.# FastSAM 模型接口,用于處理任意圖像分割任務# 該類繼承自 Model 基類,為 FastSAM(快速任意分割模型)實現提供特定功能,可實現高效且準確的圖像分割Attributes:model (str): Path to the pre - trained FastSAM model file.# 預訓練的 FastSAM 模型文件的路徑task (str): The task type, set to "segment" for FastSAM models.# 任務類型,對于 FastSAM 模型,設置為 "segment"(分割)Examples:>>> from ultralytics import FastSAM>>> model = FastSAM("last.pt")>>> results = model.predict("ultralytics/assets/bus.jpg")# 使用示例,展示如何導入 FastSAM 類、初始化模型并進行預測"""def __init__(self, model="FastSAM-x.pt"):"""Initialize the FastSAM model with the specified pre - trained weights.# 使用指定的預訓練權重初始化 FastSAM 模型Args:model (str): Path to the pre - trained FastSAM model file. Defaults to "FastSAM-x.pt".# 預訓練的 FastSAM 模型文件的路徑,默認為 "FastSAM-x.pt""""if str(model) == "FastSAM.pt":model = "FastSAM-x.pt"# 如果傳入的模型名稱是 "FastSAM.pt",則將其替換為 "FastSAM-x.pt"assert Path(model).suffix not in {".yaml", ".yml"}, "FastSAM models only support pre - trained models."# 斷言傳入的模型文件后綴不是 .yaml 或 .yml,因為 FastSAM 模型僅支持預訓練模型super().__init__(model=model, task="segment")# 調用父類 Model 的構造函數,傳入模型路徑和任務類型def predict(self, source, stream=False, bboxes=None, points=None, labels=None, texts=None, **kwargs):"""# 對圖像或視頻源進行分割預測# 支持使用邊界框、點、標簽和文本進行提示分割。該方法將這些提示信息打包并傳遞給父類的 predict 方法Args:source (str | PIL.Image | numpy.ndarray): Input source for prediction, can be a file path, URL, PIL image,or numpy array.# 預測的輸入源,可以是文件路徑、URL、PIL 圖像或 numpy 數組stream (bool): Whether to enable real - time streaming mode for video inputs.# 是否為視頻輸入啟用實時流模式# 用于提示分割的邊界框坐標,格式為 [[x1, y1, x2, y2], ...]# 用于提示分割的點坐標,格式為 [[x, y], ...]# 用于提示分割的類別標簽# 用于分割引導的文本提示# 傳遞給預測器的其他關鍵字參數Returns:# 包含預測結果的 Results 對象列表"""prompts = dict(bboxes=bboxes, points=points, labels=labels, texts=texts)# 將邊界框、點、標簽和文本提示信息打包成字典return super().predict(source, stream, prompts=prompts, **kwargs)# 調用父類的 predict 方法,傳入輸入源、流模式、提示信息和其他關鍵字參數,并返回預測結果@propertydef task_map(self):"""# 返回一個字典,將分割任務映射到相應的預測器和驗證器類"""return {"segment": {"predictor": FastSAMPredictor, "validator": FastSAMValidator}}# 返回一個字典,鍵為 "segment",值為包含預測器和驗證器類的字典
- 一種
3. predict.py
- 關鍵詞: 圖像分割預測、邊界框的交并比、縮放掩碼
- CLIP模型
CLIP(Contrastive Language-Image Pretraining)模型
是 OpenAI 開發的一種開創性的神經網絡,通過互聯網上大量多樣的(圖像,文本)對進行訓練
,具備強大的跨模態理解能力,能夠將自然語言與圖像信息緊密聯系起來
。- 模型架構
- 圖像編碼器: 可選用
Vision Transformer(ViT)或 ResNet 等架構
。以 ViT 為例,它將圖像劃分為多個小塊,然后像處理文本序列一樣處理這些圖像塊,通過多頭注意力機制捕捉圖像的全局特征
。 - 文本編碼器: 基于文本 Transformer,把文本轉換為連續的向量表示,在這個過程中理解文本語義和結構信息。
- 共享嵌入空間: 兩個編碼器將圖像和文本投影到同一個向量空間,在這個空間中,語義相似的圖像和文本對其向量距離更近,為后續的匹配任務奠定基礎。
- 圖像編碼器: 可選用
- 零樣本學習能力:
CLIP 最顯著的優勢是零樣本學習
。在 ImageNet 分類任務中,它無需使用 ImageNet 訓練集中 128 萬張標記示例進行訓練,就能達到與原始 ResNet50 模型相匹配的性能
。使用時,只要提供文本描述(如 “一只貓”“一輛汽車”),CLIP 模型就能對圖像進行分類,判斷圖像內容是否與文本匹配。
ViT-B/32
ViT-B/32 是 CLIP 模型中使用的一種視覺 Transformer(Vision Transformer,ViT)
架構的具體變體。- 模型結構:
“ViT”:
代表視覺 Transformer,是一種將 Transformer 架構應用于計算機視覺任務的模型。它將圖像分割成一系列的圖像塊(patches)
,并將這些圖像塊作為輸入序列,類似于自然語言處理中 Transformer 對文本序列的處理方式。通過這種方式,ViT 可以有效地學習圖像中的全局信息和長期依賴關系
。“B”:
通常表示基礎(Base)版本,指的是模型的規模和復雜度處于中等水平。
例如,在參數數量、層數、隱藏層維度等方面,基礎版本具有一定的設定,是一種相對較為平衡的模型配置,既能夠在性能和計算資源之間取得較好的權衡
,又能在多種視覺任務上取得不錯的效果。“32”:
表示圖像塊的大小為 32×32 像素。這意味著在將圖像輸入到 ViT 模型之前,會先將圖像分割成邊長為 32 像素的正方形小塊
。較小的圖像塊大小可以捕捉到更精細的圖像細節,但也會增加模型的計算量和參數量;而較大的圖像塊大小則可以減少計算量,但可能會丟失一些細節信息
。
import torch# 導入PyTorch庫,用于深度學習相關的張量計算和模型操作from PIL import Image# 導入PIL庫的Image模塊,用于處理圖像from ultralytics.models.yolo.segment import SegmentationPredictor# 從ultralytics的yolo模型的segment模塊中導入SegmentationPredictor類,可能是用于圖像分割預測的基類from ultralytics.utils import DEFAULT_CFG, checks# 從ultralytics的utils模塊中導入DEFAULT_CFG(可能是默認配置)和checks(可能用于檢查某些條件或配置)from ultralytics.utils.metrics import box_iou# 從ultralytics的utils模塊的metrics子模塊中導入box_iou函數,可能用于計算邊界框的交并比from ultralytics.utils.ops import scale_masks# 從ultralytics的utils模塊的ops子模塊中導入scale_masks函數,可能用于縮放掩碼from .utils import adjust_bboxes_to_image_border# 從當前目錄的utils模塊中導入adjust_bboxes_to_image_border函數,可能用于調整邊界框以適應圖像邊界class FastSAMPredictor(SegmentationPredictor):# FastSAMPredictor類,繼承自SegmentationPredictor,用于圖像分割預測,并支持多種提示方式。def __init__(self, cfg=DEFAULT_CFG, overrides=None, _callbacks=None):""" 初始化函數。Args:cfg (dict, optional): 配置字典,默認為DEFAULT_CFG。overrides (dict, optional): 用于覆蓋默認配置的字典。_callbacks (list, optional): 回調函數列表。"""super().__init__(cfg, overrides, _callbacks)# 初始化一個空字典,用于存儲各種提示信息(邊界框、點、標簽、文本等)self.prompts = {}def postprocess(self, preds, img, orig_imgs):""" 對模型預測結果進行后處理。Args:preds (torch.Tensor): 模型的預測結果。img (torch.Tensor): 輸入的圖像張量。orig_imgs (list): 原始圖像列表。Returns:list: 經過后處理和提示應用后的結果列表。"""# 從prompts字典中彈出【邊界框】提示信息,如果不存在則返回Nonebboxes = self.prompts.pop("bboxes", None)# 從prompts字典中彈出【點】提示信息,如果不存在則返回Nonepoints = self.prompts.pop("points", None)# 從prompts字典中彈出【標簽】提示信息,如果不存在則返回Nonelabels = self.prompts.pop("labels", None)# 從prompts字典中彈出【文本】提示信息,如果不存在則返回Nonetexts = self.prompts.pop("texts", None)# 調用父類的postprocess方法進行基本的后處理results = super().postprocess(preds, img, orig_imgs)for result in results:# 創建一個表示整個圖像邊界的張量,格式為 [x1, y1, x2, y2]full_box = torch.tensor([0, 0, result.orig_shape[1], result.orig_shape[0]], device=preds[0].device, dtype=torch.float32)# 調整預測的邊界框,使其適應原始圖像的邊界boxes = adjust_bboxes_to_image_border(result.boxes.xyxy, result.orig_shape)# 計算【全圖像邊界框與調整后的邊界框】之間的交并比,找到【交并比大于0.9的索引】idx = torch.nonzero(box_iou(full_box[None], boxes) > 0.9).flatten()if idx.numel() != 0:# 如果存在【交并比大于0.9的邊界框,則將其設置為全圖像邊界】result.boxes.xyxy[idx] = full_box# 調用prompt方法,應用各種提示信息到結果中return self.prompt(results, bboxes=bboxes, points=points, labels=labels, texts=texts)def prompt(self, results, bboxes=None, points=None, labels=None, texts=None):"""根據提供的提示信息(邊界框、點、標簽、文本)對分割結果進行篩選和處理。Args:results (list or object): 分割結果,可以是【單個結果或結果列表】。bboxes (list, optional): 邊界框提示信息,格式為 [[x1, y1, x2, y2], ...]。points (list, optional): 點提示信息,格式為 [[x, y], ...]。labels (list, optional): 標簽提示信息,與點提示信息對應。texts (list, optional): 文本提示信息。Returns:list: 經過提示篩選后的結果列表。"""if bboxes is None and points is None and texts is None:# 如果沒有提供任何提示信息,則直接返回原始結果return resultsprompt_results = []if not isinstance(results, list):# 如果結果不是列表,則將其轉換為列表results = [results]for result in results:if len(result) == 0:# 如果結果為空,則直接添加到提示結果列表中prompt_results.append(result)continuemasks = result.masks.dataif masks.shape[1:] != result.orig_shape:# 如果【掩碼的形狀與原始圖像形狀不一致】,則縮放掩碼masks = scale_masks(masks[None], result.orig_shape)[0]# 初始化一個布爾張量,用于標記符合條件的分割結果idx = torch.zeros(len(result), dtype=torch.bool, device=self.device)if bboxes is not None:# 將邊界框提示信息轉換為張量bboxes = torch.as_tensor(bboxes, dtype=torch.int32, device=self.device)if bboxes.ndim == 1:# 如果邊界框是一維的,則將其轉換為二維bboxes = bboxes[None]# 計算每個邊界框的面積bbox_areas = (bboxes[:, 3] - bboxes[:, 1]) * (bboxes[:, 2] - bboxes[:, 0])# 計算每個掩碼與邊界框重疊部分的面積mask_areas = torch.stack([masks[:, b[1] : b[3], b[0] : b[2]].sum(dim=(1, 2)) for b in bboxes])# 計算每個掩碼的總面積full_mask_areas = torch.sum(masks, dim=(1, 2))# 計算邊界框與掩碼的并集面積union = bbox_areas[:, None] + full_mask_areas - mask_areas# 找到重疊面積與并集面積比值最大的索引,并將其對應的idx位置設為Trueidx[torch.argmax(mask_areas / union, dim=1)] = Trueif points is not None:# 將點提示信息轉換為張量points = torch.as_tensor(points, dtype=torch.int32, device=self.device)if points.ndim == 1:# 如果點是一維的,則將其轉換為二維points = points[None]if labels is None:# 如果沒有提供標簽,則創建全為1的標簽張量labels = torch.ones(points.shape[0])# 將標簽轉換為張量labels = torch.as_tensor(labels, dtype=torch.int32, device=self.device)assert len(labels) == len(points), (f"Expected `labels` to have the same size as `point`, but got {len(labels)} and {len(points)}")# 根據標簽的總和初始化point_idx,如果【標簽總和為0(即全為負點)】,則設為全True,否則設為全Falsepoint_idx = (torch.ones(len(result), dtype=torch.bool, device=self.device)if labels.sum() == 0else torch.zeros(len(result), dtype=torch.bool, device=self.device))for point, label in zip(points, labels):# 根據點的位置和標簽,更新point_idxpoint_idx[torch.nonzero(masks[:, point[1], point[0]], as_tuple=True)[0]] = bool(label)# 將point_idx與idx進行邏輯或操作idx |= point_idxif texts is not None:if isinstance(texts, str):# 如果文本提示是字符串,則將其轉換為列表 ???texts = [texts]crop_ims, filter_idx = [], []for i, b in enumerate(result.boxes.xyxy.tolist()):x1, y1, x2, y2 = (int(x) for x in b)if masks[i].sum() <= 100:# 如果掩碼的總和小于等于100,則將其索引添加到filter_idx中并跳過filter_idx.append(i)continue# 從原始圖像中裁剪出邊界框對應的區域,并轉換為PIL圖像crop_ims.append(Image.fromarray(result.orig_img[y1:y2, x1:x2, ::-1]))# 使用CLIP模型計算裁剪圖像與文本提示之間的相似度similarity = self._clip_inference(crop_ims, texts)# 找到相似度最大的索引text_idx = torch.argmax(similarity, dim=-1)if len(filter_idx):# 如果存在過濾索引,則調整text_idxtext_idx += (torch.tensor(filter_idx, device=self.device)[None] <= int(text_idx)).sum(0)# 將text_idx對應的idx位置設為Trueidx[text_idx] = True# 將符合條件的結果添加到提示結果列表中prompt_results.append(result[idx])return prompt_resultsdef _clip_inference(self, images, texts):""" 使用CLIP模型進行推理,計算圖像與文本之間的相似度。Args:images (list): PIL圖像列表。texts (list): 文本提示列表。Returns: torch.Tensor: 圖像與文本之間的相似度矩陣,形狀為 (M, N),M為文本數量,N為圖像數量。"""try:import clipexcept ImportError:# 如果CLIP庫未安裝,則檢查并安裝checks.check_requirements("git+https://github.com/ultralytics/CLIP.git")import clipif (not hasattr(self, "clip_model")) or (not hasattr(self, "clip_preprocess")):# 如果當前對象沒有CLIP模型和預處理函數,則加載CLIP模型和預處理函數self.clip_model, self.clip_preprocess = clip.load("ViT-B/32", device=self.device)# 對圖像進行預處理,并將其轉換為張量images = torch.stack([self.clip_preprocess(image).to(self.device) for image in images])# 對文本進行分詞,并將其轉換為張量tokenized_text = clip.tokenize(texts).to(self.device)# 使用CLIP模型對圖像進行編碼,得到圖像特征image_features = self.clip_model.encode_image(images)# 使用CLIP模型對文本進行編碼,得到文本特征text_features = self.clip_model.encode_text(tokenized_text)# 對圖像特征進行歸一化image_features /= image_features.norm(dim=-1, keepdim=True)# 對文本特征進行歸一化text_features /= text_features.norm(dim=-1, keepdim=True)# 計算圖像特征與文本特征之間的相似度,并返回相似度矩陣return (image_features * text_features[:, None]).sum(-1)def set_prompts(self, prompts):"""設置提示信息字典。Args:prompts (dict): 包含各種提示信息的字典,如 "bboxes", "points", "labels", "texts" 等。"""self.prompts = prompts```
4. utils.py
-
def adjust_bboxes_to_image_border(boxes, image_shape, threshold=20):"""將邊界框調整到圖像邊界附近,確保邊界框不會超出合理范圍。Args:boxes (torch.Tensor或numpy.ndarray): 邊界框的張量或數組,形狀通常為 (N, 4),N表示邊界框的數量,每個邊界框包含四個坐標值 (x1, y1, x2, y2),分別代表左上角和右下角的坐標。image_shape (tuple): 圖像的形狀,格式為 (高度, 寬度)。threshold (int, 可選): 接近邊界的閾值。如果邊界框的坐標值與圖像邊界的距離小于該閾值,則將邊界框的坐標調整到邊界上。默認為20。Returns:torch.Tensor或numpy.ndarray: 調整后的邊界框張量或數組,形狀與輸入的boxes相同。"""# 獲取圖像的高度和寬度h, w = image_shape# 調整靠近圖像左邊界的邊界框的x1坐標boxes[boxes[:, 0] < threshold, 0] = 0 # x1# 調整靠近圖像上邊界的邊界框的y1坐標boxes[boxes[:, 1] < threshold, 1] = 0 # y1# 調整靠近圖像右邊界的邊界框的x2坐標boxes[boxes[:, 2] > w - threshold, 2] = w # x2# 調整靠近圖像下邊界的邊界框的y2坐標boxes[boxes[:, 3] > h - threshold, 3] = h # y2return boxes
5. val.py
-
from ultralytics.models.yolo.segment import SegmentationValidator # 從ultralytics的yolo模型的segment模塊導入SegmentationValidator類from ultralytics.utils.metrics import SegmentMetrics # 從ultralytics的utils模塊的metrics子模塊導入SegmentMetrics類class FastSAMValidator(SegmentationValidator): # 定義FastSAMValidator類,繼承自SegmentationValidatordef __init__(self, dataloader=None, save_dir=None, pbar=None, args=None, _callbacks=None):"""初始化FastSAMValidator類的實例。Args:dataloader (DataLoader, 可選): 數據加載器,用于加載驗證數據。默認為None。save_dir (str, 可選): 保存驗證結果的目錄。默認為None。pbar (tqdm.tqdm, 可選): 進度條對象,用于顯示驗證過程的進度。默認為None。args (Namespace, 可選): 包含驗證參數的命名空間。默認為None。_callbacks (list, 可選): 回調函數列表,用于在驗證過程中執行特定的操作。默認為None。"""super().__init__(dataloader, save_dir, pbar, args, _callbacks) # 調用父類的初始化方法self.args.task = "segment" # 設置任務類型為"segment"(分割)self.args.plots = False # 禁用混淆矩陣和其他繪圖,以避免錯誤self.metrics = SegmentMetrics(save_dir=self.save_dir) # 創建SegmentMetrics對象,用于計算分割任務的指標,并指定保存目錄