Esempio n. 1
0
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)
Esempio n. 2
0
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)
Esempio n. 6
0
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)