Beispiel #1
0
    def __init__(self, path, **kwargs):
        """
        Initialize the tile class.  See the base class for other available
        parameters.

        :param path: a filesystem path for the tile source.
        """
        super(TiffFileTileSource, self).__init__(path, **kwargs)

        largeImagePath = self._getLargeImagePath()
        try:
            alldir = self._scanDirectories()
        except (ValidationTiffException, TiffException) as exc:
            alldir = []
            lastException = exc

        # If there are no tiled images, raise an exception.
        if not len(alldir):
            msg = "File %s didn't meet requirements for tile source: %s" % (
                largeImagePath, lastException)
            config.getConfig('logger').debug(msg)
            raise TileSourceException(msg)
        # Sort the known directories by image area (width * height).  Given
        # equal area, sort by the level.
        alldir.sort()
        # The highest resolution image is our preferred image
        highest = alldir[-1][-1]
        directories = {}
        # Discard any images that use a different tiling scheme than our
        # preferred image
        for tdir in alldir:
            td = tdir[-1]
            level = tdir[2]
            if (td.tileWidth != highest.tileWidth or
                    td.tileHeight != highest.tileHeight):
                if not len(self._associatedImages):
                    self._addAssociatedImage(largeImagePath, tdir[-2], True, highest)
                continue
            # If a layer's image is not a multiple of the tile size, it should
            # be near a power of two of the highest resolution image.
            if (((td.imageWidth % td.tileWidth) and
                    not nearPowerOfTwo(td.imageWidth, highest.imageWidth)) or
                    ((td.imageHeight % td.tileHeight) and
                        not nearPowerOfTwo(td.imageHeight, highest.imageHeight))):
                continue
            directories[level] = td
        if not len(directories) or (len(directories) < 2 and max(directories.keys()) + 1 > 4):
            raise TileSourceException(
                'Tiff image must have at least two levels.')

        # Sort the directories so that the highest resolution is the last one;
        # if a level is missing, put a None value in its place.
        self._tiffDirectories = [directories.get(key) for key in
                                 range(max(directories.keys()) + 1)]
        self.tileWidth = highest.tileWidth
        self.tileHeight = highest.tileHeight
        self.levels = len(self._tiffDirectories)
        self.sizeX = highest.imageWidth
        self.sizeY = highest.imageHeight
Beispiel #2
0
def testNearPowerOfTwo():
    assert nearPowerOfTwo(45808, 11456)
    assert nearPowerOfTwo(45808, 11450)
    assert not nearPowerOfTwo(45808, 11200)
    assert nearPowerOfTwo(45808, 11400)
    assert not nearPowerOfTwo(45808, 11400, 0.005)
    assert nearPowerOfTwo(45808, 11500)
    assert not nearPowerOfTwo(45808, 11500, 0.005)
Beispiel #3
0
 def _checkSeries(self, rdr):
     firstPossibleAssoc = self._getSeriesStarts(rdr)
     self._metadata['seriesAssociatedImages'] = {}
     for seriesNum in range(firstPossibleAssoc,
                            self._metadata['seriesCount']):
         if any((seriesNum in series['series'])
                for series in self._metadata['frameSeries']):
             continue
         rdr.setSeries(seriesNum)
         info = {
             'sizeX': rdr.getSizeX(),
             'sizeY': rdr.getSizeY(),
         }
         if (info['sizeX'] < self._associatedImageMaxSize
                 and info['sizeY'] < self._associatedImageMaxSize):
             # TODO: Figure out better names for associated images.  Can
             # we tell if any of them are the macro or label image?
             info['seriesNum'] = seriesNum
             self._metadata['seriesAssociatedImages']['image%d' %
                                                      seriesNum] = info
     validate = None
     for frame in self._metadata['frameSeries']:
         for level in range(len(frame['series'])):
             rdr.setSeries(frame['series'][level])
             info = {
                 'sizeX': rdr.getSizeX(),
                 'sizeY': rdr.getSizeY(),
             }
             if not level:
                 frame.update(info)
                 self._metadata['sizeX'] = max(self._metadata['sizeX'],
                                               frame['sizeX'])
                 self._metadata['sizeY'] = max(self._metadata['sizeY'],
                                               frame['sizeY'])
             elif validate is not False:
                 if (not nearPowerOfTwo(frame['sizeX'], info['sizeX']) or
                         not nearPowerOfTwo(frame['sizeY'], info['sizeY'])):
                     frame['series'] = frame['series'][:level]
                     validate = True
         if validate is None:
             validate = False
     rdr.setSeries(0)
     self._metadata['sizeXY'] = len(self._metadata['frameSeries'])
