Beispiel #1
0
def _data_from_large_image(path, outputPath, **kwargs):
    """
    Check if the input file can be read by installed large_image tile sources.
    If so, return the metadata, internal metadata, and extract each associated
    image.

    :param path: path of the file.
    :param outputPath: the name of a temporary output file.
    :returns: a dictionary of metadata, internal_metadata, and images.  images
        is a dictionary of keys and paths.  Returns None if the path is not
        readable by large_image.
    """
    _import_pyvips()
    if not path.startswith('large_image://test'):
        try:
            ts = large_image.getTileSource(path)
        except Exception:
            return
    else:
        import urllib.parse

        tsparams = {
            k: int(v[0]) if v[0].isdigit() else v[0]
            for k, v in urllib.parse.parse_qs(
                path.split('?', 1)[1] if '?' in path else '').items()
        }
        ts = large_image.getTileSource('large_image://test', **tsparams)
    results = {
        'metadata': ts.getMetadata(),
        'internal_metadata': ts.getInternalMetadata(),
        'images': {},
        'tilesource': ts,
    }
    tasks = []
    pool = _get_thread_pool(**kwargs)
    for key in ts.getAssociatedImagesList():
        if not _use_associated_image(key, **kwargs):
            continue
        try:
            img, mime = ts.getAssociatedImage(key)
        except Exception:
            continue
        savePath = outputPath + '-%s-%s.tiff' % (
            key, time.strftime('%Y%m%d-%H%M%S'))
        # TODO: allow specifying quality separately from main image quality
        _pool_add(tasks, (pool.submit(_convert_via_vips,
                                      img,
                                      savePath,
                                      outputPath,
                                      mime=mime,
                                      forTiled=False), ))
        results['images'][key] = savePath
    _drain_pool(pool, tasks)
    return results
