Skip to content

VisiumHD: load scalefactor microns_per_pixel in anndata #286

@ConstensouxAlexis

Description

@ConstensouxAlexis

Hello,
Segmentation of nuclei on VisiumHD H&E image might require (at least for StarDist segmentation model) to have the micron per pixel information (since pre trained models can be trained on H&E images with different micron per pixel ratio, it is sometimes needed to rescale the image).
Could it be possibe for the visiumHD reader to parse this info and store it somewhere in the Anndata ? Thank you very much !
Alexis

Activity

LucaMarconato

LucaMarconato commented on Mar 11, 2025

@LucaMarconato
Member

Hi @ConstensouxAlexis, would it be an option to retrieve this coefficient from the coordinate transformation metadata?

from spatialdata.transformations import get_transformation

transformation = get_transformation(sdata['my_element'], to_coordinate_system='my_coordinate_system')
# if it's a scale
print(transformation.scale)
# in the general case, to get the `x` scale factor
transformation.to_affine_matrix(input_axes=('x',), output_axes=('x',)).flatten().item()

Adding the metadata would work for VisiumHD, but the approach above (or something adapted from it) would work for any tech and any image.
Please let me know what you think.

ConstensouxAlexis

ConstensouxAlexis commented on Mar 11, 2025

@ConstensouxAlexis
Author

Hi, thank you for your answer ! I might be wrong, but I think that if we want to derive the number of micron per pixel from the transformation metadata, we need for at least one image resolution the absolute value of the number of microns per pixel.

I think that this value depends on the microscope used to generate the full resolution image. For instance, on my VisiumHD samples, this value is different accross samples, thus the "micron_per_pixel" key in the scalefactors.json is different. However I think my usecase is marginal and I am fine parsing this value manually !

LucaMarconato

LucaMarconato commented on Mar 11, 2025

@LucaMarconato
Member

You are right, in the sense that the information on how to map pixels to microns should be present somewhere in the transformations, but if this is available there is no need to explicitly pass the metadata. Practically, the general case is that there is a series of transformations to map the image to a physical space (let's call it "micron" coordinate system). Then instead of get_transformation() one would call get_transformation_between_coordinate_systems(), between the image and the "micron" coordinate system.

Also the functions described in this issue would be of help: scverse/spatialdata#436. Regarding timelines, we are currently working on the OME-NGFF side to push for the release of the coordinate transformation specification. When this is available the ergonomics around working with units will improve, by implementing the functions in the issue above above.

For the moment I'd suggest either get_transformation() or get_transformation_between_coordinate_systems(), or manually adding the additional metadata.

  • Finally we could double check in the VisiumHD reader that the information on pixels to microns is present (ensuring that the coordinate systems express the coordinates in microns).
ConstensouxAlexis

ConstensouxAlexis commented on Mar 12, 2025

@ConstensouxAlexis
Author

Ok, thank you very much for explanations !

quentinblampey

quentinblampey commented on Aug 29, 2025

@quentinblampey
Contributor

Hi @ConstensouxAlexis,

I was also interested in accessing the microns_to_pixel value, but, since there is no microns coordinate system when reading the Visium HD data, it's not possible to simply use the information from the transformations.

I found a way to access it via the bins surfaces:

for key, geo_df in sdata.shapes.items():
    diameter = int(key[-5:-2]) # bin width in microns
    area = geo_df.geometry.iloc[0].area # bin area based on the shapes, in pixels^2

    # the line below depends on the bins_as_squares argument you used in the reader
    microns_per_pixel = diameter / (np.sqrt(area) if bins_as_squares else geo_df["radius"].iloc[0] * 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @LucaMarconato@quentinblampey@ConstensouxAlexis

        Issue actions

          VisiumHD: load scalefactor microns_per_pixel in anndata · Issue #286 · scverse/spatialdata-io