Пример #1
0
def test_prep(girderClient):  # noqa

    cfg.gc = girderClient

    iteminfo = cfg.gc.get('/item',
                          parameters={'text': "TCGA-A2-A0YE-01Z-00-DX1"})[0]

    # get RGB region at a small magnification
    MAG = 1.5
    getStr = "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d" % (
        iteminfo['_id'], 46890, 50000, 40350,
        43000) + "&magnification=%.2f" % MAG
    cfg.tissue_rgb = get_image_from_htk_response(
        cfg.gc.get(getStr, jsonResp=False))

    # get mask of things to ignore
    cfg.mask_out, _ = get_tissue_mask(cfg.tissue_rgb,
                                      deconvolve_first=False,
                                      n_thresholding_steps=1,
                                      sigma=1.5,
                                      min_size=30)
    cfg.mask_out = resize(cfg.mask_out == 0,
                          output_shape=cfg.tissue_rgb.shape[:2],
                          order=0,
                          preserve_range=True) == 1
Пример #2
0
def _get_rgb_and_pad_roi(gc, slide_id, bounds, appendStr, ROI):

    getStr = \
        "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d" \
        % (slide_id,
           bounds['XMIN'], bounds['XMAX'],
           bounds['YMIN'], bounds['YMAX'])
    getStr += appendStr
    resp = gc.get(getStr, jsonResp=False)
    rgb = get_image_from_htk_response(resp)

    # sometimes there's a couple of pixel difference d.t. rounding, so pad
    pad_y = rgb.shape[0] - ROI.shape[0]
    pad_x = rgb.shape[1] - ROI.shape[1]
    assert all([np.abs(j) < 4 for j in (pad_y, pad_x)]), \
        "too much difference in size between image and mask."\
        "something is wrong!"

    if pad_y > 0:
        ROI = np.pad(ROI, pad_width=((0, pad_y), (0, 0)), mode='constant')
    elif pad_y < 0:
        ROI = ROI[:pad_y, :]

    if pad_x > 0:
        ROI = np.pad(ROI, pad_width=((0, 0), (0, pad_x)), mode='constant')
    elif pad_x < 0:
        ROI = ROI[:, :pad_x]

    return rgb, ROI
Пример #3
0
    def test_get_image_from_htk_response(self):
        """Test get_image_from_htk_response."""
        getStr = "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d" % (
            cfg.iteminfo['_id'], 59000, 59100, 35000, 35100)
        resp = cfg.gc.get(getStr, jsonResp=False)
        rgb = get_image_from_htk_response(resp)

        assert rgb.shape == (100, 100, 3)
 def set_tissue_rgb(self):
     """Load RGB from server for single tissue piece."""
     # load RGB for this tissue piece at saliency magnification
     getStr = "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d&encoding=PNG" % (
         self.cdt.slide_id, self.xmin, self.xmax, self.ymin,
         self.ymax) + "&magnification=%d" % self.cdt.MAG
     resp = self.cdt.gc.get(getStr, jsonResp=False)
     self.tissue_rgb = get_image_from_htk_response(resp)
    def test_get_image_from_htk_response(self):
        """Test get_image_from_htk_response."""
        getStr = "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d" % (
            SAMPLE_SLIDE_ID, 59000, 59100, 35000, 35100)
        resp = gc.get(getStr, jsonResp=False)
        rgb = get_image_from_htk_response(resp)

        self.assertTupleEqual(rgb.shape, (100, 100, 3))
Пример #6
0
def _get_rgb_for_interrater(gc, bounds, slide_id):
    """"""
    getStr = \
        "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d" \
        % (slide_id,
           bounds['XMIN'], bounds['XMAX'],
           bounds['YMIN'], bounds['YMAX'])
    getStr += bounds['appendStr']
    resp = gc.get(getStr, jsonResp=False)
    rgb = get_image_from_htk_response(resp)

    return rgb
Пример #7
0
    def set_tissue_rgb(self):
        """Load RGB from server for single tissue piece."""
        # load RGB for this tissue piece at saliency magnification
        getStr = "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d&encoding=PNG" % (
            self.cd.slide_id, self.xmin, self.xmax, self.ymin,
            self.ymax) + "&magnification=%d" % self.cd.MAG
        resp = self.cd.gc.get(getStr, jsonResp=False)
        self.tissue_rgb = get_image_from_htk_response(resp)

        # color normalization if desired
        if 'main' in self.cd.cnorm_params.keys():
            self.tissue_rgb = np.uint8(
                reinhard(im_src=self.tissue_rgb,
                         target_mu=self.cd.cnorm_params['main']['mu'],
                         target_sigma=self.cd.cnorm_params['main']['sigma']))
