Skip to content

Commit f05730d

Browse files
authored
Merge pull request #44 from petebankhead/updates
Update dependencies, use BioIO, fix triangle threshold line
2 parents 04a1af4 + 41f12f6 commit f05730d

9 files changed

Lines changed: 71 additions & 63 deletions

File tree

.github/workflows/build-book.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ jobs:
1919
run:
2020
shell: bash -el {0}
2121
steps:
22-
- uses: actions/checkout@v3
22+
- uses: actions/checkout@v4
2323

2424
# Install dependencies
25-
- uses: conda-incubator/setup-miniconda@v2
25+
- uses: conda-incubator/setup-miniconda@v3
2626
with:
27-
python-version: '3.10'
27+
python-version: '3.12'
2828
mamba-version: "*"
2929
channels: conda-forge,defaults
3030
channel-priority: true
@@ -37,7 +37,7 @@ jobs:
3737
3838
# Upload the book's html (can download to check it)
3939
- name: Upload artifact
40-
uses: actions/upload-artifact@v3
40+
uses: actions/upload-artifact@v4
4141
with:
4242
name: bioimage-book-html
4343
path: _build/html

.github/workflows/deploy-book.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ jobs:
1919
run:
2020
shell: bash -el {0}
2121
steps:
22-
- uses: actions/checkout@v3
22+
- uses: actions/checkout@v4
2323

2424
# Install dependencies
25-
- uses: conda-incubator/setup-miniconda@v2
25+
- uses: conda-incubator/setup-miniconda@v3
2626
with:
27-
python-version: '3.10'
27+
python-version: '3.12'
2828
mamba-version: "*"
2929
channels: conda-forge,defaults
3030
channel-priority: true
@@ -38,7 +38,7 @@ jobs:
3838
3939
# Push the book's HTML to github-pages
4040
- name: GitHub Pages action
41-
uses: peaceiris/actions-gh-pages@v3.6.1
41+
uses: peaceiris/actions-gh-pages@v4
4242
with:
4343
github_token: ${{ secrets.GITHUB_TOKEN }}
4444
publish_dir: ./_build/html

.github/workflows/push_translations.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ jobs:
1717
run:
1818
shell: bash -el {0}
1919
steps:
20-
- uses: actions/checkout@v3
20+
- uses: actions/checkout@v4
2121

