- implement shape in Rust
- implement more readers - fix downloading of bioformats jar - (mostly) compatible with python version
This commit is contained in:
+59
-22
@@ -1,17 +1,19 @@
|
||||
use crate::axes::Axis;
|
||||
use crate::colors::Color;
|
||||
use crate::error::Error;
|
||||
use crate::reader::PixelType;
|
||||
use crate::readers::{PixelType, Reader};
|
||||
use crate::view::View;
|
||||
use console::Term;
|
||||
use ffmpeg_sidecar::command::FfmpegCommand;
|
||||
use ffmpeg_sidecar::download::auto_download;
|
||||
use ffmpeg_sidecar::event::{FfmpegEvent, LogLevel};
|
||||
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
|
||||
use itertools::Itertools;
|
||||
use ndarray::{Array2, Array3, Dimension, IxDyn, s, stack};
|
||||
use ordered_float::OrderedFloat;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct MovieOptions {
|
||||
velocity: f64,
|
||||
@@ -93,7 +95,7 @@ impl MovieOptions {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ab(tyx: View<IxDyn>) -> Result<(f64, f64), Error> {
|
||||
fn get_ab<R: Reader>(tyx: View<IxDyn, R>) -> Result<(f64, f64), Error> {
|
||||
let s = tyx
|
||||
.as_array::<f64>()?
|
||||
.iter()
|
||||
@@ -136,9 +138,25 @@ fn cframe(frame: Array2<f64>, color: &[u8], a: f64, b: f64) -> Array3<f64> {
|
||||
stack(ndarray::Axis(2), &view).unwrap()
|
||||
}
|
||||
|
||||
impl<D> View<D>
|
||||
/// a progress bar with an ok style that when py::detach is used also works in jupyter
|
||||
pub fn get_bar(count: Option<usize>) -> ProgressBar {
|
||||
let style = ProgressStyle::with_template(
|
||||
"{spinner:.green} {percent}% [{wide_bar:.green/lime}] {pos:>7}/{len:7} [{elapsed}/{eta}, {per_sec:<5}]",
|
||||
).expect("template should be working").progress_chars("#>-");
|
||||
let bar = ProgressBar::with_draw_target(
|
||||
count.map(|i| i as u64),
|
||||
ProgressDrawTarget::term_like_with_hz(Box::new(Term::buffered_stdout()), 20),
|
||||
)
|
||||
.with_style(style);
|
||||
bar.enable_steady_tick(Duration::from_millis(100));
|
||||
bar
|
||||
}
|
||||
|
||||
impl<D, R> View<D, R>
|
||||
where
|
||||
D: Dimension,
|
||||
R: Reader,
|
||||
Self: 'static,
|
||||
{
|
||||
pub fn save_as_movie<P>(&self, path: P, options: &MovieOptions) -> Result<(), Error>
|
||||
where
|
||||
@@ -211,7 +229,7 @@ where
|
||||
|
||||
let ab = if options.no_scaling {
|
||||
vec![
|
||||
match view.pixel_type {
|
||||
match view.pixel_type() {
|
||||
PixelType::I8 => (i8::MIN as f64, i8::MAX as f64),
|
||||
PixelType::U8 => (u8::MIN as f64, u8::MAX as f64),
|
||||
PixelType::I16 => (i16::MIN as f64, i16::MAX as f64),
|
||||
@@ -222,7 +240,7 @@ where
|
||||
PixelType::U64 => (u64::MIN as f64, u64::MAX as f64),
|
||||
_ => (0.0, 1.0),
|
||||
};
|
||||
view.size_c
|
||||
view.shape().c
|
||||
]
|
||||
} else {
|
||||
(0..size_c)
|
||||
@@ -233,13 +251,16 @@ where
|
||||
.collect::<Result<Vec<_>, Error>>()?
|
||||
};
|
||||
|
||||
thread::spawn(move || {
|
||||
let rt = tokio::runtime::Runtime::new()?;
|
||||
let bar = get_bar(Some(size_t));
|
||||
let rt_bar = bar.clone();
|
||||
let write_task = rt.spawn(async move {
|
||||
for t in 0..size_t {
|
||||
let mut frame = Array3::<f64>::zeros((size_y, size_x, 3));
|
||||
for c in 0..size_c {
|
||||
frame = frame
|
||||
+ cframe(
|
||||
view.get_frame(c, 0, t).unwrap(),
|
||||
view.get_frame(c, 0, t)?,
|
||||
&colors[c],
|
||||
ab[c].0,
|
||||
ab[c].1 / brightness[c],
|
||||
@@ -247,18 +268,30 @@ where
|
||||
}
|
||||
let frame = (frame.clamp(0.0, 1.0) * 255.0).round().mapv(|i| i as u8);
|
||||
let bytes: Vec<_> = frame.flatten().into_iter().collect();
|
||||
stdin.write_all(&bytes).unwrap();
|
||||
stdin.write_all(&bytes)?;
|
||||
rt_bar.inc(1);
|
||||
}
|
||||
Ok::<(), Error>(())
|
||||
});
|
||||
bar.finish();
|
||||
|
||||
let bar = get_bar(Some(size_t));
|
||||
let rt_bar = bar.clone();
|
||||
let progress_task = rt.spawn(async move {
|
||||
for event in movie.iter().map_err(|e| Error::Ffmpeg(e.to_string()))? {
|
||||
match event {
|
||||
FfmpegEvent::Log(LogLevel::Error, e) => Err(Error::Ffmpeg(e))?,
|
||||
FfmpegEvent::Progress(p) => rt_bar.set_position(p.frame as u64),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok::<(), Error>(())
|
||||
});
|
||||
|
||||
movie
|
||||
.iter()
|
||||
.map_err(|e| Error::Ffmpeg(e.to_string()))?
|
||||
.for_each(|e| match e {
|
||||
FfmpegEvent::Log(LogLevel::Error, e) => println!("Error: {}", e),
|
||||
FfmpegEvent::Progress(p) => println!("Progress: {} / 00:00:15", p.time),
|
||||
_ => {}
|
||||
});
|
||||
rt.block_on(progress_task)??;
|
||||
rt.block_on(write_task)??;
|
||||
bar.finish();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -266,20 +299,24 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::reader::Reader;
|
||||
use crate::readers::DynReader;
|
||||
use crate::view::View;
|
||||
|
||||
#[cfg(any(feature = "czi", feature = "bioformats_java"))]
|
||||
#[test]
|
||||
fn movie() -> Result<(), Error> {
|
||||
let file = "1xp53-01-AP1.czi";
|
||||
let file = "czi/1xp53-01-AP1.czi";
|
||||
let path = std::env::current_dir()?
|
||||
.join("tests")
|
||||
.join("files")
|
||||
.join(file);
|
||||
let reader = Reader::new(&path, 0)?;
|
||||
let view = reader.view();
|
||||
let view: View<_, DynReader> = View::from_path(&path)?;
|
||||
let mut options = MovieOptions::default();
|
||||
options.set_overwrite(true);
|
||||
view.save_as_movie("/home/wim/tmp/movie.mp4", &options)?;
|
||||
view.save_as_movie(
|
||||
std::env::home_dir().unwrap().join("tmp/movie.mp4"),
|
||||
&options,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user