Esempio n. 1
0
def get_contour_check_fn(contour_fn='four_pt_hard',
                         cont=None,
                         ref_patch_size=None,
                         center_shift=None):
    if contour_fn == 'four_pt_hard':
        cont_check_fn = isInContourV3_Hard(contour=cont,
                                           patch_size=ref_patch_size,
                                           center_shift=center_shift)
    elif contour_fn == 'four_pt_easy':
        cont_check_fn = isInContourV3_Easy(contour=cont,
                                           patch_size=ref_patch_size,
                                           center_shift=0.5)
    elif contour_fn == 'center':
        cont_check_fn = isInContourV2(contour=cont, patch_size=ref_patch_size)
    elif contour_fn == 'basic':
        cont_check_fn = isInContourV1(contour=cont)
    else:
        raise NotImplementedError
    return cont_check_fn
Esempio n. 2
0
    def process_contour(self,
                        cont,
                        contour_holes,
                        patch_level,
                        save_path,
                        patch_size=256,
                        step_size=256,
                        contour_fn='four_pt',
                        use_padding=True,
                        top_left=None,
                        bot_right=None):
        start_x, start_y, w, h = cv2.boundingRect(
            cont) if cont is not None else (0, 0,
                                            self.level_dim[patch_level][0],
                                            self.level_dim[patch_level][1])

        patch_downsample = (int(self.level_downsamples[patch_level][0]),
                            int(self.level_downsamples[patch_level][1]))
        ref_patch_size = (patch_size * patch_downsample[0],
                          patch_size * patch_downsample[1])

        img_w, img_h = self.level_dim[0]
        if use_padding:
            stop_y = start_y + h
            stop_x = start_x + w
        else:
            stop_y = min(start_y + h, img_h - ref_patch_size[1] + 1)
            stop_x = min(start_x + w, img_w - ref_patch_size[0] + 1)

        print("Bounding Box:", start_x, start_y, w, h)
        print("Contour Area:", cv2.contourArea(cont))

        if bot_right is not None:
            stop_y = min(bot_right[1], stop_y)
            stop_x = min(bot_right[0], stop_x)
        if top_left is not None:
            start_y = max(top_left[1], start_y)
            start_x = max(top_left[0], start_x)

        if bot_right is not None or top_left is not None:
            w, h = stop_x - start_x, stop_y - start_y
            if w <= 0 or h <= 0:
                print("Contour is not in specified ROI, skip")
                return {}, {}
            else:
                print("Adjusted Bounding Box:", start_x, start_y, w, h)

        if isinstance(contour_fn, str):
            if contour_fn == 'four_pt':
                cont_check_fn = isInContourV3_Easy(
                    contour=cont,
                    patch_size=ref_patch_size[0],
                    center_shift=0.5)
            elif contour_fn == 'four_pt_hard':
                cont_check_fn = isInContourV3_Hard(
                    contour=cont,
                    patch_size=ref_patch_size[0],
                    center_shift=0.5)
            elif contour_fn == 'center':
                cont_check_fn = isInContourV2(contour=cont,
                                              patch_size=ref_patch_size[0])
            elif contour_fn == 'basic':
                cont_check_fn = isInContourV1(contour=cont)
            else:
                raise NotImplementedError
        else:
            assert isinstance(contour_fn, Contour_Checking_fn)
            cont_check_fn = contour_fn

        step_size_x = step_size * patch_downsample[0]
        step_size_y = step_size * patch_downsample[1]

        x_range = np.arange(start_x, stop_x, step=step_size_x)
        y_range = np.arange(start_y, stop_y, step=step_size_y)
        x_coords, y_coords = np.meshgrid(x_range, y_range, indexing='ij')
        coord_candidates = np.array([x_coords.flatten(),
                                     y_coords.flatten()]).transpose()

        num_workers = mp.cpu_count()
        if num_workers > 4:
            num_workers = 4
        pool = mp.Pool(num_workers)

        iterable = [(coord, contour_holes, ref_patch_size[0], cont_check_fn)
                    for coord in coord_candidates]
        results = pool.starmap(WholeSlideImage.process_coord_candidate,
                               iterable)
        pool.close()
        results = np.array(
            [result for result in results if result is not None])

        print('Extracted {} coordinates'.format(len(results)))

        if len(results) > 1:
            asset_dict = {'coords': results}

            attr = {
                'patch_size':
                patch_size,  # To be considered...
                'patch_level':
                patch_level,
                'downsample':
                self.level_downsamples[patch_level],
                'downsampled_level_dim':
                tuple(np.array(self.level_dim[patch_level])),
                'level_dim':
                self.level_dim[patch_level],
                'name':
                self.name,
                'save_path':
                save_path
            }

            attr_dict = {'coords': attr}
            return asset_dict, attr_dict

        else:
            return {}, {}
