醫學影像預處理之裁減


背景

在數據集訓練之前,為了減小數據計算的工作量,提高訓練的速度,通常會針對感興趣的特征部分進行原圖片的裁減,這樣每張圖片既保留了待提取的特征集,又縮小了整體的尺寸,可有效縮短模型訓練耗費的時間。

理解三維圖像

DICOM坐標系是相對於病人的方向來確定的,如下圖所示:

三視圖三個截面,分別稱為軸狀位(Transverse/Axisplane)、冠狀位(Coronal/Frontal plane)和矢狀位(Sagittal plane),如下圖所示:

裁減原理

我們把一個影像文件讀到一個三維數組,shape為(x,y,z),分別沿着x、y和z三個坐標軸方向滑動讀取每一個slice中的圖像數據,從而獲取期望的特征邊界。沿X軸方向滑動得到的每一個切面為圖二所示的失狀位,同理,沿y軸滑動得到的每一個切面為圖二所示的冠狀位,沿z軸滑動得到的每一個切面為圖二所示的軸狀位。以沿x軸滑動為例,對應在讀圖軟件上,就是在矢狀位視圖滾動鼠標的效果,這個視圖中滾動的每一張切片就是沿X軸滑動得到的,此外,可以看到在另外兩個視圖中有一個豎線在沿X軸左右滑動,如下圖,其它視圖同理。

為了方便對照和理解,我把三視圖與軸狀位、冠狀位和矢狀位一一對應起來,如下圖:

理解了這些之后也就理解了裁減的原理和方法,還是以沿X軸滑動為例,先沿X軸正向滑動,遍歷每個slice,獲取特征的邊界對應的Xmin值,然后再沿X軸反向滑動,遍歷每個slice,獲取特征的邊界對應的Xmax值,這樣我們就獲取了Xmin:Xmax之間的部分,同理我們可以獲取Ymin:Ymax和Zmin:Zmax。

代碼實現

# encoding = utf-8
import nibabel as nib
import numpy as np
import os

DST_PATH = "filled with your data path"

def get_boundary(volume):

    for i in range(volume.shape[0]):
        if np.max(volume[i]) != 0:
            volume_Xmin = i
            break
    for i in range(volume.shape[0])[::-1]:
        if np.max(volume[i]) != 0:
            volume_Xmax = i
            break
    for i in range(volume.shape[1]):
        if np.max(volume[:, i, :]) != 0:
            volume_Ymin = i
            break
    for i in range(volume.shape[1])[::-1]:
        if np.max(volume[:, i, :]) != 0:
            volume_Ymax = i
            break
    for i in range(volume.shape[2]):
        if np.max(volume[:, :, i]) != 0:
            volume_Zmin = i
            break
    for i in range(volume.shape[2])[::-1]:
        if np.max(volume[:, :, i]) != 0:
            volume_Zmax = i
            break
    return (volume_Xmin, volume_Xmax,volume_Ymin,volume_Ymax,volume_Zmin,volume_Zmax)

if __name__ == "__main__":
    if not os.path.exists(DST_PATH):
      os.mkdir(DST_PATH)
    img_data = nib.load("./Zhangsan_Arterial_Data.nii.gz")
    img_label = nib.load("./Zhangsan_Arterial_Label.nii.gz")
    img_data_npy = img_data.get_fdata()
    img_label_npy = img_label.get_fdata()
    print("=======origin shape=======")
    print(img_data_npy.shape)
    volume_Xmin, volume_Xmax,volume_Ymin,volume_Ymax,volume_Zmin,volume_Zmax = get_boundary(img_label_npy)
    data_clip = img_data_npy[volume_Xmin:volume_Xmax, volume_Ymin:volume_Ymax, volume_Zmin:volume_Zmax]
    label_clip = img_label_npy[volume_Xmin:volume_Xmax, volume_Ymin:volume_Ymax, volume_Zmin:volume_Zmax]
    print("=======clip shape=========")
    print(data_clip.shape)
    nib.save(nib.Nifti1Image(data_clip.astype('int16'), affine=img_data.affine), os.path.join(DST_PATH, 'Clip_Data.nii.gz'))
    nib.save(nib.Nifti1Image(label_clip.astype('uint8'), affine=img_label.affine), os.path.join(DST_PATH, 'Clip_Label.nii.gz'))

裁減效果

裁減前:shape為(512, 512, 231)

裁減后:shape為(308, 98, 112)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM