- read ome xml tiff
This commit is contained in:
1 parent
7f07f82fdb
commit
4815690621
3 files changed
+186
-163
No files matched your search
+1
-1
Submodule image-tiff updated: 96d37bb087...9b452e93b7.
@@ -33,7 +33,7 @@ libczirw-sys = { version = "0.5", optional = true }
|
|||||||
ndarray = { version = "0.17", features = ["serde"] }
|
ndarray = { version = "0.17", features = ["serde"] }
|
||||||
num = "0.4"
|
num = "0.4"
|
||||||
numpy = { version = "0.29", optional = true }
|
numpy = { version = "0.29", optional = true }
|
||||||
ome-metadata = "0.5"
|
ome-metadata = "0.6"
|
||||||
ordered-float = { version = "5", optional = true }
|
ordered-float = { version = "5", optional = true }
|
||||||
phf = { version = "0.14", features = ["macros"] }
|
phf = { version = "0.14", features = ["macros"] }
|
||||||
postcard = { version = "1", features = ["use-std"], optional = true }
|
postcard = { version = "1", features = ["use-std"], optional = true }
|
||||||
|
|||||||
+184
-161
@@ -156,47 +156,61 @@ impl Reader for TiffReader {
|
|||||||
.unwrap_or(1)
|
.unwrap_or(1)
|
||||||
== 2;
|
== 2;
|
||||||
|
|
||||||
let imagej_bytes = reader
|
let image_description = reader.current_ifd().get_tag(Tag::ImageDescription);
|
||||||
.current_ifd()
|
|
||||||
.get_tag(Tag::Unknown(50839))
|
|
||||||
.or_else(|_| reader.current_ifd().get_tag(Tag::ImageDescription))?;
|
|
||||||
let imagej_bytes = match imagej_bytes {
|
|
||||||
Value::Ascii(s) => s.into_bytes(),
|
|
||||||
other => other.into_u8_vec()?,
|
|
||||||
};
|
|
||||||
let metadata_str = String::from_utf8_lossy(&imagej_bytes);
|
|
||||||
let metadata_map = parse_imagej_metadata(&metadata_str);
|
|
||||||
let p_ndim = if n_samples > 1 { 3u8 } else { 2u8 };
|
let p_ndim = if n_samples > 1 { 3u8 } else { 2u8 };
|
||||||
let size_c = if p_ndim == 3 {
|
let (size_c, size_t, size_z) = if let Ok(Value::Ascii(xml)) = image_description
|
||||||
n_samples
|
&& xml.starts_with("<?xml")
|
||||||
|
{
|
||||||
|
let ome = Ome::from_xml(xml)?;
|
||||||
|
(
|
||||||
|
ome.image[0].pixels.size_c as usize,
|
||||||
|
ome.image[0].pixels.size_t as usize,
|
||||||
|
ome.image[0].pixels.size_z as usize,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
metadata_map
|
let imagej_bytes = reader
|
||||||
.get("channels")
|
.current_ifd()
|
||||||
|
.get_tag(Tag::Unknown(50839))
|
||||||
|
.or_else(|_| reader.current_ifd().get_tag(Tag::ImageDescription))?;
|
||||||
|
let imagej_bytes = match imagej_bytes {
|
||||||
|
Value::Ascii(s) => s.into_bytes(),
|
||||||
|
other => other.into_u8_vec()?,
|
||||||
|
};
|
||||||
|
let metadata_str = String::from_utf8_lossy(&imagej_bytes);
|
||||||
|
let metadata_map = parse_imagej_metadata(&metadata_str);
|
||||||
|
|
||||||
|
let size_c = if p_ndim == 3 {
|
||||||
|
n_samples
|
||||||
|
} else {
|
||||||
|
metadata_map
|
||||||
|
.get("channels")
|
||||||
|
.and_then(|v| v.parse::<usize>().ok())
|
||||||
|
.unwrap_or(1)
|
||||||
|
};
|
||||||
|
let size_z = metadata_map
|
||||||
|
.get("slices")
|
||||||
.and_then(|v| v.parse::<usize>().ok())
|
.and_then(|v| v.parse::<usize>().ok())
|
||||||
.unwrap_or(1)
|
.unwrap_or(1);
|
||||||
};
|
let size_t = metadata_map
|
||||||
let size_z = metadata_map
|
.get("frames")
|
||||||
.get("slices")
|
.and_then(|v| v.parse::<usize>().ok())
|
||||||
.and_then(|v| v.parse::<usize>().ok())
|
.unwrap_or(1);
|
||||||
.unwrap_or(1);
|
|
||||||
let size_t = metadata_map
|
|
||||||
.get("frames")
|
|
||||||
.and_then(|v| v.parse::<usize>().ok())
|
|
||||||
.unwrap_or(1);
|
|
||||||
|
|
||||||
let mult = if p_ndim == 3 { n_samples } else { 1 };
|
let mult = if p_ndim == 3 { n_samples } else { 1 };
|
||||||
let expected = size_c * size_z * size_t / mult;
|
let expected = size_c * size_z * size_t / mult;
|
||||||
|
|
||||||
let mut n_ifds = 1;
|
let mut n_ifds = 1;
|
||||||
while reader.more_images() {
|
while reader.more_images() {
|
||||||
reader.next_directory()?;
|
reader.next_directory()?;
|
||||||
n_ifds += 1;
|
n_ifds += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let size_z = if n_ifds != expected && n_ifds > 0 {
|
let size_z = if n_ifds != expected && n_ifds > 0 {
|
||||||
n_ifds / (size_c * size_t / mult).max(1)
|
n_ifds / (size_c * size_t / mult).max(1)
|
||||||
} else {
|
} else {
|
||||||
size_z
|
size_z
|
||||||
|
};
|
||||||
|
(size_c, size_t, size_z)
|
||||||
};
|
};
|
||||||
drop(reader);
|
drop(reader);
|
||||||
|
|
||||||
@@ -220,139 +234,146 @@ impl Reader for TiffReader {
|
|||||||
|
|
||||||
fn metadata(&self) -> Result<Ome, Error> {
|
fn metadata(&self) -> Result<Ome, Error> {
|
||||||
let mut reader = self.get_reader()?;
|
let mut reader = self.get_reader()?;
|
||||||
let imagej_bytes = reader
|
let image_description = reader.current_ifd().get_tag(Tag::ImageDescription);
|
||||||
.current_ifd()
|
if let Ok(Value::Ascii(xml)) = image_description
|
||||||
.get_tag(Tag::Unknown(50839))
|
&& xml.starts_with("<?xml")
|
||||||
.or_else(|_| reader.current_ifd().get_tag(Tag::ImageDescription))?;
|
{
|
||||||
let imagej_bytes = match imagej_bytes {
|
Ok(Ome::from_xml(xml)?)
|
||||||
Value::Ascii(s) => s.into_bytes(),
|
} else {
|
||||||
other => other.into_u8_vec()?,
|
let imagej_bytes = reader
|
||||||
};
|
.current_ifd()
|
||||||
let metadata_str = String::from_utf8_lossy(&imagej_bytes);
|
.get_tag(Tag::Unknown(50839))
|
||||||
let metadata_map = parse_imagej_metadata(&metadata_str);
|
.or_else(|_| reader.current_ifd().get_tag(Tag::ImageDescription))?;
|
||||||
|
let imagej_bytes = match imagej_bytes {
|
||||||
|
Value::Ascii(s) => s.into_bytes(),
|
||||||
|
other => other.into_u8_vec()?,
|
||||||
|
};
|
||||||
|
let metadata_str = String::from_utf8_lossy(&imagej_bytes);
|
||||||
|
let metadata_map = parse_imagej_metadata(&metadata_str);
|
||||||
|
|
||||||
let interval_t = metadata_map
|
let interval_t = metadata_map
|
||||||
.get("interval")
|
.get("interval")
|
||||||
.and_then(|v| v.parse::<f64>().ok());
|
.and_then(|v| v.parse::<f64>().ok());
|
||||||
let ru = reader
|
let ru = reader
|
||||||
.current_ifd()
|
.current_ifd()
|
||||||
.get_tag(Tag::ResolutionUnit)
|
.get_tag(Tag::ResolutionUnit)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|i| i.into_u16().ok())
|
.and_then(|i| i.into_u16().ok())
|
||||||
.unwrap_or(2);
|
.unwrap_or(2);
|
||||||
let pixel_size = reader
|
let pixel_size = reader
|
||||||
.current_ifd()
|
.current_ifd()
|
||||||
.get_tag(Tag::XResolution)
|
.get_tag(Tag::XResolution)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|i| i.into_u64_vec().ok())
|
.and_then(|i| i.into_u64_vec().ok())
|
||||||
.and_then(|i| {
|
.and_then(|i| {
|
||||||
i.first()
|
i.first()
|
||||||
.and_then(|&n| i.get(1).map(|&d| (n as f64) / (d as f64)))
|
.and_then(|&n| i.get(1).map(|&d| (n as f64) / (d as f64)))
|
||||||
})
|
})
|
||||||
.and_then(|i| {
|
.and_then(|i| {
|
||||||
if i <= 0.0 {
|
if i <= 0.0 {
|
||||||
None
|
None
|
||||||
} else if ru == 3 {
|
} else if ru == 3 {
|
||||||
Some(1e4 / i)
|
Some(1e4 / i)
|
||||||
} else if ru == 2 {
|
} else if ru == 2 {
|
||||||
Some(25400.0 / i)
|
Some(25400.0 / i)
|
||||||
} else {
|
} else {
|
||||||
Some(1.0 / i)
|
Some(1.0 / i)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let interval_z = metadata_map
|
let interval_z = metadata_map
|
||||||
.get("spacing")
|
.get("spacing")
|
||||||
.and_then(|v| v.parse::<f64>().ok());
|
.and_then(|v| v.parse::<f64>().ok());
|
||||||
|
|
||||||
let ome_pixel_type = match self.pixel_type {
|
let ome_pixel_type = match self.pixel_type {
|
||||||
PixelType::I8 => ome::PixelType::Int8,
|
PixelType::I8 => ome::PixelType::Int8,
|
||||||
PixelType::U8 => ome::PixelType::Uint8,
|
PixelType::U8 => ome::PixelType::Uint8,
|
||||||
PixelType::I16 => ome::PixelType::Int16,
|
PixelType::I16 => ome::PixelType::Int16,
|
||||||
PixelType::U16 => ome::PixelType::Uint16,
|
PixelType::U16 => ome::PixelType::Uint16,
|
||||||
PixelType::I32 => ome::PixelType::Int32,
|
PixelType::I32 => ome::PixelType::Int32,
|
||||||
PixelType::U32 => ome::PixelType::Uint32,
|
PixelType::U32 => ome::PixelType::Uint32,
|
||||||
PixelType::F32 => ome::PixelType::Float,
|
PixelType::F32 => ome::PixelType::Float,
|
||||||
PixelType::F64 => ome::PixelType::Double,
|
PixelType::F64 => ome::PixelType::Double,
|
||||||
_ => ome::PixelType::Uint16,
|
_ => ome::PixelType::Uint16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut pixels = ome::Pixels {
|
let mut pixels = ome::Pixels {
|
||||||
id: "Pixels:0".to_string(),
|
id: "Pixels:0".to_string(),
|
||||||
size_x: self.shape.x as i32,
|
size_x: self.shape.x as i32,
|
||||||
size_y: self.shape.y as i32,
|
size_y: self.shape.y as i32,
|
||||||
size_z: self.shape.z as i32,
|
size_z: self.shape.z as i32,
|
||||||
size_c: self.shape.c as i32,
|
size_c: self.shape.c as i32,
|
||||||
size_t: self.shape.t as i32,
|
size_t: self.shape.t as i32,
|
||||||
dimension_order: ome::PixelsDimensionOrderType::Xyczt,
|
dimension_order: ome::PixelsDimensionOrderType::Xyczt,
|
||||||
r#type: ome_pixel_type,
|
r#type: ome_pixel_type,
|
||||||
physical_size_x: pixel_size.map(|v| v as f32),
|
physical_size_x: pixel_size.map(|v| v as f32),
|
||||||
physical_size_x_unit: ome::UnitsLength::um,
|
physical_size_x_unit: ome::UnitsLength::um,
|
||||||
physical_size_y: pixel_size.map(|v| v as f32),
|
physical_size_y: pixel_size.map(|v| v as f32),
|
||||||
physical_size_y_unit: ome::UnitsLength::um,
|
physical_size_y_unit: ome::UnitsLength::um,
|
||||||
physical_size_z: interval_z.map(|v| v as f32),
|
physical_size_z: interval_z.map(|v| v as f32),
|
||||||
physical_size_z_unit: ome::UnitsLength::um,
|
physical_size_z_unit: ome::UnitsLength::um,
|
||||||
time_increment: interval_t.map(|v| v as f32),
|
time_increment: interval_t.map(|v| v as f32),
|
||||||
time_increment_unit: ome::UnitsTime::s,
|
time_increment_unit: ome::UnitsTime::s,
|
||||||
significant_bits: None,
|
significant_bits: None,
|
||||||
interleaved: None,
|
interleaved: None,
|
||||||
big_endian: None,
|
big_endian: None,
|
||||||
channel: Vec::new(),
|
channel: Vec::new(),
|
||||||
bin_data: Vec::new(),
|
bin_data: Vec::new(),
|
||||||
tiff_data: Vec::new(),
|
tiff_data: Vec::new(),
|
||||||
metadata_only: None,
|
metadata_only: None,
|
||||||
plane: Vec::new(),
|
plane: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for c in 0..self.shape.c {
|
for c in 0..self.shape.c {
|
||||||
pixels.channel.push(ome::Channel {
|
pixels.channel.push(ome::Channel {
|
||||||
id: format!("Channel:{}", c),
|
id: format!("Channel:{}", c),
|
||||||
name: Some(format!("Channel {}", c)),
|
name: Some(format!("Channel {}", c)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for c in 0..self.shape.c {
|
for c in 0..self.shape.c {
|
||||||
for z in 0..self.shape.z {
|
for z in 0..self.shape.z {
|
||||||
for t in 0..self.shape.t {
|
for t in 0..self.shape.t {
|
||||||
pixels.plane.push(ome::Plane {
|
pixels.plane.push(ome::Plane {
|
||||||
the_c: Some(c as i32),
|
the_c: Some(c as i32),
|
||||||
the_z: Some(z as i32),
|
the_z: Some(z as i32),
|
||||||
the_t: Some(t as i32),
|
the_t: Some(t as i32),
|
||||||
delta_t: interval_t.and_then(|v| {
|
delta_t: interval_t.and_then(|v| {
|
||||||
if v > 0.0 {
|
if v > 0.0 {
|
||||||
Some((t as f64 * v) as f32)
|
Some((t as f64 * v) as f32)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let mut ome = Ome::default();
|
let mut ome = Ome::default();
|
||||||
ome.image.push(ome::Image {
|
ome.image.push(ome::Image {
|
||||||
id: "Image:0".to_string(),
|
id: "Image:0".to_string(),
|
||||||
name: self
|
name: self
|
||||||
.path
|
.path
|
||||||
.file_name()
|
.file_name()
|
||||||
.map(|n| n.to_string_lossy().to_string()),
|
.map(|n| n.to_string_lossy().to_string()),
|
||||||
pixels,
|
pixels,
|
||||||
instrument_ref: None,
|
instrument_ref: None,
|
||||||
objective_settings: None,
|
objective_settings: None,
|
||||||
acquisition_date: None,
|
acquisition_date: None,
|
||||||
description: None,
|
description: None,
|
||||||
experimenter_ref: None,
|
experimenter_ref: None,
|
||||||
experiment_ref: None,
|
experiment_ref: None,
|
||||||
experimenter_group_ref: None,
|
experimenter_group_ref: None,
|
||||||
imaging_environment: None,
|
imaging_environment: None,
|
||||||
stage_label: None,
|
stage_label: None,
|
||||||
roi_ref: Vec::new(),
|
roi_ref: Vec::new(),
|
||||||
microbeam_manipulation_ref: Vec::new(),
|
microbeam_manipulation_ref: Vec::new(),
|
||||||
annotation_ref: Vec::new(),
|
annotation_ref: Vec::new(),
|
||||||
});
|
});
|
||||||
Ok(ome)
|
Ok(ome)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_frame(&self, c: usize, z: usize, t: usize) -> Result<Frame, Error> {
|
fn get_frame(&self, c: usize, z: usize, t: usize) -> Result<Frame, Error> {
|
||||||
@@ -521,6 +542,8 @@ mod tests {
|
|||||||
metadata_e: "tiff/1xp53-01-AP1.tiff",
|
metadata_e: "tiff/1xp53-01-AP1.tiff",
|
||||||
metadata_f: "tiff/test.tif",
|
metadata_f: "tiff/test.tif",
|
||||||
metadata_g: "tiff/YTL1849A111_2023_05_04__14_46_19_cellnr_1_track.tif",
|
metadata_g: "tiff/YTL1849A111_2023_05_04__14_46_19_cellnr_1_track.tif",
|
||||||
metadata_h: "tiff/Wapl-AID_C46_13_tagRFPt_MCP_well1_video1_1_max.tif"
|
metadata_h: "tiff/Wapl-AID_C46_13_tagRFPt_MCP_well1_video1_1_max.tif",
|
||||||
|
metadata_i: "tiff/R1_NRF1_Gtf3a500nM_REAL_20260731_25pct_500ms_001_MMStack_PosR1_NRF1_Gtf3a500nM_REAL_20260731_25pct_500ms_001.ome.tif"
|
||||||
|
metadata_j: "tiff/20260922_Pos0_max.tif"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user