Пример #8
0
def get_slide_thumbnail(gc, slide_id):
    """Get slide thumbnail using girder client.

    Parameters
    -------------
    gc : object
        girder client to use
    slide_id : str
        girder ID of slide

    Returns
    ---------
    np array
        RGB slide thumbnail at lowest level

    """
    getStr = "/item/%s/tiles/thumbnail" % (slide_id)
    resp = gc.get(getStr, jsonResp=False)
    return get_image_from_htk_response(resp)
Пример #9
0
def _get_visualization_zoomout(
        gc, slide_id, bounds, MPP, MAG, zoomout=4):
    """Get a zoomed out visualization of ROI RGB and annotation overlay.

    Parameters
    ----------
    gc : girder_client.Girder_Client
        authenticated girder client
    slide_id : str
        girder ID of slide
    bounds : dict
        bounds of the region of interest. Must contain the keys
        XMIN, XMAX, YMIN, YMAX
    MPP : float
        Microns per pixel.
    MAG : float
        Magnification. MPP overrides this.
    zoomout : float
        how much to zoom out

    Returns
    -------
    np.array
        Zoomed out visualization. Outpu from _visualize_annotations_on_rgb().

    """
    # get append string for server request
    if MPP is not None:
        getsf_kwargs = {
            'MPP': MPP * (zoomout + 1),
            'MAG': None,
        }
    elif MAG is not None:
        getsf_kwargs = {
            'MPP': None,
            'MAG': MAG / (zoomout + 1),
        }
    else:
        getsf_kwargs = {
            'MPP': None,
            'MAG': None,
        }
    sf, appendStr = get_scale_factor_and_appendStr(
        gc=gc, slide_id=slide_id, **getsf_kwargs)

    # now get low-magnification surrounding field
    x_margin = (bounds['XMAX'] - bounds['XMIN']) * zoomout / 2
    y_margin = (bounds['YMAX'] - bounds['YMIN']) * zoomout / 2
    getStr = \
        "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d" \
        % (slide_id,
           max(0, bounds['XMIN'] - x_margin),
           bounds['XMAX'] + x_margin,
           max(0, bounds['YMIN'] - y_margin),
           bounds['YMAX'] + y_margin)
    getStr += appendStr
    resp = gc.get(getStr, jsonResp=False)
    rgb_zoomout = get_image_from_htk_response(resp)

    # plot a bounding box at the ROI region
    xmin = x_margin * sf
    xmax = xmin + (bounds['XMAX'] - bounds['XMIN']) * sf
    ymin = y_margin * sf
    ymax = ymin + (bounds['YMAX'] - bounds['YMIN']) * sf
    xmin, xmax, ymin, ymax = [str(int(j)) for j in (xmin, xmax, ymin, ymax)]
    contours_list = [{
        'color': 'rgb(255,255,0)',
        'coords_x': ",".join([xmin, xmax, xmax, xmin, xmin]),
        'coords_y': ",".join([ymin, ymin, ymax, ymax, ymin]),
    }]

    return _visualize_annotations_on_rgb(rgb_zoomout, contours_list)