Beispiel #4
0
    def _getAvailableLevels(self, path):
        """
        Some SVS files (notably some NDPI variants) have levels that cannot be
        read.  Get a list of levels, check that each is at least potentially
        readable, and return a list of these sorted highest-resolution first.

        :param path: the path of the SVS file.  After a failure, the file is
            reopened to reset the error state.
        :returns: levels.  A list of valid levels, each of which is a
            dictionary of level (the internal 0-based level number), width, and
            height.
        """
        levels = []
        svsLevelDimensions = self._openslide.level_dimensions
        for svslevel in range(len(svsLevelDimensions)):
            try:
                self._openslide.read_region((0, 0), svslevel, (1, 1))
                level = {
                    'level': svslevel,
                    'width': svsLevelDimensions[svslevel][0],
                    'height': svsLevelDimensions[svslevel][1],
                }
                if level['width'] > 0 and level['height'] > 0:
                    # add to the list so that we can sort by resolution and
                    # then by earlier entries
                    levels.append((level['width'] * level['height'],
                                   -len(levels), level))
            except openslide.lowlevel.OpenSlideError:
                self._openslide = openslide.OpenSlide(path)
        # sort highest resolution first.
        levels = [
            entry[-1]
            for entry in sorted(levels, reverse=True, key=lambda x: x[:-1])
        ]
        # Discard levels that are not a power-of-two compared to the highest
        # resolution level.
        levels = [
            entry for entry in levels
            if nearPowerOfTwo(levels[0]['width'], entry['width'])
            and nearPowerOfTwo(levels[0]['height'], entry['height'])
        ]
        return levels
Beispiel #5
0
    def __init__(self, path, **kwargs):
        """
        Initialize the tile class.  See the base class for other available
        parameters.

        :param path: a filesystem path for the tile source.
        """
        super(TiffFileTileSource, self).__init__(path, **kwargs)

        largeImagePath = self._getLargeImagePath()
        lastException = None
        # Associated images are smallish TIFF images that have an image
        # description and are not tiled.  They have their own TIFF directory.
        # Individual TIFF images can also have images embedded into their
        # directory as tags (this is a vendor-specific method of adding more
        # images into a file) -- those are stored in the individual
        # directories' _embeddedImages field.
        self._associatedImages = {}

        # Query all know directories in the tif file.  Only keep track of
        # directories that contain tiled images.
        alldir = []
        for directoryNum in itertools.count():  # pragma: no branch
            try:
                td = TiledTiffDirectory(largeImagePath, directoryNum)
            except ValidationTiffException as exc:
                lastException = exc
                self._addAssociatedImage(largeImagePath, directoryNum)
                continue
            except TiffException as exc:
                if not lastException:
                    lastException = exc
                break
            if not td.tileWidth or not td.tileHeight:
                continue
            # Calculate the tile level, where 0 is a single tile, 1 is up to a
            # set of 2x2 tiles, 2 is 4x4, etc.
            level = int(
                math.ceil(
                    math.log(
                        max(
                            float(td.imageWidth) / td.tileWidth,
                            float(td.imageHeight) / td.tileHeight)) /
                    math.log(2)))
            if level < 0:
                continue
            # Store information for sorting with the directory.
            alldir.append((level > 0, td.tileWidth * td.tileHeight, level,
                           td.imageWidth * td.imageHeight, directoryNum, td))
        # If there are no tiled images, raise an exception.
        if not len(alldir):
            msg = "File %s didn't meet requirements for tile source: %s" % (
                largeImagePath, lastException)
            config.getConfig('logger').debug(msg)
            raise TileSourceException(msg)
        # Sort the known directories by image area (width * height).  Given
        # equal area, sort by the level.
        alldir.sort()
        # The highest resolution image is our preferred image
        highest = alldir[-1][-1]
        directories = {}
        # Discard any images that use a different tiling scheme than our
        # preferred image
        for tdir in alldir:
            td = tdir[-1]
            level = tdir[2]
            if (td.tileWidth != highest.tileWidth
                    or td.tileHeight != highest.tileHeight):
                if not len(self._associatedImages):
                    self._addAssociatedImage(largeImagePath, tdir[-2], True,
                                             highest)
                continue
            # If a layer's image is not a multiple of the tile size, it should
            # be near a power of two of the highest resolution image.
            if (((td.imageWidth % td.tileWidth)
                 and not nearPowerOfTwo(td.imageWidth, highest.imageWidth)) or
                ((td.imageHeight % td.tileHeight)
                 and not nearPowerOfTwo(td.imageHeight, highest.imageHeight))):
                continue
            directories[level] = td
        if not len(directories) or (len(directories) < 2
                                    and max(directories.keys()) + 1 > 4):
            raise TileSourceException(
                'Tiff image must have at least two levels.')

        # Sort the directories so that the highest resolution is the last one;
        # if a level is missing, put a None value in its place.
        self._tiffDirectories = [
            directories.get(key) for key in range(max(directories.keys()) + 1)
        ]
        self.tileWidth = highest.tileWidth
        self.tileHeight = highest.tileHeight
        self.levels = len(self._tiffDirectories)
        self.sizeX = highest.imageWidth
        self.sizeY = highest.imageHeight