肺部多病种研究需要同时检测肺实质中的结节、索条和心脏、血管中的动脉硬化,而网上只存在肺实质的提取,索性自己写一个,先阈值化,后对背景进行flood_fill算法再取反,同时用到了一些腐蚀膨胀操作。不得不说,skimage真好用,其实skimage也有floodfill,但是不知道为什么出了bug,所以用了cv2的floodfill
import numpy as np
import skimage
from skimage.morphology import disk, rectangle, binary_dilation, binary_erosion, binary_closing, binary_opening, rectangle, remove_small_objects
import SimpleITK as sitk
import matplotlib.pyplot as plt
import cv2
#input np_array with shape (h,w)
#output np_array with shape(h,w)
def seg_whole_lungs(im):
#背景值是-1000
output = im.copy()
mid_img = im.copy()
# 二值化
mid_img = mid_img > -850
#腐蚀去除噪点
selem = disk(3)
mid_img = binary_erosion(mid_img, selem)
#闭运算去除边缘孔洞
selem = disk(4)
mid_img = binary_closing(mid_img, selem)
#开运算除掉最下面的线
selem = rectangle(1,8)
mid_img = binary_opening(mid_img, selem)
#水漫外围,再取反
mid_img = fill_water(mid_img)
h, w = mid_img.shape[:2]
binary = np.zeros([h,w], np.uint8)
binary[mid_img == 0] = 1
#去除小目标,主要用于去除最下面的奇怪异物
label_image = remove_small_objects(label(binary), 15000)
binary = label_image > 0
output[binary==0] = -1000
return output
def fill_water(image):
copyImg = image.copy()
copyImg.astype(np.float32)#cv2要求type必须是float32
#mask必须行和列都加2,且必须为uint8单通道阵列
h, w = image.shape[:2]
mask1 = np.zeros([h+2, w+2],np.uint8)
mask2 = mask1.copy()
#由于下方出现的弧线可能把图片分割成上下部分,故同时从上下两个方向进行水漫
cv2.floodFill(np.float32(copyImg), mask1, (1, 1), 1)
cv2.floodFill(np.float32(copyImg), mask2, (h-1, w-1), 1)
mask = mask1 | mask2
#还原为原来的尺寸
output = mask[1:-1, 1:-1]
return output
以下是效果图