Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 2 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
Package: ImageArray
Type: Package
Title: A framework for on-disk and in-memory image arrays
Version: 1.1.0
Date: 2026-01-20
Version: 1.1.2
Authors@R:
person("Artür", "Manukyan",
role=c("aut", "cre", "fnd"),
Expand All @@ -13,7 +12,6 @@ Description: ImageArray provides a framework for on-disk and in-memory image
Zarr and life sciences image file formats (OME Bio-Formats).
License: MIT + file LICENSE
Encoding: UTF-8
RoxygenNote: 7.3.3
biocViews: Software, Visualization
Depends:
R (>= 4.5.0),
Expand Down Expand Up @@ -42,3 +40,4 @@ Config/testthat/edition: 3
VignetteBuilder: knitr
URL: https://github.com/BIMSBbioinfo/ImageArray
BugReports: https://github.com/BIMSBbioinfo/ImageArray/issues
Config/roxygen2/version: 8.0.0
14 changes: 0 additions & 14 deletions NEWS

This file was deleted.

7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# ImageArray 1.1.2

## NEW FEATURES

* Images with any combination of XYZCT dimensions are can now be read.
See OME webpage for more information:
https://docs.openmicroscopy.org/ome-model/6.2.2/ome-tiff/specification.html#dimensionorder
30 changes: 16 additions & 14 deletions R/BFArray.R
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ BFArray <- function(image.file, series, resolution) {
len_meta <- lengths(meta.data@.Data)
meta.data@.Data <- meta.data@.Data[which(len_meta > 0)]

# full image axes from metadata (always lowercase)
if( "coreMetadata" %in% names(meta.data)) {
axes <- meta.data$coreMetadata$dimensionOrder
} else if ("coreMetadata" %in% names(meta.data[[1]])) {
axes <- meta.data@.Data[[1]]$coreMetadata$dimensionOrder
}
axes <- tolower(unlist(strsplit(axes, "")))

# get shape
series_res_meta <- vapply(
meta.data@.Data,
Expand All @@ -58,7 +66,7 @@ BFArray <- function(image.file, series, resolution) {
)
if (length(series_index) > 0) {
shape <- vapply(
c("sizeX", "sizeY", "sizeC"),
sprintf("size%s", toupper(axes)),
function(x) {
md <- meta.data@.Data[[series_index]]
if (!is.null(cm <- md$coreMetadata)) {
Expand All @@ -69,6 +77,10 @@ BFArray <- function(image.file, series, resolution) {
integer(1),
USE.NAMES = FALSE
)

names(shape) <- toupper(axes)
# remove dimensions with size 1 to mimic RBioFormats::read.image behavior
shape <- shape[shape > 1]

seed <- BFArraySeed(
filepath = image.file,
Expand Down Expand Up @@ -100,7 +112,7 @@ BFArraySeed <- function(filepath, series, resolution, shape, type) {
###

#' @describeIn BFArray-methods dim function for BFArray objects
setMethod("dim", "BFArraySeed", function(x) x@shape)
setMethod("dim", "BFArraySeed", function(x) unname(x@shape))

### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### type() getter
Expand All @@ -120,11 +132,6 @@ setMethod("type", "BFArraySeed", function(x) x@type)
stop("Please install RBioFormats: BiocManager::install('RBioFormats')")
}

# check for index length
if (length(index) > 3) {
stop("You cannot get BFArray slices more than 2 dimensions!")
}

# create slices
ind <- mapply(
function(x, y) {
Expand All @@ -147,20 +154,15 @@ setMethod("type", "BFArraySeed", function(x) x@type)
res <- array(dim = len_ind)
type(res) <- x@type
} else {
subset_list <- list(X = ind[[1]], Y = ind[[2]])
if (length(len_ind) == 3) {
subset_list <- c(subset_list, list(C = ind[[3]]))
}
subset_list <- setNames(ind , names(x@shape))
res <- RBioFormats::read.image(
file = x@filepath,
series = x@series,
resolution = x@resolution,
subset = subset_list
)
res <- EBImage::imageData(res)
if (length(dim(res)) != 3) {
res <- array(res, dim = c(dim(res), 1))
}
dim(res) <- len_ind
}

res
Expand Down
13 changes: 9 additions & 4 deletions R/ImageArray.R
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ createBFArray <- function(
image_list <- lapply(resolution, function(res) {
BFArray(image, series = series, resolution = res)
})
ImageArray(meta = list(axes = c("x", "y", "c")), levels = image_list)
ImageArray(meta = list(axes = tolower(names(image_list[[1]]@seed@shape))), levels = image_list)
}

#' createMagickArray
Expand Down Expand Up @@ -279,10 +279,13 @@ createMagickArray <- function(
stop("'n.levels' has to be 1 or a larger integer value!")
}

# create image levels
# get axes, EBImage accepts XY or XYC
axes <- c("c", "x", "y")
if (verbose) {
.img_create_msg(dim(image), 1)
}

# create image levels
image_data <- magick::image_data(image, channels = "rgb")
storage.mode(image_data) <- "integer"
image_list <- list(DelayedArray::DelayedArray(as.array(image_data)))
Expand All @@ -306,7 +309,7 @@ createMagickArray <- function(
}

# return
ImageArray(meta = list(axes = c("c", "x", "y")), levels = image_list)
ImageArray(meta = list(axes = axes), levels = image_list)
}

#' createMagickArray
Expand Down Expand Up @@ -354,7 +357,7 @@ createEBImageArray <- function(
# check dim
.check_dim(image)

# create image levels
# get axes, EBImage accepts XY or XYC
meta <- list(axes = c("x", "y", "c"))
if (verbose) {
.img_create_msg(dim_image, 1)
Expand All @@ -363,6 +366,8 @@ createEBImageArray <- function(
meta[["axes"]] <- meta[["axes"]][img_perm]
img_perm <- stats::setNames(img_perm, meta[["axes"]])
img <- aperm(image, img_perm)

# create image levels
image_list <- list(DelayedArray::DelayedArray(img))
if (n.levels > 1) {
cur_image <- image
Expand Down
2 changes: 1 addition & 1 deletion R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,4 @@ is.sequential <- function(x) {

#' @keywords internal
#' @noRd
.AXES <- c("c", "y", "x")
.AXES <- c("c", "y", "x", "z", "t")
Binary file added inst/extdata/4D-series.ome.tiff
Binary file not shown.
4 changes: 2 additions & 2 deletions man/ImageArray-methods.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions tests/testthat/test-array.R
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ test_that("check indexing (BFArray)", {
imgarray <- createImageArray(img.file, series = 1, resolution = 1:2)

# crop
imgarray_vis <- crop(imgarray, ind = list(100:200, 100:200, 1))
imgarray_vis <- crop(imgarray, ind = list(100:200, 100:200))
imgarray_vis <- as.raster(imgarray_vis)
plot(imgarray_vis)

Expand All @@ -55,15 +55,15 @@ test_that("check indexing (BFArray)", {
)

# [ method works
imgarray_vis <- imgarray[100:200,,]
expect_equal(dim(imgarray_vis), c(101, dim(imgarray)[2], 1))
imgarray_vis <- imgarray[,100:200,]
expect_equal(dim(imgarray_vis), c(dim(imgarray)[1], 101, 1))
imgarray_vis <- imgarray[,,]
imgarray_vis <- imgarray[100:200,]
expect_equal(dim(imgarray_vis), c(101, dim(imgarray)[2]))
imgarray_vis <- imgarray[,100:200]
expect_equal(dim(imgarray_vis), c(dim(imgarray)[1], 101))
imgarray_vis <- imgarray[,]
expect_equal(dim(imgarray_vis), dim(imgarray))

# [ indexing error
expect_error(imgarray[100:200,])
expect_error(imgarray[,100:200,])
expect_error(imgarray[100:200,,2])
expect_error(imgarray[-100:200,,])
expect_error(imgarray[,-100,])
Expand Down
12 changes: 6 additions & 6 deletions tests/testthat/test-bfarray.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ test_that("bfarray object", {

# create array
bfa <- BFArray(img.file, series = 1, resolution = 2)
expect_equal(dim(bfa), c(256, 256, 1))
expect_equal(dim(bfa), c(256, 256))
bfa <- BFArray(img.file, series = 1, resolution = 1)
expect_equal(dim(bfa), c(512, 512, 1))
expect_equal(dim(bfa), c(512, 512))

# methods
bfa2 <- aperm(bfa, c(2, 1, 3))
expect_equal(bfa2[1, 2, 1], bfa[2, 1, 1])
bfa2 <- aperm(bfa, c(2, 1))
expect_equal(bfa2[1, 2], bfa[2, 1])

# construct imagearray
img <- createImageArray(img.file, series = 1, resolution = 1:2)
Expand All @@ -37,9 +37,9 @@ test_that("bfarray object", {

# single channel modulate
img_modulated <- modulate(img, brightness = 200)
orig <- realize(img[1:10, 1:10,]) * 2
orig <- realize(img[1:10, 1:10]) * 2
orig[orig > 1] <- 1
newmat <- realize(img_modulated[1:10, 1:10,])
newmat <- realize(img_modulated[1:10, 1:10])
expect_equal(orig, newmat)
})

Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-imagearray-class.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ test_that("image array class", {

# incorrect axes names
expect_error(
imgarray <- ImageArray(meta = list(axes = c("c", "z", "x")),
imgarray <- ImageArray(meta = list(axes = c("b", "a", "d")),
levels = list(array(1:75, dim = c(3,5,5))))
)

Expand Down
16 changes: 16 additions & 0 deletions vignettes/ImageArray.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,22 @@ plot(bfa.raster)
dim(bfa.raster)
```

`r Biocpkg("ImageArray")` can also read images with all five dimensions (XYZCT)
available in the OME (Open Microscopy Environment) specifications.
See OME specifications webpage for more information [here](https://docs.openmicroscopy.org/ome-model/6.2.2/ome-tiff/specification.html#dimensionorder).

```{r 4d, out.width="50%"}
ome.tiff.file <- system.file("extdata", "4D-series.ome.tiff",
package = "ImageArray")

# read metadata
read.metadata(ome.tiff.file, proprietary.metadata = TRUE, filter.metadata = TRUE)

# define ImageArray object
imgarray <- createImageArray(ome.tiff.file, series = 1, resolution = 1)
imgarray
```

# Use cases

The delayed pyramid scheme introduced by `ImageArray` objects can also
Expand Down
Loading