Пример #10
0
def annotations_to_contours_no_mask(gc,
                                    slide_id,
                                    MPP=5.0,
                                    MAG=None,
                                    mode='min_bounding_box',
                                    bounds=None,
                                    idx_for_roi=None,
                                    slide_annotations=None,
                                    element_infos=None,
                                    linewidth=0.2,
                                    get_rgb=True,
                                    get_visualization=True,
                                    text=True):
    """Process annotations to get RGB and contours without intermediate masks.

    Parameters
    ----------
    gc : object
        girder client object to make requests, for example:
        gc = girder_client.GirderClient(apiUrl = APIURL)
        gc.authenticate(interactive=True)

    slide_id : str
        girder id for item (slide)

    MPP : float or None
        Microns-per-pixel -- best use this as it's more well-defined than
        magnification which is more scanner or manufacturer specific.
        MPP of 0.25 often roughly translates to 40x

    MAG : float or None
        If you prefer to use whatever magnification is reported in slide.
        If neither MPP or MAG is provided, everything is retrieved without
        scaling at base (scan) magnification.

    mode : str
        This specifies which part of the slide to get the mask from. Allowed
        modes include the following
        - wsi: get scaled up or down version of mask of whole slide
        - min_bounding_box: get minimum box for all annotations in slide
        - manual_bounds: use given ROI bounds provided by the 'bounds' param
        - polygonal_bounds: use the idx_for_roi param to get coordinates

    bounds : dict or None
        if not None, has keys 'XMIN', 'XMAX', 'YMIN', 'YMAX' for slide
        region coordinates (AT BASE MAGNIFICATION) to get labeled image
        (mask) for. Use this with the 'manual_bounds' run mode.

    idx_for_roi : int
        index of ROI within the element_infos dataframe.
        Use this with the 'polygonal_bounds' run mode.

    slide_annotations : list or None
        Give this parameter to avoid re-getting slide annotations. If you do
        provide the annotations, though, make sure you have used
        scale_slide_annotations() to scale them up or down by sf BEFOREHAND.

    element_infos : pandas DataFrame.
        The columns annidx and elementidx
        encode the dict index of annotation document and element,
        respectively, in the original slide_annotations list of dictionaries.
        This can be obained by get_bboxes_from_slide_annotations() method.
        Make sure you have used scale_slide_annotations().

    linewidth : float
        visualization line width

    get_rgb: bool
        get rgb image?

    get_visualization : bool
        get overlayed annotation bounds over RGB for visualization

    text : bool
        add text labels to visualization?

    Returns
    --------
    dict
        Results dict containing one or more of the following keys
        - bounds: dict of bounds at scan magnification
        - rgb: (mxnx3 np array) corresponding rgb image
        - contours: dict
        - visualization: (mxnx3 np array) visualization overlay

    """
    MPP, MAG, mode, bounds, idx_for_roi, get_rgb, get_visualization = \
        _sanity_checks(
            MPP, MAG, mode, bounds, idx_for_roi,
            get_rgb, get_visualization)

    # calculate the scale factor
    sf, appendStr = get_scale_factor_and_appendStr(gc=gc,
                                                   slide_id=slide_id,
                                                   MPP=MPP,
                                                   MAG=MAG)

    if slide_annotations is not None:
        assert element_infos is not None, "must also provide element_infos"
    else:
        # get annotations for slide
        slide_annotations = gc.get('/annotation/item/' + slide_id)

        # scale up/down annotations by a factor
        slide_annotations = scale_slide_annotations(slide_annotations, sf=sf)

        # get bounding box information for all annotations -> scaled by sf
        element_infos = get_bboxes_from_slide_annotations(slide_annotations)

    # Determine get region based on run mode, keeping in mind that it
    # must be at BASE MAGNIFICATION coordinates before it is passed
    # on to get_mask_from_slide()
    # if mode != 'polygonal_bound':
    bounds = _get_roi_bounds_by_run_mode(gc=gc,
                                         slide_id=slide_id,
                                         mode=mode,
                                         bounds=bounds,
                                         element_infos=element_infos,
                                         idx_for_roi=idx_for_roi,
                                         sf=sf)

    # only keep relevant elements and get uncropped bounds
    elinfos_roi, uncropped_bounds = _keep_relevant_elements_for_roi(
        element_infos,
        sf=sf,
        mode=mode,
        idx_for_roi=idx_for_roi,
        roiinfo=copy.deepcopy(bounds))

    # find relevant portion from slide annotations to use
    # (with overflowing beyond edge)
    annotations_slice = _trim_slide_annotations_to_roi(
        copy.deepcopy(slide_annotations), elinfos_roi=elinfos_roi)

    # get roi polygon vertices
    rescaled_bounds = {k: int(v * sf) for k, v in bounds.items()}
    if mode == 'polygonal_bounds':
        roi_coords = _get_coords_from_element(
            copy.deepcopy(slide_annotations[int(
                element_infos.loc[idx_for_roi,
                                  'annidx'])]['annotation']['elements'][int(
                                      element_infos.loc[idx_for_roi,
                                                        'elementidx'])]))
        cropping_bounds = None
    else:
        roi_coords = None
        cropping_bounds = rescaled_bounds

    # tabularize to use contours
    _, contours_df = parse_slide_annotations_into_tables(
        annotations_slice,
        cropping_bounds=cropping_bounds,
        cropping_polygon_vertices=roi_coords,
        use_shapely=mode in ('manual_bounds', 'polygonal_bounds'),
    )
    contours_list = contours_df.to_dict(orient='records')

    # Final bounds (relative to slide at base magnification)
    bounds = {k: int(v / sf) for k, v in rescaled_bounds.items()}
    result = dict()

    # get RGB
    if get_rgb:
        getStr = \
            "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d&encoding=PNG" \
            % (slide_id,
               bounds['XMIN'], bounds['XMAX'],
               bounds['YMIN'], bounds['YMAX'])
        getStr += appendStr
        resp = gc.get(getStr, jsonResp=False)
        rgb = get_image_from_htk_response(resp)
        result['rgb'] = rgb

    # Assign to results
    result.update({
        'contours': contours_list,
        'bounds': bounds,
    })

    # get visualization of annotations on RGB
    if get_visualization:
        result['visualization'] = _visualize_annotations_on_rgb(
            rgb=rgb,
            contours_list=contours_list,
            linewidth=linewidth,
            text=text)

    return result
