@@ -298,7 +298,6 @@ def xenium(
298
298
f"{ XeniumKeys .MORPHOLOGY_FOCUS_CHANNEL_IMAGE .value .format (0 )} to "
299
299
f"{ XeniumKeys .MORPHOLOGY_FOCUS_CHANNEL_IMAGE .value .format (len (files ) - 1 )} , found { files } "
300
300
)
301
- # the 'dummy' channel is a temporary workaround, see _get_images() for more details
302
301
if len (files ) == 1 :
303
302
channel_names = {
304
303
0 : XeniumKeys .MORPHOLOGY_FOCUS_CHANNEL_0 .value ,
@@ -309,7 +308,6 @@ def xenium(
309
308
1 : XeniumKeys .MORPHOLOGY_FOCUS_CHANNEL_1 .value ,
310
309
2 : XeniumKeys .MORPHOLOGY_FOCUS_CHANNEL_2 .value ,
311
310
3 : XeniumKeys .MORPHOLOGY_FOCUS_CHANNEL_3 .value ,
312
- 4 : "dummy" ,
313
311
}
314
312
# this reads the scale 0 for all the 1 or 4 channels (the other files are parsed automatically)
315
313
# dask.image.imread will call tifffile.imread which will give a warning saying that reading multi-file
@@ -601,6 +599,8 @@ def xenium_aligned_image(
601
599
imread_kwargs : Mapping [str , Any ] = MappingProxyType ({}),
602
600
image_models_kwargs : Mapping [str , Any ] = MappingProxyType ({}),
603
601
dims : tuple [str , ...] | None = None ,
602
+ rgba : bool = False ,
603
+ c_coords : list [str ] | None = None ,
604
604
) -> DataTree :
605
605
"""
606
606
Read an image aligned to a Xenium dataset, with an optional alignment file.
@@ -619,6 +619,13 @@ def xenium_aligned_image(
619
619
Example: for an image with shape (1, y, 1, x, 3), use dims=("anystring", "y", "dummy", "x", "c"). Values that
620
620
are not "c", "x" or "y" are considered dummy dimensions and will be squeezed (the data must have len 1 for
621
621
those axes).
622
+ rgba
623
+ Interprets the `c` channel as RGBA, by setting the channel names to `r`, `g`, `b` (`a`). When `c_coords` is not
624
+ `None`, this argument is ignored.
625
+ c_coords
626
+ Channel names for the image. By default, the function will try to infer the channel names from the image
627
+ shape and name (by detecting if the name suggests that the image is a H&E image). Example: for an RGB image with
628
+ shape (3, y, x), use c_coords=["r", "g", "b"].
622
629
623
630
Returns
624
631
-------
@@ -645,10 +652,6 @@ def xenium_aligned_image(
645
652
else :
646
653
assert len (image .shape ) == 3
647
654
assert image .shape [0 ] in [3 , 4 ]
648
- if image .shape [0 ] == 4 :
649
- # as explained before in _get_images(), we need to add a dummy channel until we support 4-channel images as
650
- # non-RGBA images in napari
651
- image = da .concatenate ([image , da .zeros_like (image [0 :1 ])], axis = 0 )
652
655
dims = ("c" , "y" , "x" )
653
656
else :
654
657
logging .info (f"Image has shape { image .shape } , parsing with dims={ dims } ." )
@@ -667,10 +670,19 @@ def xenium_aligned_image(
667
670
alignment = pd .read_csv (alignment_file , header = None ).values
668
671
transformation = Affine (alignment , input_axes = ("x" , "y" ), output_axes = ("x" , "y" ))
669
672
673
+ if c_coords is None and (rgba or image_path .name .endswith (XeniumKeys .ALIGNED_HE_IMAGE_SUFFIX )):
674
+ c_index = dims .index ("c" )
675
+ n_channels = image .shape [c_index ]
676
+ if n_channels == 3 :
677
+ c_coords = ["r" , "g" , "b" ]
678
+ elif n_channels == 4 :
679
+ c_coords = ["r" , "g" , "b" , "a" ]
680
+
670
681
return Image2DModel .parse (
671
682
image ,
672
683
dims = dims ,
673
684
transformations = {"global" : transformation },
685
+ c_coords = c_coords ,
674
686
** image_models_kwargs ,
675
687
)
676
688
@@ -790,6 +802,3 @@ def prefix_suffix_uint32_from_cell_id_str(cell_id_str: ArrayLike) -> tuple[Array
790
802
cell_id_prefix = [int (x , 16 ) for x in cell_id_prefix_hex ]
791
803
792
804
return np .array (cell_id_prefix , dtype = np .uint32 ), np .array (dataset_suffix_int )
793
-
794
-
795
- ##
0 commit comments