def getCubicInputChunk(self, center_xyz, maxWidth_mm): center_irc = xyz2irc(center_xyz, self.origin_xyz, self.vxSize_xyz, self.direction_tup) ct_start = [int(round(i)) for i in xyz2irc(tuple(x - maxWidth_mm / 2 for x in center_xyz), self.origin_xyz, self.vxSize_xyz, self.direction_tup)] ct_end = [int(round(i)) + 1 for i in xyz2irc(tuple(x + maxWidth_mm / 2 for x in center_xyz), self.origin_xyz, self.vxSize_xyz, self.direction_tup)] for axis in range(3): if ct_start[axis] > ct_end[axis]: ct_start[axis], ct_end[axis] = ct_end[axis], ct_start[axis] pad_start = [0, 0, 0] pad_end = [ct_end[axis] - ct_start[axis] for axis in range(3)] # log.info([ct_end, ct_start, pad_end]) chunk_ary = np.zeros(pad_end, dtype=np.float32) for axis in range(3): if ct_start[axis] < 0: pad_start[axis] = -ct_start[axis] ct_start[axis] = 0 if ct_end[axis] > self.ary.shape[axis]: pad_end[axis] -= ct_end[axis] - self.ary.shape[axis] ct_end[axis] = self.ary.shape[axis] pad_slices = tuple(slice(s,e) for s, e in zip(pad_start, pad_end)) ct_slices = tuple(slice(s,e) for s, e in zip(ct_start, ct_end)) chunk_ary[pad_slices] = self.ary[ct_slices] return chunk_ary, center_irc
def getRawCandidate(self, center_xyz, width_irc): center_irc = xyz2irc(center_xyz, self.origin_xyz, self.vxSize_xyz, self.direction_a) slice_list = [] for axis, center_val in enumerate(center_irc): start_ndx = int(round(center_val - width_irc[axis] / 2)) end_ndx = int(start_ndx + width_irc[axis]) assert center_val >= 0 and center_val < self.hu_a.shape[axis], repr( [ self.series_uid, center_xyz, self.origin_xyz, self.vxSize_xyz, center_irc, axis ]) if start_ndx < 0: # log.warning("Crop outside of CT array: {} {}, center:{} shape:{} width:{}".format( # self.series_uid, center_xyz, center_irc, self.hu_a.shape, width_irc)) start_ndx = 0 end_ndx = int(width_irc[axis]) if end_ndx > self.hu_a.shape[axis]: # log.warning("Crop outside of CT array: {} {}, center:{} shape:{} width:{}".format( # self.series_uid, center_xyz, center_irc, self.hu_a.shape, width_irc)) end_ndx = self.hu_a.shape[axis] start_ndx = int(self.hu_a.shape[axis] - width_irc[axis]) slice_list.append(slice(start_ndx, end_ndx)) ct_chunk = self.hu_a[tuple(slice_list)] return ct_chunk, center_irc
def getRawCandidate(self, center_xyz, width_irc): center_irc = xyz2irc( center_xyz, self.origin_xyz, self.vxSize_xyz, self.direction_a, )#将候选结节坐标(xyz)转换为irc坐标 slice_list = [] #裁剪整个ct图像,提取出结节图像 for axis, center_val in enumerate(center_irc):#center_irc是一个元组(i坐标的值,r的值,c的值) start_ndx = int(round(center_val - width_irc[axis]/2))#width_irc :图像的深度、高度、宽度 end_ndx = int(start_ndx + width_irc[axis]) assert center_val >= 0 and center_val < self.hu_a.shape[axis], repr([self.series_uid, center_xyz, self.origin_xyz, self.vxSize_xyz, center_irc, axis]) #当如上做法导致所裁剪的小区域的起始坐标和结束坐标超出整个ct图像的边界时 if start_ndx < 0: # log.warning("Crop outside of CT array: {} {}, center:{} shape:{} width:{}".format( # self.series_uid, center_xyz, center_irc, self.hu_a.shape, width_irc)) start_ndx = 0 end_ndx = int(width_irc[axis]) if end_ndx > self.hu_a.shape[axis]: # log.warning("Crop outside of CT array: {} {}, center:{} shape:{} width:{}".format( # self.series_uid, center_xyz, center_irc, self.hu_a.shape, width_irc)) end_ndx = self.hu_a.shape[axis] start_ndx = int(self.hu_a.shape[axis] - width_irc[axis]) slice_list.append(slice(start_ndx, end_ndx)) ct_chunk = self.hu_a[tuple(slice_list)]#([s,e],[],[]) return ct_chunk, center_irc
def getRawNodule(self, center_xyz, width_irc): center_irc = xyz2irc(center_xyz, self.origin_xyz, self.vxSize_xyz, self.direction_tup) slice_list = [] for axis, center_val in enumerate(center_irc): start_ndx = int(round(center_val - width_irc[axis] / 2)) end_ndx = int(start_ndx + width_irc[axis]) assert center_val >= 0 and center_val < self.hu_a.shape[axis], \ repr([self.series_uid, center_xyz, self.origin_xyz, self.vxSize_xyz, center_irc, axis]) if start_ndx < 0: start_ndx = 0 end_ndx = int(width_irc[axis]) if end_ndx > self.hu_a.shape[axis]: end_ndx = self.hu_a.shape[axis] start_ndx = int(self.hu_a.shape[axis] - width_irc[axis]) slice_list.append(slice(start_ndx, end_ndx)) ct_chunk = self.hu_a[tuple(slice_list)] return ct_chunk, center_irc
def buildAnnotationMask(self, noduleInfo_list, threshold_hu=-500): boundingBox_a = np.zeros_like(self.hu_a, dtype=np.bool) for noduleInfo_tup in noduleInfo_list: center_irc = xyz2irc(noduleInfo_tup.center_xyz, self.origin_xyz, self.vxSize_xyz, self.direction_tup) ci = int(center_irc.index) cr = int(center_irc.row) cc = int(center_irc.col) radius = 2 # Index ci_min = ci - radius ci_max = ci + radius try: while self.hu_a[ci_max, cr, cc] > threshold_hu and \ self.hu_a[ci_min, cr, cc] > threshold_hu: ci_min -= 1 ci_max += 1 except IndexError: ci_min += 1 ci_max -= 1 # Row cr_min = ci - radius cr_max = ci + radius try: while self.hu_a[ci, cr_max, cc] > threshold_hu and \ self.hu_a[ci, cr_max, cc] > threshold_hu: cr_min -= 1 cr_max += 1 except IndexError: cr_min += 1 cr_max -= 1 # Column cc_min = ci - radius cc_max = ci + radius try: while self.hu_a[ci, cr, cc_max] > threshold_hu and \ self.hu_a[ci, cr, cc_min] > threshold_hu: cc_min -= 1 cc_max += 1 except IndexError: cc_min += 1 cc_max -= 1 slice_tup = ( slice(ci - radius, ci + radius + 1), slice(ci - radius, ci + radius + 1), slice(ci - radius, ci + radius + 1), ) boundingBox_a[slice_tup] = True thresholded_a = boundingBox_a & (self.hu_a > threshold_hu) # Every "False" next to a "True" is converted to "True". # iterations=2 means that the process is repeted two times. mask_a = morph.binary_dilation(thresholded_a, iterations=2) return mask_a, thresholded_a, boundingBox_a
def getRawCandidate(self, center_xyz, width_irc): ''' The getRawNodule function takes the center expressed in the patient coordinate system (X,Y,Z) as well as width in voxels, And returns a cubic chunk of CT as well as the center of the candidate converted to array coordinates. ''' center_irc = xyz2irc( center_xyz, self.origin_xyz, self.vxSize-xyz, self.direction_a) slice_list = [] for axis, center_val in enumerate(center_irc): start_ndx = int(round(center_val - width_irc[axis]/2)) end_ndx = int(start_ndx + width_irc[axis]) assert center_val >= 0 and center_val < self.hu_a.shape[axis], repr([self.series_uid, center_xyz, self.origin_xyz, self.vxSize_xyz, center_irc, axis]) if start_ndx < 0: #Crop outside of CT array start_ndx = 0 end_ndx = int(width_irc[axis]) if end_ndx > self.hu_array.shape[axis]: #Crop outside of CT array end_ndx = self.hu_array.shape[axis] start_ndx = int(self.hu_array.shape[axis] - width_irc[axis]) slice_list.append(slice(start_ndx, end_ndx)) ct_chunk = self.hu_array[tuple(slice_list)] return ct_chunk, center_irc
def buildAnnotationMask(self, positiveInfo_list, threshold_hu=-700): boundingBox_a = np.zeros_like(self.hu_a, dtype=np.bool) for candidateInfo_tup in positiveInfo_list: center_irc = xyz2irc( candidateInfo_tup.center_xyz, self.origin_xyz, self.vxSize_xyz, self.direction_a, ) ci = int(center_irc.index) cr = int(center_irc.row) cc = int(center_irc.col) index_radius = 2 try: while ( self.hu_a[ci + index_radius, cr, cc] > threshold_hu and self.hu_a[ci - index_radius, cr, cc] > threshold_hu ): index_radius += 1 except IndexError: index_radius -= 1 row_radius = 2 try: while ( self.hu_a[ci, cr + row_radius, cc] > threshold_hu and self.hu_a[ci, cr - row_radius, cc] > threshold_hu ): row_radius += 1 except IndexError: row_radius -= 1 col_radius = 2 try: while ( self.hu_a[ci, cr, cc + col_radius] > threshold_hu and self.hu_a[ci, cr, cc - col_radius] > threshold_hu ): col_radius += 1 except IndexError: col_radius -= 1 # assert index_radius > 0, repr([candidateInfo_tup.center_xyz, center_irc, self.hu_a[ci, cr, cc]]) # assert row_radius > 0 # assert col_radius > 0 boundingBox_a[ ci - index_radius : ci + index_radius + 1, cr - row_radius : cr + row_radius + 1, cc - col_radius : cc + col_radius + 1, ] = True mask_a = boundingBox_a & (self.hu_a > threshold_hu) return mask_a
def buildAnnotationMask(self, noduleInfo_list, threshold_hu = -500): boundingBox_a = np.zeros_like(self.hu_a, dtype=np.bool) for noduleInfo_tup in noduleInfo_list: center_irc = xyz2irc( noduleInfo_tup.center_xyz, self.origin_xyz, self.vxSize_xyz, self.direction_tup, ) ci = int(center_irc.index) cr = int(center_irc.row) cc = int(center_irc.col) index_radius = 2 try: while self.hu_a[ci + index_radius, cr, cc] > threshold_hu and \ self.hu_a[ci - index_radius, cr, cc] > threshold_hu: index_radius += 1 except IndexError: index_radius -= 1 row_radius = 2 try: while self.hu_a[ci, cr + row_radius, cc] > threshold_hu and \ self.hu_a[ci, cr - row_radius, cc] > threshold_hu: row_radius += 1 except IndexError: row_radius -= 1 col_radius = 2 try: while self.hu_a[ci, cr, cc + col_radius] > threshold_hu and \ self.hu_a[ci, cr, cc - col_radius] > threshold_hu: col_radius += 1 except IndexError: col_radius -= 1 # assert index_radius > 0, repr([noduleInfo_tup.center_xyz, center_irc, self.hu_a[ci, cr, cc]]) # assert row_radius > 0 # assert col_radius > 0 slice_tup = ( slice(ci - index_radius, ci + index_radius + 1), slice(cr - row_radius, cr + row_radius + 1), slice(cc - col_radius, cc + row_radius + 1), ) boundingBox_a[slice_tup] = True thresholded_a = boundingBox_a & (self.hu_a > threshold_hu) mask_a = morph.binary_dilation(thresholded_a, iterations=2) return mask_a, thresholded_a, boundingBox_a
def logImages(self, epoch_ndx, train_dl, test_dl): for mode_str, dl in [('trn', train_dl), ('tst', test_dl)]: for i, series_uid in enumerate(sorted(dl.dataset.series_list)[:12]): ct = getCt(series_uid) noduleInfo_tup = (ct.malignantInfo_list or ct.benignInfo_list)[0] center_irc = xyz2irc(noduleInfo_tup.center_xyz, ct.origin_xyz, ct.vxSize_xyz, ct.direction_tup) sample_tup = dl.dataset[(series_uid, int(center_irc.index))] input_tensor = sample_tup[0].unsqueeze(0) label_tensor = sample_tup[1].unsqueeze(0) input_devtensor = input_tensor.to(self.device) label_devtensor = label_tensor.to(self.device) prediction_devtensor = self.model(input_devtensor) prediction_ary = prediction_devtensor.to('cpu').detach().numpy() image_ary = np.zeros((512, 512, 3), dtype=np.float32) image_ary[:,:,:] = (input_tensor[0,2].numpy().reshape((512,512,1))) * 0.25 image_ary[:,:,0] += prediction_ary[0,0] * 0.5 image_ary[:,:,1] += prediction_ary[0,1] * 0.25 # image_ary[:,:,2] += prediction_ary[0,2] * 0.5 # log.debug([image_ary.__array_interface__['typestr']]) # image_ary = (image_ary * 255).astype(np.uint8) # log.debug([image_ary.__array_interface__['typestr']]) writer = getattr(self, mode_str + '_writer') try: writer.add_image('{}/{}_pred'.format(mode_str, i), image_ary, self.totalTrainingSamples_count, dataformats='HWC') except: log.debug([image_ary.shape, image_ary.dtype]) raise if epoch_ndx == 1: label_ary = label_tensor.numpy() image_ary = np.zeros((512, 512, 3), dtype=np.float32) image_ary[:,:,:] = (input_tensor[0,2].numpy().reshape((512,512,1))) * 0.25 image_ary[:,:,0] += label_ary[0,0] * 0.5 image_ary[:,:,1] += label_ary[0,1] * 0.25 image_ary[:,:,2] += (input_tensor[0,-1].numpy() - (label_ary[0,0].astype(np.bool) | label_ary[0,1].astype(np.bool))) * 0.25 # log.debug([image_ary.__array_interface__['typestr']]) image_ary = (image_ary * 255).astype(np.uint8) # log.debug([image_ary.__array_interface__['typestr']]) writer = getattr(self, mode_str + '_writer') writer.add_image('{}/{}_label'.format(mode_str, i), image_ary, self.totalTrainingSamples_count, dataformats='HWC')
def getScaledInputChunk(self, center_xyz, width_mm, voxels_int): center_irc = xyz2irc(center_xyz, self.origin_xyz, self.vxSize_xyz, self.direction_tup) ct_start = [int(round(i)) for i in xyz2irc(tuple(x - width_mm/2 for x in center_xyz), self.origin_xyz, self.vxSize_xyz, self.direction_tup)] ct_end = [int(round(i)) + 1 for i in xyz2irc(tuple(x + width_mm/2 for x in center_xyz), self.origin_xyz, self.vxSize_xyz, self.direction_tup)] for axis in range(3): if ct_start[axis] > ct_end[axis]: ct_start[axis], ct_end[axis] = ct_end[axis], ct_start[axis] pad_start = [0, 0, 0] pad_end = [ct_end[axis] - ct_start[axis] for axis in range(3)] # log.info([ct_end, ct_start, pad_end]) pad_ary = np.zeros(pad_end, dtype=np.float32) for axis in range(3): if ct_start[axis] < 0: pad_start[axis] = -ct_start[axis] ct_start[axis] = 0 if ct_end[axis] > self.ary.shape[axis]: pad_end[axis] -= ct_end[axis] - self.ary.shape[axis] ct_end[axis] = self.ary.shape[axis] pad_slices = tuple(slice(s,e) for s, e in zip(pad_start, pad_end)) ct_slices = tuple(slice(s,e) for s, e in zip(ct_start, ct_end)) pad_ary[pad_slices] = self.ary[ct_slices] try: zoom_seq = tuple(voxels_int/pad_ary.shape[axis] for axis in range(3)) except: log.error([ct_end, ct_start, pad_end, center_irc, center_xyz, width_mm, self.vxSize_xyz]) raise chunk_ary = scipy.ndimage.zoom(pad_ary, zoom_seq, order=1) # log.info("chunk_ary.shape {}".format([chunk_ary.shape, pad_ary.shape, zoom_seq, voxels_int])) return chunk_ary, center_irc
def buildAnnotationMask(self, noduleInfo_list, threshold_gcc = 0.5): boundingBox_ary = np.zeros_like(self.ary, dtype=np.bool) for noduleInfo_tup in noduleInfo_list: center_irc = xyz2irc(noduleInfo_tup.center_xyz, self.origin_xyz, self.vxSize_xyz, self.direction_tup) center_index = int(center_irc.index) center_row = int(center_irc.row) center_col = int(center_irc.col) index_radius = 2 try: while self.ary[center_index + index_radius, center_row, center_col] > threshold_gcc and \ self.ary[center_index - index_radius, center_row, center_col] > threshold_gcc: index_radius += 1 except IndexError: index_radius -= 1 row_radius = 2 try: while self.ary[center_index, center_row + row_radius, center_col] > threshold_gcc and \ self.ary[center_index, center_row - row_radius, center_col] > threshold_gcc: row_radius += 1 except IndexError: row_radius -= 1 col_radius = 2 try: while self.ary[center_index, center_row, center_col + col_radius] > threshold_gcc and \ self.ary[center_index, center_row, center_col - col_radius] > threshold_gcc: col_radius += 1 except IndexError: col_radius -= 1 # assert index_radius > 0, repr([noduleInfo_tup.center_xyz, center_irc, self.ary[center_index, center_row, center_col]]) # assert row_radius > 0 # assert col_radius > 0 slice_tup = ( slice( # max(0, center_index - index_radius), center_index - index_radius, center_index + index_radius + 1, ), slice( # max(0, center_row - row_radius), center_row - row_radius, center_row + row_radius + 1, ), slice( # max(0, center_col - col_radius), center_col - col_radius, center_col + row_radius + 1, ), ) boundingBox_ary[slice_tup] = True thresholded_ary = boundingBox_ary & (self.ary > threshold_gcc) mask_ary = scipy.ndimage.morphology.binary_dilation(thresholded_ary, iterations=2) return mask_ary, thresholded_ary, boundingBox_ary