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