- metadata
This commit is contained in:
+107
-89
@@ -8,9 +8,7 @@ use ome_metadata::ome::{
|
||||
impl Metadata for Ome {
|
||||
fn get_instrument(&self) -> Option<&Instrument> {
|
||||
let instrument_id = self.get_image()?.instrument_ref.as_ref()?.id.clone();
|
||||
self.instrument
|
||||
.iter()
|
||||
.find(|i| i.id == instrument_id)
|
||||
self.instrument.iter().find(|i| i.id == instrument_id)
|
||||
}
|
||||
|
||||
fn get_image(&self) -> Option<&Image> {
|
||||
@@ -42,23 +40,11 @@ pub trait Metadata {
|
||||
.find(|o| o.id == objective_id)
|
||||
}
|
||||
|
||||
fn get_tube_lens(&self) -> Option<Objective> {
|
||||
Some(Objective {
|
||||
manufacturer: None,
|
||||
model: Some("Unknown".to_string()),
|
||||
serial_number: None,
|
||||
lot_number: None,
|
||||
id: "TubeLens:1".to_string(),
|
||||
correction: None,
|
||||
immersion: None,
|
||||
lens_na: None,
|
||||
nominal_magnification: Some(1.0),
|
||||
calibrated_magnification: None,
|
||||
working_distance: None,
|
||||
working_distance_unit: UnitsLength::um,
|
||||
iris: None,
|
||||
annotation_ref: vec![],
|
||||
})
|
||||
fn get_tube_lens(&self) -> Option<&Objective> {
|
||||
self.get_instrument()?
|
||||
.objective
|
||||
.iter()
|
||||
.find(|o| o.id.starts_with("Objective:Tubelens"))
|
||||
}
|
||||
|
||||
/// shape of the data along cztyx axes
|
||||
@@ -110,31 +96,40 @@ pub trait Metadata {
|
||||
|
||||
/// distance between planes in z-stack in nm
|
||||
fn delta_z(&self) -> Result<Option<f64>, Error> {
|
||||
if let Some(pixels) = self.get_pixels() {
|
||||
if let Some(z) = pixels.physical_size_z {
|
||||
return Ok(Some(
|
||||
Ok(
|
||||
if let Some(pixels) = self.get_pixels()
|
||||
&& let Some(z) = pixels.physical_size_z
|
||||
{
|
||||
Some(
|
||||
pixels
|
||||
.physical_size_z_unit
|
||||
.convert(&UnitsLength::nm, z as f64)?,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// time interval in seconds for time-lapse images
|
||||
fn time_interval(&self) -> Result<Option<f64>, Error> {
|
||||
if let Some(pixels) = self.get_pixels() {
|
||||
if let Some(t) = pixels.plane.iter().map(|p| p.the_t).max() {
|
||||
if t > 0 {
|
||||
let plane_a = pixels.plane
|
||||
.iter()
|
||||
.find(|p| (p.the_c == 0) && (p.the_z == 0) && (p.the_t == 0));
|
||||
let plane_b = pixels.plane
|
||||
.iter()
|
||||
.find(|p| (p.the_c == 0) && (p.the_z == 0) && (p.the_t == t));
|
||||
if let (Some(a), Some(b)) = (plane_a, plane_b) {
|
||||
if let (Some(a_t), Some(b_t)) = (a.delta_t, b.delta_t) {
|
||||
if let Some(pixels) = self.get_pixels()
|
||||
&& let Some(t) = pixels.plane.iter().filter_map(|p| p.the_t).max()
|
||||
&& (t > 0)
|
||||
{
|
||||
let plane_a = pixels.plane.iter().find(|p| {
|
||||
(p.the_c.is_none() || (p.the_c == Some(0)))
|
||||
&& (p.the_z.is_none() || (p.the_z == Some(0)))
|
||||
&& (p.the_t == Some(0))
|
||||
});
|
||||
let plane_b = pixels.plane.iter().find(|p| {
|
||||
(p.the_c.is_none() || (p.the_c == Some(0)))
|
||||
&& (p.the_z.is_none() || (p.the_z == Some(0)))
|
||||
&& (p.the_t == Some(t))
|
||||
});
|
||||
if let (Some(a), Some(b)) = (plane_a, plane_b)
|
||||
&& let (Some(a_t), Some(b_t)) = (a.delta_t, b.delta_t)
|
||||
{
|
||||
return Ok(Some(
|
||||
(b.delta_t_unit.convert(&UnitsTime::s, b_t as f64)?
|
||||
- a.delta_t_unit.convert(&UnitsTime::s, a_t as f64)?)
|
||||
@@ -143,26 +138,26 @@ pub trait Metadata {
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// exposure time for channel, z=0 and t=0
|
||||
fn exposure_time(&self, channel: usize) -> Result<Option<f64>, Error> {
|
||||
let c = channel as i32;
|
||||
if let Some(pixels) = self.get_pixels() {
|
||||
if let Some(p) = pixels.plane
|
||||
.iter()
|
||||
.find(|p| (p.the_c == c) && (p.the_z == 0) && (p.the_t == 0))
|
||||
Ok(
|
||||
if let Some(pixels) = self.get_pixels()
|
||||
&& let Some(p) = pixels.plane.iter().find(|p| {
|
||||
(p.the_c == Some(c))
|
||||
&& (p.the_z.is_none() || (p.the_z == Some(0)))
|
||||
&& (p.the_t.is_none() || (p.the_t == Some(0)))
|
||||
})
|
||||
&& let Some(t) = p.exposure_time
|
||||
{
|
||||
if let Some(t) = p.exposure_time {
|
||||
return Ok(Some(p.exposure_time_unit.convert(&UnitsTime::s, t as f64)?));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
Some(p.exposure_time_unit.convert(&UnitsTime::s, t as f64)?)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn binning(&self, channel: usize) -> Option<usize> {
|
||||
@@ -184,36 +179,37 @@ pub trait Metadata {
|
||||
}
|
||||
|
||||
fn laser_wavelengths(&self, channel: usize) -> Result<Option<f64>, Error> {
|
||||
if let Some(pixels) = self.get_pixels() {
|
||||
if let Some(channel) = pixels.channel.get(channel) {
|
||||
if let Some(w) = channel.excitation_wavelength {
|
||||
return Ok(Some(
|
||||
Ok(
|
||||
if let Some(pixels) = self.get_pixels()
|
||||
&& let Some(channel) = pixels.channel.get(channel)
|
||||
&& let Some(w) = channel.excitation_wavelength
|
||||
{
|
||||
Some(
|
||||
channel
|
||||
.excitation_wavelength_unit
|
||||
.convert(&UnitsLength::nm, w as f64)?,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn laser_powers(&self, channel: usize) -> Result<Option<f64>, Error> {
|
||||
if let Some(pixels) = self.get_pixels() {
|
||||
if let Some(channel) = pixels.channel.get(channel) {
|
||||
if let Some(ls) = &channel.light_source_settings {
|
||||
if let Some(a) = ls.attenuation {
|
||||
return if (0. ..=1.).contains(&a) {
|
||||
if let Some(pixels) = self.get_pixels()
|
||||
&& let Some(channel) = pixels.channel.get(channel)
|
||||
&& let Some(ls) = &channel.light_source_settings
|
||||
&& let Some(a) = ls.attenuation
|
||||
{
|
||||
if (0. ..=1.).contains(&a) {
|
||||
Ok(Some(1f64 - (a as f64)))
|
||||
} else {
|
||||
Err(Error::InvalidAttenuation(a.to_string()))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn objective_name(&self) -> Option<String> {
|
||||
Some(self.get_objective()?.model.as_ref()?.clone())
|
||||
@@ -249,19 +245,28 @@ pub trait Metadata {
|
||||
}
|
||||
|
||||
fn gain(&self, channel: usize) -> Option<f64> {
|
||||
if let Some(pixels) = self.get_pixels() {
|
||||
Some(
|
||||
*pixels
|
||||
.channel
|
||||
.get(channel)?
|
||||
.detector_settings
|
||||
.as_ref()?
|
||||
.gain
|
||||
.as_ref()? as f64,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
self.get_pixels()
|
||||
.and_then(|p| p.channel.get(channel))
|
||||
.and_then(|c| c.detector_settings.as_ref())
|
||||
.map(|ds| ds.id.as_str())
|
||||
.and_then(|detector_id| {
|
||||
self.get_instrument()
|
||||
.and_then(|i| i.detector.iter().find(|d| d.id == detector_id))
|
||||
.and_then(|d| d.amplification_gain)
|
||||
.map(|g| g as f64)
|
||||
})
|
||||
}
|
||||
|
||||
fn is_zstack(&self) -> Result<bool, Error> {
|
||||
self.get_pixels()
|
||||
.map(|p| Ok(p.size_z > 1))
|
||||
.unwrap_or_else(|| Err(Error::NoImageOrPixels))
|
||||
}
|
||||
|
||||
fn is_time_lapse(&self) -> Result<bool, Error> {
|
||||
self.get_pixels()
|
||||
.map(|p| Ok(p.size_t > 1))
|
||||
.unwrap_or_else(|| Err(Error::NoImageOrPixels))
|
||||
}
|
||||
|
||||
fn summary(&self) -> Result<String, Error> {
|
||||
@@ -274,10 +279,14 @@ pub trait Metadata {
|
||||
if let Ok(Some(pixel_size)) = self.pixel_size() {
|
||||
s.push_str(&format!("pixel size: {pixel_size:.2} nm\n"));
|
||||
}
|
||||
if let Ok(Some(delta_z)) = self.delta_z() {
|
||||
if let Ok(Some(delta_z)) = self.delta_z()
|
||||
&& self.is_zstack()?
|
||||
{
|
||||
s.push_str(&format!("z-interval: {delta_z:.2} nm\n"))
|
||||
}
|
||||
if let Ok(Some(time_interval)) = self.time_interval() {
|
||||
if let Ok(Some(time_interval)) = self.time_interval()
|
||||
&& self.is_time_lapse()?
|
||||
{
|
||||
s.push_str(&format!("time interval: {time_interval:.2} s\n"))
|
||||
}
|
||||
let exposure_time = (0..size_c)
|
||||
@@ -288,12 +297,15 @@ pub trait Metadata {
|
||||
.collect::<Vec<_>>();
|
||||
if !exposure_time.is_empty() {
|
||||
s.push_str(&format!(
|
||||
"exposure time: {}\n",
|
||||
exposure_time.into_iter().join(" | ")
|
||||
"exposure time: {} s\n",
|
||||
exposure_time
|
||||
.iter()
|
||||
.map(|e| format!("{:.2}", e))
|
||||
.join(" | ")
|
||||
));
|
||||
}
|
||||
if let Some(magnification) = self.magnification() {
|
||||
s.push_str(&format!("magnification: {magnification}x\n"))
|
||||
s.push_str(&format!("magnification: {magnification:.1}x\n"))
|
||||
}
|
||||
if let Some(objective_name) = self.objective_name() {
|
||||
s.push_str(&format!("objective: {objective_name}\n"))
|
||||
@@ -320,7 +332,10 @@ pub trait Metadata {
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
if !gain.is_empty() {
|
||||
s.push_str(&format!("gain: {}\n", gain.into_iter().join(" ")));
|
||||
s.push_str(&format!(
|
||||
"gain: {}\n",
|
||||
gain.into_iter().join(" | ")
|
||||
));
|
||||
}
|
||||
let laser_wavelengths = (0..size_c)
|
||||
.map(|c| self.laser_wavelengths(c))
|
||||
@@ -342,8 +357,11 @@ pub trait Metadata {
|
||||
.collect::<Vec<_>>();
|
||||
if !laser_powers.is_empty() {
|
||||
s.push_str(&format!(
|
||||
"laser powers: {}\n",
|
||||
laser_powers.into_iter().join(" | ")
|
||||
"laser powers: {} %\n",
|
||||
laser_powers
|
||||
.into_iter()
|
||||
.map(|p| format!("{:.3}", 100.0 * p))
|
||||
.join(" | ")
|
||||
));
|
||||
}
|
||||
let binning = (0..size_c)
|
||||
|
||||
Reference in New Issue
Block a user