girder / large_image

Python modules to work with large multiresolution images.
http://girder.github.io/large_image/
Apache License 2.0
190 stars 41 forks source link

[help] Get level shape #1546

Open alevangel opened 2 months ago

alevangel commented 2 months ago

I'm having trouble obtaining the shape of the image level for each level. In OpenSlide, there is the parameter slide.level_dimensions[level], but I haven't found anything similar in this library. How can I accomplish that?

cooperlab commented 2 months ago

I think you can do this with a combination of the getMetadata and convertRegionScale methods of tilesource.

https://github.com/girder/large_image/blob/2ac58341d5c59d163ed4ddfce0b424ac97950da3/large_image/tilesource/base.py#L1615

The lead developer is away on leave but can respond when he returns.

alevangel commented 2 months ago

@cooperlab using getMetadata, I can only obtain information about the Whole Slide Image at the highest resolution level. However, I would also like to retrieve the shapes of other resolution levels.

cooperlab commented 2 months ago

I understand. Given the size and resolution of the native level, convertRegionScale can translate the "region" of the whole slide to other resolutions which would give you the corresponding size. large_image provides more flexibility in reading at off-level magnifications but it does complicate things a bit. I just wanted to provide a hint until @manthey can reply in case you need a quick solution.

alevangel commented 2 months ago

@cooperlab , very appreciated. Could you provide me with some example code? I can’t figure out how to implement it.

alevangel commented 2 months ago

I have attempted the following solution to address the problem at hand.

I am awaiting a response from @manthey to determine if there is a more robust solution available.

def _correct_level(self, level: int):
        max_level = self.slide.levels - 1
        # Large Image levels are in the opposite order of OpenSlide levels
        return max_level - level

def get_image_shape(self, level: int = 0):
level = self._correct_level(level)

# get magnification for level
mag = self.slide.getMagnificationForLevel(level)
metadata = self.slide.metadata

left, top, right, bottom = self.slide._getRegionBounds(
    metadata, desiredMagnification=mag)
regionWidth = right - left
regionHeight = bottom - top

if mag.get('scale') in (1.0, None):
    maxWidth, maxHeight = regionWidth, regionHeight
else:
    maxWidth = regionWidth / cast(float, mag['scale'])
    maxHeight = regionHeight / cast(float, mag['scale'])

outWidth, outHeight, calcScale = large_image.tilesource.utilities._calculateWidthHeight(
    maxWidth, maxHeight, regionWidth, regionHeight)

return outHeight, outWidth

I adapted the code provided here:

https://github.com/girder/large_image/blob/2ac58341d5c59d163ed4ddfce0b424ac97950da3/large_image/tilesource/tileiterator.py#L211C1-L227C60

cooperlab commented 2 months ago

@alevangel you can also use the result of getMetadata to define a region that is the entire slide full magnification, and then convert this to other magnifications using convertRegionScale. You would set sourceRegion['units']='base_pixels' and then use getMagnificationForLevel to determine the targetScale argument value.