Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coordinateTransformations generated for 0.4 are scale-only #403

Open
d-v-b opened this issue Nov 6, 2024 · 2 comments
Open

coordinateTransformations generated for 0.4 are scale-only #403

d-v-b opened this issue Nov 6, 2024 · 2 comments

Comments

@d-v-b
Copy link

d-v-b commented Nov 6, 2024

The most common methods of image downsampling result in a translation of the downsampled image, but this code for generating coordinateTransformations metadata only returns scale transformations, which will be incorrect for almost all multiscale pyramids.

def generate_coordinate_transformations(
self, shapes: List[tuple]
) -> Optional[List[List[Dict[str, Any]]]]:
data_shape = shapes[0]
coordinate_transformations: List[List[Dict[str, Any]]] = []
# calculate minimal 'scale' transform based on pyramid dims
for shape in shapes:
assert len(shape) == len(data_shape)
scale = [full / level for full, level in zip(data_shape, shape)]
coordinate_transformations.append([{"type": "scale", "scale": scale}])
return coordinate_transformations

Suggested fix: generate translation transforms

@will-moore
Copy link
Member

Thanks for this @d-v-b.
Let me just clarify on how to generate the translations here. Looking at the spec 0.4: "If translation is given it MUST be listed after scale to ensure that it is given in physical coordinates".

So, if we have an image that has a pixel size of 1 microns then the 'scale' for each resolution would look like this (given a zoom factor of 2 between resolutions):

dataset0: {"scale": [1, 1]}
dataset1: {"scale": [2, 2]}
dataset2: {"scale": [4, 4]}
dataset3: {"scale": [8, 8]}

When mapping to physical coordinates, I guess the translation needed after scaling depends on where the 'anchor' is when you're scaling. I'm assuming that this is the centre of the pixel at [0, 0]. So after scaling then the top-left of that pixel at 2 x its original size will be at -0.5, 0.5 microns. So then we need to translate 0.5, 0.5, and so on..

dataset0: {"translation": [0, 0]}
dataset1: {"translation": [0.5, 0.5]}
dataset2: {"translation": [1.5, 1.5]}
dataset3: {"translation": [3.5, 3.5]}

So the translation for each resolution will be:

(physical-pixel-size-at-resolution-N - physical-pixel-size-at-resolution-0) / 2.

That seems to be what https://github.com/thewtex/ngff-zarr is doing when it generates translations.

@d-v-b
Copy link
Author

d-v-b commented Nov 26, 2024

yep that's basically it for the most common types of downsampling methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants