Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c7fc56d
Initial plan
Copilot Sep 9, 2025
e4ce70e
Replace aicsimageio with bioio in imports and class references
Copilot Sep 9, 2025
be54c3b
Add default physical pixel sizes to BioImage obj
jni Nov 14, 2025
ebfc88c
typo: filw -> file
jni Nov 14, 2025
df1990a
Add physical pixel size to BioImage in create_data
jni Nov 14, 2025
d31ab66
Add bioio plugin dependencies
jni Nov 14, 2025
8998f42
Use separate resolutionunit for tifffile write
jni Nov 14, 2025
337a699
Use bioio-tifffile to read raw.tif
jni Nov 15, 2025
8a616e5
Fix patch to patch bioio instead of aicsimageio
jni Nov 15, 2025
6ad1df2
update core tests
jamesyan-git Nov 25, 2025
692e429
fix dependency issues
pr4deepr Nov 26, 2025
f0c6669
use bioio for reading psf with czi extension
pr4deepr Nov 26, 2025
dc3e6ee
update dependencies
pr4deepr Nov 26, 2025
f453a3e
update fawltydeps
pr4deepr Nov 26, 2025
077e847
Update test matrix to 3.10 3.13
jni Dec 2, 2025
7aad4d1
Remove white space
jni Dec 2, 2025
d865bd9
fix issues with workflow_path when running tests locally in windows
pr4deepr Dec 2, 2025
7920379
remove bioio_bioformats
pr4deepr Dec 3, 2025
f0d6bfa
testing if modifying install order fixes tiff reading issues
pr4deepr Dec 3, 2025
d7d77cc
enable bioformats in fawltydeps
pr4deepr Dec 3, 2025
cd01a8d
tifffile to fawltydeps
pr4deepr Dec 3, 2025
4179fb8
fix tifffile in pyproject
pr4deepr Dec 3, 2025
76c9ed0
remove bioformats due to instability
pr4deepr Dec 3, 2025
b825398
add omet-tiff for tif writing
pr4deepr Dec 3, 2025
154b592
add tifffile constraints back
pr4deepr Dec 3, 2025
e82bbb6
specify min bioio-ome tif version
pr4deepr Dec 3, 2025
76b5132
change 'h5' to 'BDV h5'
jamesyan-git Dec 3, 2025
f03f86f
add to fawltydeps
pr4deepr Dec 3, 2025
21f17f5
loosen tifffile version restriction
pr4deepr Dec 3, 2025
556ad20
add testing for 3.11 3.12
pr4deepr Dec 3, 2025
306190f
remove debugging code
jamesyan-git Dec 5, 2025
8bdbc66
Merge branch 'master' into move-to-bdvh5
jamesyan-git Dec 5, 2025
91f40c0
merge latest changes
jamesyan-git Dec 5, 2025
d4f73b7
Merge branch 'move-to-bdvh5' of https://github.com/jamesyan-git/napar…
jamesyan-git Dec 5, 2025
d365716
update toml
jamesyan-git Dec 5, 2025
1763a9e
fix bdv_h5 enum bug
jamesyan-git Dec 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/lint/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ runs:
using: "composite"
steps:
- run: |
pip install fawltydeps==0.12.0
pip install fawltydeps
fawltydeps --check --detailed --verbose
shell: bash -l {0}
working-directory: ${{ inputs.directory }}
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/test_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8","3.9","3.10"] #not compatible with py 3.10 and 3.12 yet
python-version: ["3.10", "3.11", "3.12"]

env:
DISPLAY: ":99.0"
Expand All @@ -46,7 +46,7 @@ jobs:
with:
# Install a specific version of uv.
version: "0.6.17"

- name: Install core
timeout-minutes: 10
run: |
Expand Down Expand Up @@ -94,9 +94,9 @@ jobs:
# github secrets (see readme for details)
needs: [test]
runs-on: ubuntu-latest
environment:
environment:
name: github-pages
permissions:
permissions:
id-token: write
pages: write
contents: write
Expand Down Expand Up @@ -136,7 +136,7 @@ jobs:
uses: actions/deploy-pages@v4

