- added ome_xml method
- some pyo3 methods
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ndbioimage"
|
name = "ndbioimage"
|
||||||
version = "2025.1.2"
|
version = "2025.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Wim Pomp <w.pomp@nki.nl>"]
|
authors = ["Wim Pomp <w.pomp@nki.nl>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
@@ -31,9 +31,9 @@ optional = true
|
|||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
anyhow = { version = "1.0.95"}
|
||||||
j4rs = { version = "0.22", features = [] }
|
j4rs = { version = "0.22", features = [] }
|
||||||
retry = { version = "2.0.0"}
|
retry = { version = "2.0.0"}
|
||||||
anyhow = { version = "1.0.95"}
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
python = ["dep:pyo3", "dep:numpy"]
|
python = ["dep:pyo3", "dep:numpy"]
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ macro_rules! method_arg {
|
|||||||
|
|
||||||
macro_rules! method {
|
macro_rules! method {
|
||||||
($name:ident, $method:expr $(,[$($n:tt: $t:ty$(|$p:tt)?),*])? $(=> $tt:ty$(|$c:tt)?)?) => {
|
($name:ident, $method:expr $(,[$($n:tt: $t:ty$(|$p:tt)?),*])? $(=> $tt:ty$(|$c:tt)?)?) => {
|
||||||
pub fn $name(&self, $($($n: $t),*)?) -> method_return!($($tt)?) {
|
pub(crate) fn $name(&self, $($($n: $t),*)?) -> method_return!($($tt)?) {
|
||||||
let args: Vec<InvocationArg> = vec![$($( method_arg!($n:$t$(|$p)?) ),*)?];
|
let args: Vec<InvocationArg> = vec![$($( method_arg!($n:$t$(|$p)?) ),*)?];
|
||||||
let _result = jvm().invoke(&self.0, $method, &args)?;
|
let _result = jvm().invoke(&self.0, $method, &args)?;
|
||||||
|
|
||||||
@@ -55,10 +55,10 @@ macro_rules! method {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DebugTools;
|
pub(crate) struct DebugTools;
|
||||||
|
|
||||||
impl DebugTools {
|
impl DebugTools {
|
||||||
pub fn set_root_level(level: &str) -> Result<()> {
|
pub(crate) fn set_root_level(level: &str) -> Result<()> {
|
||||||
jvm().invoke_static(
|
jvm().invoke_static(
|
||||||
"loci.common.DebugTools",
|
"loci.common.DebugTools",
|
||||||
"setRootLevel",
|
"setRootLevel",
|
||||||
@@ -68,10 +68,10 @@ impl DebugTools {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChannelSeparator(Instance);
|
pub(crate) struct ChannelSeparator(Instance);
|
||||||
|
|
||||||
impl ChannelSeparator {
|
impl ChannelSeparator {
|
||||||
pub fn new(image_reader: &ImageReader) -> Result<Self> {
|
pub(crate) fn new(image_reader: &ImageReader) -> Result<Self> {
|
||||||
let jvm = jvm();
|
let jvm = jvm();
|
||||||
let channel_separator = jvm.create_instance(
|
let channel_separator = jvm.create_instance(
|
||||||
"loci.formats.ChannelSeparator",
|
"loci.formats.ChannelSeparator",
|
||||||
@@ -80,7 +80,7 @@ impl ChannelSeparator {
|
|||||||
Ok(ChannelSeparator(channel_separator))
|
Ok(ChannelSeparator(channel_separator))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_bytes(&self, index: i32) -> Result<Vec<u8>> {
|
pub(crate) fn open_bytes(&self, index: i32) -> Result<Vec<u8>> {
|
||||||
let bi8 = self.open_bi8(index)?;
|
let bi8 = self.open_bi8(index)?;
|
||||||
Ok(unsafe { std::mem::transmute::<Vec<i8>, Vec<u8>>(bi8) })
|
Ok(unsafe { std::mem::transmute::<Vec<i8>, Vec<u8>>(bi8) })
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ impl ChannelSeparator {
|
|||||||
method!(get_index, "getIndex", [z: i32|p, c: i32|p, t: i32|p] => i32|c);
|
method!(get_index, "getIndex", [z: i32|p, c: i32|p, t: i32|p] => i32|c);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ImageReader(Instance);
|
pub(crate) struct ImageReader(Instance);
|
||||||
|
|
||||||
impl Drop for ImageReader {
|
impl Drop for ImageReader {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
@@ -98,17 +98,27 @@ impl Drop for ImageReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ImageReader {
|
impl ImageReader {
|
||||||
pub fn new() -> Result<Self> {
|
pub(crate) fn new() -> Result<Self> {
|
||||||
let reader = jvm().create_instance("loci.formats.ImageReader", InvocationArg::empty())?;
|
let reader = jvm().create_instance("loci.formats.ImageReader", InvocationArg::empty())?;
|
||||||
Ok(ImageReader(reader))
|
Ok(ImageReader(reader))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_bytes(&self, index: i32) -> Result<Vec<u8>> {
|
pub(crate) fn open_bytes(&self, index: i32) -> Result<Vec<u8>> {
|
||||||
let bi8 = self.open_bi8(index)?;
|
let bi8 = self.open_bi8(index)?;
|
||||||
Ok(unsafe { std::mem::transmute::<Vec<i8>, Vec<u8>>(bi8) })
|
Ok(unsafe { std::mem::transmute::<Vec<i8>, Vec<u8>>(bi8) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ome_xml(&self) -> Result<String> {
|
||||||
|
let mds = self.get_metadata_store()?;
|
||||||
|
Ok(jvm()
|
||||||
|
.chain(&mds)?
|
||||||
|
.cast("loci.formats.ome.OMEPyramidStore")?
|
||||||
|
.invoke("dumpXML", &[])?
|
||||||
|
.to_rust()?)
|
||||||
|
}
|
||||||
|
|
||||||
method!(set_metadata_store, "setMetadataStore", [ome_data: Instance]);
|
method!(set_metadata_store, "setMetadataStore", [ome_data: Instance]);
|
||||||
|
method!(get_metadata_store, "getMetadataStore" => Instance);
|
||||||
method!(set_id, "setId", [id: &str]);
|
method!(set_id, "setId", [id: &str]);
|
||||||
method!(set_series, "setSeries", [series: i32|p]);
|
method!(set_series, "setSeries", [series: i32|p]);
|
||||||
method!(open_bi8, "openBytes", [index: i32|p] => Vec<i8>|c);
|
method!(open_bi8, "openBytes", [index: i32|p] => Vec<i8>|c);
|
||||||
@@ -129,10 +139,10 @@ impl ImageReader {
|
|||||||
method!(close, "close");
|
method!(close, "close");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MetadataTools(Instance);
|
pub(crate) struct MetadataTools(Instance);
|
||||||
|
|
||||||
impl MetadataTools {
|
impl MetadataTools {
|
||||||
pub fn new() -> Result<Self> {
|
pub(crate) fn new() -> Result<Self> {
|
||||||
let meta_data_tools =
|
let meta_data_tools =
|
||||||
jvm().create_instance("loci.formats.MetadataTools", InvocationArg::empty())?;
|
jvm().create_instance("loci.formats.MetadataTools", InvocationArg::empty())?;
|
||||||
Ok(MetadataTools(meta_data_tools))
|
Ok(MetadataTools(meta_data_tools))
|
||||||
|
|||||||
43
src/lib.rs
43
src/lib.rs
@@ -144,7 +144,7 @@ pub struct Reader {
|
|||||||
image_reader: ImageReader,
|
image_reader: ImageReader,
|
||||||
/// path to file
|
/// path to file
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
/// which (if more) than 1 of the series in the file to open
|
/// which (if more than 1) of the series in the file to open
|
||||||
pub series: i32,
|
pub series: i32,
|
||||||
/// size x (horizontal)
|
/// size x (horizontal)
|
||||||
pub size_x: usize,
|
pub size_x: usize,
|
||||||
@@ -154,7 +154,7 @@ pub struct Reader {
|
|||||||
pub size_c: usize,
|
pub size_c: usize,
|
||||||
/// size z (# slices)
|
/// size z (# slices)
|
||||||
pub size_z: usize,
|
pub size_z: usize,
|
||||||
/// size t (time/frames)
|
/// size t (# time/frames)
|
||||||
pub size_t: usize,
|
pub size_t: usize,
|
||||||
/// pixel type ((u)int(8/16/32) or float(32/64))
|
/// pixel type ((u)int(8/16/32) or float(32/64))
|
||||||
pub pixel_type: PixelType,
|
pub pixel_type: PixelType,
|
||||||
@@ -214,6 +214,11 @@ impl Reader {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get ome metadata as xml string
|
||||||
|
pub fn ome_xml(&self) -> Result<String> {
|
||||||
|
self.image_reader.ome_xml()
|
||||||
|
}
|
||||||
|
|
||||||
fn deinterleave(&self, bytes: Vec<u8>, channel: usize) -> Result<Vec<u8>> {
|
fn deinterleave(&self, bytes: Vec<u8>, channel: usize) -> Result<Vec<u8>> {
|
||||||
let chunk_size = match self.pixel_type {
|
let chunk_size = match self.pixel_type {
|
||||||
PixelType::INT8 => 1,
|
PixelType::INT8 => 1,
|
||||||
@@ -311,7 +316,10 @@ mod tests {
|
|||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
fn open(file: &str) -> Result<Reader> {
|
fn open(file: &str) -> Result<Reader> {
|
||||||
let path = std::env::current_dir()?.join("tests").join("files").join(file);
|
let path = std::env::current_dir()?
|
||||||
|
.join("tests")
|
||||||
|
.join("files")
|
||||||
|
.join(file);
|
||||||
Reader::new(&path, 0)
|
Reader::new(&path, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,4 +371,33 @@ mod tests {
|
|||||||
println!("{:?}", frames);
|
println!("{:?}", frames);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_sequence() -> Result<()> {
|
||||||
|
let file = "YTL1841B2-2-1_1hr_DMSO_galinduction_1/Pos0/img_000000000_mScarlet_GFP-mSc-filter_004.tif";
|
||||||
|
let reader = open(file)?;
|
||||||
|
println!("reader: {:?}", reader);
|
||||||
|
let frame = reader.get_frame(0, 4, 0)?;
|
||||||
|
println!("frame: {:?}", frame);
|
||||||
|
let frame = reader.get_frame(0, 2, 0)?;
|
||||||
|
println!("frame: {:?}", frame);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_sequence1() -> Result<()> {
|
||||||
|
let file = "4-Pos_001_002/img_000000000_Cy3-Cy3_filter_000.tif";
|
||||||
|
let reader = open(file)?;
|
||||||
|
println!("reader: {:?}", reader);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ome_xml() -> Result<()> {
|
||||||
|
let file = "Experiment-2029.czi";
|
||||||
|
let reader = open(file)?;
|
||||||
|
let xml = reader.ome_xml()?;
|
||||||
|
println!("{}", xml);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/py.rs
49
src/py.rs
@@ -1,14 +1,51 @@
|
|||||||
|
use crate::{Frame, Reader};
|
||||||
|
use numpy::{IntoPyArray, PyArrayMethods, ToPyArray};
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::BoundObject;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// Formats the sum of two numbers as string.
|
#[pyclass(subclass)]
|
||||||
#[pyfunction]
|
#[pyo3(name = "Reader")]
|
||||||
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
|
#[derive(Debug)]
|
||||||
Ok((a + b).to_string())
|
struct PyReader {
|
||||||
|
path: PathBuf,
|
||||||
|
series: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl PyReader {
|
||||||
|
#[new]
|
||||||
|
fn new(path: &str, series: usize) -> PyResult<Self> {
|
||||||
|
Ok(PyReader {
|
||||||
|
path: PathBuf::from(path),
|
||||||
|
series: series as i32,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_frame<'py>(
|
||||||
|
&self,
|
||||||
|
py: Python<'py>,
|
||||||
|
c: usize,
|
||||||
|
z: usize,
|
||||||
|
t: usize,
|
||||||
|
) -> PyResult<Bound<'py, PyAny>> {
|
||||||
|
let reader = Reader::new(&self.path, self.series)?; // TODO: prevent making a new Reader each time
|
||||||
|
Ok(match reader.get_frame(c, z, t)? {
|
||||||
|
Frame::INT8(arr) => arr.to_pyarray(py).into_any(),
|
||||||
|
Frame::UINT8(arr) => arr.to_pyarray(py).into_any(),
|
||||||
|
Frame::INT16(arr) => arr.to_pyarray(py).into_any(),
|
||||||
|
Frame::UINT16(arr) => arr.to_pyarray(py).into_any(),
|
||||||
|
Frame::INT32(arr) => arr.to_pyarray(py).into_any(),
|
||||||
|
Frame::UINT32(arr) => arr.to_pyarray(py).into_any(),
|
||||||
|
Frame::FLOAT(arr) => arr.to_pyarray(py).into_any(),
|
||||||
|
Frame::DOUBLE(arr) => arr.to_pyarray(py).into_any(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Python module implemented in Rust.
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
|
#[pyo3(name = "ndbioimage_rs")]
|
||||||
fn ndbioimage_rs(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn ndbioimage_rs(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
|
m.add_class::<PyReader>()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user