def generate_images_with_boxes(images, boxes, output_folder): # Generate images for boxes. `boxes` should be an array of dict # Format: {'label': '?', 'SOPInstanceUID': dcm.SOPInstanceUID, 'top_left': [5, 5], 'bottom_right': [10, 10]} create_folder(output_folder) for index, image in enumerate(images): dcm = pydicom.dcmread(image.path) pixels = get_pixels(dcm) pixels = np.reshape(pixels, (dcm.Rows, dcm.Columns, 3)) pil_image = Image.fromarray(pixels) draw = ImageDraw.Draw(pil_image) image_boxes = [ box for box in boxes if image.instanceUID == box['SOPInstanceUID'] ] for box in image_boxes: # apply box ul = box['top_left'] br = box['bottom_right'] points = [ tuple(ul), (br[0], ul[1]), tuple(br), (ul[0], br[1]), tuple(ul) ] draw.line(points, fill="red", width=5) boxes.remove(box) # write image to output folder output_filename = os.path.join( output_folder, str(index) + '_' + os.path.basename(os.path.normpath(image.path))) output_filename += '.png' pil_image.save(output_filename)
def compare_folder(origin, codes, res): psnr = [] ssim = [] total_pixels = 0 for filename in os.listdir(origin): original_i = os.path.join(origin, filename) res_i = os.path.join(res, filename) psnr.append(metric.psnr(original_i, res_i)) ssim.append(metric.msssim(original_i, res_i)) total_pixels += utils.get_pixels(original_i) print(psnr[-1], ssim[-1]) total_size = utils.get_size_folder(codes) bpp = total_size / total_pixels print(bpp, mean(psnr), mean(ssim)) return bpp, mean(psnr), mean(ssim)
def process_patient(uid, path, series_dict): print("Patient: ", uid) dst_dir = os.path.join(settings.SP_IMAGE_DIR, uid) if not os.path.exists(dst_dir): os.mkdir(dst_dir) series_paths = [ os.path.join(path, x) for x in os.listdir(path) if os.path.isdir(os.path.join(path, x)) ] series_uids = [ x for x in os.listdir(path) if os.path.isdir(os.path.join(path, x)) ] for index, series in enumerate(series_paths): try: series_dst_dir = os.path.join(dst_dir, series_uids[index]) if not os.path.exists(series_dst_dir): os.mkdir(series_dst_dir) slices = utils.load_scan(series) #cos_value = (slices[0].ImageOrientationPatient[0]) #cos_degree = round(math.degrees(math.acos(cos_value)),2) pixels = utils.get_pixels(slices) image = pixels print("Volume shape is: {}".format(image.shape)) #invert_order = slices[1].ImagePositionPatient[2] > slices[0].ImagePositionPatient[2] #pixel_spacing = slices[0].PixelSpacing #pixel_spacing.append(slices[0].SliceThickness) #pixel_spacing = [float(s) for s in pixel_spacing] #print("Pixel spacing is: {}".format(pixel_spacing)) #image = utils.resample_images(image,pixel_spacing,settings.TARGET_VOXEL_MM) #if not invert_order: #image = np.flipud(image) for index, img in enumerate(image): #if cos_degree>0.0: #img = cv_flip(img,img.shape[1],img.shape[0],cos_degree) img = utils.normalize(img) img_name = "img_%s_%s" % (str(index).rjust(4, '0'), "_i.png") save_path = os.path.join(series_dst_dir, img_name) cv2.imwrite(save_path, img * 255) except Exception as e: print("Series: {}, Exception: {}".format(series, e))
def collate_fn(data, batch_size, img_size): img, mask = data[0] batch_x, batch_y = [], [] num_img = len(batch_x) num_white_img = 0 # randomly crop image and mask at white pixels pixels = get_pixels(mask[0], img_size, img_size) num_pix = len(pixels[0]) while True: if num_pix == 0: s_x = np.random.randint(0, img.shape[1] - img_size + 1) s_y = np.random.randint(0, img.shape[2] - img_size + 1) else: index = np.random.randint(num_pix) s_x = pixels[0][index] s_y = pixels[1][index] y = mask[:, s_x:s_x + img_size, s_y:s_y + img_size] if len(np.where(y != 0)[0]) > 0: num_white_img += 1 x = img[:, s_x:s_x + img_size, s_y:s_y + img_size] if num_white_img < 1: continue batch_x.append(x) batch_y.append(y) num_img = len(batch_x) if num_img == batch_size: break # for i in range(batch_size): # s_x = np.random.randint(0, img.shape[1] - img_size + 1) # s_y = np.random.randint(0, img.shape[2] - img_size + 1) # y = mask[:, s_x:s_x + img_size, s_y:s_y + img_size] # x = img[:, s_x:s_x + img_size, s_y:s_y + img_size] # batch_x.append(x) # batch_y.append(y) batch_x = np.array(batch_x) batch_y = np.array(batch_y) loss_weight = calculate_bce_loss(batch_y) if torch.cuda.is_available(): batch_x = torch.cuda.FloatTensor(batch_x) batch_y = torch.cuda.FloatTensor(batch_y) else: batch_x = torch.FloatTensor(batch_x) batch_y = torch.FloatTensor(batch_y) return batch_x, batch_y, loss_weight
def generate_images_for_single_image_masks(dicom_images, inference_results, response_json, output_folder): """ This function will save images to disk to preview how a mask looks on the input images. It saves one image for each input DICOM file with the corresponding `inference_results` mask applied as overlay. - dicom_images: Array of DCM_Image or path to a folder with images - inference_results: Array with mask buffers (one for each image) - response_json: The JSON response from the inference server - output_folder: Where the output images will be saved The difference with `generate_images_with_masks` is that `generate_images_with_masks` applies each mask to the whole volume while this functions applies each mask to one image. """ images, masks = _get_images_and_masks(dicom_images, inference_results) create_folder(output_folder) # Filter out secondary capture outputs all_mask_parts = filter_mask_parts(response_json) binary_masks, secondary_captures = filter_masks_by_binary_type( masks, all_mask_parts, response_json) # Create DICOM files for secondary capture outputs for index, sc in enumerate(secondary_captures): dcm = pydicom.read_file(BytesIO(sc.tobytes())) file_path = os.path.join(output_folder, 'sc_' + str(index) + '.dcm') pydicom.dcmwrite(file_path, dcm) for index, (image, mask, json_part) in enumerate( zip(images, binary_masks, all_mask_parts)): dcm = pydicom.dcmread(image.path) pixels = get_pixels(dcm) # Reshape and add alpha pixels = np.reshape(pixels, (-1, 3)) pixels = np.hstack( (pixels, np.reshape(np.full(pixels.shape[0], 255, dtype=np.uint8), (-1, 1)))) # get mask for this image pixels = _draw_mask_on_image(pixels, mask, json_part, response_json, index, 0) # write image to output folder output_filename = os.path.join( output_folder, str(index) + '_' + os.path.basename(os.path.normpath(image.path))) output_filename += '.png' pixels = np.reshape(pixels, (dcm.Rows, dcm.Columns, 4)) plt.imsave(output_filename, pixels)
def process_scan(uid, path): ''' This function processes dicom files, rescales the patient volume and saves the volume as png images Inputs: uid: patient uid path: path to dicom folder for this patient ''' print("Patient: ", uid) dst_dir = os.path.join(settings.CA_NDSB_IMG_DIR, uid) if not os.path.exists(dst_dir): os.mkdir(dst_dir) slices = utils.load_scan(path) cos_value = (slices[0].ImageOrientationPatient[0]) cos_degree = round(math.degrees(math.acos(cos_value)), 2) pixels = utils.get_pixels(slices) image = pixels print("Volume shape is: {}".format(image.shape)) invert_order = slices[1].ImagePositionPatient[2] > slices[ 0].ImagePositionPatient[2] pixel_spacing = slices[0].PixelSpacing pixel_spacing.append(slices[0].SliceThickness) pixel_spacing = [float(s) for s in pixel_spacing] print("Pixel spacing is: {}".format(pixel_spacing)) image = utils.rescale_patient_images(image, pixel_spacing, settings.TARGET_VOXEL_MM) print("Rescaled shape: {}".format(image.shape)) img_list = [] if not invert_order: image = np.flipud(image) for index2, img in enumerate(image): seg_img, mask = utils.get_segmented_lungs(img.copy()) img_list.append(seg_img) img = utils.normalize(img) if cos_degree > 0.0: img = cv_flip(img, img.shape[1], img.shape[0], cos_degree) img_name = "img_%s_%s" % (str(index2).rjust(4, '0'), "_i.png") mask_name = "img_%s_%s" % (str(index2).rjust(4, '0'), "_m.png") cv2.imwrite(os.path.join(dst_dir, img_name), img * 255) cv2.imwrite(os.path.join(dst_dir, mask_name), mask * 255)
def generate_images_with_masks(dicom_images, inference_results, response_json, output_folder): """ This function will save images to disk to preview how a mask looks on the input images. It saves one image for each input DICOM file. All masks in `inference_results` will be applied to the whole 3D volume of DICOM images. Each mask will show in a different color. - dicom_images: Array of DCM_Image or path to a folder with images - inference_results: Array with mask buffers (one for each image), or path to folder with a numpy file containing one mask. - response_json: The JSON response from the inference server - output_folder: Where the output images will be saved """ images, masks = _get_images_and_masks(dicom_images, inference_results) create_folder(output_folder) # Filter out secondary capture outputs all_mask_parts = [ p for p in response_json["parts"] if p['binary_type'] != 'dicom_secondary_capture' ] secondary_capture_indexes = [ i for (i, p) in enumerate(response_json["parts"]) if p['binary_type'] == 'dicom_secondary_capture' ] masks = np.array(masks) secondary_capture_indexes_bool = np.in1d(range(masks.shape[0]), secondary_capture_indexes) secondary_captures = masks[secondary_capture_indexes_bool] non_sc_masks = masks[~secondary_capture_indexes_bool] # Create DICOM files for secondary capture outputs for index, sc in enumerate(secondary_captures): dcm = pydicom.read_file(BytesIO(sc.tobytes())) file_path = os.path.join(output_folder, 'sc_' + str(index) + '.dcm') pydicom.dcmwrite(file_path, dcm) offset = 0 for index, image in enumerate(images): dcm = pydicom.dcmread(image.path) pixels = get_pixels(dcm) # Reshape and add alpha pixels = np.reshape(pixels, (-1, 3)) pixels = np.hstack( (pixels, np.reshape(np.full(pixels.shape[0], 255, dtype=np.uint8), (-1, 1)))) for mask_index, (mask, json_part) in enumerate( zip(non_sc_masks, all_mask_parts)): # If the input holds multiple timepoints but the result only includes 1 timepoint if image.timepoint is not None and image.timepoint > 0 and json_part[ 'binary_data_shape']['timepoints'] == 1: continue # get mask for this image image_mask = mask[offset:offset + dcm.Rows * dcm.Columns] pixels = _draw_mask_on_image(pixels, image_mask, json_part, response_json, mask_index, mask_index) offset += dcm.Rows * dcm.Columns # write image to output folder output_filename = os.path.join( output_folder, str(index) + '_' + os.path.basename(os.path.normpath(image.path))) output_filename += '.png' if pixels.shape[1] != 4: pixels = np.hstack( (pixels, np.reshape(np.full(pixels.shape[0], 255, dtype=np.uint8), (-1, 1)))) pixels = np.reshape(pixels, (dcm.Rows, dcm.Columns, 4)) plt.imsave(output_filename, pixels) for mask_index, mask in enumerate(non_sc_masks): assert mask.shape[ 0] <= offset, "Mask {} does not have the same size ({}) as the volume ({})".format( mask_index, mask.shape[0], offset)
def generate_images_with_labels(images, json_response, output_folder): """ Generates png images with classification labels plotted on top. :param array [DCM_Image] images: images to be plotted on :param dict json_response: dict containing the classification labels. It can be freeform, but needs to contain either or both of the following: "study_ml_json": { "label1": "xxx", // freeform } or "series_ml_json": { "X.X.X.X": { // SeriesInstanceUID "label1": "xxx", // freeform }, ... } :param string output_folder: path to output folder """ Y_SPACING = 10 X_SPACING = 5 X_INDENT = 5 study_level_y = 0 for index, image in enumerate(images): dcm = pydicom.dcmread(image.path) series_instance_uid = dcm.SeriesInstanceUID pixels = get_pixels(dcm) pixels = np.reshape(pixels, (dcm.Rows, dcm.Columns, 3)) pil_image = Image.fromarray(pixels) draw = ImageDraw.Draw(pil_image) if index == 0 and 'study_ml_json' in json_response: study_labels = json_response['study_ml_json'] draw.text((X_SPACING, study_level_y), text='Study level classification prediction:') study_level_y += Y_SPACING for label, val in study_labels.items(): draw.text((X_SPACING + X_INDENT, study_level_y), text=(f'{label}: {val}')) study_level_y += Y_SPACING y = study_level_y series_labels = {} if 'series_ml_json' in json_response and series_instance_uid in json_response[ 'series_ml_json']: series_labels = json_response['series_ml_json'][ series_instance_uid] draw.text((X_SPACING, y), text='Series level classification prediction:') y += Y_SPACING for label, val in series_labels.items(): draw.text((X_SPACING + X_INDENT, y), text=(f'{label}: {val}')) y += Y_SPACING # write image to output folder output_filename = os.path.join( output_folder, str(index) + '_' + os.path.basename(os.path.normpath(image.path))) output_filename += '.png' pil_image.save(output_filename)