根据mask绘制contour
import cv2
import numpy as np
import SimpleITK as sitk
dcm_file = r'G:\data\3Dircadb\3Dircadb1.3\PATIENT_DICOM\image_137'
dcm_liver = r'G:\data\3Dircadb\3Dircadb1.3\MASKS_DICOM\liver\image_137'
dcm_tumor = r'G:\data\3Dircadb\3Dircadb1.3\MASKS_DICOM\livertumor\image_137'
def drawContour():
image = sitk.ReadImage(dcm_file)
image_array = sitk.GetArrayFromImage(image)
image_array = np.squeeze(image_array)
image_array = image_array.astype(np.float32)
# windowing 操作
# min:-200, max:200
# img = (img-min)/(max - min)
image_array = (image_array - (-200)) / 400.0
image_array[image_array > 1] = 1.0
image_array[image_array < 0] = 0.0
# 不必须转化为0-255
# 若不转化为彩色,那么最后画出来的contour也只能是灰度的
image_array = cv2.cvtColor(image_array, cv2.COLOR_GRAY2BGR)
liver = sitk.ReadImage(dcm_liver)
liver_array = sitk.GetArrayFromImage(liver)
liver_array = np.squeeze(liver_array)
# liver_array *= 255 不必须
tumor = sitk.ReadImage(dcm_tumor)
tumor_array = sitk.GetArrayFromImage(tumor)
tumor_array = np.squeeze(tumor_array)
# tumor_array *= 255 不必须
# findContours 必须目标是white,背景是black (0,1 和 0,255 都可以)
# py3 只返回2个参数,而非之前的3个
contours, hierarchy = cv2.findContours(
liver_array, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours2, hierarchy2 = cv2.findContours(
tumor_array, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]
# drawContours 直接改变原图
# 第三个参数 index
# 第四个参数color: BGR
# 两种不同的方式指明画哪个contour
cv2.drawContours(image_array, [cnt], 0, (0, 0, 255), 1)
cv2.drawContours(image_array, contours2, -1,
(255, 0, 0), 1) # index=-1表示画所有的contour
cv2.imshow("liver_contour", image_array)
cv2.waitKey()
drawContour()
根据mask绘制bounding box
主要解决两个问题:
1、如何用给定的mask找到最小包围矩形
2、如何用给定的矩形在原图上绘制bounding box(利用matplotlib)
只有一个类的情况
import numpy as np
import matplotlib.patches as patches
import matplotlib.pyplot as plt
"""
masks shape: (batch_size, height, width)
且mask为单通道,一个类别
"""
maxw=maxh=0
#
for i in range(masks.shape[0]):
# Create figure and axes
fig,ax = plt.subplots(1)
mask = masks[i]
# np.nonzero会返回形如(array,array)的东西
# 第一个是行的index,第二个是列的index
# 例如 np.nonzero(np.array([[0,1],[2,0]])
# 会返回 ( array([0,1]), array([1,0]) )
coor = np.nonzero(mask)
xmin = coor[0][0]
xmax = coor[0][-1]
coor[1].sort() # 直接改变原数组,没有返回值
ymin = coor[1][0]
ymax = coor[1][-1]
bottomleft = (ymin, xmin)
width = ymax - ymin
height = xmax - xmin
# 这儿可以不要,这是为了找到最大值方便分割成统一的矩形
if width > maxw:
maxw = width
if height > maxh:
maxh = height
# Display the image
ax.imshow(mask,cmap=plt.cm.gray)
# Create a Rectangle patch
rect = patches.Rectangle(bottomleft,width,height,linewidth=1,edgecolor='r',facecolor='none')
# Add the patch to the Axes
ax.add_patch(rect)
plt.show()
结果示例
若有一系列的图片,想对这些图片全都进行裁剪后输入网络(包含目标区域),这样收敛的更快。虽然网络可以接受任意尺度的图片,但由于我们一般都是batch_size个图片一起输入网络,中间会有拼接等操作,就需要不同的图片间size是相同的,于是,可以随机运行原始图片进行bounding box描绘,然后找出其中的最大值,对这个最大值进行适当扩张,就可以当作最后要截取的目标区域了。
for i in range(masks.shape[0]):
# Create figure and axes
fig,ax = plt.subplots(1)
mask = masks[i]
# find coordinates of liver
coor = np.nonzero(mask)
xmin = coor[0][0] # x代表了行
xmax = coor[0][-1]
coor[1].sort() # 直接改变原数组,没有返回值
ymin = coor[1][0]
ymax = coor[1][-1]
width_center = (ymax + ymin) // 2
height_center = (xmax + xmin) // 2
# print("w-center,h-center",width_center,height_center)
# pre-parameter: height:256, width:324
# 参数的选定:是之前随机运行后,挑出的最大值,然后适当扩大后的结果
height = 256
width = 324
istart = int(height_center - height/2)
#注意逻辑!
if istart < 0:
istart = 0
iend = height
else:
iend = int(istart + height)
if iend > 512:
istart = 512 - height
iend = 512
jstart = int(width_center - width/2)
if jstart < 0:
jstart = 0
jend = width
jend = int(jstart + width)
if jend > 512:
jstart = 512 - width
jend = 512
print("[%d:%d,%d:%d]"%(istart,iend,jstart,jend))
mask_crop = mask[istart:iend,jstart:jend]
# Display the image
ax.imshow(mask_crop,cmap=plt.cm.gray)
# Create a Rectangle patch
# rect = patches.Rectangle(bottomleft,width,height,linewidth=1,edgecolor='r',facecolor='none')
# Add the patch to the Axes
# ax.add_patch(rect)
plt.show()
最后,批量展示图片,方法一:
from HDF5DatasetGenerator import HDF5DatasetGenerator
import matplotlib.pyplot as plt
reader = HDF5DatasetGenerator(dbPath=outputPath,batchSize=BATCH_SIZE)
myiter = reader.generator()
images, masks = myiter.__next__()
reader.close()
masks = np.squeeze(masks)
images = np.squeeze(images)
masks = masks.astype("float")
images_per_row = 5
n_features = BATCH_SIZE #这儿只展示一个batch size的图片
h_size = height # 取出的图片高度
w_size = width
n_cols = n_features // images_per_row
display_grid = np.zeros((h_size * n_cols, images_per_row * w_size))
for col in range(n_cols): # Tiles each filter into a big horizontal grid
for row in range(images_per_row):
xchannel = masks[col * images_per_row + row,:,:]
xchannel -= xchannel.mean() # Post-processes the feature to make it visually palatable
xchannel /= xchannel.std()
xchannel *= 64
xchannel += 128
xchannel = np.clip(xchannel, 0, 255).astype('uint8')
display_grid[col * h_size : (col + 1) * h_size, # Displays the grid
row * w_size : (row + 1) * w_size] = xchannel
h_scale = 1. / h_size
w_scale = 1. / w_size
plt.figure(figsize=(h_scale * display_grid.shape[1],
w_scale * display_grid.shape[0]))
plt.title("images")
plt.grid(False)
plt.imshow(display_grid, aspect='auto', cmap=plt.cm.gray)
剪切后的masks展示
批量展示图片,方法二:
import matplotlib.pyplot as plt
def sample_stack(stack, name, rows=1, cols=3, start_with=0, show_every=1):
"""
参数说明:
stack:需要展示的图片,格式为(N,height,width),灰度图
name: 保存图片的路径
rows,cols:展示几行几列
start_with:从第几张开始展示
show_every:每隔几张展示一张图
"""
fig,ax = plt.subplots(rows,cols,figsize=[6*cols,6*rows])
if rows==1 or cols==1 :
nums = rows*cols
for i in range(nums):
ind = start_with + i*show_every
ax[int(i % nums)].set_title('slice %d' % ind)
ax[int(i % nums)].imshow(stack[ind],cmap='gray')
ax[int(i % nums)].axis('off')
else:
for i in range(rows*cols):
ind = start_with + i*show_every
ax[int(i/cols),int(i % cols)].set_title('slice %d' % ind)
ax[int(i/cols),int(i % cols)].imshow(stack[ind],cmap='gray')
ax[int(i/cols),int(i % cols)].axis('off')
# 这句话一定要在show之前写,否则show函数之后会创建新的空白图
plt.savefig(name)
plt.show()