Пример #11
0
    def test_reinhard(self):
        """Test reinhard."""
        # get RGB image at a small magnification
        slide_info = gc.get('item/%s/tiles' % SAMPLE_SLIDE_ID)
        getStr = "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d" % (
            SAMPLE_SLIDE_ID, 0, slide_info['sizeX'], 0, slide_info['sizeY']
            ) + "&magnification=%.2f" % MAG
        tissue_rgb = get_image_from_htk_response(
            gc.get(getStr, jsonResp=False))

        # # SANITY CHECK! normalize to LAB mean and std from SAME slide
        # mean_lab, std_lab = lab_mean_std(tissue_rgb)
        # tissue_rgb_normalized = reinhard(
        #     tissue_rgb, target_mu=mean_lab, target_sigma=std_lab)
        #
        # # we expect the images to be (almost) exactly the same
        # assert np.mean(tissue_rgb - tissue_rgb_normalized) < 1

        # Normalize to pre-set color standard
        tissue_rgb_normalized = reinhard(
            tissue_rgb, target_mu=cnorm['mu'], target_sigma=cnorm['sigma'])

        # check that it matches
        mean_lab, std_lab = lab_mean_std(tissue_rgb_normalized)
        self.assertTrue(all(
            np.abs(mean_lab - cnorm['mu']) < [0.1, 0.1, 0.1]))
        self.assertTrue(all(
            np.abs(std_lab - cnorm['sigma']) < [0.1, 0.1, 0.1]))

        # get tissue mask
        thumbnail_rgb = get_slide_thumbnail(gc, SAMPLE_SLIDE_ID)
        labeled, mask = get_tissue_mask(
            thumbnail_rgb, deconvolve_first=True,
            n_thresholding_steps=1, sigma=1.5, min_size=30)

        # # visualize result
        # vals = np.random.rand(256, 3)
        # vals[0, ...] = [0.9, 0.9, 0.9]
        # cMap = ListedColormap(1 - vals)
        #
        # f, ax = plt.subplots(1, 3, figsize=(20, 20))
        # ax[0].imshow(thumbnail_rgb)
        # ax[1].imshow(labeled, cmap=cMap)
        # ax[2].imshow(mask, cmap=cMap)
        # plt.show()

        # Do MASKED normalization to preset standard
        mask_out = resize(
            labeled == 0, output_shape=tissue_rgb.shape[:2],
            order=0, preserve_range=True) == 1
        tissue_rgb_normalized = reinhard(
            tissue_rgb, target_mu=cnorm['mu'], target_sigma=cnorm['sigma'],
            mask_out=mask_out)

        # check that it matches
        mean_lab, std_lab = lab_mean_std(
            tissue_rgb_normalized, mask_out=mask_out)
        self.assertTrue(all(
            np.abs(mean_lab - cnorm['mu']) < [0.1, 0.1, 0.1]))
        self.assertTrue(all(
            np.abs(std_lab - cnorm['sigma']) < [0.1, 0.1, 0.1]))
Пример #12
0
# and using reordered such that columns are the order:
# Hamtoxylin, Eosin, Null
W_target = np.array([[0.5807549, 0.08314027, 0.08213795],
                     [0.71681094, 0.90081588, 0.41999816],
                     [0.38588316, 0.42616716, -0.90380025]])

# %%===========================================================================

print("Getting images to be normalized ...")

# get RGB image at a small magnification
slide_info = gc.get('item/%s/tiles' % SAMPLE_SLIDE_ID)
getStr = "/item/%s/tiles/region?left=%d&right=%d&top=%d&bottom=%d" % (
    SAMPLE_SLIDE_ID, 0, slide_info['sizeX'], 0,
    slide_info['sizeY']) + "&magnification=%.2f" % MAG
tissue_rgb = get_image_from_htk_response(gc.get(getStr, jsonResp=False))

# get mask of things to ignore
thumbnail_rgb = get_slide_thumbnail(gc, SAMPLE_SLIDE_ID)
mask_out, _ = get_tissue_mask(thumbnail_rgb,
                              deconvolve_first=True,
                              n_thresholding_steps=1,
                              sigma=1.5,
                              min_size=30)
mask_out = resize(mask_out == 0,
                  output_shape=tissue_rgb.shape[:2],
                  order=0,
                  preserve_range=True) == 1

# since this is a unit test, just work on a small image
tissue_rgb = tissue_rgb[1000:1500, 2500:3000, :]