使用MaskR-CNN進行血細胞分割

程序員咋不禿頭 2024-06-21 10:12:35

介紹

血細胞分析是診斷各種醫學疾病的重要步驟,從感染和貧血到更嚴重的疾病如白血病。傳統上,這一過程是通過老方法進行的——實驗室技術員通過顯微鏡查看血塗片玻片,花費幾個小時。這一過程不僅令人乏味,還容易出現人爲錯誤,尤其是在處理大量樣本或複雜病例時。

難怪醫療專業人員一直渴望自動化這一重要分析。借助計算機視覺和深度學習算法的力量,我們可以以更高的准確性和效率處理血細胞檢查。一項改變這一應用的技術是圖像分割——本質上是從圖像的周圍區域中挑選出並分離單個細胞。

目錄圖像分割與 Mask R-CNNMask R-CNN 簡介及其在實例分割中的作用Mask R-CNN 架構和關鍵組件概述使用 Mask R-CNN 實現血細胞分割步驟1. 導入依賴項步驟2. 設置種子步驟3. 定義文件路徑步驟4. 定義自定義數據集類步驟5. 創建 DataLoader步驟6. 定義和修改模型步驟7. 訓練模型步驟8. 評估模型步驟9. 計算交並比(IoU)與其他技術的比較結論圖像分割與 Mask R-CNN

圖像分割涉及將圖像分成幾個片段或區域,每個片段或區域代表圖像中單獨的對象或對象的一部分。此過程對于獲取有價值的數據和理解圖像的內容至關重要。語義分割和實例分割是分割的兩個基本類別。

語義分割:語義分割爲圖像中的每個像素分配一個類標簽,而不區分同一類的不同實例。實例分割:實例分割爲像素分配類標簽,這有助于區分同一類的許多實例。

圖像分割的應用多種多樣,包括醫學成像(如腫瘤檢測和器官描繪)到自動駕駛(識別和跟蹤行人和車輛等物體)、衛星圖像(土地覆蓋分類)和增強現實。

Mask R-CNN 簡介及其在實例分割中的作用

現代深度學習模型(如 Mask R-CNN(基于掩碼區域的卷積神經網絡))用于處理實例分割。它在每個感興趣區域(RoI)上增加了分割掩碼預測分支,擴展了用于對象檢測的Faster R-CNN模型。通過這一新增強,Mask R-CNN現在可以通過檢測圖像中的對象並爲每個對象生成像素級的掩碼來實現實例分割。

Mask R-CNN是一種在需要精確對象邊界的應用中非常成功的方法,例如在醫學影像中分割血液樣本中的不同類型細胞。它在正確識別和勾畫圖像中的特定對象方面表現出色。

Mask R-CNN 架構和關鍵組件概述

Mask R-CNN 架構建立在 Faster R-CNN 框架之上,並包含幾個關鍵組件:

主幹網絡:通常爲深度卷積神經網絡(例如 ResNet 或 ResNeXt),充當特征提取器。該網絡處理輸入圖像並生成特征圖。區域提議網絡 (RPN):此組件生成區域提議,即特征圖中可能包含對象的潛在區域。RPN 是一個輕量級神經網絡,可輸出這些區域的邊界框和對象性分數。RoI Align:對 RoI Pooling 的改進,RoI Align 通過避免量化問題,准確地從建議的感興趣區域中提取特征,確保特征的精確對齊。邊界框頭:一個完全連接的網絡,采用 RoI 特征並執行對象分類和邊界框回歸以細化初始區域提議。Mask Head:一個小型卷積網絡,采用 RoI 特征並預測每個對象的二進制掩碼,在像素級別對對象進行分割。

這些組件的集成使 Mask R-CNN 能夠有效檢測物體並生成高質量的分割蒙版,使其成爲執行詳細而准確的實例分割任務的強大工具。血細胞分割等醫療應用尤其受益于此架構,其中精確的物體邊界對于准確分析和診斷至關重要。

使用 Mask R-CNN 實現血細胞分割

現在讓我們實現 Mask RCNN 進行血細胞分割。

步驟1. 導入依賴項

import osimport torchimport numpy as npimport matplotlib.pyplot as pltfrom PIL import Imagefrom torch.utils.data import Dataset, DataLoaderfrom torchvision.transforms import Compose, ToTensor, Resizefrom torchvision.models.detection import maskrcnn_resnet50_fpnfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictorfrom torchvision.models.detection.mask_rcnn import MaskRCNNPredictor