2222
# Install dependencies
23-
- uses: conda-incubator/setup-miniconda@v2
23+
- uses: conda-incubator/setup-miniconda@v3
2424
with:
25-
python-version: '3.10'
25+
python-version: '3.12'
2626
mamba-version: "*"
2727
channels: conda-forge,defaults
2828
channel-priority: true

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ Changelog
44
This page summarizes the main changes.
55
To see all changes, check out the [commit log](https://github.com/bioimagebook/bioimagebook.github.io/commits/main).
66

7+
## 2 July 2025
8+
* Dependency updates
9+
* Replace AICSImageIO with BioIO
10+
* Fix triangle threshold line
11+
* With thanks to Emily Shin
12+
713
## 5 February 2024
814
* Add initial support for translations
915
* With huge thanks to @bethac07!

_config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
title : "Introduction to Bioimage Analysis"
22
author : "Pete Bankhead" # The author of the book
3-
copyright : "2022-2024" # Copyright year to be placed in the footer
3+
copyright : "2022-2025" # Copyright year to be placed in the footer
44
logo : 'images/book-logo-smaller.png'
55

66
exclude_patterns : [_build, Thumbs.db, .DS_Store, "locales/_build/**", "**.ipynb_checkpoints", '_unused/**', 'nbs/*']

chapters/1-concepts/5-pixel_size/python.md

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ jupytext:
55
extension: .md
66
format_name: myst
77
format_version: 0.13
8-
jupytext_version: 1.14.5
8+
jupytext_version: 1.17.2
99
kernelspec:
10+
name: python3
1011
display_name: Python 3 (ipykernel)
1112
language: python
12-
name: python3
1313
---
1414

1515
# Python: Pixel size & dimensions
@@ -34,12 +34,10 @@ The situation is improving though.
3434

3535
Here, we'll look at accessing pixel size information using two popular image-reading libraries:
3636
* [`imageio`](https://pypi.org/project/imageio/) - which very commonly used, and makes reading lots of common image types straightforward
37-
* [`AICSImageIO`](https://pypi.org/project/aicsimageio/3.2.1/) - which is a bit more complex, but has some *extremely* useful features for working with scientific images
37+
* [`bioio`](https://bioio-devs.github.io/bioio) - which is a bit more complex, but has some *extremely* useful features for working with scientific images
3838

3939
+++
4040

41-
42-
4341
### ImageIO
4442

4543
To explore pixel sizes with `imageio`, let's return to the neuron image used in the 'Channels & colors' chapter.
@@ -98,41 +96,41 @@ So while `imageio` is excellent for reading images easily - generally just a qui
9896

9997
+++
10098

101-
### Using AICSImageIO
99+
### Using BioIO
102100

103-
The best alternative I know for working with scientific (especially biomedical) images is [**AICSImageIO**](https://github.com/AllenCellModeling/aicsimageio).
101+
The best alternative I know for working with scientific (especially biomedical) images is [**BioIO**](https://bioio-devs.github.io/bioio) (the successor to [AICSImageIO](https://github.com/AllenCellModeling/aicsimageio)).
104102
This is a really useful Python library that standardizes reading and writing multiple file formats - and, depending upon how it's installed, can even access lots more awkward proprietary file formats with the help of [Bio-Formats](http://www.openmicroscopy.org/bio-formats/).
105103

106-
Although it's possible to use a version of `imread` with AICSImageIO, it's worth learning the alternative way of doing things by creating an `AICSImage` object.
104+
Although it's possible to use a version of `imread` with BioIO, it's worth learning the alternative way of doing things by creating an `BioImage` object.
107105
This provides us with a way to access pixels and lots of other useful things whenever we need them.
108106

109107
```{code-cell} ipython3
110-
from aicsimageio.aics_image import AICSImage
108+
from bioio import BioImage
111109
112-
# Create an AICSImage
113-
img_aics = AICSImage(path)
110+
# Create a BioImage
111+
img_bio = BioImage(path)
114112
115113
# Print its main attributes
116-
print(img_aics)
117-
for d in dir(img_aics):
114+
print(img_bio)
115+
for d in dir(img_bio):
118116
if not d.startswith('_'):
119117
print(d)
120118
```
121119

122120
From this, we can immediately see the attribute that will provide us with pixel sizes directly.
123121

124122
```{code-cell} ipython3
125-
print(img_aics.physical_pixel_sizes)
123+
print(img_bio.physical_pixel_sizes)
126124
```
127125

128-
One perhaps non-obvious thing to know when using AICSImageIO is that the `AICSImage` isn't a regular NumPy array of the kind that `imageio.imread` would return.
126+
One perhaps non-obvious thing to know when using BioIO is that the `BioImage` isn't a regular NumPy array of the kind that `imageio.imread` would return.
129127
Rather, if you want that, you need to request the data.
130128

131129
Using this knowledge, we can check that we have the same mean pixel value for both - as a quick way to ascertain that the actual pixel values are likely to match.
132130

133131
```{code-cell} ipython3
134132
print(f'Mean pixel value from imageio: {im_iio.mean():.2f} (total pixel count {im_iio.size})')
135-
print(f'Mean pixel value from AICSImageIO: {img_aics.data.mean():.2f} (total pixel count {img_aics.data.size})')
133+
print(f'Mean pixel value from BioIO: {img_bio.data.mean():.2f} (total pixel count {img_bio.data.size})')
136134
```
137135

138136
## Dimensions
@@ -146,7 +144,7 @@ We might well expect that the NumPy arrays representing the pixel values are the
146144
NumPy is incredibly flexible when it comes to handling multidimensional arrays.
147145
And while that flexibility can be really helpful, it can also complicate things.
148146

149-
To see it in action, let's check the dimensions of the images we read using imageio and AICSImageIO.
147+
To see it in action, let's check the dimensions of the images we read using imageio and BioIO.
150148

151149
```{code-cell} ipython3
152150
# Print shape of image read by imageio
@@ -155,26 +153,26 @@ path = find_image('Rat_Hippocampal_Neuron.tif')[0]
155153
im_iio = iio.imread(path)
156154
print(f'Shape of image read by imageio: {im_iio.shape}')
157155
158-
# Print shape of image read by AICSImageIO
159-
from aicsimageio.aics_image import AICSImage
160-
im_aics = AICSImage(path).data
161-
print(f'Shape of image read by AICSImageIO: {im_aics.shape}')
156+
# Print shape of image read by bioio
157+
from bioio import BioImage
158+
im_bio = BioImage(path).data
159+
print(f'Shape of image read by BioIO: {im_bio.shape}')
162160
163-
print(f'Arrays the same? {np.array_equal(im_aics, im_iio)}')
161+
print(f'Arrays the same? {np.array_equal(im_bio, im_iio)}')
164162
```
165163

166-
We can see the number of pixels are the same, but there are some extra 'singleton' dimensions stuck into the results from AICSImageIO (i.e. with length `1`).
164+
We can see the number of pixels are the same, but there are some extra 'singleton' dimensions stuck into the results from BioIO (i.e. with length `1`).
167165

168166
Fortunately, we can easily remove them with an `np.squeeze` - and end up with the same arrays.
169167

170168
```{code-cell} ipython3
171-
im_aics_squeezed = np.squeeze(im_aics)
172-
print(f'Shape of image read by AICSImageIO & squeezed: {im_aics_squeezed.shape}')
169+
im_bio_squeezed = np.squeeze(im_bio)
170+
print(f'Shape of image read by BioIO & squeezed: {im_bio_squeezed.shape}')
173171
174-
print(f'Arrays the same? {np.array_equal(im_aics_squeezed, im_iio)}')
172+
print(f'Arrays the same? {np.array_equal(im_bio_squeezed, im_iio)}')
175173
```
176174

177-
So a natural question is: **why has AICSImageIO snuck in some extra dimensions?**
175+
So a natural question is: **why has BioIO snuck in some extra dimensions?**
178176

179177
Before answering that, we should ask ourselves something else.
180178
**What exactly do we _have_ along the dimension of length `5`?**
@@ -201,12 +199,12 @@ for ii in range(n_slices):
201199
To me, that looks very much like we have 5 different channels.
202200
I'm making some assumptions there... but they seem pretty safe assumptions.
203201

204-
However AICSImageIO removes this ambiguity in a couple of ways.
205-
1. You can expect `AICSImage` to return a 5D array, with the dimensions in a consistent order: `TCZYX` (although there is at least one caveat in the next section!)
202+
However BioIO removes this ambiguity in a couple of ways.
203+
1. You can expect `BioIO` to return a 5D array, with the dimensions in a consistent order: `TCZYX` (although there is at least one caveat in the next section!)
206204
2. You can easily query the dimensions and order to be sure
207205

208206
```{code-cell} ipython3
209-
image = AICSImage(path)
207+
image = BioImage(path)
210208
print(image.dims)
211209
print(f'Shape: {image.dims.shape}')
212210
print(f'Order: {image.dims.order}')
@@ -266,19 +264,19 @@ except Exception as ex:
266264
So imageio might get channels at the start or the end.
267265
For RGB, it seems to prefer the end.
268266

269-
What does AICSImageIO do?
267+
What does BioIO do?
270268

271-
Since I said AICSImageIO is consistent, I'd like to say it puts the channels in the same place for the RGB and 5-channel image... but no.
269+
Since I said BioIO is consistent, I'd like to say it puts the channels in the same place for the RGB and 5-channel image... but no.
272270
It also treats RGB as a special case.
273271

274272
```{code-cell} ipython3
275-
image = AICSImage(path)
273+
image = BioImage(path)
276274
277275
print(image.shape)
278276
print(image.dims.order)
279277
```
280278

281-
It's a little hard to find, but the AICSImageIO documentation mentions that [you can expect 5 dimensions for non-RGB images, but RGB images have 6 dimensions](https://allencellmodeling.github.io/aicsimageio/aicsimageio.readers.html#aicsimageio.readers.bioformats_reader.BioFile.to_numpy) - where the sixth is called `S` for `Samples`.
279+
It's a little hard to find, but the BioIO documentation mentions that [you can expect 5 dimensions for non-RGB images, but RGB images have 6 dimensions](https://bioio-devs.github.io/bioio/bioio.html#bioio.bio_image.BioImage.get_image_data) - where the sixth is called `S` for `Samples`.
282280

283281
The good thing is that, assuming you don't have anything else going on with the first 3 dimensions - i.e. they are just `(1, 1, 1)` - a simple `np.squeeze` is enough to convert the pixel array into a matplotlib-friendly channels-last RGB format.
284282

chapters/1-concepts/6-files/python.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ jupytext:
55
extension: .md
66
format_name: myst
77
format_version: 0.13
8-
jupytext_version: 1.14.5
8+
jupytext_version: 1.17.2
99
kernelspec:
10+
name: python3
1011
display_name: Python 3 (ipykernel)
1112
language: python
12-
name: python3
1313
---
1414

1515
# Python: Files & file formats
@@ -97,9 +97,9 @@ im = tifffile.imread(path)
9797
print(f'Print the mean for comparison: {im.mean()}')
9898
```
9999

100-
### AICSImageIO
100+
### BioIO
101101

102-
[AICSImageIO](https://github.com/AllenCellModeling/aicsimageio) is an excellent package for reading lots of image formats in Python - and is particularly strong when it comes to reading multidimensional images and metadata.
102+
[BioIO](https://bioio-devs.github.io/bioio/) is an excellent package for reading lots of image formats in Python - and is particularly strong when it comes to reading multidimensional images and metadata.
103103

104104
It can even handle a variety of microscopy formats, and optionally use [Bio-Formats](https://www.openmicroscopy.org/bio-formats/).
105105

@@ -126,4 +126,4 @@ Dask isn't an image reading package, but [dask-image](https://image.dask.org/) i
126126

127127
Finally, [Napari](https://napari.org) isn't an image reading library either; rather, it's a fantastic open-source, extensible, multidimensional image viewer for Python.
128128

129-
Napari can bring everything together - working with dask arrays and reading images with plugins, such as [napari-aicsimageio](https://github.com/AllenCellModeling/napari-aicsimageio) and [napari-lazy-openslide](https://github.com/manzt/napari-lazy-openslide).
129+
Napari can bring everything together - working with dask arrays and reading images with plugins, such as [napari-lazy-openslide](https://github.com/manzt/napari-lazy-openslide).

chapters/2-processing/3-thresholding/thresholding.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -770,8 +770,8 @@ def plot_triangle_threshold(im, bins, thresh, pos=None):
770770
x3 = centers[int(thresh)]
771771
y3 = hist[int(thresh)]
772772
n = np.sqrt((y2 - y1)**2 + (x2 - x1)**2)
773-
x4 = (y2 - y1) / n
774-
y4 = -(x2 - x1) / n
773+
x4 = x3 + (y2 - y1) / n
774+
y4 = y3 - (x2 - x1) / n
775775
# Find intersection
776776
# Thank you, wikipedia
777777
# https://en.wikipedia.org/wiki/Line–line_intersection#Given_two_points_on_each_line

environment.yml

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,21 @@ name: bioimage-book
22
channels:
33
- conda-forge
44
dependencies:
5-
- python=3.10
6-
- aicsimageio=4.10.*
5+
- python=3.12
76
- imageio
8-
- jupyter-book=0.15.*
7+
- jupyter-book=1.0.*
98
- jupytext
109
- matplotlib=3.8.*
1110
- myst-nb
12-
- nbclassic=1.0.*
13-
- numpy=1.26.*
14-
- pandas=2.2.*
15-
- scikit-image=0.22.*
16-
- scipy=1.12.*
17-
- sphinx-intl=2.1.*
18-
- sphinx-sitemap=2.5.*
11+
- nbclassic=1.3.*
12+
- numpy=2.3.*
13+
- pandas=2.3.*
14+
- scikit-image=0.25.*
15+
- scipy=1.16.*
16+
- sphinx-intl=2.3.*
17+
- sphinx-sitemap=2.7.*
18+
- pip
19+
- pip:
20+
- bioio
21+
- bioio-tifffile
22+
- bioio-imageio

0 commit comments

Comments
 (0)