def interp_2d_yx(image_2d, row_size_new, col_size_new, kind=CV2_interp_type.linear, kernal_size=0): '''2d image interpolation :param image_2d: 2d volume, format: yx :param row_size_new: can be call "y" :param col_size_new: can be call "x" :param kind: interpolation methods, cv2.INTER_LINEAR cv2.INTER_NEAREST cv2.INTER_CUBIC(slow) :param kernel_size: used in median blurring for interpolation results. if 0, then no blurring operation :return: resized image volume ,its dtype is same with image_2d ''' if len(image_2d.shape) != 2: # 输入图像的shape错误, 返回错误码 Error.exit(ErrorCode.process_input_shape_error) resize_slice = cv2.resize(image_2d, (col_size_new, row_size_new), interpolation=kind) resize_slice = resize_slice if kernal_size: # smoothes an image using the median filter image_new = cv2.medianBlur(resize_slice, kernal_size) else: image_new = resize_slice image_new = np.array(image_new, dtype=image_2d.dtype) return image_new
def anti_interp_2d_pack(image_block, info_dict: InfoDict, kernal_size=0): '''2d image interpolation package :param image_block: 3d volume, format: zyx :param info_dict: should have info_dict.image_before_interp :param kind: interpolation methods, cv2.INTER_LINEAR cv2.INTER_NEAREST cv2.INTER_CUBIC(slow) :param kernel_size: used in median blurring for interpolation results. if 0, then no blurring operation :return image_interp: resized image volume ,its dtype is same with image_block :return info_dict: info_dict ''' if len(image_block.shape) != 3: # 输入图像的shape错误, 返回错误码 Error.exit(ErrorCode.process_input_shape_error) if not "image_shape_before_interp" in info_dict: Error.exit(ErrorCode.process_module_error) raw_dtype = image_block.dtype image_block = check_for_cv2_dtype(image_block, raw_dtype) origin_x = info_dict.image_shape_before_interp[2] origin_y = info_dict.image_shape_before_interp[1] image_anti_interp = np.zeros((image_block.shape[0], origin_x, origin_y), np.float32) for i in range(image_block.shape[0]): image_one = interp_2d_yx(image_block[i, :, :], origin_x, origin_y, info_dict.interp_kind, kernal_size) image_anti_interp[i, :, :] = image_one return image_anti_interp, info_dict
def read_slice_w_filter(dcm_path): try: if not os.path.exists(dcm_path): Error.exit(ErrorCode.ld_ct_path_not_exist) scan = pydicom.dcmread(dcm_path, force=True) except PermissionError: return None return is_valid_image(scan)
def condition_not_happen_assert(info='', error_code=None, msg=None): """ 条件不应该存在的断言 """ print(info) if True: print('The condition meet problem, this condition should not happen!') if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def path_exist_assert(input_path: str, error_code=None, msg=None): """ 保证输入路径存在 """ is_exist = os.path.exists(input_path) if not is_exist: print('The input(name:%s) is not exist, path: %s' % (get_varname(input_path), str(input_path))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def instance_of_assert(input_: object, type_: type, error_code=None, msg=None): """ 断言输入的类型是子类 """ if not isinstance(input_, type_): print( 'The input(name:%s) not meet the required, \nexpect type:%s has instance type input type:%s' % (get_varname(input_), str(type_), str(type(input_)))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def type_assert(input_: object, type_: type, error_code=None, msg=None): """ 断言输入的类型 """ if type(input_) != type_: print( 'The input(name:%s) type not meet the required, \nexpect type:%s, input type:%s' % (get_varname(input_), str(type_), str(type(input_)))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def not_None_assert(input_1: object, error_code=None, msg=None): """ 保证input_1 不等于 None """ if input_1 is None: print('The input(name:%s) not meet the required, \n' 'expect input1 is not None, \ninput1:%s' % (get_varname(input_1), str(input_1))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def file_not_exist_assert(input_file: str, error_code=None, msg=None): """ 保证输入路径不存在 """ is_exist = os.path.exists(input_file) if is_exist: print('The input(name:%s) is exist, file: %s' % (get_varname(input_file), str(input_file))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def equal_assert(input_1: object, input_2: object, error_code=None, msg=None): """ 保证input_1 等于 input_2 """ if input_1 != input_2: print('The input1(name:%s), input2(name:%s) not meet the required, \n' 'expect input1 equal to input2, \ninput1:%s, input2:%s' % (get_varname(input_1), get_varname(input_2), str(input_1), str(input_2))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def array2json(mask_3d, info_dict, roi_ind=0, organ_names=None): """ 逐层计算单个roi的物理坐标,并存储为json文件。 :param mask_3d: :param info_dict: :param roi_ind: :return: """ # 增加organ_names的适用性---by YY if organ_names is None: organ_names = info_dict.organ_names if not os.path.exists(info_dict.goal_path): raise Error(ErrorCode.tofile_ouput_path_not_exist) if not organ_names[roi_ind]: raise Error(ErrorCode.tofile_json_name_is_none) response_ind = [ a for a in range(mask_3d.shape[0]) if np.amax(mask_3d[a]) > 0 ] ###提取含有分割结果的各层的信息 #J就是slice的层号 label_slice_list = [] transform_matrix = grid2world_matrix(info_dict.iop, info_dict.spacing_list) for r in response_ind: slice_obj = slice_roi_contours( mask_3d[r], info_dict.sop_list[r], info_dict.ipp_list[r], transform_matrix, organ_names[roi_ind], contour_type=info_dict.contour_type, chain_mode=info_dict.chain_mode, smooth_polygon_times=info_dict.smooth_polygon_times, smooth_polgygon_degree=info_dict.smooth_polygon_degree) label_slice_list.extend(slice_obj) # sop_list = [info_dict.sop_list[i] for i in response_ind] # ipp_list = [info_dict.ipp_list[i] for i in response_ind] # with ProcessPoolExecutor() as executor: # future_obj = executor.map(slice_roi_contours, mask_3d[response_ind], # sop_list, ipp_list, # itertools.repeat(transform_matrix, len(response_ind)), # itertools.repeat(organ_names[roi_ind], len(response_ind)), # itertools.repeat(info_dict.contour_type, len(response_ind)), # itertools.repeat(info_dict.chain_mode, len(response_ind)) # ) # for ll_slice in future_obj: # label_slice_list.extend(ll_slice) one_roi2json(label_slice_list, info_dict.goal_path)
def sort_filter_slices(info_dict, slice_data_dict): # 获取医院名称 # 显示有初始有多少张ct num_slice_total = len(slice_data_dict) print(' %s %s contains %d slices' % (info_dict.hospital, info_dict.pid, num_slice_total)) # 筛选有效层并排序 order_slice_list = _sort_slices(slice_data_dict, info_dict.ipp_order_reverse) order_slice_list = _filter_series(order_slice_list, info_dict.include_series) info_dict.image_shape_raw[0] = len(order_slice_list) # 提取单张图片的信息 # 获取每层的唯一标识号 info_dict.sop_list = [str(x.sop_uid) for x in order_slice_list] # SOPInstanceUID # 获取每层的屋里坐标 info_dict.ipp_list = [list(x.ipp) for x in order_slice_list] # ImagePositionPatient # 患者增强的识别号 info_dict.pid_aug = '_'.join([ str(info_dict.pid), str(info_dict.series_uid[-10:]), str(info_dict.image_shape_raw[0]) ]) # 显示有效层的数量 num_slice_valid = len(order_slice_list) print(' Valid imaging slices: %d' % len(order_slice_list)) if num_slice_total == 0 or num_slice_valid == 0: raise Error(ErrorCode.ld_ct_load_fail) return order_slice_list, info_dict
def array_bivalue_assert(input_array: np.ndarray, error_code=None, msg=None): """ 保证输入tuple的长度为length """ # 断言保证 type_assert(input_array, np.ndarray, error_code=error_code) value_num = len(np.unique(input_array)) if value_num > 2: print('The input array(name:%s) is not bi value array, \n' 'input array values:%s' % (get_varname(input_array), str(np.unique(input_array)))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def list_length_assert(input_: list, length: int, error_code=None, msg=None): """ 保证输入矩阵为x维矩阵 """ # 断言输入保证 type_assert(input_, list, error_code=error_code) list_length = len(input_) if list_length != length: print('The input(name:%s) not meet the required, \n' 'expect list length:%s, input list length:%s' % (get_varname(input_), str(length), str(list_length))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def in_list_assert(item: object, input_list: list, error_code=None, msg=None): """ 保证item在input list中 """ # 断言保证 type_assert(input_list, list, error_code=error_code) if item not in input_list: print('The %s,%s not meet the required, \n' 'expect item in input list,\nitem :%s, input_list: %s' % (get_varname(item), get_varname(input_list), str(item), str(input_list))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def type_multi_assert(input_: object, type_list: list, error_code=None, msg=None): """ 断言输入类型为type list内的类型 """ # 断言保证 list_type_assert(type_list, type, error_code=error_code) input_type = type(input_) if input_type not in type_list: print( 'The input(name:%s) not meet the required, \nexpect type:%s, input type:%s' % (get_varname(input_), str(type_list), str(input_type))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def check_shape(image, standar_shape=(512, 512), interp_kind=cv2.INTER_NEAREST): """ 检查图像尺寸,如果不为设定大小(512,512),则调整到设定尺寸 :param1: image - 待检测尺寸,shape = 3 param2: standar_shape 标准尺寸 :param3: cv2插值方式 :return: 调整后的图像大小 """ assertor.type_assert(image, np.ndarray, error_code=ErrorCode.process_data_type_error, msg='Assert pos: check_shape module') img_shape = image.shape raw_dtype = image.dtype image = check_for_cv2_dtype(image, raw_dtype) if len(img_shape) != 3: # 输入图像的shape错误, 返回错误码 Error.exit(ErrorCode.process_input_shape_error) if img_shape[1] == standar_shape[0] and img_shape[2] == standar_shape[1]: return image resize_image = np.zeros(shape=(image.shape[0], standar_shape[0], standar_shape[1]), dtype=image.dtype) for i in range(image.shape[0]): resize_image[i, :, :] = cv2.resize( image[i, :, :], (standar_shape[1], standar_shape[0]), interpolation=interp_kind) resize_image = anti_check_for_cv2_dtype(resize_image, raw_dtype) return resize_image # if __name__ == '__main__': # # test_data = np.zeros(shape=(3,1024, 1024),dtype=np.uint32) #np.uint16 # image = check_shape(test_data,(512,512)) # print('dtype:',image.dtype) # print(image.shape)
def dict_has_key_assert(key: object, input_dict: dict, error_code=None, msg=None): """ 保证key在input dict的key中 """ # 断言保证 type_assert(input_dict, dict, error_code=error_code) if key not in list(input_dict.keys()): print('The %s,%s not meet the required, \n' 'expect key in input dict,\nkey :%s, input_dict: %s' % (get_varname(key), get_varname(input_dict), str(key), str(input_dict))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def tuple_length_assert(input_tuple: tuple, length: int, error_code=None, msg=None): """ 保证输入tuple的长度为length """ # 断言保证 type_assert(input_tuple, tuple, error_code=error_code) type_assert(length, int, error_code=error_code) tuple_length = len(input_tuple) if tuple_length != length: print('The input(name:%s) not meet the required, \n' 'expect tuple length:%s, input tuple length:%s' % (get_varname(input_tuple), str(length), str(tuple_length))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def array_x_dims_multi_assert(input_array: np.ndarray, dims_list: list, error_code=None, msg=None): """ 保证输入矩阵为x维矩阵,x为在dims_list中的数据 """ # 断言输入保证 type_assert(input_array, np.ndarray, error_code=error_code) type_assert(dims_list, list, error_code=error_code) array_dim = len(input_array.shape) if array_dim not in dims_list: print( 'The input(name:%s) not meet the required, \nexpect dims:%s, input dims:%s' % (get_varname(input_array), str(dims_list), str(array_dim))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def array_dtype_assert(input_array: np.ndarray, dtype_: type, error_code=None, msg=None): """ 保证输入矩阵的dtype """ # 断言保证 type_assert(input_array, np.ndarray, error_code=error_code) type_assert(dtype_, type, error_code=error_code) array_dtype = input_array.dtype if array_dtype != dtype_: print('The input(name:%s) not meet the required, \n' 'expect array dtype:%s, input array dtype:%s' % (get_varname(input_array), str(dtype_), str(array_dtype))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def mask2csv(mask_3d, info_dict, roi_ind=0, organ_names=None): """ 逐层计算单个roi的物理坐标,并存储为json文件。 :param mask_3d: :param info_dict: :param roi_ind: :return: """ # 增加organ_names的适用性---by YY if organ_names is None: organ_names = info_dict.organ_names if not os.path.exists(info_dict.goal_path): raise Error(ErrorCode.tofile_ouput_path_not_exist) if not organ_names[roi_ind]: raise Error(ErrorCode.tofile_json_name_is_none) response_ind = [ a for a in range(mask_3d.shape[0]) if np.amax(mask_3d[a]) > 0 ] sop_list = [info_dict.sop_list[i] for i in response_ind] ipp_list = [info_dict.ipp_list[i] for i in response_ind] ###提取含有分割结果的各层的信息 #J就是slice的层号 label_slice_list = [] # for r in response_ind: # slice_obj = slice_roi_contours_csv(mask_3d[r], info_dict.sop_list[r], info_dict.ipp_list[r], # organ_names[roi_ind], # contour_type=info_dict.contour_type, # chain_mode = info_dict.chain_mode) # label_slice_list.extend(slice_obj) with ProcessPoolExecutor(max_workers=16) as executor: future_obj = executor.map( slice_roi_contours_csv, mask_3d[response_ind], sop_list, ipp_list, itertools.repeat(organ_names[roi_ind], len(response_ind)), itertools.repeat(info_dict.contour_type, len(response_ind)), itertools.repeat(info_dict.chain_mode, len(response_ind))) for ll_slice in future_obj: label_slice_list.extend(ll_slice) to_csv(label_slice_list, info_dict.goal_path)
def array_length_assert(input_: np.ndarray, length: int, axis=0, error_code=None, msg=None): """ 保证输入矩阵的axis维长度为length """ # 断言输入保证 type_assert(input_, np.ndarray, error_code=error_code) greater_or_equal_assert(len(input_.shape), axis, error_code=error_code) list_length = input_.shape[axis] if list_length != length: print('The input(name:%s) not meet the required, \n' 'expect array length:%s, input array length:%s' % (get_varname(input_), str(length), str(list_length))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def array_shape_assert(input_array: np.ndarray, shape: tuple, error_code=None, msg=None): """ 保证输入矩阵的shape """ # 断言保证 type_assert(input_array, np.ndarray, error_code=error_code) tuple_type_assert(shape, int, error_code=error_code) tuple_length_assert(shape, len(input_array.shape), error_code=error_code) array_shape = input_array.shape if array_shape != shape: print('The input(name:%s) not meet the required, \n' 'expect array shape:%s, input array shape:%s' % (get_varname(input_array), str(shape), str(array_shape))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def notFoundHandler(self): """ Sends a 404 Not Found response with a Matrix-compliant JSON error object body. """ self.send_response(404, "Not Found") self.send_header("Content-Type", "application/json") err = Error("No resource was found for this request", ErrorCode.NOT_FOUND) response = str(err).encode() + b'\n' self.send_header("Content-Length", str(len(response))) self.end_headers() self.wfile.write(response)
def load_dcm_scan(info_dict): """ 读取单套CT序列,筛选出有效的dicom图像文件,提取序列信息并得到图像 :param info_dict: 带有data_path, include_series 指定序列等字段 :return: image_3d(按ipp_z从小到大排列的扫描图像), info_dict(添加sop_list和ipp_list) """ # 1. 筛选出可用pydicom读取成功的文件 # 扫描数据根目录,筛选出dcm数据 # 存两个字典(key=路径,value=pydicom object) # path_slices_dict存断层扫描,path_rts_dict存rs path_slices_dicts, path_rts_dicts = scan4image_rt(info_dict.data_path) series_list = list(path_slices_dicts.keys()) most_series = None if len(series_list) == 0: Error.exit(ErrorCode.ld_ct_load_fail) elif len(series_list) == 1: most_series = series_list[0] else: nb_slices_in_series = [len(path_slices_dicts[s]) for s in series_list] most_series = series_list[nb_slices_in_series.index( max(nb_slices_in_series))] # 2. 将pydicom类转换成自定义类,筛选出带有效图像数据的层 slice_data_dict, info_dict.slice_path = data_in_image_scans( path_slices_dicts[most_series]) # 3. 提取断层扫描数据基本信息, info_dict = get_case_info(info_dict, slice_data_dict) # 筛选图像数据并根据参数排序 order_slice_list, info_dict = sort_filter_slices(info_dict, slice_data_dict) # 4. 提取扫描图像数据 image_3d = np.stack([s.image for s in order_slice_list], axis=0) return image_3d, info_dict
def equal_multi_assert(input_1: object, input_2_list: list, error_code=None, msg=None): """ 保证input_1 等于 input_2_list中的值 """ type_assert(input_2_list, list, error_code=error_code) rst_bool = False for input_2 in input_2_list: temp_bool = (input_1 == input_2) rst_bool = rst_bool or temp_bool if not rst_bool: print( 'The input1(name:%s), input2(name:%s) not meet the required, \n' 'expect input1 equal to the value in input2 list, \ninput1:%s, input2:%s' % (get_varname(input_1), get_varname(input_2), str(input_1), str(input_2))) if error_code is not None: Error.warn(error_code) if msg is not None: print(msg)
def image_interp(data, target_size, interpolation): """插值函数(默认线性插值) # Arguments: data:待插值图像,三维数组 target_size:插值后x、y的大小 # Returns img_new:插值后的图像 # Example """ if len(np.shape(data)) != 3: print('DataError: the channel of data is not equal to 3') Error.exit(ErrorCode.process_input_shape_error) print('start interpolation......') z_old, rows_old, cols_old = np.shape(data) if len(target_size) == 2: rows_new = target_size[0] cols_new = target_size[1] elif len(target_size) == 1: rows_new = target_size[0] cols_new = target_size[0] else: rows_new = rows_old cols_new = cols_old img_new = np.zeros([z_old, rows_new, cols_new], dtype=np.float32) for i in range(z_old): # note: cv2.resize 函数的size输入为 宽(cols_new) * 高(rows_new) img_new[i, :, :] = cv2.resize(data[i, :, :], (cols_new, rows_new), interpolation=interpolation) print('complete interpolation......') return img_new
conf = yaml.safe_load(f) # load data logging.info('loading data from %s' % conf['input']['filename']) x, y, t, z = loader(conf['input']['filename'], conf['input']['variable']) # convert time/sla to desired units tconv = t * conf['t_fact'] + conf['t_offset'] zconv = z * conf['z_fact'] # init errors logging.info('init errors') err_dict = {} for err in conf['errors']: logging.debug('init error %s' % err) err_dict[err] = Error(conf[err]) # variables to store results nx, ny, nt = len(x), len(y), len(t) ng = nx * ny trend, trendci = np.full((nx, ny), np.nan, dtype=float), np.full((nx, ny), np.nan, dtype=float) accel, accelci = np.full((nx, ny), np.nan, dtype=float), np.full((nx, ny), np.nan, dtype=float) covariances = np.full((nx, ny, nt, nt), np.nan, dtype=float) # loop through grid points logging.info('going through the grid...') cnt = 1
def crop_by_size_and_shift(imgs, image_size, center=None, pixely=0, pixelx=0): ''' 剪切函数,相当于原来的cutting(),pixelx、pixely的移动值是相对图像中心 注意参数次序和原来的cutting函数不同,shift参数不用传入 :param imgs: 需要裁剪的数据 :param image_size: 需要的图像大小 :param pixely: 偏移y :param pixelx: 偏移x :return: ''' if len(imgs.shape) == 2: # 2D image imgs = imgs.copy() image_sizeY = image_size[0] image_sizeX = image_size[1] if center is None: center = [imgs.shape[0] // 2, imgs.shape[1] // 2] pixely = int(center[0] - imgs.shape[0] // 2) + pixely pixelx = int(center[1] - imgs.shape[1] // 2) + pixelx # z, x, y = np.shape(imgs) y, x = np.shape(imgs) shift = np.max([ abs(pixely), abs(pixelx), np.max((abs(y - image_sizeY), abs(x - image_sizeX))) ]) judge = sum([ y > (image_sizeY + abs(pixely) * 2), x > (image_sizeX + abs(pixelx) * 2) ]) imgs_new = [] image_std = imgs # for i, image_std in enumerate(imgs): if judge == 2: image_std = image_std[int((y - image_sizeY) / 2 + pixely):int((y + image_sizeY) / 2 + pixely), int((x - image_sizeX) / 2 + pixelx):int((x + image_sizeX) / 2) + pixelx] # imgs_new.append(image_std) else: image_new = np.min(image_std) * np.ones( [image_sizeY + shift * 2, image_sizeX + shift * 2], dtype=np.int32) image_new[int((image_sizeY + shift * 2 - y) / 2):int((image_sizeY + shift * 2 - y) / 2) + y, int((image_sizeX + shift * 2 - x) / 2):int((image_sizeX + shift * 2 - x) / 2) + x] = image_std y1, x1 = np.shape(image_new) image_std = image_new[int((y1 - image_sizeY) / 2 + pixely):int((y1 + image_sizeY) / 2 + pixely), int((x1 - image_sizeX) / 2 + pixelx):int((x1 + image_sizeX) / 2) + pixelx] # imgs_new = np.array(imgs_new, np.float32) imgs_new = image_std elif len(imgs.shape) == 3: # 3D image imgs = imgs.copy() image_sizeY = image_size[0] image_sizeX = image_size[1] if center is None: center = [imgs.shape[1] // 2, imgs.shape[2] // 2] pixely = int(center[0] - imgs.shape[1] // 2) + pixely pixelx = int(center[1] - imgs.shape[2] // 2) + pixelx z, y, x = np.shape(imgs) # x, y = np.shape(imgs) shift = np.max([ abs(pixely), abs(pixelx), np.max((abs(y - image_sizeY), abs(x - image_sizeX))) ]) judge = sum([ y > (image_sizeY + abs(pixely) * 2), x > (image_sizeX + abs(pixelx) * 2) ]) imgs_new = [] image_std = imgs if judge == 2: for i, image_std in enumerate(imgs): image_std = image_std[int((y - image_sizeY) / 2 + pixely):int((y + image_sizeY) / 2 + pixely), int((x - image_sizeX) / 2 + pixelx):int((x + image_sizeX) / 2) + pixelx] imgs_new.append(image_std) else: for i, image_std in enumerate(imgs): # 按最小值填补imgs外不足部分 image_new = np.min(image_std) * np.ones( [image_sizeY + shift * 2, image_sizeX + shift * 2], dtype=np.int32) image_new[int((image_sizeY + shift * 2 - y) / 2):int((image_sizeY + shift * 2 - y) / 2) + y, int((image_sizeX + shift * 2 - x) / 2):int((image_sizeX + shift * 2 - x) / 2) + x] = image_std y1, x1 = np.shape(image_new) image_std = image_new[int((y1 - image_sizeY) / 2 + pixely):int((y1 + image_sizeY) / 2 + pixely), int((x1 - image_sizeX) / 2 + pixelx):int((x1 + image_sizeX) / 2) + pixelx] imgs_new.append(image_std) imgs_new = np.array(imgs_new) else: Error.exit(ErrorCode.process_input_shape_error) return imgs_new