步驟2. 設置種子

設置種子將確保我們每次運行代碼時都會獲得相同的隨機生成。

seed = 42np.random.seed(seed)torch.manual_seed(seed)

步驟3. 定義文件路徑

初始化圖像路徑和用于檢索圖像的目標(掩碼)。

images_dir = '/content/images_BloodCellSegmentation'targets_dir = '/content/targets_BloodCellSegmentation'

步驟4. 定義自定義數據集類

BloodCellSegDataset:創建一個自定義數據集類,用于加載和預處理血細胞圖像及其掩模。

init:此構造函數通過列出所有圖像文件名,並爲圖像和蒙版構建完整路徑來初始化數據集。

getitem:該函數加載

圖像及其掩碼,對掩碼進行預處理以創建二進制掩碼計算邊界框調整圖像和蒙版的大小應用轉換。

len:此函數返回數據集中的圖像總數。

class BloodCellSegDataset(Dataset): def __init__(self, images_dir, masks_dir): self.image_names = os.listdir(images_dir) self.images_paths = [os.path.join(images_dir, image_name) for image_name in self.image_names] self.masks_paths = [os.path.join(masks_dir, image_name.split('.')[0] + '.png') for image_name in self.image_names] def __getitem__(self, idx): image = Image.open(self.images_paths[idx]) mask = Image.open(self.masks_paths[idx]) mask = np.array(mask) mask = ((mask == 128) | (mask == 255)) get_x = (mask.sum(axis=0) > 0).astype(int) get_y = (mask.sum(axis=1) > 0).astype(int) x1, x2 = get_x.argmax(), get_x.shape[0] - get_x[::-1].argmax() y1, y2 = get_y.argmax(), get_y.shape[0] - get_y[::-1].argmax() boxes = torch.as_tensor([[x1, y1, x2, y2]], dtype=torch.float32) area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0]) mask = Image.fromarray(mask) label = torch.ones((1,), dtype=torch.int64) image_id = torch.tensor([idx]) iscrowd = torch.zeros((1,), dtype=torch.int64) transform = Compose([Resize(224), ToTensor()]) boxes *= (224 / image.size[0]) image = transform(image) mask = transform(mask) target = {'masks': mask, 'labels': label, 'boxes': boxes, "image_id": image_id, "area": area, "iscrowd": iscrowd} return image, target def __len__(self): return len(self.image_names)

步驟5. 創建DataLoader

collate_fn:此函數用于處理批量數據,確保格式正確。

DataLoader:用于創建 pytorch 數據加載器

處理批處理改組並行加載數據。def collate_fn(batch): return tuple(zip(*batch))dataset = BloodCellSegDataset(images_dir, targets_dir)data_loader = DataLoader(dataset, batch_size=8, num_workers=2, shuffle=True, collate_fn=collate_fn)

步驟6. 定義和修改模型

maskrcnn_resnet50_fpn:這將加載一個預先訓練的 Mask R-CNN 模型,該模型具有 ResNet-50 主幹和特征金字塔網絡 (FPN)。

num_classes:這設置了我們的數據集中的類別數量。

FastRCNNPredictor:這取代了適合自定義類別數量的分類頭。

MaskRCNNPredictor:這取代了適合自定義類別數量的掩碼預測頭。

model = maskrcnn_resnet50_fpn(pretrained=True)num_classes = 2in_features = model.roi_heads.box_predictor.cls_score.in_featuresmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)in_features_mask = model.roi_heads.mask_predictor.conv5_mask.in_channelsnum_filters = 256model.roi_heads.mask_predictor = MaskRCNNPredictor(in_features_mask, num_filters, num_classes)

步驟7. 訓練模型

model.to(“cuda”):這將我們的模型轉移到 GPU 以加速訓練。

torch.optim.Adam:這定義了我們的優化器,用于更新模型參數。

model.train():將模型設置爲訓練模式並使其能夠改變權重。

訓練循環:

我們經曆了多個時期的叠代。一批批圖像和目標被傳輸到 GPU。該模型清除下一個時期的梯度,並傳遞圖像來計算損失。損失反向傳播,模型參數更新。計算並打印每個時期的平均損失。model = model.to("cuda")optimizer = torch.optim.Adam(model.parameters(), lr=0.001)model.train()for epoch in range(10): epoch_loss = cnt = 0 for batch_x, batch_y in tqdm(data_loader): batch_x = list(image.to("cuda") for image in batch_x) batch_y = [{k: v.to("cuda") for k, v in t.items()} for t in batch_y] optimizer.zero_grad() loss_dict = model(batch_x, batch_y) losses = sum(loss for loss in loss_dict.values()) losses.backward() optimizer.step() epoch_loss += loss_dict['loss_mask'].item() cnt += 1 epoch_loss /= cnt print("Training loss for epoch {} is {} ".format(epoch + 1, epoch_loss))

步驟8. 評估模型

我們加載一個示例圖像及其原始蒙版。我們對圖像和蒙版應用變換。我們將模型設置爲評估模式,這樣模型就不會計算梯度。我們將圖像傳入模型以獲得預測的掩碼。最後,我們使用 Matplotlib 將原始和預測的蒙版可視化。image = Image.open('/content/images_BloodCellSegmentation/002.bmp')gt_mask = Image.open('/content/targets_BloodCellSegmentation/002.png')gt_mask = np.array(gt_mask)gt_mask = ((gt_mask == 128) | (gt_mask == 255))gt_mask = Image.fromarray(gt_mask)transform = Compose([Resize(224), ToTensor()])image = transform(image)gt_mask = transform(gt_mask)model.eval()output = model(image.unsqueeze(dim=0).to('cuda'))output = output[0]['masks'][0].cpu().detach().numpy()plt.imshow(gt_mask.squeeze(), cmap='gray')plt.imshow((output.squeeze() > 0.5).astype(int), cmap='gray')

步驟9. 計算交並比(IoU)

IoU計算:

在這裏,我們將預測的和原始的蒙版壓平。然後我們計算預測掩碼和原始掩碼的交集和並集。現在我們計算 IoU 分數,這是評估分割性能的指標。mask = (output.squeeze() > 0.5).astype(int)pred = mask.ravel().copy()gt_mask = gt_mask.numpy()target = gt_mask.ravel().copy().astype(int)pred_inds = pred == 1target_inds = target == 1intersection = pred_inds[target_inds].sum()union = pred_inds.sum() + target_inds.sum() - intersectioniou = (float(intersection) / float(max(union, 1)))iou與其他技術的比較

雖然Mask R-CNN是分割領域的新秀,但我們不能忽視一些更古老、更傳統的方法。阈值和邊緣檢測等技術長期以來一直是血細胞分割的主力。

但問題是,這些簡單的方法通常無法處理現實世界醫學圖像中無窮無盡的變化。阈值化根據像素強度分離物體/背景,但它很難處理噪音、染色不均勻等問題。邊緣檢測根據強度梯度尋找邊界,但細胞簇和重疊會使其偏離目標。

然後我們有了更新的深度學習模型,如 U-Net 和 SegNet,它們專門爲密集像素分割任務而設計。它們確實提升了分割遊戲的水平,但它們的最佳點是識別特定類別的所有像素,如“細胞”與“背景”。

Mask R-CNN 采用不同的基于實例的方法,分離並勾勒出每個單獨的對象實例。雖然語義分割會告訴你屬于“汽車”的所有像素,但實例分割會告訴你每個不同汽車對象周圍的精確邊界。對于血細胞分析,能夠勾勒出每個細胞至關重要。

因此,盡管其他深度學習模型在各自的語義任務上表現出色,但 Mask R-CNN 在實例分割方面的專長使其在複雜的細胞輪廓描繪方面具有優勢(無意雙關)。其定位和分割單個實例以及分離聚類細胞的能力是無與倫比的。

結論

Mask R-CNN 在血細胞分割中的應用證明了深度學習技術在醫學診斷中的前景。通過足夠的研究和投資,我們可以自動化日常任務並提高醫療專業人員的工作效率。

Mask R-CNN 可以通過自動化分割過程極大地影響血細胞分析的有效性和准確性,從而提高患者護理和診斷結果。通過利用 Mask R-CNN 的先進功能,該技術可以輕松克服手動分割技術的缺點,並爲更先進的醫學成像解決方案創造未來的機會。

0 阅读:0

程序員咋不禿頭

簡介:感謝大家的關注