根据mask绘制contour ,bounding box。批量展示图片 等工具函数

根据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()
  • 8
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值