- uses: ncipollo/release-action@v1.18.0
name: Create GitHub release
name: Create GitHub release
if: contains(github.ref, 'tags')
with:
skipIfReleaseExists: true
Expand Down
16 changes: 7 additions & 9 deletions core/lls_core/deconvolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import logging
import importlib.util
from typing import Collection, Iterable,Union,Literal, Optional, TYPE_CHECKING
from aicsimageio.aics_image import AICSImage
from bioio import BioImage
import bioio_czi
from skimage.io import imread
from aicspylibczi import CziFile
from numpy.typing import NDArray
import os
import numpy as np
Expand Down Expand Up @@ -62,12 +62,10 @@ def read_psf(psf_paths: Collection[Path],
for psf in psf_paths:
if psf.exists() and psf.is_file():
if psf.suffix == ".czi":
psf_czi = CziFile(psf.__str__())
psf_aics = psf_czi.read_image()
psf_czi = BioImage(psf.__str__(), reader=bioio_czi.Reader)
psf_aics = psf_czi.data
# make sure shape is 3D
psf_aics = psf_aics[0][0] # np.expand_dims(psf_aics[0],axis=0)
# if len(psf_aics[0])>=1:
#psf_channels = len(psf_aics[0])
psf_aics = psf_aics[0][0]
assert len(
psf_aics.shape) == 3, f"PSF should be a 3D image (shape of 3), but got {psf_aics.shape}"
# pad psf to multiple of 16 for decon
Expand All @@ -79,8 +77,8 @@ def read_psf(psf_paths: Collection[Path],
if len(psf_aics_data.shape) != 3:
raise ValueError(f"PSF should be a 3D image (shape of 3), but got {psf_aics.shape}")
else:
#Use AICSImageIO
psf_aics = AICSImage(str(psf))
#Use BioIO
psf_aics = BioImage(str(psf))
psf_aics_data = psf_aics.data[0][0]
psf_aics_data = pad_image_nearest_multiple(
img=psf_aics_data, nearest_multiple=16)
Expand Down
17 changes: 9 additions & 8 deletions core/lls_core/models/deskew.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import numpy as np

if TYPE_CHECKING:
from aicsimageio.types import PhysicalPixelSizes
from bioio import PhysicalPixelSizes

class DefinedPixelSizes(FieldAccessModel):
"""
Expand Down Expand Up @@ -161,7 +161,7 @@ def convert_skew(cls, v: Any):

@validator("physical_pixel_sizes", pre=True, always=True)
def convert_pixels(cls, v: Any, values: dict[Any, Any]):
from aicsimageio.types import PhysicalPixelSizes
from bioio import PhysicalPixelSizes
if isinstance(v, PhysicalPixelSizes):
v = DefinedPixelSizes.from_physical(v)
elif isinstance(v, tuple) and len(v) == 3:
Expand All @@ -176,15 +176,16 @@ def convert_pixels(cls, v: Any, values: dict[Any, Any]):

@root_validator(pre=True)
def read_image(cls, values: dict):
from aicsimageio import AICSImage
print("READING IMAGE DESKEW")
from bioio import BioImage
from os import fspath

img = values["input_image"]

aics: AICSImage | None = None
aics: BioImage | None = None
if is_pathlike(img):
aics = AICSImage(fspath(img))
elif isinstance(img, AICSImage):
aics = BioImage(fspath(img))
elif isinstance(img, BioImage):
aics = img
elif isinstance(img, DataArray):
if set(img.dims) >= {"Z", "Y", "X"}:
Expand All @@ -198,9 +199,9 @@ def read_image(cls, values: dict):
else:
raise ValueError("Only 3D numpy arrays are currently supported. If you have a different shape, please use a DataArray and name your dimensions C, T, Z, Y and/or Z.")
else:
raise ValueError("Value of input_image was neither a path, an AICSImage, or array-like.")
raise ValueError("Value of input_image was neither a path, a BioImage, or array-like.")

# If the image was convertible to AICSImage, we should use the metadata from there
# If the image was convertible to BioImage, we should use the metadata from there
if aics:
values["input_image"] = aics.xarray_dask_data
# Take pixel sizes from the image metadata, but only if they're defined
Expand Down
3 changes: 2 additions & 1 deletion core/lls_core/models/lattice_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class LatticeData(OutputParams, DeskewParams):

@root_validator(pre=True)
def read_image(cls, values: dict):
print("READING IMAGE LATTICE")
from lls_core.types import is_pathlike
from pathlib import Path
input_image = values.get("input_image")
Expand Down Expand Up @@ -499,7 +500,7 @@ def process_into_image(self) -> ArrayLike:

def get_writer(self) -> Type[Writer]:
from lls_core.writers import BdvWriter, TiffWriter, OMEZarrWriter
if self.save_type == SaveFileType.h5:
if self.save_type == SaveFileType.bdv_h5:
return BdvWriter
elif self.save_type == SaveFileType.tiff:
return TiffWriter
Expand Down
6 changes: 3 additions & 3 deletions core/lls_core/models/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class SaveFileType(StrEnum):
"""
Choice of File extension to save
"""
h5 = "h5"
bdv_h5 = "BDV h5"
tiff = "tiff"
omezarr = "omezarr"

Expand All @@ -30,7 +30,7 @@ class OutputParams(FieldAccessModel):
default=None
)
save_type: SaveFileType = Field(
default=SaveFileType.h5,
default=SaveFileType.bdv_h5.value,
description=f"The data type to save the result as. This will also be used to determine the file extension of the output files. Choices: `{enum_choices(SaveFileType)}`. Choices can alternatively be specifed as `str`, for example `'tiff'`."
)
time_range: range = Field(
Expand Down Expand Up @@ -58,7 +58,7 @@ def add_save_suffix(cls, v: str, values: dict):

@property
def file_extension(self):
if self.save_type == SaveFileType.h5:
if self.save_type == SaveFileType.bdv_h5:
return "h5"
elif self.save_type == SaveFileType.omezarr:
return "ome.zarr"
Expand Down
2 changes: 1 addition & 1 deletion core/lls_core/models/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def enum_choices(enum: Type[Enum]) -> str:
"""
Returns a human readable list of enum choices
"""
return "{" + ", ".join([f'"{it.name}"' for it in enum]) + "}"
return "{" + ", ".join([f'"{it.value}"' for it in enum]) + "}"

@contextmanager
def ignore_keyerror():
Expand Down
34 changes: 17 additions & 17 deletions core/lls_core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import numpy as np
from numpy.typing import NDArray
from xarray import DataArray
from aicsimageio import AICSImage
from bioio import BioImage
from os import fspath, PathLike as OriginalPathLike

# This is a superset of os.PathLike
Expand All @@ -19,20 +19,20 @@ def is_pathlike(x: Any) -> TypeGuard[PathLike]:
def is_arraylike(arr: Any) -> TypeGuard[ArrayLike]:
return isinstance(arr, (DaskArray, np.ndarray, OCLArray, DataArray))

ImageLike: TypeAlias = Union[PathLike, AICSImage, ArrayLike]
def image_like_to_image(img: ImageLike) -> DataArray:
"""
Converts an image in one of many formats to a DataArray
"""
# First try treating it as a path
try:
img = AICSImage(fspath(img))
except TypeError:
pass
if isinstance(img, AICSImage):
return img.xarray_dask_data
else:
for required_key in ("shape", "dtype", "ndim", "__array__", "__array_ufunc__"):
if not hasattr(img, required_key):
raise ValueError(f"The provided object {img} is not array like!")
ImageLike: TypeAlias = Union[PathLike, BioImage, ArrayLike]
def image_like_to_image(img: ImageLike) -> DataArray:
"""
Converts an image in one of many formats to a DataArray
"""
# First try treating it as a path
try:
img = BioImage(fspath(img))
except TypeError:
pass
if isinstance(img, BioImage):
return img.xarray_dask_data
else:
for required_key in ("shape", "dtype", "ndim", "__array__", "__array_ufunc__"):
if not hasattr(img, required_key):
raise ValueError(f"The provided object {img} is not array like!")
return DataArray(img)
3 changes: 2 additions & 1 deletion core/lls_core/writers.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ def flush(self):
str(path),
data = images_array,
bigtiff=True,
resolution=(1./self.lattice.dx, 1./self.lattice.dy, "MICROMETER"),
resolution=(1./self.lattice.dx, 1./self.lattice.dy),
resolutionunit="MICROMETER",
metadata={'spacing': self.lattice.new_dz, 'unit': 'um', 'axes': 'TZCYX'},
imagej=True
)
Expand Down
Loading
Loading