Beispiel #2
0
    def testGetTileSource(self):
        from large_image import getTileSource, tilesource

        try:
            source = getTileSource(
                os.path.join(os.path.dirname(__file__), 'test_files',
                             'yb10kx5k.png'))
            self.assertTrue(False)
        except tilesource.TileSourceException:
            source = None
        self.assertIsNone(source)

        source = getTileSource(os.path.join(
            os.environ['LARGE_IMAGE_DATA'], 'sample_svs_image.TCGA-DU-6399-'
            '01A-01-TS1.e8eb65de-d63e-42db-af6f-14fefbbdf7bd.svs'),
                               encoding='PNG')
        tileMetadata = source.getMetadata()
        params = {'encoding': 'PNG'}
        self._testTilesZXY(source, tileMetadata, params, PNGHeader)

        source = getTileSource(
            os.path.join(os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        tileMetadata = source.getMetadata()
        tileMetadata['sparse'] = 5
        self._testTilesZXY(source, tileMetadata)

        source = getTileSource('large_image://dummy')
        self.assertEqual(source.getTile(0, 0, 0), '')
        tileMetadata = source.getMetadata()
        self.assertEqual(tileMetadata['tileWidth'], 0)
        self.assertEqual(tileMetadata['tileHeight'], 0)
        self.assertEqual(tileMetadata['sizeX'], 0)
        self.assertEqual(tileMetadata['sizeY'], 0)
        self.assertEqual(tileMetadata['levels'], 0)

        params = {
            'maxLevel': 6,
            'tileWidth': 240,
            'tileHeight': 170,
            'fractal': False,
            'encoding': 'PNG'
        }
        source = getTileSource('large_image://test', **params)
        tileMetadata = source.getMetadata()
        self.assertEqual(tileMetadata['tileWidth'], 240)
        self.assertEqual(tileMetadata['tileHeight'], 170)
        self.assertEqual(tileMetadata['sizeX'], 15360)
        self.assertEqual(tileMetadata['sizeY'], 10880)
        self.assertEqual(tileMetadata['levels'], 7)
        self._testTilesZXY(source, tileMetadata, params, PNGHeader)
    def testGetTileSource(self):
        from large_image import getTileSource, tilesource

        try:
            source = getTileSource(os.path.join(
                os.path.dirname(__file__), 'test_files', 'yb10kx5k.png'))
            self.assertTrue(False)
        except tilesource.TileSourceException:
            source = None
        self.assertIsNone(source)

        source = getTileSource(os.path.join(
            os.environ['LARGE_IMAGE_DATA'], 'sample_svs_image.TCGA-DU-6399-'
            '01A-01-TS1.e8eb65de-d63e-42db-af6f-14fefbbdf7bd.svs'),
            encoding='PNG')
        tileMetadata = source.getMetadata()
        params = {'encoding': 'PNG'}
        self._testTilesZXY(source, tileMetadata, params, PNGHeader)

        source = getTileSource(os.path.join(
            os.environ['LARGE_IMAGE_DATA'], 'sample_image.ptif'))
        tileMetadata = source.getMetadata()
        tileMetadata['sparse'] = 5
        self._testTilesZXY(source, tileMetadata)

        source = getTileSource('large_image://dummy')
        self.assertEqual(source.getTile(0, 0, 0), '')
        tileMetadata = source.getMetadata()
        self.assertEqual(tileMetadata['tileWidth'], 0)
        self.assertEqual(tileMetadata['tileHeight'], 0)
        self.assertEqual(tileMetadata['sizeX'], 0)
        self.assertEqual(tileMetadata['sizeY'], 0)
        self.assertEqual(tileMetadata['levels'], 0)

        params = {
            'maxLevel': 6,
            'tileWidth': 240,
            'tileHeight': 170,
            'fractal': False,
            'encoding': 'PNG'
        }
        source = getTileSource('large_image://test', **params)
        tileMetadata = source.getMetadata()
        self.assertEqual(tileMetadata['tileWidth'], 240)
        self.assertEqual(tileMetadata['tileHeight'], 170)
        self.assertEqual(tileMetadata['sizeX'], 15360)
        self.assertEqual(tileMetadata['sizeY'], 10880)
        self.assertEqual(tileMetadata['levels'], 7)
        self._testTilesZXY(source, tileMetadata, params, PNGHeader)
Beispiel #4
0
def get_image_from_slide(file, mag=1.25):
    """ Extract an image at the desired magnification from a slide file
    
    Parameters
    ==========
    file: path to the slide (str) or the slide (large_image)
    mag : magnification to extract the image (float)
    
    Return
    ======
    image: array 
    """

    # ----- Check if slide is already the slide or the input name -----
    if type(file) is str:
        # Read the slide
        slide = large_image.getTileSource(file)
    else:
        slide = file

    # ----- Get slide at given magnification -----
    if mag == 'base':
        mag = slide.getNativeMagnification()['magnification']

    image, _ = slide.getRegion(scale=dict(magnification=mag),
                               format=large_image.tilesource.TILE_FORMAT_NUMPY)

    return image[:, :, :3]
Beispiel #5
0
def detect_tile_nuclei(slide_path, tile_position, args, **it_kwargs):

    # get slide tile source
    ts = large_image.getTileSource(slide_path)

    # get requested tile
    tile_info = ts.getSingleTile(
        tile_position=tile_position,
        format=large_image.tilesource.TILE_FORMAT_NUMPY,
        **it_kwargs)

    # get tile image
    im_tile = tile_info['tile'][:, :, :3]

    # perform color normalization
    im_nmzd = htk_cnorm.reinhard(im_tile, args.reference_mu_lab,
                                 args.reference_std_lab)

    # perform color decovolution
    w = cli_utils.get_stain_matrix(args)

    im_stains = htk_cdeconv.color_deconvolution(im_nmzd, w).Stains

    im_nuclei_stain = im_stains[:, :, 0].astype(np.float)

    # segment nuclei
    im_nuclei_seg_mask = cli_utils.detect_nuclei_kofahi(im_nuclei_stain, args)

    # generate nuclei annotations
    nuclei_annot_list = cli_utils.create_tile_nuclei_annotations(
        im_nuclei_seg_mask, tile_info, args.nuclei_annotation_format)

    return nuclei_annot_list
def main(args):
    utils.create_dask_client(args)
    ts = large_image.getTileSource(args.inputImageFile)
    make_label_image = args.outputLabelImage is not None
    region = utils.get_region_dict(
        args.region,
        *(args.maxRegionSize, ts) if make_label_image else ()).get('region')
    ppc_params = ppc.Parameters(
        **{k: getattr(args, k)
           for k in ppc.Parameters._fields})
    results = ppc.count_slide(
        args.inputImageFile,
        ppc_params,
        region,
        args.tile_grouping,
        make_label_image,
    )
    if make_label_image:
        stats, label_image = results
        # Colorize label image.  Colors from the "coolwarm" color map
        color_map = np.empty((4, 3), dtype=np.uint8)
        color_map[ppc.Labels.NEGATIVE] = 255
        color_map[ppc.Labels.WEAK] = 60, 78, 194
        color_map[ppc.Labels.PLAIN] = 221, 220, 220
        color_map[ppc.Labels.STRONG] = 180, 4, 38
        # Cleverly index color_map
        label_image = color_map[label_image]
        skimage.io.imsave(args.outputLabelImage, label_image)
    else:
        stats, = results
    with open(args.returnParameterFile, 'w') as f:
        for k, v in zip(stats._fields, stats):
            f.write('{} = {}\n'.format(k, v))
def main(args):

    # Read Input Image
    print('>> Reading input image')

    print(args.inputImageFile)

    ts = large_image.getTileSource(args.inputImageFile)

    im_input = ts.getRegion(format=large_image.tilesource.TILE_FORMAT_NUMPY,
                            **utils.get_region_dict(args.region,
                                                    args.maxRegionSize, ts))[0]

    # Create stain matrix
    print('>> Creating stain matrix')

    w = utils.get_stain_matrix(args)
    print(w)

    # Perform color deconvolution
    print('>> Performing color deconvolution')
    im_stains = htk_cd.color_deconvolution(im_input, w).Stains

    # write stain images to output
    print('>> Outputting individual stain images')

    print(args.outputStainImageFile_1)
    skimage.io.imsave(args.outputStainImageFile_1, im_stains[:, :, 0])

    print(args.outputStainImageFile_2)
    skimage.io.imsave(args.outputStainImageFile_2, im_stains[:, :, 1])

    print(args.outputStainImageFile_3)
    skimage.io.imsave(args.outputStainImageFile_3, im_stains[:, :, 2])
def average_color(imagePath, magnification=None):
    """
    Print the average color for a tiled image file.

    :param imagePath: path of the file to analyze.
    :param magnification: optional magnification to use for the analysis.
    """
    source = large_image.getTileSource(imagePath)
    # get a thumbnail no larger than 1024x1024 pixels
    thumbnail, mimeType = source.getThumbnail(
        width=1024, height=1024, encoding='JPEG')
    print('Made a thumbnail of type %s taking %d bytes' % (
        mimeType, len(thumbnail)))
    # We could save it, if we want to.
    # open('/tmp/thumbnail.jpg', 'wb').write(thumbnail)

    tileMeans = []
    tileWeights = []
    # iterate through the tiles at a particular magnification:
    for tile in source.tileIterator(
            format=large_image.tilesource.TILE_FORMAT_NUMPY,
            scale={'magnification': magnification},
            resample=True):
        # The tile image data is in tile['tile'] and is a numpy
        # multi-dimensional array
        mean = numpy.mean(tile['tile'], axis=(0, 1))
        tileMeans.append(mean)
        tileWeights.append(tile['width'] * tile['height'])
        print('x: %d  y: %d  w: %d  h: %d  mag: %g  color: %g %g %g' % (
            tile['x'], tile['y'], tile['width'], tile['height'],
            tile['magnification'], mean[0], mean[1], mean[2]))
    mean = numpy.average(tileMeans, axis=0, weights=tileWeights)
    print('Average color: %g %g %g' % (mean[0], mean[1], mean[2]))
def read_tf_largeImage(tif_file_path, mag):
    wsi_image = large_image.getTileSource(tif_file_path)
    rgba_image, _ = wsi_image.getRegion(
        scale=dict(magnification=mag),
        format=large_image.tilesource.TILE_FORMAT_NUMPY)
    slide_w, slide_h = rgba_image.shape[1], rgba_image.shape[0]
    return rgba_image, (slide_w, slide_h)
Beispiel #10
0
def _sample_pixels_tile(slide_path, iter_args, positions, sample_fraction,
                        tissue_seg_mag, min_coverage, im_fgnd_mask_lres):
    start_position, position_count = positions
    sample_pixels = [np.empty((0, 3))]
    ts = large_image.getTileSource(slide_path)
    for position in range(start_position, start_position + position_count):
        tile = ts.getSingleTile(tile_position=position, **iter_args)
        # get current region in base_pixels
        rgn_hres = {'left': tile['gx'], 'top': tile['gy'],
                    'right': tile['gx'] + tile['gwidth'],
                    'bottom': tile['gy'] + tile['gheight'],
                    'units': 'base_pixels'}

        # get foreground mask for current tile at low resolution
        rgn_lres = ts.convertRegionScale(rgn_hres,
                                         targetScale={'magnification':
                                                      tissue_seg_mag},
                                         targetUnits='mag_pixels')

        top = np.int(rgn_lres['top'])
        bottom = np.int(rgn_lres['bottom'])
        left = np.int(rgn_lres['left'])
        right = np.int(rgn_lres['right'])

        tile_fgnd_mask_lres = im_fgnd_mask_lres[top:bottom, left:right]

        # skip tile if there is not enough foreground in the slide
        cur_fgnd_frac = tile_fgnd_mask_lres.mean()

        if np.isnan(cur_fgnd_frac) or cur_fgnd_frac <= min_coverage:
            continue

        # get current tile image
        im_tile = tile['tile'][:, :, :3]

        # get tile foreground mask at resolution of current tile
        tile_fgnd_mask = scipy.misc.imresize(
            tile_fgnd_mask_lres,
            im_tile.shape,
            interp='nearest'
        )

        # generate linear indices of sample pixels in fgnd mask
        nz_ind = np.nonzero(tile_fgnd_mask.flatten())[0]

        # Handle fractions in the desired sample size by rounding up
        # or down, weighted by the fractional amount.
        float_samples = sample_fraction * nz_ind.size
        num_samples = int(np.floor(float_samples))
        num_samples += np.random.binomial(1, float_samples - num_samples)

        sample_ind = np.random.choice(nz_ind, num_samples)

        # convert rgb tile image to Nx3 array
        tile_pix_rgb = np.reshape(im_tile, (-1, 3))

        # add rgb triplet of sample pixels
        sample_pixels.append(tile_pix_rgb[sample_ind, :])

    return np.concatenate(sample_pixels, 0)
Beispiel #11
0
def sum_squares(imagePath, magnification=None, **kwargs):
    """
    Print the sum-of-squares of each color channel for a tiled image file.

    :param imagePath: path of the file to analyze.
    :param magnification: optional magnification to use for the analysis.
    """
    source = large_image.getTileSource(imagePath)

    tileSumSquares = []
    # iterate through the tiles at a particular magnification:
    for tile in source.tileIterator(
            format=large_image.tilesource.TILE_FORMAT_NUMPY,
            scale={'magnification': magnification},
            resample=True, **kwargs):
        # The tile image data is in tile['tile'] and is a numpy
        # multi-dimensional array
        data = tile['tile']
        # trim off any overlap so we don't include it in our calculations.
        data = data[
            tile['tile_overlap']['top']:
                data.shape[0]-tile['tile_overlap']['bottom'],
            tile['tile_overlap']['left']:
                data.shape[1]-tile['tile_overlap']['right'],
            :]
        sumsq = numpy.sum(data**2, axis=(0, 1))
        tileSumSquares.append(sumsq)
        print('x: %d  y: %d  w: %d  h: %d  mag: %g  sums: %d %d %d' % (
            tile['x'], tile['y'], tile['width'], tile['height'],
            tile['magnification'], sumsq[0], sumsq[1], sumsq[2]))
    sumsq = numpy.sum(tileSumSquares, axis=0)
    print('Sum of squares: %d %d %d' % (sumsq[0], sumsq[1], sumsq[2]))
Beispiel #12
0
def average_color(imagePath, magnification=None):
    """
    Print the average color for a tiled image file.

    :param imagePath: path of the file to analyze.
    :param magnification: optional magnification to use for the analysis.
    """
    source = large_image.getTileSource(imagePath)
    # get a thumbnail no larger than 1024x1024 pixels
    thumbnail, mimeType = source.getThumbnail(width=1024,
                                              height=1024,
                                              encoding='JPEG')
    print('Made a thumbnail of type %s taking %d bytes' %
          (mimeType, len(thumbnail)))
    # We could save it, if we want to.
    # open('/tmp/thumbnail.jpg', 'wb').write(thumbnail)

    tileMeans = []
    tileWeights = []
    # iterate through the tiles at a particular magnification:
    for tile in source.tileIterator(
            format=large_image.tilesource.TILE_FORMAT_NUMPY,
            scale={'magnification': magnification},
            resample=True):
        # The tile image data is in tile['tile'] and is a numpy
        # multi-dimensional array
        mean = numpy.mean(tile['tile'], axis=(0, 1))
        tileMeans.append(mean)
        tileWeights.append(tile['width'] * tile['height'])
        print('x: %d  y: %d  w: %d  h: %d  mag: %g  color: %g %g %g' %
              (tile['x'], tile['y'], tile['width'], tile['height'],
               tile['magnification'], mean[0], mean[1], mean[2]))
    mean = numpy.average(tileMeans, axis=0, weights=tileWeights)
    print('Average color: %g %g %g' % (mean[0], mean[1], mean[2]))
    return mean
 def retrive_wsi_low_res(self, file):
     print("show wsi", file)
     ts = large_image.getTileSource(os.path.join(cfg.FILE_DIR, file))
     im_low_res, _ = ts.getRegion(
         scale=dict(magnification=1.25),
         format=large_image.tilesource.TILE_FORMAT_NUMPY)
     plt.imshow(im_low_res)
     plt.savefig(file + '.png')
    def get_slide_metadata(self, file):
        ts = large_image.getTileSource(os.path.join(cfg.FILE_DIR, file))
        print(ts.getMetadata())

        # Get the magnification associated with all levels of the image pyramid
        for i in range(ts.levels):
            print('Level-{} : {}'.format(i,
                                         ts.getMagnificationForLevel(level=i)))
def detect_tile_nuclei(slide_path, tile_position, args, it_kwargs,
                       src_mu_lab=None, src_sigma_lab=None):

    # get slide tile source
    ts = large_image.getTileSource(slide_path)

    # get requested tile
    tile_info = ts.getSingleTile(
        tile_position=tile_position,
        format=large_image.tilesource.TILE_FORMAT_NUMPY,
        **it_kwargs)

    # get tile image
    im_tile = tile_info['tile'][:, :, :3]

    # perform color normalization
    im_nmzd = htk_cnorm.reinhard(im_tile,
                                 args.reference_mu_lab,
                                 args.reference_std_lab,
                                 src_mu=src_mu_lab,
                                 src_sigma=src_sigma_lab)

    # perform color decovolution
    w = cli_utils.get_stain_matrix(args)

    im_stains = htk_cdeconv.color_deconvolution(im_nmzd, w).Stains

    im_nuclei_stain = im_stains[:, :, 0].astype(np.float)

    # segment nuclear foreground
    im_nuclei_fgnd_mask = im_nuclei_stain < args.foreground_threshold

    # segment nuclei
    im_nuclei_seg_mask = htk_nuclear.detect_nuclei_kofahi(
        im_nuclei_stain,
        im_nuclei_fgnd_mask,
        args.min_radius,
        args.max_radius,
        args.min_nucleus_area,
        args.local_max_search_radius
    )

    # Delete border nuclei
    if args.ignore_border_nuclei is True:

        im_nuclei_seg_mask = htk_seg_label.delete_border(im_nuclei_seg_mask)

    # generate nuclei annotations
    nuclei_annot_list = []

    flag_nuclei_found = np.any(im_nuclei_seg_mask)

    if flag_nuclei_found:
        nuclei_annot_list = cli_utils.create_tile_nuclei_annotations(
            im_nuclei_seg_mask, tile_info, args.nuclei_annotation_format)

    return nuclei_annot_list
Beispiel #16
0
def positive_pixel_count_tiles(args, kwargs, position, count):
    ts = large_image.getTileSource(args.inputImageFile)
    total = dict((k, 0) for k in results_keys)
    for pos in range(position, position + count):
        tile = ts.getSingleTile(tile_position=pos, **kwargs)['tile']
        subtotal = positive_pixel_count_single_tile(args, tile, makeLabelImage=False)
        for k in results_keys:
            total[k] += subtotal[k]
    return total
def compute_tile_nuclei_features(slide_path, tile_position, args, it_kwargs,
                                 src_mu_lab=None, src_sigma_lab=None):

    # get slide tile source
    ts = large_image.getTileSource(slide_path)

    # get requested tile
    tile_info = ts.getSingleTile(
        tile_position=tile_position,
        format=large_image.tilesource.TILE_FORMAT_NUMPY,
        **it_kwargs)

    # get tile image
    im_tile = tile_info['tile'][:, :, :3]

    # perform color normalization
    im_nmzd = htk_cnorm.reinhard(im_tile,
                                 args.reference_mu_lab,
                                 args.reference_std_lab,
                                 src_mu=src_mu_lab,
                                 src_sigma=src_sigma_lab)

    # perform color decovolution
    w = cli_utils.get_stain_matrix(args)

    im_stains = htk_cdeconv.color_deconvolution(im_nmzd, w).Stains

    im_nuclei_stain = im_stains[:, :, 0].astype(np.float)

    # segment nuclei
    im_nuclei_seg_mask = cli_utils.detect_nuclei_kofahi(im_nuclei_stain, args)

    # generate nuclei annotations
    nuclei_annot_list = cli_utils.create_tile_nuclei_annotations(
        im_nuclei_seg_mask, tile_info, args.nuclei_annotation_format)

    # compute nuclei features
    if args.cytoplasm_features:
        im_cytoplasm_stain = im_stains[:, :, 1].astype(np.float)
    else:
        im_cytoplasm_stain = None

    fdata = htk_features.compute_nuclei_features(
        im_nuclei_seg_mask, im_nuclei_stain, im_cytoplasm_stain,
        fsd_bnd_pts=args.fsd_bnd_pts,
        fsd_freq_bins=args.fsd_freq_bins,
        cyto_width=args.cyto_width,
        num_glcm_levels=args.num_glcm_levels,
        morphometry_features_flag=args.morphometry_features,
        fsd_features_flag=args.fsd_features,
        intensity_features_flag=args.intensity_features,
        gradient_features_flag=args.gradient_features,
    )

    fdata.columns = ['Feature.' + col for col in fdata.columns]

    return nuclei_annot_list, fdata
Beispiel #18
0
def test_tiff_tile_source(file_, output):
    """Check whether large_image can return a tile with svs sources."""
    test_url = 'https://data.kitware.com/api/v1/file/{}/download'.format(file_)
    urllib.urlretrieve(test_url, output)
    image = large_image.getTileSource(output)
    # Make sure it is the svs tile source
    assert isinstance(image, large_image.tilesource.SVSFileTileSource)
    # Make sure we can get a tile without an exception
    assert type(image.getTile(0, 0, 0)) == str
def _count_tiles(slide_path, params, kwargs, position, count):
    ts = large_image.getTileSource(slide_path)

    subtotal = np.array((0, 0))
    for pos in range(position, position + count):
        tile = ts.getSingleTile(tile_position=pos, **kwargs)['tile']
        subtotal = subtotal + np.array(tile.shape[0:2])

    return subtotal
def test_pil_tile_source():
    """Check whether large_image can return a tile with pil source."""
    test_url = 'https://data.kitware.com/api/v1/item/590346fe8d777f16d01e0546/download'  # noqa: E501
    test_png = '/tmp/Easy1.png'
    urllib.urlretrieve(test_url, test_png)
    image = large_image.getTileSource(test_png)
    # Make sure it is the pil tile source
    assert isinstance(image, large_image.tilesource.PILFileTileSource)
    # Make sure we can get a tile without an exception
    assert type(image.getTile(0, 0, 0)) == str
def _count_tiles(slide_path, params, kwargs, position, count):
    ts = large_image.getTileSource(slide_path)
    lpotf = len(OutputTotals._fields)
    total = [0] * lpotf
    for pos in range(position, position + count):
        tile = ts.getSingleTile(tile_position=pos, **kwargs)['tile']
        subtotal = _count_image(tile, params)[0]
        for k in range(lpotf):
            total[k] += subtotal[k]
    return OutputTotals._make(total)
    def tile_wsi(self, file, magnification, tile_width, tile_hight,
                 tile_overlap_x, tile_overlap_y):
        ts = large_image.getTileSource(os.path.join(cfg.FILE_DIR, file))

        num_tiles = 0
        num_empty_tiles = 0
        num_nuclei = 0

        tile_means = []
        tile_areas = []

        for tile_info in tqdm(
                ts.tileIterator(
                    #region=dict(left=5000, top=5000, width=20000, height=20000, units='base_pixels'),
                    scale=dict(magnification=magnification),
                    tile_size=dict(width=tile_width, height=tile_hight),
                    tile_overlap=dict(x=tile_overlap_x, y=tile_overlap_y),
                    format=large_image.tilesource.TILE_FORMAT_PIL)):
            #print(tile_info)

            if (num_tiles > 0 and num_tiles % 100 == 0):
                print('Tile - {} '.format(num_tiles))
                print('Empty Tile - {} '.format(num_empty_tiles))
                #display(tile_info)

            #img
            im_tile = np.array(tile_info['tile'])

            # To check the content of the image
            if (self.is_good_tile(im_tile)):
                if (cfg.SAVE_TILES):
                    self.save_tile_to_disk(im_tile,
                                           (tile_info['x'], tile_info['y']),
                                           file, magnification)
                #mean rgb
                tile_mean_rgb = np.mean(im_tile[:, :, :3], axis=(0, 1))
                tile_means.append(tile_mean_rgb)
                tile_areas.append(tile_info['width'] * tile_info['height'])

                num_tiles += 1
                """ Here is the call for computing morphometry features for each good tile"""
                num_nuclei += self.nuclei_seg.compute_nuclei_feat(
                    im_tile, (tile_info['x'], tile_info['y']), file,
                    magnification)
            else:
                """ This image is one solid color so no need to save it"""
                num_empty_tiles += 1

        slide_mean_rgb = np.average(tile_means, axis=0, weights=tile_areas)
        print('Slide: ', file)
        print('Total num of Nuclei = {}'.format(num_nuclei))
        print('Number of tiles = {}'.format(num_tiles))
        print('Number of empty tiles = {}'.format(num_empty_tiles))
        print('Slide mean color = {}'.format(slide_mean_rgb))
Beispiel #23
0
def test_mapnik_tile_source(test_url, output):
    """Check whether large_image can return a tile with mapnik sources."""
    urllib.urlretrieve(test_url, output)
    image = large_image.getTileSource(output)
    metadata = image.getMetadata()
    # Make sure it is the mapnik tile source
    assert metadata['geospatial']
    assert metadata['bounds']
    assert isinstance(image, large_image.tilesource.MapnikTileSource)
    # Make sure we can get a tile without an exception
    assert type(image.getTile(0, 0, 0)) == str
def count_slide(slide_path,
                params,
                region=None,
                tile_grouping=256,
                make_label_image=False):
    """Compute a count of positive pixels in the slide at slide_path.
    This routine can also create a label image.

    Parameters
    ---------
    slide_path : string (path)
        Path to the slide to analyze.
    params : Parameters
        An instance of Parameters, which see for further documentation
    region : dict, optional
        A valid region dict (per a large_image
        TileSource.tileIterator's region argument)
    tile_grouping : int
        The number of tiles to process as part of a single task
    make_label_image : bool, default=False
        Whether to make a label image.  See also "Notes"

    Returns
    -------
    stats : Output
        Various statistics on the input image.  See Output.
    label_image : array-like, only if make_label_image is set

    Notes
    -----
    The return value is either a single or a pair -- it is in either
    case a tuple.  Dask is used as configured to compute the
    statistics, but only if make_label_image is reset.  If
    make_label_image is set, everything is computed in a
    single-threaded manner.

    """
    ts = large_image.getTileSource(slide_path)
    kwargs = dict(format=large_image.tilesource.TILE_FORMAT_NUMPY)
    if region is not None:
        kwargs['region'] = region
    if make_label_image:
        tile = ts.getRegion(**kwargs)[0]
        return count_image(tile, params)
    else:
        results = []
        total_tiles = ts.getSingleTile(**kwargs)['iterator_range']['position']
        for position in range(0, total_tiles, tile_grouping):
            results.append(
                delayed(_count_tiles)(slide_path, params, kwargs, position,
                                      min(tile_grouping,
                                          total_tiles - position)))
        results = delayed(_combine)(results).compute()
    return _totals_to_stats(results),
def main(args):
    #
    # read input image
    #
    print('>> Reading input image')

    print(args.inputImageFile)
    slide_name = os.path.basename(args.inputImageFile)
    slide_name = os.path.splitext(slide_name)[0]

    ts = large_image.getTileSource(args.inputImageFile)

    #
    # read annotation file
    #
    print('\n>> Reading annotation file ...\n')

    with open(args.inputAnnotationFile) as json_file:
        annotation_data = json.load(json_file)

    data = []
    if isinstance(annotation_data, dict):
        data.append(annotation_data)

    elif isinstance(annotation_data, list):
        data = list(annotation_data)

    #
    # read GTCode file
    #
    print('\n>> Reading Ground Truth file ...\n')

    GTCodes = args.inputGTCodeFile

    #
    #  convert annotation to mask
    #
    print('\n>> Performing conversion from annotation to mask ...\n')

    MASK_SAVEPATH = args.outputDirectory
    # create folders if necessary
    for folder in [MASK_SAVEPATH, ]:
        try:
            os.mkdir(folder)
        except:
            pass

    get_all_roi_masks_for_slide(ts, data, GTCodes,
                                MASK_SAVEPATH=MASK_SAVEPATH, slide_name=slide_name, verbose=True,
                                get_roi_mask_kwargs={
                                    'iou_thresh': 0.0, 'crop_to_roi': True, 'use_shapely': True,
                                    'verbose': True},
                                )
Beispiel #26
0
def compute_superpixel_data(img_path, tile_position, wsi_mean, wsi_stddev):

    # get slide tile source
    ts = large_image.getTileSource(img_path)

    # get requested tile information
    tile_info = ts.getSingleTile(
        tile_position=tile_position,
        resample=True,
        format=large_image.tilesource.TILE_FORMAT_NUMPY)

    im_tile = tile_info['tile'][:, :, :3]

    reference_mu_lab = [8.63234435, -0.11501964, 0.03868433]
    reference_std_lab = [0.57506023, 0.10403329, 0.01364062]

    # perform color normalization
    im_nmzd = htk_cnorm.reinhard(im_tile, reference_mu_lab, reference_std_lab,
                                 wsi_mean, wsi_stddev)
    patchSize = 32
    # compute the number of super-pixels
    im_width, im_height = im_nmzd.shape[:2]
    n_superpixels = (im_width / patchSize) * (im_height / patchSize)

    #
    # Generate labels using a superpixel algorithm (SLIC)
    # In SLIC, compactness controls image space proximity.
    # Higher compactness will make the shape of superpixels more square.
    #

    compactness = 50
    im_label = slic(im_nmzd, n_segments=n_superpixels,
                    compactness=compactness) + 1

    region_props = regionprops(im_label)

    # set superpixel data list
    s_data = []

    for i in range(len(region_props)):
        # get x, y centroids for superpixel
        cen_x, cen_y = region_props[i].centroid

        # get bounds of superpixel region
        min_row, max_row, min_col, max_col = \
            get_patch_bounds(cen_x, cen_y, patchSize, im_width, im_height)

        rgb_data = im_nmzd[min_row:max_row, min_col:max_col]

        s_data.append(rgb_data)

    return s_data
Beispiel #27
0
def tiling(path, folder, counter):

    # if counter == 0:
    ts = large_image.getTileSource(path)
    num_tiles = 0
    # print(wsi_path)
    tile_means = []
    tile_areas = []
    it = 0
    for tile_info in ts.tileIterator(
            region=dict(left=5000,
                        top=5000,
                        width=20000,
                        height=20000,
                        units='base_pixels'),
            scale=dict(magnification=20),
            tile_size=dict(width=400, height=400),
            tile_overlap=dict(x=0, y=0),
            format=large_image.tilesource.TILE_FORMAT_PIL):
        print("------------------------" + str(nm_im) + "----" + str(counter) +
              "----" + str(it) + "------------------------")
        im_tile = (tile_info['tile'])
        im_tile = np.array(im_tile)
        flag = check_image(im_tile)
        if flag:
            plt.imshow(im_tile)
            plt.show()
            print(im_tile.shape)

            cv2.imwrite('test_images/lgg/' + str(counter) + '.png', im_tile)
            counter += 1
        it += 1
        # print(it, tile_info['gheight'],tile_info['gheight'])
        # plt.imshow(im_tile)
        # plt.show()
        # if tile_info['gwidth']==2000 and tile_info['gheight']==2000:
        #     im_tile.convert('LA').save(str("im1/grayscale/")+str(it)+'.png')
        #     # plt.savefig(str("im1/color/")+str(it)+'.png')
        # # tile_mean_rgb = np.mean(im_tile[:, :, :3], axis=(0, 1))

        # # tile_means.append( tile_mean_rgb )
        # tile_areas.append( tile_info['width'] * tile_info['height'] )

        num_tiles += 1

    # slide_mean_rgb = np.average(tile_means, axis=0, weights=tile_areas)
    # print(it)
    print('Number of tiles = {}'.format(num_tiles))
    # print('Slide mean color = {}'.format(slide_mean_rgb))
    ts.getNativeMagnification()
    ts.getMagnificationForLevel(level=0)
    return counter
Beispiel #28
0
    def testTiffClosed(self):
        # test the Tiff files are properly closed.
        orig_del = TiledTiffDirectory.__del__
        orig_init = TiledTiffDirectory.__init__
        self.delCount = 0
        self.initCount = 0

        def countDelete(*args, **kwargs):
            self.delCount += 1
            orig_del(*args, **kwargs)

        def countInit(*args, **kwargs):
            self.initCount += 1
            orig_init(*args, **kwargs)

        imagePath = utilities.externaldata('data/sample_image.ptif.sha512')
        cachesClear()
        gc.collect(2)
        TiledTiffDirectory.__del__ = countDelete
        TiledTiffDirectory.__init__ = countInit
        self.initCount = 0
        self.delCount = 0
        source = large_image.getTileSource(imagePath)
        assert source is not None
        assert self.initCount == 12
        assert self.delCount < 12
        # Create another source; we shouldn't init it again, as it should be
        # cached.
        source = large_image.getTileSource(imagePath)
        assert source is not None
        assert self.initCount == 12
        assert self.delCount < 12
        source = None
        # Clear the cache to free references and force garbage collection
        cachesClear()
        gc.collect(2)
        cachesClear()
        assert self.delCount == 12
Beispiel #29
0
    def test_get_region_dict(self):

        ts = large_image.getTileSource(
            os.path.join(utilities.externaldata('data/Easy1.png.sha512')))

        result = cli_utils.get_region_dict([-1, -1, -1, -1], 2000, ts)
        expected = {}
        assert result == expected, "Expected {}, got {}".format(
            expected, result)

        result = cli_utils.get_region_dict([100, 110, 250, 240], 500, ts)
        expected = dict(region=dict(left=100, top=110, width=250, height=240))
        assert result == expected, "Expected {}, got {}".format(
            expected, result)
Beispiel #30
0
    def test_get_region_dict(self):

        ts = large_image.getTileSource(os.path.join(TEST_DATA_DIR,
                                                    'Easy1.png'))

        result = cli_utils.get_region_dict([-1, -1, -1, -1], 2000, ts)
        expected = {}
        assert result == expected, "Expected {}, got {}".format(
            expected, result)

        result = cli_utils.get_region_dict([100, 110, 250, 240], 500, ts)
        expected = dict(region=dict(left=100, top=110, width=250, height=240))
        assert result == expected, "Expected {}, got {}".format(
            expected, result)
Beispiel #31
0
def detect_tile_nuclei(slide_path, tile_position, args, **it_kwargs):

    # get slide tile source
    ts = large_image.getTileSource(slide_path)

    # get requested tile
    tile_info = ts.getSingleTile(tile_position=tile_position, **it_kwargs)

    # get tile image
    im_tile = tile_info['tile'][:, :, :3]

    # segment nuclei
    im_nuclei_seg_mask = detect_nuclei_kofahi(im_tile, args)

    # generate nuclei bounding boxes annotations
    obj_props = skimage.measure.regionprops(im_nuclei_seg_mask)

    nuclei_bbox_list = []

    gx = tile_info['gx']
    gy = tile_info['gy']
    wfrac = tile_info['gwidth'] / np.double(tile_info['width'])
    hfrac = tile_info['gheight'] / np.double(tile_info['height'])

    for i in range(len(obj_props)):

        cx = obj_props[i].centroid[1]
        cy = obj_props[i].centroid[0]
        width = obj_props[i].bbox[3] - obj_props[i].bbox[1] + 1
        height = obj_props[i].bbox[2] - obj_props[i].bbox[0] + 1

        # convert to base pixel coords
        cx = gx + cx * wfrac
        cy = gy + cy * hfrac
        width *= wfrac
        height *= hfrac

        # create annotation json
        cur_bbox = {
            "type": "rectangle",
            "center": [cx, cy, 0],
            "width": width,
            "height": height,
            "rotation": 0
        }

        nuclei_bbox_list.append(cur_bbox)

    return nuclei_bbox_list
def load_ROI(WSI_path, xml_file_path, magnification=20):
    ROI_width, ROI_height = ROI_width_and_height_on_WSI(xml_file_path)
    ROI_coords = ROI_coordinates(xml_file_path)
    left = ROI_coords[0][0]
    top = ROI_coords[0][1]
    ts = large_image.getTileSource(WSI_path)
    ROI, _ = ts.getRegionAtAnotherScale(
        sourceRegion=dict(left=left,
                          top=top,
                          width=ROI_width,
                          height=ROI_height,
                          units='base_pixels'),
        targetScale=dict(magnification=magnification),
        format=large_image.tilesource.TILE_FORMAT_NUMPY)
    return ROI
def sample_pixels(slide_path, magnification, sample_percent,
                  tissue_seg_mag=1.25, min_coverage=0.1):
    """Generates a sampling of pixels from a whole-slide image.

    Useful for generating statistics or Reinhard color-normalization or
    adaptive deconvolution. Uses mixture modeling approach to focus
    sampling in tissue regions.

    Parameters
    ----------
    slide_path : str
        path and filename of slide.
    magnification : double
        Desired magnification for sampling (defaults to native scan
        magnification).
    sample_percent : double
        Percentage of pixels to sample. Must be in the range [0, 1].
    tissue_seg_mag: double, optional
        low resolution magnification at which foreground will be segmented.
        Default value = 1.25.
    min_coverage: double, optional
        minimum sample_percent of tile covered by tissue to be included in sampling.
        Ranges between [0,1). Default value = 0.1.

    Returns
    -------
    Pixels : array_like
        A Nx3 matrix of RGB pixel values sampled from the whole-slide.

    See Also
    --------
    histomicstk.preprocessing.color_normalization.reinhard,
    histomicstk.preprocessing.color_deconvolution.SparseColorDeconvolution
    """

    ts = large_image.getTileSource(slide_path)

    # get enitre whole-silde image at low resolution
    scale_lres = {'magnification': tissue_seg_mag}
    im_lres, _ = ts.getRegion(
        format=large_image.tilesource.TILE_FORMAT_NUMPY,
        scale=scale_lres
    )
    im_lres = im_lres[:, :, :3]

    # compute foreground mask of whole-slide image at low-res
    im_fgnd_mask_lres = simple_mask(im_lres)

    # generate sample pixels
    sample_pixels = []

    scale_hres = {'magnfication': magnification}

    for tile in ts.tileIterator(
            scale=scale_hres,
            format=large_image.tilesource.TILE_FORMAT_NUMPY):

        # get current region in base_pixels
        rgn_hres = {'left': tile['gx'], 'top': tile['gy'],
                    'right': tile['gx'] + tile['gwidth'],
                    'bottom': tile['gy'] + tile['gheight'],
                    'units': 'base_pixels'}

        # get foreground mask for current tile at low resolution
        rgn_lres = ts.convertRegionScale(rgn_hres,
                                         targetScale=scale_lres,
                                         targetUnits='mag_pixels')

        tile_fgnd_mask_lres = \
            im_fgnd_mask_lres[rgn_lres['top']:rgn_lres['bottom'],
                              rgn_lres['left']:rgn_lres['right']]

        # skip tile if there is not enough foreground in the slide
        cur_fgnd_frac = tile_fgnd_mask_lres.mean()

        if np.isnan(cur_fgnd_frac) or cur_fgnd_frac <= min_coverage:
            continue

        # get current tile image
        im_tile = tile['tile'][:, :, :3]

        # get tile foreground mask at resolution of current tile
        tile_fgnd_mask = scipy.misc.imresize(
            tile_fgnd_mask_lres,
            im_tile.shape,
            interp='nearest'
        )

        # generate linear indices of sample pixels in fgnd mask
        nz_ind = np.nonzero(tile_fgnd_mask.flatten())[0]
        sample_ind = np.random.choice(nz_ind,
                                      np.ceil(sample_percent * nz_ind.size))

        # convert rgb tile image to Nx3 array
        tile_pix_rgb = np.reshape(im_tile,
                                  (im_tile.shape[0] * im_tile.shape[1], 3))

        # add rgb triplet of sample pixels
        sample_pixels.append(tile_pix_rgb[sample_ind, :])

    # concatenate pixel values in list
    try:
        sample_pixels = np.concatenate(sample_pixels, 0)
    except ValueError:
        print "Sampling could not identify any foreground regions."

    return sample_pixels