Esempio n. 3
0
    def _getPatchGenerator(self,
                           cont,
                           cont_idx,
                           patch_level,
                           save_path,
                           patch_size=256,
                           step_size=256,
                           custom_downsample=1,
                           white_black=True,
                           white_thresh=15,
                           black_thresh=50,
                           contour_fn='four_pt',
                           use_padding=True):
        start_x, start_y, w, h = cv2.boundingRect(
            cont) if cont is not None else (0, 0,
                                            self.level_dim[patch_level][0],
                                            self.level_dim[patch_level][1])
        print("Bounding Box:", start_x, start_y, w, h)
        print("Contour Area:", cv2.contourArea(cont))

        if custom_downsample > 1:
            assert custom_downsample == 2
            target_patch_size = patch_size
            patch_size = target_patch_size * 2
            step_size = step_size * 2
            print(
                "Custom Downsample: {}, Patching at {} x {}, But Final Patch Size is {} x {}"
                .format(custom_downsample, patch_size, patch_size,
                        target_patch_size, target_patch_size))

        patch_downsample = (int(self.level_downsamples[patch_level][0]),
                            int(self.level_downsamples[patch_level][1]))
        ref_patch_size = (patch_size * patch_downsample[0],
                          patch_size * patch_downsample[1])

        step_size_x = step_size * patch_downsample[0]
        step_size_y = step_size * patch_downsample[1]

        if isinstance(contour_fn, str):
            if contour_fn == 'four_pt':
                cont_check_fn = isInContourV3_Easy(
                    contour=cont,
                    patch_size=ref_patch_size[0],
                    center_shift=0.5)
            elif contour_fn == 'four_pt_hard':
                cont_check_fn = isInContourV3_Hard(
                    contour=cont,
                    patch_size=ref_patch_size[0],
                    center_shift=0.5)
            elif contour_fn == 'center':
                cont_check_fn = isInContourV2(contour=cont,
                                              patch_size=ref_patch_size[0])
            elif contour_fn == 'basic':
                cont_check_fn = isInContourV1(contour=cont)
            else:
                raise NotImplementedError
        else:
            assert isinstance(contour_fn, Contour_Checking_fn)
            cont_check_fn = contour_fn

        img_w, img_h = self.level_dim[0]
        if use_padding:
            stop_y = start_y + h
            stop_x = start_x + w
        else:
            stop_y = min(start_y + h, img_h - ref_patch_size[1])
            stop_x = min(start_x + w, img_w - ref_patch_size[0])

        count = 0
        for y in range(start_y, stop_y, step_size_y):
            for x in range(start_x, stop_x, step_size_x):

                if not self.isInContours(
                        cont_check_fn,
                    (x, y), self.holes_tissue[cont_idx], ref_patch_size[0]
                ):  #point not inside contour and its associated holes
                    continue

                count += 1
                patch_PIL = self.wsi.read_region(
                    (x, y), patch_level,
                    (patch_size, patch_size)).convert('RGB')
                if custom_downsample > 1:
                    patch_PIL = patch_PIL.resize(
                        (target_patch_size, target_patch_size))

                if white_black:
                    if isBlackPatch(np.array(patch_PIL),
                                    rgbThresh=black_thresh) or isWhitePatch(
                                        np.array(patch_PIL),
                                        satThresh=white_thresh):
                        continue

                patch_info = {
                    'x':
                    x // (patch_downsample[0] * custom_downsample),
                    'y':
                    y // (patch_downsample[1] * custom_downsample),
                    'cont_idx':
                    cont_idx,
                    'patch_level':
                    patch_level,
                    'downsample':
                    self.level_downsamples[patch_level],
                    'downsampled_level_dim':
                    tuple(
                        np.array(self.level_dim[patch_level]) //
                        custom_downsample),
                    'level_dim':
                    self.level_dim[patch_level],
                    'patch_PIL':
                    patch_PIL,
                    'name':
                    self.name,
                    'save_path':
                    save_path
                }

                yield patch_info

        print("patches extracted: {}".format(count))