diff --git a/Cargo.toml b/Cargo.toml index c43c1c7..8dba3c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "bayer" -version = "0.1.5" +version = "0.2.0" +edition = "2021" authors = ["David Wang "] homepage = "https://github.com/wangds/libbayer.git" repository = "https://github.com/wangds/libbayer.git" @@ -23,14 +24,14 @@ default = ["rayon"] bench = [] [dependencies] -byteorder = "1.1" -libc = "0.2" -rayon = { version = "0.8", optional = true } -quick-error = "1.2" +byteorder = "1.4.3" +libc = "0.2.138" +rayon = { version = "1.6.1", optional = true } +quick-error = "2" [dev-dependencies] -flic = "0.1" -sdl2 = { version = "0.30", features = ["image"] } +flic = "0.1.6" +sdl2 = { version = "0.35.2", features = ["image"] } [badges] -travis-ci = { repository = "wangds/libbayer" } +travis-ci = { repository = "virtualritz/libbayer" } diff --git a/README.md b/README.md index 9ce040a..20cb692 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,25 @@ +# `bayer` -LibBayer [![Version][version-img]][version-url] [![Status][travis-ci-img]][travis-ci-url] -======== +[![Version][version-img]][version-url] [![Status][travis-ci-img]][travis-ci-url] +Routines for demosaicing Bayer sensor (RAW) images. -About ------ +Both 8-bit and 16-bit images are supported. -LibBayer provides routines for demosaicing Bayer (raw) images. - -The library supports 8-bit and 16-bit images. - -Several demosaicing algorithms are available. See the src/demosaic +Several demosaicing algorithms are available. See the `src/demosaic` directory for a list and their individual descriptions. Pixels on the border of the image are retained by replicating or mirroring the data in the neighbourhood. -LibBayer is written entirely in Rust. C bindings to the underlying +The crate is written entirely in Rust. C bindings to the underlying algorithms are provided. +## Examples -Examples --------- - -An example program is provided in the `examples/` directory: - -* _showbayer_ - a simple Bayer file viewer. -* _writebayer_ - converts an image to a raw Bayer image file. - -To clone this repository, run: +* `showbayer` – a simple Bayer file viewer. +* `writebayer` – converts an image to a raw Bayer image file. -```sh -git clone https://github.com/wangds/libbayer.git -``` - -Then build the library and run the example programs using Cargo. +Run the examples programs using `cargo`. ```sh cargo build --release --example showbayer @@ -48,24 +34,15 @@ cargo run --release --example showbayer Change the colour filter array (CFA) pattern and the demosaicing algorithm from inside the example program. +## Basic Usage - -Basic Usage ------------ - -Add LibBayer as a dependency to your project's Cargo.toml: +Add `bayer` as a dependency to your project's `Cargo.toml`: ```toml [dependencies] bayer = "0.1" ``` -Import the library in your project, e.g.: - -```rust -extern crate bayer; -``` - Open a Bayer file from disk. ```rust @@ -84,6 +61,7 @@ let img_h = 200; let depth = bayer::RasterDepth::Depth8; let bytes_per_pixel = 3; let mut buf = vec![0; bytes_per_pixel * img_w * img_h]; + let mut dst = bayer::RasterMut::new(img_w, img_h, depth, &mut buf); ``` @@ -92,6 +70,7 @@ Then run the demosaicing process: ```rust let cfa = bayer::CFA::RGGB; let alg = bayer::Demosaic::Linear; + bayer::run_demosaic(&mut file, bayer::BayerDepth:Depth8, cfa, alg, &mut dst); ``` @@ -99,19 +78,14 @@ Note that many cameras will capture 12-bits per pixel (channel), but store the data as 16-bits per pixel. These should be treated as 16-bits per pixel for the purposes of this library. - -Documentation -------------- +## Documentation * [Documentation][documentation]. - -Author ------- +## Author David Wang - [documentation]: https://docs.rs/bayer/ [travis-ci-img]: https://travis-ci.org/wangds/libbayer.svg?branch=master [travis-ci-url]: https://travis-ci.org/wangds/libbayer diff --git a/benches/benches.rs b/benches/benches.rs index a35d435..ae99129 100644 --- a/benches/benches.rs +++ b/benches/benches.rs @@ -4,11 +4,8 @@ #[cfg(all(feature = "bench", test))] mod bench { - extern crate bayer; - extern crate test; - - use std::io::Cursor; use self::bayer::*; + use std::io::Cursor; const IMG_W: usize = 128; const IMG_H: usize = 128; @@ -20,65 +17,113 @@ mod bench { #[bench] fn bench_none_u8(b: &mut test::Bencher) { - let mut dst = unsafe{ RasterMut::new( - IMG_W, IMG_H, RasterDepth::Depth8, &mut BUF_U8) }; - b.iter(|| run_demosaic(&mut Cursor::new(&SRC_U8[..]), - BayerDepth::Depth8, CFA::RGGB, Demosaic::None, &mut dst)); + let mut dst = unsafe { RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut BUF_U8) }; + b.iter(|| { + run_demosaic( + &mut Cursor::new(&SRC_U8[..]), + BayerDepth::Depth8, + CFA::RGGB, + Demosaic::None, + &mut dst, + ) + }); } #[bench] fn bench_none_u16(b: &mut test::Bencher) { - let mut dst = unsafe{ RasterMut::new( - IMG_W, IMG_H, RasterDepth::Depth16, &mut BUF_U16) }; - b.iter(|| run_demosaic(&mut Cursor::new(&SRC_U16[..]), - BayerDepth::Depth16LE, CFA::RGGB, Demosaic::None, &mut dst)); + let mut dst = unsafe { RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth16, &mut BUF_U16) }; + b.iter(|| { + run_demosaic( + &mut Cursor::new(&SRC_U16[..]), + BayerDepth::Depth16LE, + CFA::RGGB, + Demosaic::None, + &mut dst, + ) + }); } #[bench] fn bench_nearest_neighbour_u8(b: &mut test::Bencher) { - let mut dst = unsafe{ RasterMut::new( - IMG_W, IMG_H, RasterDepth::Depth8, &mut BUF_U8) }; - b.iter(|| run_demosaic(&mut Cursor::new(&SRC_U8[..]), - BayerDepth::Depth8, CFA::RGGB, Demosaic::NearestNeighbour, &mut dst)); + let mut dst = unsafe { RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut BUF_U8) }; + b.iter(|| { + run_demosaic( + &mut Cursor::new(&SRC_U8[..]), + BayerDepth::Depth8, + CFA::RGGB, + Demosaic::NearestNeighbour, + &mut dst, + ) + }); } #[bench] fn bench_nearest_neighbour_u16(b: &mut test::Bencher) { - let mut dst = unsafe{ RasterMut::new( - IMG_W, IMG_H, RasterDepth::Depth16, &mut BUF_U16) }; - b.iter(|| run_demosaic(&mut Cursor::new(&SRC_U16[..]), - BayerDepth::Depth16LE, CFA::RGGB, Demosaic::NearestNeighbour, &mut dst)); + let mut dst = unsafe { RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth16, &mut BUF_U16) }; + b.iter(|| { + run_demosaic( + &mut Cursor::new(&SRC_U16[..]), + BayerDepth::Depth16LE, + CFA::RGGB, + Demosaic::NearestNeighbour, + &mut dst, + ) + }); } #[bench] fn bench_linear_u8(b: &mut test::Bencher) { - let mut dst = unsafe{ RasterMut::new( - IMG_W, IMG_H, RasterDepth::Depth8, &mut BUF_U8) }; - b.iter(|| run_demosaic(&mut Cursor::new(&SRC_U8[..]), - BayerDepth::Depth8, CFA::RGGB, Demosaic::Linear, &mut dst)); + let mut dst = unsafe { RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut BUF_U8) }; + b.iter(|| { + run_demosaic( + &mut Cursor::new(&SRC_U8[..]), + BayerDepth::Depth8, + CFA::RGGB, + Demosaic::Linear, + &mut dst, + ) + }); } #[bench] fn bench_linear_u16(b: &mut test::Bencher) { - let mut dst = unsafe{ RasterMut::new( - IMG_W, IMG_H, RasterDepth::Depth16, &mut BUF_U16) }; - b.iter(|| run_demosaic(&mut Cursor::new(&SRC_U16[..]), - BayerDepth::Depth16LE, CFA::RGGB, Demosaic::Linear, &mut dst)); + let mut dst = unsafe { RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth16, &mut BUF_U16) }; + b.iter(|| { + run_demosaic( + &mut Cursor::new(&SRC_U16[..]), + BayerDepth::Depth16LE, + CFA::RGGB, + Demosaic::Linear, + &mut dst, + ) + }); } #[bench] fn bench_cubic_u8(b: &mut test::Bencher) { - let mut dst = unsafe{ RasterMut::new( - IMG_W, IMG_H, RasterDepth::Depth8, &mut BUF_U8) }; - b.iter(|| run_demosaic(&mut Cursor::new(&SRC_U8[..]), - BayerDepth::Depth8, CFA::RGGB, Demosaic::Cubic, &mut dst)); + let mut dst = unsafe { RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut BUF_U8) }; + b.iter(|| { + run_demosaic( + &mut Cursor::new(&SRC_U8[..]), + BayerDepth::Depth8, + CFA::RGGB, + Demosaic::Cubic, + &mut dst, + ) + }); } #[bench] fn bench_cubic_u16(b: &mut test::Bencher) { - let mut dst = unsafe{ RasterMut::new( - IMG_W, IMG_H, RasterDepth::Depth16, &mut BUF_U16) }; - b.iter(|| run_demosaic(&mut Cursor::new(&SRC_U16[..]), - BayerDepth::Depth16LE, CFA::RGGB, Demosaic::Cubic, &mut dst)); + let mut dst = unsafe { RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth16, &mut BUF_U16) }; + b.iter(|| { + run_demosaic( + &mut Cursor::new(&SRC_U16[..]), + BayerDepth::Depth16LE, + CFA::RGGB, + Demosaic::Cubic, + &mut dst, + ) + }); } } diff --git a/examples/showbayer.rs b/examples/showbayer.rs index e3fe973..9ab135d 100644 --- a/examples/showbayer.rs +++ b/examples/showbayer.rs @@ -1,19 +1,9 @@ //! ShowBayer. - -extern crate bayer; -extern crate sdl2; - -use std::cmp::min; -use std::env; -use std::fs::File; -use std::path::Path; -use std::slice; use bayer::*; -use sdl2::event::Event; -use sdl2::keyboard::Keycode; -use sdl2::pixels::PixelFormatEnum; +use sdl2::{event::Event, keyboard::Keycode, pixels::PixelFormatEnum}; +use std::{cmp::min, env, fs::File, path::Path, slice}; -#[derive(Copy,Clone,Debug,Eq,PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] enum ImgDepth { Depth8, Depth12BE, @@ -46,51 +36,112 @@ fn main() { let sdl = sdl2::init().unwrap(); let video = sdl.video().unwrap(); - let window - = video.window("ShowBayer", bayer_w as u32, bayer_h as u32) + let window = video + .window("ShowBayer", bayer_w as u32, bayer_h as u32) .position_centered() .opengl() - .build().unwrap(); + .build() + .unwrap(); let mut canvas = window.into_canvas().build().unwrap(); let mut event_pump = sdl.event_pump().unwrap(); let texture_creator = canvas.texture_creator(); - let mut texture = texture_creator.create_texture_streaming( - PixelFormatEnum::RGB24, - bayer_w as u32, bayer_h as u32).unwrap(); + let mut texture = texture_creator + .create_texture_streaming(PixelFormatEnum::RGB24, bayer_w as u32, bayer_h as u32) + .unwrap(); let bytes_per_pixel = bytes_per_pixel(raster_depth(depth)); let mut buf = vec![0; bayer_w * bayer_h * bytes_per_pixel]; - read_file(&Path::new(&files[0]), bayer_w, bayer_h, depth, cfa, alg, - &mut buf, &mut texture); + read_file( + &Path::new(&files[0]), + bayer_w, + bayer_h, + depth, + cfa, + alg, + &mut buf, + &mut texture, + ); let mut redraw = true; 'mainloop: loop { if let Some(e) = event_pump.wait_event_timeout(60) { match e { - Event::Quit {..} - | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { + Event::Quit { .. } + | Event::KeyDown { + keycode: Some(Keycode::Escape), + .. + } => { break 'mainloop; - }, + } - Event::KeyDown { keycode: Some(Keycode::F1), .. } => { cfa = CFA::BGGR; }, - Event::KeyDown { keycode: Some(Keycode::F2), .. } => { cfa = CFA::GBRG; }, - Event::KeyDown { keycode: Some(Keycode::F3), .. } => { cfa = CFA::GRBG; }, - Event::KeyDown { keycode: Some(Keycode::F4), .. } => { cfa = CFA::RGGB; }, + Event::KeyDown { + keycode: Some(Keycode::F1), + .. + } => { + cfa = CFA::BGGR; + } + Event::KeyDown { + keycode: Some(Keycode::F2), + .. + } => { + cfa = CFA::GBRG; + } + Event::KeyDown { + keycode: Some(Keycode::F3), + .. + } => { + cfa = CFA::GRBG; + } + Event::KeyDown { + keycode: Some(Keycode::F4), + .. + } => { + cfa = CFA::RGGB; + } - Event::KeyDown { keycode: Some(Keycode::Num0), .. } => { alg = Demosaic::None; }, - Event::KeyDown { keycode: Some(Keycode::Num1), .. } => { alg = Demosaic::NearestNeighbour; }, - Event::KeyDown { keycode: Some(Keycode::Num2), .. } => { alg = Demosaic::Linear; }, - Event::KeyDown { keycode: Some(Keycode::Num3), .. } => { alg = Demosaic::Cubic; }, + Event::KeyDown { + keycode: Some(Keycode::Num0), + .. + } => { + alg = Demosaic::None; + } + Event::KeyDown { + keycode: Some(Keycode::Num1), + .. + } => { + alg = Demosaic::NearestNeighbour; + } + Event::KeyDown { + keycode: Some(Keycode::Num2), + .. + } => { + alg = Demosaic::Linear; + } + Event::KeyDown { + keycode: Some(Keycode::Num3), + .. + } => { + alg = Demosaic::Cubic; + } - Event::KeyDown { keycode: Some(Keycode::Space), .. } - | Event::KeyDown { keycode: Some(Keycode::Right), .. } => { + Event::KeyDown { + keycode: Some(Keycode::Space), + .. + } + | Event::KeyDown { + keycode: Some(Keycode::Right), + .. + } => { idx = (idx + 1) % files.len(); } - Event::KeyDown { keycode: Some(Keycode::Left), .. } => { + Event::KeyDown { + keycode: Some(Keycode::Left), + .. + } => { if idx == 0 { idx = files.len() - 1; } else { @@ -123,8 +174,16 @@ fn main() { print_alg(alg); } - read_file(&Path::new(&files[idx]), bayer_w, bayer_h, depth, cfa, alg, - &mut buf, &mut texture); + read_file( + &Path::new(&files[idx]), + bayer_w, + bayer_h, + depth, + cfa, + alg, + &mut buf, + &mut texture, + ); } present_to_screen(&mut canvas, &texture); @@ -166,7 +225,7 @@ fn parse_depth(s: &String) -> ImgDepth { fn bayer_depth(depth: ImgDepth) -> BayerDepth { match depth { - ImgDepth::Depth8 => BayerDepth::Depth8, + ImgDepth::Depth8 => BayerDepth::Depth8, ImgDepth::Depth12BE => BayerDepth::Depth16BE, ImgDepth::Depth12LE => BayerDepth::Depth16LE, ImgDepth::Depth16BE => BayerDepth::Depth16BE, @@ -176,7 +235,7 @@ fn bayer_depth(depth: ImgDepth) -> BayerDepth { fn raster_depth(depth: ImgDepth) -> RasterDepth { match depth { - ImgDepth::Depth8 => RasterDepth::Depth8, + ImgDepth::Depth8 => RasterDepth::Depth8, ImgDepth::Depth12BE => RasterDepth::Depth16, ImgDepth::Depth12LE => RasterDepth::Depth16, ImgDepth::Depth16BE => RasterDepth::Depth16, @@ -212,22 +271,33 @@ fn print_alg(alg: Demosaic) { } fn read_file( - path: &Path, bayer_w: usize, bayer_h: usize, - depth: ImgDepth, cfa: CFA, alg: Demosaic, - buf: &mut [u8], texture: &mut sdl2::render::Texture) { + path: &Path, + bayer_w: usize, + bayer_h: usize, + depth: ImgDepth, + cfa: CFA, + alg: Demosaic, + buf: &mut [u8], + texture: &mut sdl2::render::Texture, +) { let maybe_file = File::open(path); match maybe_file { Ok(mut f) => { - let result = run_demosaic(&mut f, bayer_depth(depth), cfa, alg, - &mut RasterMut::new(bayer_w, bayer_h, raster_depth(depth), buf)); + let result = demosaic( + &mut f, + bayer_depth(depth), + cfa, + alg, + &mut RasterMut::new(bayer_w, bayer_h, raster_depth(depth), buf), + ); match result { Ok(_) => (), Err(e) => { println!("Error occurred - {}", e); return; - }, + } } - }, + } Err(e) => { println!("Error occurred - {}", e); return; @@ -238,48 +308,56 @@ fn read_file( } fn render_to_texture( - texture: &mut sdl2::render::Texture, - w: usize, h: usize, depth: ImgDepth, buf: &[u8]) { + texture: &mut sdl2::render::Texture, + w: usize, + h: usize, + depth: ImgDepth, + buf: &[u8], +) { match raster_depth(depth) { RasterDepth::Depth8 => { - texture.with_lock(None, |buffer: &mut [u8], pitch: usize| { - for y in 0..h { - let src_offset = (3 * w) * y; - let dst_offset = pitch * y; - - for i in 0..3 * w { - buffer[dst_offset + i] = buf[src_offset + i]; + texture + .with_lock(None, |buffer: &mut [u8], pitch: usize| { + for y in 0..h { + let src_offset = (3 * w) * y; + let dst_offset = pitch * y; + + for i in 0..3 * w { + buffer[dst_offset + i] = buf[src_offset + i]; + } } - } - }).unwrap(); - }, + }) + .unwrap(); + } RasterDepth::Depth16 => { - let shr = if depth == ImgDepth::Depth12BE || depth == ImgDepth::Depth12LE { 4 } else { 8 }; - let buf = unsafe { - slice::from_raw_parts(buf.as_ptr() as *const u16, buf.len() / 2) + let shr = if depth == ImgDepth::Depth12BE || depth == ImgDepth::Depth12LE { + 4 + } else { + 8 }; - - texture.with_lock(None, |buffer: &mut [u8], pitch: usize| { - for y in 0..h { - let src_offset = (3 * w) * y; - let dst_offset = pitch * y; - - for i in 0..3 * w { - // shr = 8 for u16 to u8, or - // shr = 4 for u12 to u8. - let v = buf[src_offset + i] >> shr; - buffer[dst_offset + i] = min(v, 255) as u8; + let buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *const u16, buf.len() / 2) }; + + texture + .with_lock(None, |buffer: &mut [u8], pitch: usize| { + for y in 0..h { + let src_offset = (3 * w) * y; + let dst_offset = pitch * y; + + for i in 0..3 * w { + // shr = 8 for u16 to u8, or + // shr = 4 for u12 to u8. + let v = buf[src_offset + i] >> shr; + buffer[dst_offset + i] = min(v, 255) as u8; + } } - } - }).unwrap(); - }, + }) + .unwrap(); + } } } -fn present_to_screen( - canvas: &mut sdl2::render::WindowCanvas, - texture: &sdl2::render::Texture) { +fn present_to_screen(canvas: &mut sdl2::render::WindowCanvas, texture: &sdl2::render::Texture) { canvas.clear(); let _ = canvas.copy(&texture, None, None); canvas.present(); diff --git a/examples/writebayer.rs b/examples/writebayer.rs index 3e611f4..d43aaf7 100644 --- a/examples/writebayer.rs +++ b/examples/writebayer.rs @@ -4,12 +4,12 @@ extern crate bayer; extern crate flic; extern crate sdl2; +use sdl2::image::LoadSurface; +use sdl2::surface::Surface; use std::env; use std::fs::File; use std::io::Write; -use std::path::{Path,PathBuf}; -use sdl2::image::LoadSurface; -use sdl2::surface::Surface; +use std::path::{Path, PathBuf}; fn main() { let args: Vec = env::args().skip(1).collect(); @@ -19,8 +19,10 @@ fn main() { return; } - sdl2::image::init(sdl2::image::INIT_JPG | sdl2::image::INIT_PNG | sdl2::image::INIT_TIF) - .unwrap(); + sdl2::image::init( + sdl2::image::InitFlag::JPG | sdl2::image::InitFlag::PNG | sdl2::image::InitFlag::TIF, + ) + .unwrap(); let cfa = parse_cfa(&args[0]); let files = &args[1..]; @@ -45,8 +47,10 @@ fn main() { let mut buf = vec![0; w * h]; let mut pal = vec![0; 3 * 256]; - if flic.read_next_frame( - &mut flic::RasterMut::new(w, h, &mut buf, &mut pal)).is_err() { + if flic + .read_next_frame(&mut flic::RasterMut::new(w, h, &mut buf, &mut pal)) + .is_err() + { continue; } @@ -85,8 +89,7 @@ fn parse_cfa(s: &String) -> bayer::CFA { } } -fn write_mosaic_rgba(dst: &PathBuf, - s: &[u8], w: usize, h: usize, cfa: bayer::CFA) { +fn write_mosaic_rgba(dst: &PathBuf, s: &[u8], w: usize, h: usize, cfa: bayer::CFA) { let mut v = Vec::with_capacity(w * h); let mut cfa_y = cfa; @@ -95,12 +98,9 @@ fn write_mosaic_rgba(dst: &PathBuf, for x in 0..w { let c = match cfa_x { - bayer::CFA::BGGR => - s[4 * w * y + 4 * x + 2], - bayer::CFA::GBRG | bayer::CFA::GRBG => - s[4 * w * y + 4 * x + 1], - bayer::CFA::RGGB => - s[4 * w * y + 4 * x + 0], + bayer::CFA::BGGR => s[4 * w * y + 4 * x + 2], + bayer::CFA::GBRG | bayer::CFA::GRBG => s[4 * w * y + 4 * x + 1], + bayer::CFA::RGGB => s[4 * w * y + 4 * x + 0], }; v.push(c); @@ -116,8 +116,7 @@ fn write_mosaic_rgba(dst: &PathBuf, } } -fn write_mosaic_pal(dst: &PathBuf, - buf: &[u8], pal: &[u8], w: usize, h: usize, cfa: bayer::CFA) { +fn write_mosaic_pal(dst: &PathBuf, buf: &[u8], pal: &[u8], w: usize, h: usize, cfa: bayer::CFA) { let mut v = Vec::with_capacity(w * h); let mut cfa_y = cfa; @@ -126,12 +125,9 @@ fn write_mosaic_pal(dst: &PathBuf, for x in 0..w { let c = match cfa_x { - bayer::CFA::BGGR => - pal[3 * buf[w * y + x] as usize + 2], - bayer::CFA::GBRG | bayer::CFA::GRBG => - pal[3 * buf[w * y + x] as usize + 1], - bayer::CFA::RGGB => - pal[3 * buf[w * y + x] as usize + 0], + bayer::CFA::BGGR => pal[3 * buf[w * y + x] as usize + 2], + bayer::CFA::GBRG | bayer::CFA::GRBG => pal[3 * buf[w * y + x] as usize + 1], + bayer::CFA::RGGB => pal[3 * buf[w * y + x] as usize + 0], }; v.push(c); diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..80a6f79 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,5 @@ +edition = "2021" +use_field_init_shorthand = true +reorder_impl_items = true +wrap_comments = true +format_code_in_doc_comments = true diff --git a/src/bayer.rs b/src/bayer.rs index 82d3385..209f369 100644 --- a/src/bayer.rs +++ b/src/bayer.rs @@ -1,16 +1,16 @@ //! Bayer image definitions. +use byteorder::{BigEndian, LittleEndian, ReadBytesExt}; use std::io::Read; -use byteorder::{BigEndian,LittleEndian,ReadBytesExt}; -use ::BayerResult; +use crate::BayerResult; -/// The 2x2 colour filter array (CFA) pattern. +/// The 2×2 colour filter array (CFA) pattern. /// /// The sequence of R, G, B describe the colours of the top-left, -/// top-right, bottom-left, and bottom-right pixels in the 2x2 block, +/// top-right, bottom-left, and bottom-right pixels in the 2×2 block, /// in that order. -#[derive(Clone,Copy,Debug,Eq,PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum CFA { BGGR, GBRG, @@ -20,56 +20,53 @@ pub enum CFA { /// The depth and endianness of the raw image. /// -/// Note that many cameras only capture 12-bits per pixel, but still +/// Note that many cameras only capture 12 bits per pixel, but still /// store the data as 16-bits per pixel. These should be treated as -/// 16-bits per pixel for the purposes of this library. -#[derive(Clone,Copy,Debug,Eq,PartialEq)] +/// 16 bits per pixel for the purposes of this library. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum BayerDepth { Depth8, Depth16BE, Depth16LE, } -/// Trait for reading 8-bpp Bayer lines. +/// Trait for reading 8 bit per pixel Bayer lines. pub trait BayerRead8 { - fn read_line(&self, r: &mut Read, dst: &mut [u8]) -> BayerResult<()>; + fn read_line(&self, r: &mut dyn Read, dst: &mut [u8]) -> BayerResult<()>; } -/// Trait for reading 16-bpp Bayer lines, big-endian or little-endian. +/// Trait for reading 16 bit per pixel Bayer lines. Big-endian or little-endian. pub trait BayerRead16 { - fn read_line(&self, r: &mut Read, dst: &mut [u16]) -> BayerResult<()>; + fn read_line(&self, r: &mut dyn Read, dst: &mut [u16]) -> BayerResult<()>; } -/// Read the exact number of bytes required to fill buf. -/// For u8 source data. -pub fn read_exact_u8(r: &mut Read, buf: &mut [u8]) - -> BayerResult<()> { +/// Read the exact number of bytes required to fill `buf`. +/// For [`u8`] source data. +pub fn read_exact_u8(r: &mut dyn Read, buf: &mut [u8]) -> BayerResult<()> { r.read_exact(buf)?; Ok(()) } -/// Read the exact number of bytes required to fill buf. -/// For u16 big-endian source data. -pub fn read_exact_u16be(r: &mut Read, buf: &mut [u16]) - -> BayerResult<()> { - for i in 0..buf.len() { - buf[i] = r.read_u16::()?; +/// Read the exact number of bytes required to fill `buf`. +/// For [`u16`] big-endian source data. +pub fn read_exact_u16be(r: &mut dyn Read, buf: &mut [u16]) -> BayerResult<()> { + for item in buf { + *item = r.read_u16::()?; } Ok(()) } -/// Read the exact number of bytes required to fill buf. -/// For u16 little-endian source data. -pub fn read_exact_u16le(r: &mut Read, buf: &mut [u16]) - -> BayerResult<()> { - for i in 0..buf.len() { - buf[i] = r.read_u16::()?; +/// Read the exact number of bytes required to fill `buf`. +/// For [`u16`] little-endian source data. +pub fn read_exact_u16le(r: &mut dyn Read, buf: &mut [u16]) -> BayerResult<()> { + for item in buf { + *item = r.read_u16::()?; } Ok(()) } impl CFA { - /// The 2x2 pixel block obtained when moving right 1 column. + /// The 2×2 pixel block obtained when moving right one column. pub fn next_x(self) -> Self { match self { CFA::BGGR => CFA::GBRG, @@ -79,7 +76,7 @@ impl CFA { } } - /// The 2x2 pixel block obtained when moving down 1 row. + /// The 2×2 pixel block obtained when moving down one row. pub fn next_y(self) -> Self { match self { CFA::BGGR => CFA::GRBG, diff --git a/src/border_mirror.rs b/src/border_mirror.rs index 2975b9c..3116d26 100644 --- a/src/border_mirror.rs +++ b/src/border_mirror.rs @@ -10,8 +10,8 @@ use std::io::Read; -use ::BayerResult; -use bayer::*; +use crate::bayer::*; +use crate::BayerResult; /// Tuple structs (x1, x2, x3) designating the different sub-regions /// of the output lines. @@ -35,8 +35,8 @@ macro_rules! fill_row { j = $x1 + 1; while i > 0 { $dst[i - 1] = $dst[j]; - i = i - 1; - j = j + 1; + i -= 1; + j += 1; } // Right border. @@ -44,10 +44,10 @@ macro_rules! fill_row { j = $x2 - 2; while i < $x3 { $dst[i] = $dst[j]; - i = i + 1; - j = j - 1; + i += 1; + j -= 1; } - }} + }}; } impl BorderMirror8 { @@ -62,8 +62,7 @@ impl BorderMirror8 { } impl BayerRead8 for BorderMirror8 { - fn read_line(&self, r: &mut Read, dst: &mut [u8]) - -> BayerResult<()> { + fn read_line(&self, r: &mut dyn Read, dst: &mut [u8]) -> BayerResult<()> { let BorderMirror8(x1, x2, x3) = *self; read_exact_u8(r, &mut dst[x1..x2])?; fill_row!(dst, x1, x2, x3); @@ -83,8 +82,7 @@ impl BorderMirror16BE { } impl BayerRead16 for BorderMirror16BE { - fn read_line(&self, r: &mut Read, dst: &mut [u16]) - -> BayerResult<()> { + fn read_line(&self, r: &mut dyn Read, dst: &mut [u16]) -> BayerResult<()> { let BorderMirror16BE(x1, x2, x3) = *self; read_exact_u16be(r, &mut dst[x1..x2])?; fill_row!(dst, x1, x2, x3); @@ -104,8 +102,7 @@ impl BorderMirror16LE { } impl BayerRead16 for BorderMirror16LE { - fn read_line(&self, r: &mut Read, dst: &mut [u16]) - -> BayerResult<()> { + fn read_line(&self, r: &mut dyn Read, dst: &mut [u16]) -> BayerResult<()> { let BorderMirror16LE(x1, x2, x3) = *self; read_exact_u16le(r, &mut dst[x1..x2])?; fill_row!(dst, x1, x2, x3); @@ -115,19 +112,17 @@ impl BayerRead16 for BorderMirror16LE { #[cfg(test)] mod tests { - use std::io::Cursor; - use bayer::BayerRead8; use super::BorderMirror8; + use crate::bayer::BayerRead8; + use std::io::Cursor; #[test] fn test_mirror_even() { - let src = [ - 1,2, 3,4, 5,6 ]; + let src = [1, 2, 3, 4, 5, 6]; let expected = [ - 5,4, 3,2, - /*-----*/ 1,2, 3,4, 5,6, - /*--------------------*/ 5,4, 3,2 ]; + 5, 4, 3, 2, /* - */ 1, 2, 3, 4, 5, 6, /* - */ 5, 4, 3, 2, + ]; let rdr = BorderMirror8::new(6, 4); let mut buf = [0u8; 4 + 6 + 4]; @@ -139,13 +134,9 @@ mod tests { #[test] fn test_mirror_odd() { - let src = [ - 1,2, 3,4, 5, ]; + let src = [1, 2, 3, 4, 5]; - let expected = [ - 4, 3,2, - /*---*/ 1,2, 3,4, 5, - /*---------------*/ 4, 3,2 ]; + let expected = [4, 3, 2, /* - */ 1, 2, 3, 4, 5, /* - */ 4, 3, 2]; let rdr = BorderMirror8::new(5, 3); let mut buf = [0u8; 3 + 5 + 3]; diff --git a/src/border_none.rs b/src/border_none.rs index 85bff11..a6650cc 100644 --- a/src/border_none.rs +++ b/src/border_none.rs @@ -2,8 +2,8 @@ use std::io::Read; -use ::BayerResult; -use bayer::*; +use crate::bayer::*; +use crate::BayerResult; pub struct BorderNone8; pub struct BorderNone16BE; @@ -16,8 +16,7 @@ impl BorderNone8 { } impl BayerRead8 for BorderNone8 { - fn read_line(&self, r: &mut Read, dst: &mut [u8]) - -> BayerResult<()> { + fn read_line(&self, r: &mut dyn Read, dst: &mut [u8]) -> BayerResult<()> { read_exact_u8(r, dst) } } @@ -29,8 +28,7 @@ impl BorderNone16BE { } impl BayerRead16 for BorderNone16BE { - fn read_line(&self, r: &mut Read, dst: &mut [u16]) - -> BayerResult<()> { + fn read_line(&self, r: &mut dyn Read, dst: &mut [u16]) -> BayerResult<()> { read_exact_u16be(r, dst) } } @@ -42,8 +40,7 @@ impl BorderNone16LE { } impl BayerRead16 for BorderNone16LE { - fn read_line(&self, r: &mut Read, dst: &mut [u16]) - -> BayerResult<()> { + fn read_line(&self, r: &mut dyn Read, dst: &mut [u16]) -> BayerResult<()> { read_exact_u16le(r, dst) } } diff --git a/src/border_replicate.rs b/src/border_replicate.rs index af1b344..4710f69 100644 --- a/src/border_replicate.rs +++ b/src/border_replicate.rs @@ -10,8 +10,8 @@ use std::io::Read; -use ::BayerResult; -use bayer::*; +use crate::bayer::*; +use crate::BayerResult; /// Tuple structs (x1, x2, x3) designating the different sub-regions /// of the output lines. @@ -40,7 +40,7 @@ macro_rules! fill_row { while i < $x1 { $dst[i + 0] = r0; $dst[i + 1] = g0; - i = i + 2; + i += 2; } // Right border. @@ -50,12 +50,12 @@ macro_rules! fill_row { while i + 1 < $x3 { $dst[i + 0] = r0; $dst[i + 1] = g0; - i = i + 2; + i += 2; } if i == $x3 - 1 { $dst[i] = r0; } - }} + }}; } impl BorderReplicate8 { @@ -70,8 +70,7 @@ impl BorderReplicate8 { } impl BayerRead8 for BorderReplicate8 { - fn read_line(&self, r: &mut Read, dst: &mut [u8]) - -> BayerResult<()> { + fn read_line(&self, r: &mut dyn Read, dst: &mut [u8]) -> BayerResult<()> { let BorderReplicate8(x1, x2, x3) = *self; read_exact_u8(r, &mut dst[x1..x2])?; fill_row!(dst, x1, x2, x3); @@ -91,8 +90,7 @@ impl BorderReplicate16BE { } impl BayerRead16 for BorderReplicate16BE { - fn read_line(&self, r: &mut Read, dst: &mut [u16]) - -> BayerResult<()> { + fn read_line(&self, r: &mut dyn Read, dst: &mut [u16]) -> BayerResult<()> { let BorderReplicate16BE(x1, x2, x3) = *self; read_exact_u16be(r, &mut dst[x1..x2])?; fill_row!(dst, x1, x2, x3); @@ -112,8 +110,7 @@ impl BorderReplicate16LE { } impl BayerRead16 for BorderReplicate16LE { - fn read_line(&self, r: &mut Read, dst: &mut [u16]) - -> BayerResult<()> { + fn read_line(&self, r: &mut dyn Read, dst: &mut [u16]) -> BayerResult<()> { let BorderReplicate16LE(x1, x2, x3) = *self; read_exact_u16le(r, &mut dst[x1..x2])?; fill_row!(dst, x1, x2, x3); @@ -123,19 +120,17 @@ impl BayerRead16 for BorderReplicate16LE { #[cfg(test)] mod tests { - use std::io::Cursor; - use bayer::BayerRead8; use super::BorderReplicate8; + use crate::bayer::BayerRead8; + use std::io::Cursor; #[test] fn test_replicate_even() { - let src = [ - 1,2, 3,4, 5,6 ]; + let src = [1, 2, 3, 4, 5, 6]; let expected = [ - 1,2, 1,2, - /*-----*/ 1,2, 3,4, 5,6, - /*--------------------*/ 5,6, 5,6 ]; + 1, 2, 1, 2, /* - */ 1, 2, 3, 4, 5, 6, /* - */ 5, 6, 5, 6, + ]; let rdr = BorderReplicate8::new(6, 4); let mut buf = [0u8; 4 + 6 + 4]; @@ -147,13 +142,9 @@ mod tests { #[test] fn test_replicate_odd() { - let src = [ - 1,2, 3,4, 5, ]; + let src = [1, 2, 3, 4, 5]; - let expected = [ - 2, 1,2, - /*---*/ 1,2, 3,4, 5, - /*---------------*/ 4, 5,4 ]; + let expected = [2, 1, 2, /* - */ 1, 2, 3, 4, 5, /* - */ 4, 5, 4]; let rdr = BorderReplicate8::new(5, 3); let mut buf = [0u8; 3 + 5 + 3]; diff --git a/src/demosaic/cubic.rs b/src/demosaic/cubic.rs index 13d0e60..7828a79 100644 --- a/src/demosaic/cubic.rs +++ b/src/demosaic/cubic.rs @@ -29,16 +29,14 @@ use std::slice; #[cfg(feature = "rayon")] use rayon::prelude::*; -use ::{BayerDepth,BayerError,BayerResult,CFA,RasterMut}; -use bayer::{BayerRead8,BayerRead16}; -use border_mirror::*; -use demosaic::check_depth; +use crate::bayer::{BayerRead16, BayerRead8}; +use crate::border_mirror::*; +use crate::demosaic::check_depth; +use crate::{BayerDepth, BayerError, BayerResult, RasterMut, CFA}; const PADDING: usize = 3; -pub fn run(r: &mut Read, - depth: BayerDepth, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +pub fn run(r: &mut dyn Read, depth: BayerDepth, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { if dst.w < 4 || dst.h < 4 { return Err(BayerError::WrongResolution); } @@ -69,7 +67,7 @@ macro_rules! apply_kernel_row { while i + 1 < $w { apply_kernel_c!($T; $row, $w, $prv3, $prv2, $prv1, $curr, $nxt1, $nxt2, $nxt3, cfa_c, i); apply_kernel_g!($T; $row, $w, $prv3, $prv2, $prv1, $curr, $nxt1, $nxt2, $nxt3, cfa_g, i + 1); - i = i + 2; + i += 2; } if i < $w { @@ -87,38 +85,40 @@ macro_rules! apply_kernel_c { let (c, d) = if $cfa == CFA::BGGR { (2, 0) } else { (0, 2) }; let j = $i + PADDING; - let g_pos - = ( $prv1[j] as u32 - + $curr[j - 1] as u32 + $curr[j + 1] as u32 - + $nxt1[j] as u32) * 81 - + ( $prv3[j] as u32 - + $curr[j - 3] as u32 + $curr[j + 3] as u32 - + $nxt3[j] as u32); - let g_neg - = ( $prv2[j - 1] as u32 + $prv2[j + 1] as u32 - + $prv1[j - 2] as u32 + $prv1[j + 2] as u32 - + $nxt1[j - 2] as u32 + $nxt1[j + 2] as u32 - + $nxt2[j - 1] as u32 + $nxt2[j + 1] as u32) * 9; - - let d_pos - = ( $prv1[j - 1] as u32 + $prv1[j + 1] as u32 - + $nxt1[j - 1] as u32 + $nxt1[j + 1] as u32) * 81 - + ( $prv3[j - 3] as u32 + $prv3[j + 3] as u32 - + $nxt3[j - 3] as u32 + $nxt3[j + 3] as u32); - let d_neg - = ( $prv3[j - 1] as u32 + $prv3[j + 1] as u32 - + $prv1[j - 3] as u32 + $prv1[j + 3] as u32 - + $nxt1[j - 3] as u32 + $nxt1[j + 3] as u32 - + $nxt3[j - 1] as u32 + $nxt3[j + 1] as u32) * 9; + let g_pos = ($prv1[j] as u32 + $curr[j - 1] as u32 + $curr[j + 1] as u32 + $nxt1[j] as u32) + * 81 + + ($prv3[j] as u32 + $curr[j - 3] as u32 + $curr[j + 3] as u32 + $nxt3[j] as u32); + let g_neg = ($prv2[j - 1] as u32 + + $prv2[j + 1] as u32 + + $prv1[j - 2] as u32 + + $prv1[j + 2] as u32 + + $nxt1[j - 2] as u32 + + $nxt1[j + 2] as u32 + + $nxt2[j - 1] as u32 + + $nxt2[j + 1] as u32) + * 9; + + let d_pos = + ($prv1[j - 1] as u32 + $prv1[j + 1] as u32 + $nxt1[j - 1] as u32 + $nxt1[j + 1] as u32) + * 81 + + ($prv3[j - 3] as u32 + + $prv3[j + 3] as u32 + + $nxt3[j - 3] as u32 + + $nxt3[j + 3] as u32); + let d_neg = ($prv3[j - 1] as u32 + + $prv3[j + 1] as u32 + + $prv1[j - 3] as u32 + + $prv1[j + 3] as u32 + + $nxt1[j - 3] as u32 + + $nxt1[j + 3] as u32 + + $nxt3[j - 1] as u32 + + $nxt3[j + 1] as u32) + * 9; $row[3 * $i + c] = $curr[j]; - $row[3 * $i + 1] - = min(g_pos.saturating_sub(g_neg) / 256, - $T::max_value() as u32) as $T; - $row[3 * $i + d] - = min(d_pos.saturating_sub(d_neg) / 256, - $T::max_value() as u32) as $T; - }} + $row[3 * $i + 1] = min(g_pos.saturating_sub(g_neg) / 256, $T::max_value() as u32) as $T; + $row[3 * $i + d] = min(d_pos.saturating_sub(d_neg) / 256, $T::max_value() as u32) as $T; + }}; } macro_rules! apply_kernel_g { @@ -135,24 +135,19 @@ macro_rules! apply_kernel_g { let v_pos = ($prv1[j] as u32 + $nxt1[j] as u32) * 9; let v_neg = ($prv3[j] as u32 + $nxt3[j] as u32); - $row[3 * $i + h] - = min(h_pos.saturating_sub(h_neg) / 16, - $T::max_value() as u32) as $T; + $row[3 * $i + h] = min(h_pos.saturating_sub(h_neg) / 16, $T::max_value() as u32) as $T; $row[3 * $i + 1] = $curr[j]; - $row[3 * $i + v] - = min(v_pos.saturating_sub(v_neg) / 16, - $T::max_value() as u32) as $T; - }} + $row[3 * $i + v] = min(v_pos.saturating_sub(v_neg) / 16, $T::max_value() as u32) as $T; + }}; } -/*--------------------------------------------------------------*/ -/* Rayon */ -/*--------------------------------------------------------------*/ +/* -------------------------------------------------------------- */ +/* Rayon */ +/* -------------------------------------------------------------- */ #[cfg(feature = "rayon")] #[allow(unused_parens)] -fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u8(r: &mut dyn Read, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut data = vec![0u8; (2 * PADDING + w) * (2 * PADDING + h)]; @@ -160,107 +155,114 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) { let stride = 2 * PADDING + w; let rdr = BorderMirror8::new(w, PADDING); - for mut row in data.chunks_mut(stride).skip(PADDING).take(h) { - rdr.read_line(r, &mut row)?; + for row in data.chunks_mut(stride).skip(PADDING).take(h) { + rdr.read_line(r, row)?; } { let (top, src) = data.split_at_mut(stride * PADDING); - top[(stride * 0)..(stride * 1)].copy_from_slice(&src[(stride * 3)..(stride * 4)]); - top[(stride * 1)..(stride * 2)].copy_from_slice(&src[(stride * 2)..(stride * 3)]); - top[(stride * 2)..(stride * 3)].copy_from_slice(&src[(stride * 1)..(stride * 2)]); + top[..stride].copy_from_slice(&src[(stride * 3)..(stride * 4)]); + top[stride..(stride * 2)].copy_from_slice(&src[(stride * 2)..(stride * 3)]); + top[(stride * 2)..(stride * 3)].copy_from_slice(&src[stride..(stride * 2)]); } { let (src, bottom) = data.split_at_mut(stride * (h + PADDING)); let yy = PADDING + h; - bottom[(stride * 0)..(stride * 1)].copy_from_slice(&src[(stride * (yy - 2))..(stride * (yy - 1))]); - bottom[(stride * 1)..(stride * 2)].copy_from_slice(&src[(stride * (yy - 3))..(stride * (yy - 2))]); - bottom[(stride * 2)..(stride * 3)].copy_from_slice(&src[(stride * (yy - 4))..(stride * (yy - 3))]); + bottom[..stride].copy_from_slice(&src[(stride * (yy - 2))..(stride * (yy - 1))]); + bottom[stride..(stride * 2)] + .copy_from_slice(&src[(stride * (yy - 3))..(stride * (yy - 2))]); + bottom[(stride * 2)..(stride * 3)] + .copy_from_slice(&src[(stride * (yy - 4))..(stride * (yy - 3))]); } } - dst.buf.par_chunks_mut(dst.stride).enumerate() - .for_each(|(y, mut row)| { - let stride = 2 * PADDING + w; - let prv3 = &data[(stride * (PADDING + y - 3)) .. (stride * (PADDING + y - 2))]; - let prv2 = &data[(stride * (PADDING + y - 2)) .. (stride * (PADDING + y - 1))]; - let prv1 = &data[(stride * (PADDING + y - 1)) .. (stride * (PADDING + y + 0))]; - let curr = &data[(stride * (PADDING + y + 0)) .. (stride * (PADDING + y + 1))]; - let nxt1 = &data[(stride * (PADDING + y + 1)) .. (stride * (PADDING + y + 2))]; - let nxt2 = &data[(stride * (PADDING + y + 2)) .. (stride * (PADDING + y + 3))]; - let nxt3 = &data[(stride * (PADDING + y + 3)) .. (stride * (PADDING + y + 4))]; - let cfa_y = if y % 2 == 0 { cfa } else { cfa.next_y() }; - - apply_kernel_row!(u8; row, prv3, prv2, prv1, curr, nxt1, nxt2, nxt3, cfa_y, w); - }); + dst.buf + .par_chunks_mut(dst.stride) + .enumerate() + .for_each(|(y, row)| { + let stride = 2 * PADDING + w; + let prv3 = &data[(stride * (PADDING + y - 3))..(stride * (PADDING + y - 2))]; + let prv2 = &data[(stride * (PADDING + y - 2))..(stride * (PADDING + y - 1))]; + let prv1 = &data[(stride * (PADDING + y - 1))..(stride * (PADDING + y))]; + let curr = &data[(stride * (PADDING + y))..(stride * (PADDING + y + 1))]; + let nxt1 = &data[(stride * (PADDING + y + 1))..(stride * (PADDING + y + 2))]; + let nxt2 = &data[(stride * (PADDING + y + 2))..(stride * (PADDING + y + 3))]; + let nxt3 = &data[(stride * (PADDING + y + 3))..(stride * (PADDING + y + 4))]; + let cfa_y = if y % 2 == 0 { cfa } else { cfa.next_y() }; + + apply_kernel_row!(u8; row, prv3, prv2, prv1, curr, nxt1, nxt2, nxt3, cfa_y, w); + }); Ok(()) } #[cfg(feature = "rayon")] #[allow(unused_parens)] -fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u16(r: &mut dyn Read, be: bool, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut data = vec![0u16; (2 * PADDING + w) * (2 * PADDING + h)]; // Read all data. { let stride = 2 * PADDING + w; - let rdr: Box = if be { + let rdr: Box = if be { Box::new(BorderMirror16BE::new(w, PADDING)) } else { Box::new(BorderMirror16LE::new(w, PADDING)) }; - for mut row in data.chunks_mut(stride).skip(PADDING).take(h) { - rdr.read_line(r, &mut row)?; + for row in data.chunks_mut(stride).skip(PADDING).take(h) { + rdr.read_line(r, row)?; } { let (top, src) = data.split_at_mut(stride * PADDING); - top[(stride * 0)..(stride * 1)].copy_from_slice(&src[(stride * 3)..(stride * 4)]); - top[(stride * 1)..(stride * 2)].copy_from_slice(&src[(stride * 2)..(stride * 3)]); - top[(stride * 2)..(stride * 3)].copy_from_slice(&src[(stride * 1)..(stride * 2)]); + top[..stride].copy_from_slice(&src[(stride * 3)..(stride * 4)]); + top[stride..(stride * 2)].copy_from_slice(&src[(stride * 2)..(stride * 3)]); + top[(stride * 2)..(stride * 3)].copy_from_slice(&src[stride..(stride * 2)]); } { let (src, bottom) = data.split_at_mut(stride * (h + PADDING)); let yy = PADDING + h; - bottom[(stride * 0)..(stride * 1)].copy_from_slice(&src[(stride * (yy - 2))..(stride * (yy - 1))]); - bottom[(stride * 1)..(stride * 2)].copy_from_slice(&src[(stride * (yy - 3))..(stride * (yy - 2))]); - bottom[(stride * 2)..(stride * 3)].copy_from_slice(&src[(stride * (yy - 4))..(stride * (yy - 3))]); + bottom[..stride].copy_from_slice(&src[(stride * (yy - 2))..(stride * (yy - 1))]); + bottom[stride..(stride * 2)] + .copy_from_slice(&src[(stride * (yy - 3))..(stride * (yy - 2))]); + bottom[(stride * 2)..(stride * 3)] + .copy_from_slice(&src[(stride * (yy - 4))..(stride * (yy - 3))]); } } - dst.buf.par_chunks_mut(dst.stride).enumerate() - .for_each(|(y, mut row)| { - let stride = 2 * PADDING + w; - let prv3 = &data[(stride * (PADDING + y - 3)) .. (stride * (PADDING + y - 2))]; - let prv2 = &data[(stride * (PADDING + y - 2)) .. (stride * (PADDING + y - 1))]; - let prv1 = &data[(stride * (PADDING + y - 1)) .. (stride * (PADDING + y + 0))]; - let curr = &data[(stride * (PADDING + y + 0)) .. (stride * (PADDING + y + 1))]; - let nxt1 = &data[(stride * (PADDING + y + 1)) .. (stride * (PADDING + y + 2))]; - let nxt2 = &data[(stride * (PADDING + y + 2)) .. (stride * (PADDING + y + 3))]; - let nxt3 = &data[(stride * (PADDING + y + 3)) .. (stride * (PADDING + y + 4))]; - let cfa_y = if y % 2 == 0 { cfa } else { cfa.next_y() }; - - let row16 = unsafe{ slice::from_raw_parts_mut(row.as_mut_ptr() as *mut u16, row.len() / 2) }; - apply_kernel_row!(u16; row16, prv3, prv2, prv1, curr, nxt1, nxt2, nxt3, cfa_y, w); - }); + dst.buf + .par_chunks_mut(dst.stride) + .enumerate() + .for_each(|(y, row)| { + let stride = 2 * PADDING + w; + let prv3 = &data[(stride * (PADDING + y - 3))..(stride * (PADDING + y - 2))]; + let prv2 = &data[(stride * (PADDING + y - 2))..(stride * (PADDING + y - 1))]; + let prv1 = &data[(stride * (PADDING + y - 1))..(stride * (PADDING + y))]; + let curr = &data[(stride * (PADDING + y))..(stride * (PADDING + y + 1))]; + let nxt1 = &data[(stride * (PADDING + y + 1))..(stride * (PADDING + y + 2))]; + let nxt2 = &data[(stride * (PADDING + y + 2))..(stride * (PADDING + y + 3))]; + let nxt3 = &data[(stride * (PADDING + y + 3))..(stride * (PADDING + y + 4))]; + let cfa_y = if y % 2 == 0 { cfa } else { cfa.next_y() }; + + let row16 = + unsafe { slice::from_raw_parts_mut(row.as_mut_ptr() as *mut u16, row.len() / 2) }; + apply_kernel_row!(u16; row16, prv3, prv2, prv1, curr, nxt1, nxt2, nxt3, cfa_y, w); + }); Ok(()) } -/*--------------------------------------------------------------*/ -/* Naive */ -/*--------------------------------------------------------------*/ +/* -------------------------------------------------------------- */ +/* Naive */ +/* -------------------------------------------------------------- */ #[cfg(not(feature = "rayon"))] #[allow(unused_parens)] -fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut prv3 = vec![0u8; 2 * PADDING + w]; let mut prv2 = vec![0u8; 2 * PADDING + w]; @@ -281,7 +283,8 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) prv2.copy_from_slice(&nxt2); prv3.copy_from_slice(&nxt3); - { // y = 0. + { + // y = 0. let row = dst.borrow_row_u8_mut(0); apply_kernel_row!(u8; row, nxt3, nxt2, nxt1, curr, nxt1, nxt2, nxt3, cfa, w); cfa = cfa.next_y(); @@ -296,19 +299,22 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) cfa = cfa.next_y(); } - { // y = h - 3. + { + // y = h - 3. let row = dst.borrow_row_u8_mut(h - 3); apply_kernel_row!(u8; row, prv2, prv1, curr, nxt1, nxt2, nxt3, nxt2, cfa, w); cfa = cfa.next_y(); } - { // y = h - 2. + { + // y = h - 2. let row = dst.borrow_row_u8_mut(h - 2); apply_kernel_row!(u8; row, prv1, curr, nxt1, nxt2, nxt3, nxt2, nxt1, cfa, w); cfa = cfa.next_y(); } - { // y = h - 1. + { + // y = h - 1. let row = dst.borrow_row_u8_mut(h - 1); apply_kernel_row!(u8; row, curr, nxt1, nxt2, nxt3, nxt2, nxt1, curr, cfa, w); } @@ -318,8 +324,7 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) #[cfg(not(feature = "rayon"))] #[allow(unused_parens)] -fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut prv3 = vec![0u16; 2 * PADDING + w]; let mut prv2 = vec![0u16; 2 * PADDING + w]; @@ -344,7 +349,8 @@ fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) prv2.copy_from_slice(&nxt2); prv3.copy_from_slice(&nxt3); - { // y = 0. + { + // y = 0. let row = dst.borrow_row_u16_mut(0); apply_kernel_row!(u16; row, nxt3, nxt2, nxt1, curr, nxt1, nxt2, nxt3, cfa, w); cfa = cfa.next_y(); @@ -359,19 +365,22 @@ fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) cfa = cfa.next_y(); } - { // y = h - 3. + { + // y = h - 3. let row = dst.borrow_row_u16_mut(h - 3); apply_kernel_row!(u16; row, prv2, prv1, curr, nxt1, nxt2, nxt3, nxt2, cfa, w); cfa = cfa.next_y(); } - { // y = h - 2. + { + // y = h - 2. let row = dst.borrow_row_u16_mut(h - 2); apply_kernel_row!(u16; row, prv1, curr, nxt1, nxt2, nxt3, nxt2, nxt1, cfa, w); cfa = cfa.next_y(); } - { // y = h - 1. + { + // y = h - 1. let row = dst.borrow_row_u16_mut(h - 1); apply_kernel_row!(u16; row, curr, nxt1, nxt2, nxt3, nxt2, nxt1, curr, cfa, w); } @@ -381,70 +390,78 @@ fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) #[cfg(test)] mod tests { - use std::io::Cursor; - use ::{CFA,RasterDepth,RasterMut}; use super::debayer_u8; + use crate::{RasterDepth, RasterMut, CFA}; + use std::io::Cursor; #[test] fn test_even() { - // R: set.seed(0); matrix(floor(runif(n=64, min=0, max=256)), nrow=8, byrow=TRUE) + // R: set.seed(0); matrix(floor(runif(n=64, min=0, max=256)), nrow=8, + // byrow=TRUE) let src = [ - 229, 67, 95,146,232, 51,229,241, - 169,161, 15, 52, 45,175, 98,197, - 127,183,253, 97,199,239, 54,166, - 32, 68, 98, 3, 97,222, 87,123, - 153,126, 47,211,171,203, 27,185, - 105,210,165,200,141,135,202, 5, - 122,187,177,122,220,112, 62, 18, - 25, 80,132,169,104,233, 75,117 ]; + 229, 67, 95, 146, 232, 51, 229, 241, 169, 161, 15, 52, 45, 175, 98, 197, 127, 183, 253, + 97, 199, 239, 54, 166, 32, 68, 98, 3, 97, 222, 87, 123, 153, 126, 47, 211, 171, 203, + 27, 185, 105, 210, 165, 200, 141, 135, 202, 5, 122, 187, 177, 122, 220, 112, 62, 18, + 25, 80, 132, 169, 104, 233, 75, 117, + ]; let expected = [ - 229,122,186, 161, 67,172, 95, 43,108, 155,146, 58, 232, 61,104, 239, 51,169, 229,117,196, 228,241,206, - 182,169,174, 177,110,161, 177, 15, 98, 201, 70, 52, 219, 45,105, 189,104,175, 154, 98,195, 145,159,197, - 127,159,116, 185,183,105, 253, 95, 48, 242, 97, 15, 199,121,106, 123,239,203, 54,153,195, 35,166,167, - 135, 32, 76, 140,103, 68, 151, 98, 21, 176,121, 3, 179, 97,114, 105,159,222, 27, 87,180, 8,115,123, - 153, 80,146, 98,126,141, 47,157,116, 111,211,100, 171,168,142, 106,203,175, 27,179,110, 9,185, 52, - 139,105,211, 115,154,210, 99,165,209, 153,167,200, 193,141,175, 124,179,135, 42,202, 57, 23,160, 5, - 122,118,139, 143,187,145, 177,158,170, 211,122,194, 220,110,200, 143,112,184, 62, 94,114, 42, 18, 60, - 118, 25, 68, 148,129, 80, 193,132,120, 224,111,169, 226,104,213, 148, 95,233, 66, 75,171, 46, 16,117 ]; + 229, 122, 186, 161, 67, 172, 95, 43, 108, 155, 146, 58, 232, 61, 104, 239, 51, 169, + 229, 117, 196, 228, 241, 206, 182, 169, 174, 177, 110, 161, 177, 15, 98, 201, 70, 52, + 219, 45, 105, 189, 104, 175, 154, 98, 195, 145, 159, 197, 127, 159, 116, 185, 183, 105, + 253, 95, 48, 242, 97, 15, 199, 121, 106, 123, 239, 203, 54, 153, 195, 35, 166, 167, + 135, 32, 76, 140, 103, 68, 151, 98, 21, 176, 121, 3, 179, 97, 114, 105, 159, 222, 27, + 87, 180, 8, 115, 123, 153, 80, 146, 98, 126, 141, 47, 157, 116, 111, 211, 100, 171, + 168, 142, 106, 203, 175, 27, 179, 110, 9, 185, 52, 139, 105, 211, 115, 154, 210, 99, + 165, 209, 153, 167, 200, 193, 141, 175, 124, 179, 135, 42, 202, 57, 23, 160, 5, 122, + 118, 139, 143, 187, 145, 177, 158, 170, 211, 122, 194, 220, 110, 200, 143, 112, 184, + 62, 94, 114, 42, 18, 60, 118, 25, 68, 148, 129, 80, 193, 132, 120, 224, 111, 169, 226, + 104, 213, 148, 95, 233, 66, 75, 171, 46, 16, 117, + ]; const IMG_W: usize = 8; const IMG_H: usize = 8; let mut buf = [0u8; 3 * IMG_W * IMG_H]; - let res = debayer_u8(&mut Cursor::new(&src[..]), CFA::RGGB, - &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf)); + let res = debayer_u8( + &mut Cursor::new(&src[..]), + CFA::RGGB, + &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf), + ); assert!(res.is_ok()); assert_eq!(&buf[..], &expected[..]); } #[test] fn test_odd() { - // R: set.seed(0); matrix(floor(runif(n=49, min=0, max=256)), nrow=7, byrow=TRUE) + // R: set.seed(0); matrix(floor(runif(n=49, min=0, max=256)), nrow=7, + // byrow=TRUE) let src = [ - 229, 67, 95,146,232, 51,229, - 241,169,161, 15, 52, 45,175, - 98,197,127,183,253, 97,199, - 239, 54,166, 32, 68, 98, 3, - 97,222, 87,123,153,126, 47, - 211,171,203, 27,185,105,210, - 165,200,141,135,202, 5,122 ]; + 229, 67, 95, 146, 232, 51, 229, 241, 169, 161, 15, 52, 45, 175, 98, 197, 127, 183, 253, + 97, 199, 239, 54, 166, 32, 68, 98, 3, 97, 222, 87, 123, 153, 126, 47, 211, 171, 203, + 27, 185, 105, 210, 165, 200, 141, 135, 202, 5, 122, + ]; let expected = [ - 229,147,204, 161, 67,183, 95,123, 96, 155,146, 12, 232, 52, 14, 238, 51, 38, 229,123, 41, - 171,241,188, 136,163,169, 111,161, 90, 177,144, 15, 247, 52, 20, 243, 93, 45, 225,175, 48, - 98,236,114, 102,197,104, 127,185, 61, 195,183, 23, 253, 95, 42, 230, 97, 71, 199, 99, 76, - 85,239, 56, 88,208, 54, 105,166, 38, 160,129, 32, 201, 68, 63, 159, 53, 98, 116, 3,106, - 97,231,114, 88,222,105, 87,178, 63, 126,123, 30, 153,125, 63, 97,126,104, 47,124,114, - 135,211,189, 122,214,171, 114,203, 94, 149,165, 27, 174,185, 57, 124,138,105, 79,210,114, - 165,203,205, 150,200,185, 141,184,101, 175,135, 26, 202,116, 56, 160, 5,105, 122, 93,115 ]; + 229, 147, 204, 161, 67, 183, 95, 123, 96, 155, 146, 12, 232, 52, 14, 238, 51, 38, 229, + 123, 41, 171, 241, 188, 136, 163, 169, 111, 161, 90, 177, 144, 15, 247, 52, 20, 243, + 93, 45, 225, 175, 48, 98, 236, 114, 102, 197, 104, 127, 185, 61, 195, 183, 23, 253, 95, + 42, 230, 97, 71, 199, 99, 76, 85, 239, 56, 88, 208, 54, 105, 166, 38, 160, 129, 32, + 201, 68, 63, 159, 53, 98, 116, 3, 106, 97, 231, 114, 88, 222, 105, 87, 178, 63, 126, + 123, 30, 153, 125, 63, 97, 126, 104, 47, 124, 114, 135, 211, 189, 122, 214, 171, 114, + 203, 94, 149, 165, 27, 174, 185, 57, 124, 138, 105, 79, 210, 114, 165, 203, 205, 150, + 200, 185, 141, 184, 101, 175, 135, 26, 202, 116, 56, 160, 5, 105, 122, 93, 115, + ]; const IMG_W: usize = 7; const IMG_H: usize = 7; let mut buf = [0u8; 3 * IMG_W * IMG_H]; - let res = debayer_u8(&mut Cursor::new(&src[..]), CFA::RGGB, - &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf)); + let res = debayer_u8( + &mut Cursor::new(&src[..]), + CFA::RGGB, + &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf), + ); assert!(res.is_ok()); assert_eq!(&buf[..], &expected[..]); } @@ -452,29 +469,32 @@ mod tests { #[test] fn test_overflow() { let src = [ - 255,255,255,255,255,255,255, - 255,255,255,255,255,255,255, - 255,255,255, 0,255,255,255, - 255,255, 0, 0, 0,255,255, - 255,255,255, 0,255,255,255, - 255,255,255,255,255,255,255, - 255,255,255,255,255,255,255 ]; + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, + 255, 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, 0, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + ]; let expected = [ - 255,255,251, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,251, - 255,255,255, 255,255,255, 255,255,255, 255,190,255, 255,255,255, 255,255,255, 255,255,255, - 255,255,255, 255,255,255, 255,111,174, 255, 0,111, 255,111,174, 255,255,255, 255,255,255, - 255,255,255, 255,190,255, 255, 0,111, 255, 0, 0, 255, 0,111, 255,190,255, 255,255,255, - 255,255,255, 255,255,255, 255,111,174, 255, 0,111, 255,111,174, 255,255,255, 255,255,255, - 255,255,255, 255,255,255, 255,255,255, 255,190,255, 255,255,255, 255,255,255, 255,255,255, - 255,255,251, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,255, 255,255,251 ]; + 255, 255, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 190, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 111, 174, + 255, 0, 111, 255, 111, 174, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 190, 255, + 255, 0, 111, 255, 0, 0, 255, 0, 111, 255, 190, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 111, 174, 255, 0, 111, 255, 111, 174, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 190, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 251, + ]; const IMG_W: usize = 7; const IMG_H: usize = 7; let mut buf = [0u8; 3 * IMG_W * IMG_H]; - let res = debayer_u8(&mut Cursor::new(&src[..]), CFA::RGGB, - &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf)); + let res = debayer_u8( + &mut Cursor::new(&src[..]), + CFA::RGGB, + &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf), + ); assert!(res.is_ok()); assert_eq!(&buf[..], &expected[..]); } diff --git a/src/demosaic/linear.rs b/src/demosaic/linear.rs index 76dffdb..9647621 100644 --- a/src/demosaic/linear.rs +++ b/src/demosaic/linear.rs @@ -20,16 +20,14 @@ use std::slice; #[cfg(feature = "rayon")] use rayon::prelude::*; -use ::{BayerDepth,BayerError,BayerResult,CFA,RasterMut}; -use bayer::{BayerRead8,BayerRead16}; -use border_replicate::*; -use demosaic::check_depth; +use crate::bayer::{BayerRead16, BayerRead8}; +use crate::border_replicate::*; +use crate::demosaic::check_depth; +use crate::{BayerDepth, BayerError, BayerResult, RasterMut, CFA}; const PADDING: usize = 1; -pub fn run(r: &mut Read, - depth: BayerDepth, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +pub fn run(r: &mut dyn Read, depth: BayerDepth, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { if dst.w < 2 || dst.h < 2 { return Err(BayerError::WrongResolution); } @@ -57,7 +55,7 @@ macro_rules! apply_kernel_row { while i + 1 < $w { apply_kernel_c!($T; $row, $prev, $curr, $next, cfa_c, i); apply_kernel_g!($T; $row, $prev, $curr, $next, cfa_g, i + 1); - i = i + 2; + i += 2; } if i < $w { @@ -73,14 +71,15 @@ macro_rules! apply_kernel_c { let j = $i + PADDING; $row[3 * $i + c] = $curr[j]; - $row[3 * $i + 1] - = (( $prev[j] as u32 - + $curr[j - 1] as u32 + $curr[j + 1] as u32 - + $next[j] as u32) / 4) as $T; - $row[3 * $i + d] - = (( $prev[j - 1] as u32 + $prev[j + 1] as u32 - + $next[j - 1] as u32 + $next[j + 1] as u32) / 4) as $T; - }} + $row[3 * $i + 1] = + (($prev[j] as u32 + $curr[j - 1] as u32 + $curr[j + 1] as u32 + $next[j] as u32) / 4) + as $T; + $row[3 * $i + d] = (($prev[j - 1] as u32 + + $prev[j + 1] as u32 + + $next[j - 1] as u32 + + $next[j + 1] as u32) + / 4) as $T; + }}; } macro_rules! apply_kernel_g { @@ -89,21 +88,18 @@ macro_rules! apply_kernel_g { let (h, v) = if $cfa == CFA::GBRG { (2, 0) } else { (0, 2) }; let j = $i + PADDING; - $row[3 * $i + h] - = (($curr[j - 1] as u32 + $curr[j + 1] as u32) / 2) as $T; + $row[3 * $i + h] = (($curr[j - 1] as u32 + $curr[j + 1] as u32) / 2) as $T; $row[3 * $i + 1] = $curr[j]; - $row[3 * $i + v] - = (($prev[j] as u32 + $next[j] as u32) / 2) as $T; - }} + $row[3 * $i + v] = (($prev[j] as u32 + $next[j] as u32) / 2) as $T; + }}; } -/*--------------------------------------------------------------*/ -/* Rayon */ -/*--------------------------------------------------------------*/ +/* -------------------------------------------------------------- */ +/* Rayon */ +/* -------------------------------------------------------------- */ #[cfg(feature = "rayon")] -fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u8(r: &mut dyn Read, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut data = vec![0u8; (2 * PADDING + w) * (2 * PADDING + h)]; @@ -112,93 +108,92 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) let stride = 2 * PADDING + w; let rdr = BorderReplicate8::new(w, PADDING); - for mut row in data.chunks_mut(stride).skip(PADDING).take(h) { - rdr.read_line(r, &mut row)?; + for row in data.chunks_mut(stride).skip(PADDING).take(h) { + rdr.read_line(r, row)?; } { let (top, src) = data.split_at_mut(stride * PADDING); - top[(stride * 0)..(stride * 1)].copy_from_slice( - &src[(stride * 1)..(stride * 2)]); + top[..stride].copy_from_slice(&src[stride..(stride * 2)]); } { let (src, bottom) = data.split_at_mut(stride * (h + PADDING)); let yy = PADDING + h; - bottom[(stride * 0)..(stride * 1)].copy_from_slice( - &src[(stride * (yy - 2))..(stride * (yy - 1))]); + bottom[..stride].copy_from_slice(&src[(stride * (yy - 2))..(stride * (yy - 1))]); } } - dst.buf.par_chunks_mut(dst.stride).enumerate() - .for_each(|(y, mut row)| { - let stride = 2 * PADDING + w; - let prev = &data[(stride * (PADDING + y - 1)) .. (stride * (PADDING + y + 0))]; - let curr = &data[(stride * (PADDING + y + 0)) .. (stride * (PADDING + y + 1))]; - let next = &data[(stride * (PADDING + y + 1)) .. (stride * (PADDING + y + 2))]; - let cfa_y = if y % 2 == 0 { cfa } else { cfa.next_y() }; + dst.buf + .par_chunks_mut(dst.stride) + .enumerate() + .for_each(|(y, row)| { + let stride = 2 * PADDING + w; + let prev = &data[(stride * (PADDING + y - 1))..(stride * (PADDING + y))]; + let curr = &data[(stride * (PADDING + y))..(stride * (PADDING + y + 1))]; + let next = &data[(stride * (PADDING + y + 1))..(stride * (PADDING + y + 2))]; + let cfa_y = if y % 2 == 0 { cfa } else { cfa.next_y() }; - apply_kernel_row!(u8; row, prev, curr, next, cfa_y, w); - }); + apply_kernel_row!(u8; row, prev, curr, next, cfa_y, w); + }); Ok(()) } #[cfg(feature = "rayon")] -fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u16(r: &mut dyn Read, be: bool, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut data = vec![0u16; (2 * PADDING + w) * (2 * PADDING + h)]; // Read all data. { let stride = 2 * PADDING + w; - let rdr: Box = if be { + let rdr: Box = if be { Box::new(BorderReplicate16BE::new(w, PADDING)) } else { Box::new(BorderReplicate16LE::new(w, PADDING)) }; - for mut row in data.chunks_mut(stride).skip(PADDING).take(h) { - rdr.read_line(r, &mut row)?; + for row in data.chunks_mut(stride).skip(PADDING).take(h) { + rdr.read_line(r, row)?; } { let (top, src) = data.split_at_mut(stride * PADDING); - top[(stride * 0)..(stride * 1)].copy_from_slice( - &src[(stride * 1)..(stride * 2)]); + top[..stride].copy_from_slice(&src[stride..(stride * 2)]); } { let (src, bottom) = data.split_at_mut(stride * (h + PADDING)); let yy = PADDING + h; - bottom[(stride * 0)..(stride * 1)].copy_from_slice( - &src[(stride * (yy - 2))..(stride * (yy - 1))]); + bottom[..stride].copy_from_slice(&src[(stride * (yy - 2))..(stride * (yy - 1))]); } } - dst.buf.par_chunks_mut(dst.stride).enumerate() - .for_each(|(y, mut row)| { - let stride = 2 * PADDING + w; - let prev = &data[(stride * (PADDING + y - 1)) .. (stride * (PADDING + y + 0))]; - let curr = &data[(stride * (PADDING + y + 0)) .. (stride * (PADDING + y + 1))]; - let next = &data[(stride * (PADDING + y + 1)) .. (stride * (PADDING + y + 2))]; - let cfa_y = if y % 2 == 0 { cfa } else { cfa.next_y() }; - - let row16 = unsafe{ slice::from_raw_parts_mut(row.as_mut_ptr() as *mut u16, row.len() / 2) }; - apply_kernel_row!(u16; row16, prev, curr, next, cfa_y, w); - }); + dst.buf + .par_chunks_mut(dst.stride) + .enumerate() + .for_each(|(y, row)| { + let stride = 2 * PADDING + w; + let prev = &data[(stride * (PADDING + y - 1))..(stride * (PADDING + y))]; + let curr = &data[(stride * (PADDING + y))..(stride * (PADDING + y + 1))]; + let next = &data[(stride * (PADDING + y + 1))..(stride * (PADDING + y + 2))]; + let cfa_y = if y % 2 == 0 { cfa } else { cfa.next_y() }; + + let row16 = + unsafe { slice::from_raw_parts_mut(row.as_mut_ptr() as *mut u16, row.len() / 2) }; + apply_kernel_row!(u16; row16, prev, curr, next, cfa_y, w); + }); Ok(()) } -/*--------------------------------------------------------------*/ -/* Naive */ -/*--------------------------------------------------------------*/ +/* -------------------------------------------------------------- */ +/* Naive */ +/* -------------------------------------------------------------- */ #[cfg(not(feature = "rayon"))] -fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut prev = vec![0u8; 2 * PADDING + w]; let mut curr = vec![0u8; 2 * PADDING + w]; @@ -209,7 +204,8 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) rdr.read_line(r, &mut curr)?; rdr.read_line(r, &mut next)?; - { // y = 0. + { + // y = 0. let row = dst.borrow_row_u8_mut(0); apply_kernel_row!(u8; row, next, curr, next, cfa, w); cfa = cfa.next_y(); @@ -224,7 +220,8 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) cfa = cfa.next_y(); } - { // y = h - 1. + { + // y = h - 1. let row = dst.borrow_row_u8_mut(h - 1); apply_kernel_row!(u8; row, curr, next, curr, cfa, w); } @@ -233,8 +230,7 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) } #[cfg(not(feature = "rayon"))] -fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut prev = vec![0u16; 2 * PADDING + w]; let mut curr = vec![0u16; 2 * PADDING + w]; @@ -249,7 +245,8 @@ fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) rdr.read_line(r, &mut curr)?; rdr.read_line(r, &mut next)?; - { // y = 0. + { + // y = 0. let row = dst.borrow_row_u16_mut(0); apply_kernel_row!(u16; row, next, curr, next, cfa, w); cfa = cfa.next_y(); @@ -264,7 +261,8 @@ fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) cfa = cfa.next_y(); } - { // y = h - 1. + { + // y = h - 1. let row = dst.borrow_row_u16_mut(h - 1); apply_kernel_row!(u16; row, curr, next, curr, cfa, w); } @@ -274,31 +272,33 @@ fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) #[cfg(test)] mod tests { - use std::io::Cursor; - use ::{CFA,RasterDepth,RasterMut}; use super::debayer_u8; + use crate::{RasterDepth, RasterMut, CFA}; + use std::io::Cursor; #[test] fn test_even() { - // R: set.seed(0); matrix(floor(runif(n=16, min=0, max=256)), nrow=4, byrow=TRUE) + // R: set.seed(0); matrix(floor(runif(n=16, min=0, max=256)), nrow=4, + // byrow=TRUE) let src = [ - 229, 67, 95,146, - 232, 51,229,241, - 169,161, 15, 52, - 45,175, 98,197 ]; + 229, 67, 95, 146, 232, 51, 229, 241, 169, 161, 15, 52, 45, 175, 98, 197, + ]; let expected = [ - 229,149, 51, 162, 67, 51, 95,167,146, 95,146,241, - 199,232, 51, 127,172, 51, 55,229,146, 55,164,241, - 169,149,113, 92,161,113, 15,135,166, 15, 52,219, - 169, 45,175, 92,116,175, 15, 98,186, 15, 75,197 ]; + 229, 149, 51, 162, 67, 51, 95, 167, 146, 95, 146, 241, 199, 232, 51, 127, 172, 51, 55, + 229, 146, 55, 164, 241, 169, 149, 113, 92, 161, 113, 15, 135, 166, 15, 52, 219, 169, + 45, 175, 92, 116, 175, 15, 98, 186, 15, 75, 197, + ]; const IMG_W: usize = 4; const IMG_H: usize = 4; let mut dst = [0u8; 3 * IMG_W * IMG_H]; - let res = debayer_u8(&mut Cursor::new(&src[..]), CFA::RGGB, - &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut dst[..])); + let res = debayer_u8( + &mut Cursor::new(&src[..]), + CFA::RGGB, + &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut dst[..]), + ); assert!(res.is_ok()); assert_eq!(&dst[..], &expected[..]); } @@ -306,22 +306,22 @@ mod tests { #[test] fn test_odd() { // R: set.seed(0); matrix(floor(runif(n=9, min=0, max=256)), nrow=3, byrow=TRUE) - let src = [ - 229, 67, 95, - 146,232, 51, - 229,241,169 ]; + let src = [229, 67, 95, 146, 232, 51, 229, 241, 169]; let expected = [ - 229,106,232, 162, 67,232, 95, 59,232, - 229,146,232, 180,126,232, 132, 51,232, - 229,193,232, 199,241,232, 169,146,232 ]; + 229, 106, 232, 162, 67, 232, 95, 59, 232, 229, 146, 232, 180, 126, 232, 132, 51, 232, + 229, 193, 232, 199, 241, 232, 169, 146, 232, + ]; const IMG_W: usize = 3; const IMG_H: usize = 3; let mut buf = [0u8; 3 * IMG_W * IMG_H]; - let res = debayer_u8(&mut Cursor::new(&src[..]), CFA::RGGB, - &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf)); + let res = debayer_u8( + &mut Cursor::new(&src[..]), + CFA::RGGB, + &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf), + ); assert!(res.is_ok()); assert_eq!(&buf[..], &expected[..]); } diff --git a/src/demosaic/mod.rs b/src/demosaic/mod.rs index ebf5444..4ad42f7 100644 --- a/src/demosaic/mod.rs +++ b/src/demosaic/mod.rs @@ -1,9 +1,9 @@ //! Collection of demosaicing algorithms. -use ::{BayerDepth,RasterDepth}; +use crate::{BayerDepth, RasterDepth}; /// The demosaicing algorithm to use to fill in the missing data. -#[derive(Clone,Copy,Debug,Eq,PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Demosaic { None, NearestNeighbour, @@ -13,9 +13,7 @@ pub enum Demosaic { macro_rules! rotate { ($v0:ident <- $v1:ident) => {{ - let rot = $v0; - $v0 = $v1; - $v1 = rot; + std::mem::swap(&mut $v0, &mut $v1) }}; ($v0:ident <- $v1:ident <- $v2:ident) => {{ let rot = $v0; @@ -43,9 +41,7 @@ pub mod none; /// Check if the image depth and the raster depth are compatible. fn check_depth(bayer: BayerDepth, raster: RasterDepth) -> bool { match raster { - RasterDepth::Depth8 => - bayer == BayerDepth::Depth8, - RasterDepth::Depth16 => - bayer == BayerDepth::Depth16BE || bayer == BayerDepth::Depth16LE, + RasterDepth::Depth8 => bayer == BayerDepth::Depth8, + RasterDepth::Depth16 => bayer == BayerDepth::Depth16BE || bayer == BayerDepth::Depth16LE, } } diff --git a/src/demosaic/nearestneighbour.rs b/src/demosaic/nearestneighbour.rs index 998a3e8..a73d2bb 100644 --- a/src/demosaic/nearestneighbour.rs +++ b/src/demosaic/nearestneighbour.rs @@ -2,16 +2,14 @@ use std::io::Read; -use ::{BayerDepth,BayerError,BayerResult,CFA,RasterMut}; -use bayer::{BayerRead8,BayerRead16}; -use border_replicate::*; -use demosaic::check_depth; +use crate::bayer::{BayerRead16, BayerRead8}; +use crate::border_replicate::*; +use crate::demosaic::check_depth; +use crate::{BayerDepth, BayerError, BayerResult, RasterMut, CFA}; const PADDING: usize = 1; -pub fn run(r: &mut Read, - depth: BayerDepth, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +pub fn run(r: &mut dyn Read, depth: BayerDepth, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { if dst.w < 2 || dst.h < 2 { return Err(BayerError::WrongResolution); } @@ -28,24 +26,23 @@ pub fn run(r: &mut Read, macro_rules! apply_kernel_row { ($row:ident, $prev:expr, $curr:expr, $cfa:expr, $w:expr) => {{ - let (mut i, cfa_c, cfa_g) = - if $cfa == CFA::BGGR || $cfa == CFA::RGGB { - (0, $cfa, $cfa.next_x()) - } else { - apply_kernel_g!($row, $prev, $curr, $cfa, 0); - (1, $cfa.next_x(), $cfa) - }; + let (mut i, cfa_c, cfa_g) = if $cfa == CFA::BGGR || $cfa == CFA::RGGB { + (0, $cfa, $cfa.next_x()) + } else { + apply_kernel_g!($row, $prev, $curr, $cfa, 0); + (1, $cfa.next_x(), $cfa) + }; while i + 1 < $w { apply_kernel_c!($row, $prev, $curr, cfa_c, i); apply_kernel_g!($row, $prev, $curr, cfa_g, i + 1); - i = i + 2; + i += 2; } if i < $w { apply_kernel_c!($row, $prev, $curr, cfa_c, i); } - }} + }}; } macro_rules! apply_kernel_c { @@ -57,7 +54,7 @@ macro_rules! apply_kernel_c { $row[3 * $i + c] = $curr[j]; $row[3 * $i + 1] = $curr[j - 1]; $row[3 * $i + d] = $prev[j - 1]; - }} + }}; } macro_rules! apply_kernel_g { @@ -69,13 +66,12 @@ macro_rules! apply_kernel_g { $row[3 * $i + h] = $curr[j - 1]; $row[3 * $i + 1] = $curr[j]; $row[3 * $i + v] = $prev[j]; - }} + }}; } -/*--------------------------------------------------------------*/ +/* -------------------------------------------------------------- */ -fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u8(r: &mut dyn Read, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut prev = vec![0u8; 2 * PADDING + w]; let mut curr = vec![0u8; 2 * PADDING + w]; @@ -85,13 +81,15 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) rdr.read_line(r, &mut prev)?; rdr.read_line(r, &mut curr)?; - { // y = 0. + { + // y = 0. let row = dst.borrow_row_u8_mut(0); apply_kernel_row!(row, curr, prev, cfa, w); cfa = cfa.next_y(); } - { // y = 1. + { + // y = 1. let row = dst.borrow_row_u8_mut(1); apply_kernel_row!(row, prev, curr, cfa, w); cfa = cfa.next_y(); @@ -109,14 +107,13 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) Ok(()) } -fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u16(r: &mut dyn Read, be: bool, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut prev = vec![0u16; 2 * PADDING + w]; let mut curr = vec![0u16; 2 * PADDING + w]; let mut cfa = cfa; - let rdr: Box = if be { + let rdr: Box = if be { Box::new(BorderReplicate16BE::new(w, PADDING)) } else { Box::new(BorderReplicate16LE::new(w, PADDING)) @@ -124,13 +121,15 @@ fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) rdr.read_line(r, &mut prev)?; rdr.read_line(r, &mut curr)?; - { // y = 0. + { + // y = 0. let row = dst.borrow_row_u16_mut(0); apply_kernel_row!(row, curr, prev, cfa, w); cfa = cfa.next_y(); } - { // y = 1. + { + // y = 1. let row = dst.borrow_row_u16_mut(1); apply_kernel_row!(row, prev, curr, cfa, w); cfa = cfa.next_y(); @@ -150,31 +149,33 @@ fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) #[cfg(test)] mod tests { - use std::io::Cursor; - use ::{CFA,RasterDepth,RasterMut}; use super::debayer_u8; + use crate::{RasterDepth, RasterMut, CFA}; + use std::io::Cursor; #[test] fn test_even() { - // R: set.seed(0); matrix(floor(runif(n=16, min=0, max=256)), nrow=4, byrow=TRUE) + // R: set.seed(0); matrix(floor(runif(n=16, min=0, max=256)), nrow=4, + // byrow=TRUE) let src = [ - 229, 67, 95,146, - 232, 51,229,241, - 169,161, 15, 52, - 45,175, 98,197 ]; + 229, 67, 95, 146, 232, 51, 229, 241, 169, 161, 15, 52, 45, 175, 98, 197, + ]; let expected = [ - 229, 67, 51, 229, 67, 51, 95, 67, 51, 95,146,241, - 229,232, 51, 229,232, 51, 95,229, 51, 95,229,241, - 169,161, 51, 169,161, 51, 15,161, 51, 15, 52,241, - 169, 45,175, 169, 45,175, 15, 98,175, 15, 98,197 ]; + 229, 67, 51, 229, 67, 51, 95, 67, 51, 95, 146, 241, 229, 232, 51, 229, 232, 51, 95, + 229, 51, 95, 229, 241, 169, 161, 51, 169, 161, 51, 15, 161, 51, 15, 52, 241, 169, 45, + 175, 169, 45, 175, 15, 98, 175, 15, 98, 197, + ]; const IMG_W: usize = 4; const IMG_H: usize = 4; let mut buf = [0u8; 3 * IMG_W * IMG_H]; - let res = debayer_u8(&mut Cursor::new(&src[..]), CFA::RGGB, - &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf)); + let res = debayer_u8( + &mut Cursor::new(&src[..]), + CFA::RGGB, + &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf), + ); assert!(res.is_ok()); assert_eq!(&buf[..], &expected[..]); } @@ -182,22 +183,22 @@ mod tests { #[test] fn test_odd() { // R: set.seed(0); matrix(floor(runif(n=9, min=0, max=256)), nrow=3, byrow=TRUE) - let src = [ - 229, 67, 95, - 146,232, 51, - 229,241,169 ]; + let src = [229, 67, 95, 146, 232, 51, 229, 241, 169]; let expected = [ - 229, 67,232, 229, 67,232, 95, 67,232, - 229,146,232, 229,146,232, 95, 51,232, - 229,241,232, 229,241,232, 169,241,232 ]; + 229, 67, 232, 229, 67, 232, 95, 67, 232, 229, 146, 232, 229, 146, 232, 95, 51, 232, + 229, 241, 232, 229, 241, 232, 169, 241, 232, + ]; const IMG_W: usize = 3; const IMG_H: usize = 3; let mut buf = [0u8; 3 * IMG_W * IMG_H]; - let res = debayer_u8(&mut Cursor::new(&src[..]), CFA::RGGB, - &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf)); + let res = debayer_u8( + &mut Cursor::new(&src[..]), + CFA::RGGB, + &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf), + ); assert!(res.is_ok()); assert_eq!(&buf[..], &expected[..]); } diff --git a/src/demosaic/none.rs b/src/demosaic/none.rs index 6be58a0..4a0120f 100644 --- a/src/demosaic/none.rs +++ b/src/demosaic/none.rs @@ -2,14 +2,12 @@ use std::io::Read; -use ::{BayerDepth,BayerError,BayerResult,CFA,RasterMut}; -use bayer::{BayerRead8,BayerRead16}; -use border_none::*; -use demosaic::check_depth; - -pub fn run(r: &mut Read, - depth: BayerDepth, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +use crate::bayer::{BayerRead16, BayerRead8}; +use crate::border_none::*; +use crate::demosaic::check_depth; +use crate::{BayerDepth, BayerError, BayerResult, RasterMut, CFA}; + +pub fn run(r: &mut dyn Read, depth: BayerDepth, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { if dst.w < 2 || dst.h < 2 { return Err(BayerError::WrongResolution); } @@ -30,24 +28,23 @@ macro_rules! apply_kernel_row { *e = 0; } - let (mut i, cfa_c) = - if $cfa == CFA::BGGR || $cfa == CFA::RGGB { - (0, $cfa) - } else { - apply_kernel_g!($row, $curr, 0); - (1, $cfa.next_x()) - }; + let (mut i, cfa_c) = if $cfa == CFA::BGGR || $cfa == CFA::RGGB { + (0, $cfa) + } else { + apply_kernel_g!($row, $curr, 0); + (1, $cfa.next_x()) + }; while i + 1 < $w { apply_kernel_c!($row, $curr, cfa_c, i); apply_kernel_g!($row, $curr, i + 1); - i = i + 2; + i += 2; } if i < $w { apply_kernel_c!($row, $curr, cfa_c, i); } - }} + }}; } macro_rules! apply_kernel_c { @@ -57,19 +54,18 @@ macro_rules! apply_kernel_c { } else { $row[3 * $i + 0] = $curr[$i]; } - }} + }}; } macro_rules! apply_kernel_g { ($row:ident, $curr:expr, $i:expr) => {{ $row[3 * $i + 1] = $curr[$i]; - }} + }}; } -/*--------------------------------------------------------------*/ +/* -------------------------------------------------------------- */ -fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u8(r: &mut dyn Read, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut curr = vec![0u8; w]; let mut cfa = cfa; @@ -86,13 +82,12 @@ fn debayer_u8(r: &mut Read, cfa: CFA, dst: &mut RasterMut) Ok(()) } -fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) - -> BayerResult<()> { +fn debayer_u16(r: &mut dyn Read, be: bool, cfa: CFA, dst: &mut RasterMut) -> BayerResult<()> { let (w, h) = (dst.w, dst.h); let mut curr = vec![0u16; w]; let mut cfa = cfa; - let rdr: Box = if be { + let rdr: Box = if be { Box::new(BorderNone16BE::new()) } else { Box::new(BorderNone16LE::new()) @@ -110,31 +105,32 @@ fn debayer_u16(r: &mut Read, be: bool, cfa: CFA, dst: &mut RasterMut) #[cfg(test)] mod tests { - use std::io::Cursor; - use ::{CFA,RasterDepth,RasterMut}; use super::debayer_u8; + use crate::{RasterDepth, RasterMut, CFA}; + use std::io::Cursor; #[test] fn test_even() { - // R: set.seed(0); matrix(floor(runif(n=16, min=0, max=256)), nrow=4, byrow=TRUE) + // R: set.seed(0); matrix(floor(runif(n=16, min=0, max=256)), nrow=4, + // byrow=TRUE) let src = [ - 229, 67, 95,146, - 232, 51,229,241, - 169,161, 15, 52, - 45,175, 98,197 ]; + 229, 67, 95, 146, 232, 51, 229, 241, 169, 161, 15, 52, 45, 175, 98, 197, + ]; let expected = [ - 229, 0, 0, 0, 67, 0, 95, 0, 0, 0,146, 0, - 0,232, 0, 0, 0, 51, 0,229, 0, 0, 0,241, - 169, 0, 0, 0,161, 0, 15, 0, 0, 0, 52 , 0, - 0, 45, 0, 0, 0,175, 0, 98, 0, 0, 0,197 ]; + 229, 0, 0, 0, 67, 0, 95, 0, 0, 0, 146, 0, 0, 232, 0, 0, 0, 51, 0, 229, 0, 0, 0, 241, + 169, 0, 0, 0, 161, 0, 15, 0, 0, 0, 52, 0, 0, 45, 0, 0, 0, 175, 0, 98, 0, 0, 0, 197, + ]; const IMG_W: usize = 4; const IMG_H: usize = 4; let mut buf = [0u8; 3 * IMG_W * IMG_H]; - let res = debayer_u8(&mut Cursor::new(&src[..]), CFA::RGGB, - &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf)); + let res = debayer_u8( + &mut Cursor::new(&src[..]), + CFA::RGGB, + &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf), + ); assert!(res.is_ok()); assert_eq!(&buf[..], &expected[..]); } @@ -142,22 +138,22 @@ mod tests { #[test] fn test_odd() { // R: set.seed(0); matrix(floor(runif(n=9, min=0, max=256)), nrow=3, byrow=TRUE) - let src = [ - 229, 67, 95, - 146,232, 51, - 229,241,169 ]; + let src = [229, 67, 95, 146, 232, 51, 229, 241, 169]; let expected = [ - 229, 0, 0, 0, 67, 0, 95, 0, 0, - 0,146, 0, 0, 0,232, 0, 51, 0, - 229, 0, 0, 0,241, 0, 169, 0, 0 ]; + 229, 0, 0, 0, 67, 0, 95, 0, 0, 0, 146, 0, 0, 0, 232, 0, 51, 0, 229, 0, 0, 0, 241, 0, + 169, 0, 0, + ]; const IMG_W: usize = 3; const IMG_H: usize = 3; let mut buf = [0u8; 3 * IMG_W * IMG_H]; - let res = debayer_u8(&mut Cursor::new(&src[..]), CFA::RGGB, - &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf)); + let res = debayer_u8( + &mut Cursor::new(&src[..]), + CFA::RGGB, + &mut RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth8, &mut buf), + ); assert!(res.is_ok()); assert_eq!(&buf[..], &expected[..]); } diff --git a/src/errcode.rs b/src/errcode.rs index 5a75bfd..b1990eb 100644 --- a/src/errcode.rs +++ b/src/errcode.rs @@ -1,31 +1,27 @@ //! Bayer error codes. +use quick_error::quick_error; use std::io; pub type BayerResult = Result; quick_error! { + #[derive(Debug)] + pub enum BayerError { + NoGood { + display("No good") + } -#[derive(Debug)] -pub enum BayerError { - // Generic failure. Please try to make something more meaningful. - NoGood { - description("No good") - } - - WrongResolution { - description("Wrong resolution") - } - WrongDepth { - description("Wrong depth") - } + WrongResolution { + display("Wrong resolution") + } + WrongDepth { + display("Wrong depth") + } - Io(err: io::Error) { - from() - description(err.description()) - display("IO error: {}", err) - cause(err) + Io(err: io::Error) { + from() + display("IO error: {}", err) + } } } - -} diff --git a/src/ffi.rs b/src/ffi.rs index 2b9f213..e368417 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,15 +1,15 @@ //! Foreign function interface. -use std::io::{Cursor,Read}; +use libc::{c_uchar, c_uint, size_t}; +use std::io::{Cursor, Read}; use std::mem; use std::ptr; use std::slice; -use libc::{c_uchar,c_uint,size_t}; -use ::{BayerDepth,BayerError,BayerResult,CFA,RasterDepth,RasterMut}; -use demosaic; +use crate::demosaic; +use crate::{BayerDepth, BayerError, BayerResult, RasterDepth, RasterMut, CFA}; -/// Dummy opaque structure, equivalent to RasterMut<'a>. +/// Dummy opaque structure, equivalent to [`RasterMut`]. pub struct CRasterMut; // Print with "file:line - " prefix, for more informative error messages. @@ -23,21 +23,28 @@ macro_rules! printerrorln { }}; } -unsafe fn transmute_raster_mut<'a>(dst: *mut CRasterMut) - -> &'a mut RasterMut<'a> { +unsafe fn transmute_raster_mut<'a>(dst: *mut CRasterMut) -> &'a mut RasterMut<'a> { let ptr: *mut RasterMut = mem::transmute(dst); &mut *ptr } -fn run_demosaic(file: &'static str, line: u32, - run: F, - src: *const c_uchar, src_len: size_t, - depth: c_uint, be: c_uint, cfa: c_uint, - dst: *mut CRasterMut) - -> c_uint - where F: FnOnce(&mut Read, BayerDepth, CFA, &mut RasterMut) -> BayerResult<()> { +#[allow(clippy::too_many_arguments)] +fn run_demosaic( + file: &'static str, + line: u32, + run: F, + src: *const c_uchar, + src_len: size_t, + depth: c_uint, + be: c_uint, + cfa: c_uint, + dst: *mut CRasterMut, +) -> c_uint +where + F: FnOnce(&mut dyn Read, BayerDepth, CFA, &mut RasterMut) -> BayerResult<()>, +{ if src.is_null() || dst.is_null() { - println!("{} {} - bad input parameters", file, line); + println!("{file} {line} - bad input parameters"); return 1; } @@ -46,7 +53,7 @@ fn run_demosaic(file: &'static str, line: u32, (16, 0) => BayerDepth::Depth16LE, (16, _) => BayerDepth::Depth16BE, _ => { - println!("{} {} - invalid depth", file, line); + println!("{file} {line} - invalid depth"); return 2; } }; @@ -57,15 +64,15 @@ fn run_demosaic(file: &'static str, line: u32, 2 => CFA::GRBG, 3 => CFA::RGGB, _ => { - println!("{} {} - invalid cfa", file, line); + println!("{file} {line} - invalid cfa"); return 1; } }; - let src_slice = unsafe{ slice::from_raw_parts(src, src_len) }; - let dst_raster = unsafe{ transmute_raster_mut(dst) }; + let src_slice = unsafe { slice::from_raw_parts(src, src_len) }; + let dst_raster = unsafe { transmute_raster_mut(dst) }; - match run(&mut Cursor::new(&src_slice[..]), depth, cfa, dst_raster) { + match run(&mut Cursor::new(src_slice), depth, cfa, dst_raster) { Ok(_) => 0, Err(BayerError::WrongResolution) => 2, Err(BayerError::WrongDepth) => 3, @@ -73,68 +80,135 @@ fn run_demosaic(file: &'static str, line: u32, } } -/*--------------------------------------------------------------*/ -/* Demosaicing algorithms */ -/*--------------------------------------------------------------*/ +/* -------------------------------------------------------------- */ +/* Demosaicing algorithms */ +/* -------------------------------------------------------------- */ /// Demosaicing without any interpolation. +/// +/// Before using this, allocate a [`CRasterMut`] for `dst` by calling +/// [`bayerrs_raster_mut_alloc()`]. +/// +/// This modifies the [`buf`] you passed in the aforementioned call. #[no_mangle] pub extern "C" fn bayerrs_demosaic_none( - src: *const c_uchar, src_len: size_t, - depth: c_uint, be: c_uint, cfa: c_uint, - dst: *mut CRasterMut) - -> c_uint { - run_demosaic(file!(), line!(), - demosaic::none::run, - src, src_len, depth, be, cfa, dst) + src: *const c_uchar, + src_len: size_t, + depth: c_uint, + be: c_uint, + cfa: c_uint, + dst: *mut CRasterMut, +) -> c_uint { + run_demosaic( + file!(), + line!(), + demosaic::none::run, + src, + src_len, + depth, + be, + cfa, + dst, + ) } /// Demosaicing using nearest neighbour interpolation. #[no_mangle] pub extern "C" fn bayerrs_demosaic_nearest_neighbour( - src: *const c_uchar, src_len: size_t, - depth: c_uint, be: c_uint, cfa: c_uint, - dst: *mut CRasterMut) - -> c_uint { - run_demosaic(file!(), line!(), - demosaic::nearestneighbour::run, - src, src_len, depth, be, cfa, dst) + src: *const c_uchar, + src_len: size_t, + depth: c_uint, + be: c_uint, + cfa: c_uint, + dst: *mut CRasterMut, +) -> c_uint { + run_demosaic( + file!(), + line!(), + demosaic::nearestneighbour::run, + src, + src_len, + depth, + be, + cfa, + dst, + ) } /// Demosaicing using linear interpolation. #[no_mangle] pub extern "C" fn bayerrs_demosaic_linear( - src: *const c_uchar, src_len: size_t, - depth: c_uint, be: c_uint, cfa: c_uint, - dst: *mut CRasterMut) - -> c_uint { - run_demosaic(file!(), line!(), - demosaic::linear::run, - src, src_len, depth, be, cfa, dst) + src: *const c_uchar, + src_len: size_t, + depth: c_uint, + be: c_uint, + cfa: c_uint, + dst: *mut CRasterMut, +) -> c_uint { + run_demosaic( + file!(), + line!(), + demosaic::linear::run, + src, + src_len, + depth, + be, + cfa, + dst, + ) } /// Demosaicing using cubic interpolation. #[no_mangle] pub extern "C" fn bayerrs_demosaic_cubic( - src: *const c_uchar, src_len: size_t, - depth: c_uint, be: c_uint, cfa: c_uint, - dst: *mut CRasterMut) - -> c_uint { - run_demosaic(file!(), line!(), - demosaic::cubic::run, - src, src_len, depth, be, cfa, dst) + src: *const c_uchar, + src_len: size_t, + depth: c_uint, + be: c_uint, + cfa: c_uint, + dst: *mut CRasterMut, +) -> c_uint { + run_demosaic( + file!(), + line!(), + demosaic::cubic::run, + src, + src_len, + depth, + be, + cfa, + dst, + ) } -/*--------------------------------------------------------------*/ -/* Raster */ -/*--------------------------------------------------------------*/ - -/// Allocate a new raster. +/* -------------------------------------------------------------- */ +/* Raster */ +/* -------------------------------------------------------------- */ + +/// Allocate a new [`CRasterMut`]. +/// +/// # Safety +/// +/// The `buf` point to a region of memory with at least `buf_len` size and big +/// enough to hold the geometry described by the first six parameters. +/// +/// Otherwise calling any of the `bayerrs_demosaic...()` functions on the +/// resulting [`CRasterMut`] pointer will cause undefined behaviour. +/// +/// When you are done with the returned `CRasterMut`, pass it to +/// [`bayerrs_raster_mut_free()`] to deallocate the memoriy it points to. +/// Otherwise calling this function will leak. #[no_mangle] -pub extern "C" fn bayerrs_raster_mut_alloc( - x: size_t, y: size_t, w: size_t, h: size_t, stride: size_t, depth: c_uint, - buf: *mut c_uchar, buf_len: size_t) - -> *mut CRasterMut { +pub unsafe extern "C" fn bayerrs_raster_mut_alloc( + x: size_t, + y: size_t, + w: size_t, + h: size_t, + stride: size_t, + depth: c_uint, + buf: *mut c_uchar, + buf_len: size_t, +) -> *mut CRasterMut { if buf.is_null() { printerrorln!("bad input parameters"); return ptr::null_mut(); @@ -149,20 +223,28 @@ pub extern "C" fn bayerrs_raster_mut_alloc( } }; - let buf_slice = unsafe{ slice::from_raw_parts_mut(buf, buf_len) }; + let buf_slice = slice::from_raw_parts_mut(buf, buf_len); let raster = RasterMut::with_offset(x, y, w, h, stride, depth, buf_slice); let rptr = Box::into_raw(Box::new(raster)); - let cptr: *mut CRasterMut = unsafe{ mem::transmute(rptr) }; + let cptr: *mut CRasterMut = mem::transmute(rptr); cptr } -/// Free a previously allocated raster. +/// Free a previously allocated [`CRasterMut`]. +/// +/// # Safety +/// +/// This will do nothing if `raster` is a null pointer. +/// +/// The `raster` pointer was must have been initialized from calling +/// [`bayerrs_raster_mut_alloc()`] initially. Otherwise calling this function +/// will cause undefined behaviour. #[no_mangle] -pub extern "C" fn bayerrs_raster_mut_free(raster: *mut CRasterMut) { +pub unsafe extern "C" fn bayerrs_raster_mut_free(raster: *mut CRasterMut) { if raster.is_null() { return; } - let rptr: *mut RasterMut = unsafe{ mem::transmute(raster) }; - let _raster = unsafe{ Box::from_raw(rptr) }; + let rptr: *mut RasterMut = mem::transmute(raster); + let _raster = Box::from_raw(rptr); } diff --git a/src/lib.rs b/src/lib.rs index b16c1e7..1f6eb3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,23 +1,55 @@ -//! This crate provides routines for demosaicing Bayer raw images. - -extern crate byteorder; -extern crate libc; - -#[cfg(feature = "rayon")] -extern crate rayon; - -#[macro_use] -extern crate quick_error; - +//! Routines for demosaicing Bayer sensor (RAW) images. +//! +//! Both 8bit and 16bit images are supported. +//! +//! Several demosaicing algorithms are available. Pixels on the border +//! of the image are retained by replicating or mirroring the data in +//! the neighbourhood. +//! +//! ## Examples +//! +//! Open a Bayer file from disk: +//! +//! ```ignore +//! let mut file = File::open(Path::new("example.raw"))?; +//! ``` +//! +//! This RAW data contains the red, green, or blue values at each pixel +//! only. There is no additional header data, so the image width and +//! height, pixel depth, and CFA pattern must be provided from elsewhere. +//! +//! Allocate the buffer to which we will decode the image: +//! +//! ```ignore +//! let img_w = 320; +//! let img_h = 200; +//! let depth = bayer::RasterDepth::Depth8; +//! let bytes_per_pixel = 3; +//! let mut buf = vec![0; bytes_per_pixel * img_w * img_h]; +//! +//! let mut dst = bayer::RasterMut::new(img_w, img_h, depth, &mut buf); +//! ``` +//! +//! Run the demosaicing process: +//! +//! ```ignore +//! let cfa = bayer::CFA::RGGB; +//! let alg = bayer::Demosaic::Linear; +//! +//! bayer::run_demosaic(&mut file, bayer::BayerDepth:Depth8, cfa, alg, &mut dst); +//! ``` +//! +//! Note that many cameras will capture 12bits per pixel (channel), but +//! store the data as 16 bits per pixel. These should be treated as +//! 16-bits per pixel for the purposes of this library. +pub use crate::{ + bayer::{BayerDepth, CFA}, + demosaic::Demosaic, + errcode::{BayerError, BayerResult}, + raster::RasterDepth, +}; use std::io::Read; -pub use bayer::BayerDepth; -pub use bayer::CFA; -pub use demosaic::Demosaic; -pub use errcode::BayerError; -pub use errcode::BayerResult; -pub use raster::RasterDepth; - /// Mutable raster structure. pub struct RasterMut<'a> { x: usize, @@ -51,19 +83,23 @@ mod raster; /// let img = vec![0; width * height]; /// let mut buf = vec![0; 3 * width * height]; /// -/// let mut dst = bayer::RasterMut::new( -/// width, height, bayer::RasterDepth::Depth8, -/// &mut buf); -/// bayer::run_demosaic(&mut Cursor::new(&img[..]), -/// bayer::BayerDepth::Depth8, -/// bayer::CFA::RGGB, -/// bayer::Demosaic::None, -/// &mut dst); +/// let mut dst = bayer::RasterMut::new(width, height, bayer::RasterDepth::Depth8, &mut buf); +/// +/// bayer::demosaic( +/// &mut Cursor::new(&img[..]), +/// bayer::BayerDepth::Depth8, +/// bayer::CFA::RGGB, +/// bayer::Demosaic::None, +/// &mut dst, +/// ); /// ``` -pub fn run_demosaic(r: &mut Read, - depth: BayerDepth, cfa: CFA, alg: Demosaic, - dst: &mut RasterMut) - -> BayerResult<()> { +pub fn demosaic( + r: &mut dyn Read, + depth: BayerDepth, + cfa: CFA, + alg: Demosaic, + dst: &mut RasterMut, +) -> BayerResult<()> { match alg { Demosaic::None => demosaic::none::run(r, depth, cfa, dst), Demosaic::NearestNeighbour => demosaic::nearestneighbour::run(r, depth, cfa, dst), diff --git a/src/raster.rs b/src/raster.rs index 926e84c..7cb307f 100644 --- a/src/raster.rs +++ b/src/raster.rs @@ -2,10 +2,10 @@ use std::slice; -use ::RasterMut; +use crate::RasterMut; /// Depth of a raster. -#[derive(Clone,Copy,Debug,Eq,PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum RasterDepth { Depth8, Depth16, @@ -21,12 +21,9 @@ impl<'a> RasterMut<'a> { /// const IMG_H: usize = 200; /// let mut buf = [0; 3 * IMG_W * IMG_H]; /// - /// bayer::RasterMut::new( - /// IMG_W, IMG_H, bayer::RasterDepth::Depth8, - /// &mut buf); + /// bayer::RasterMut::new(IMG_W, IMG_H, bayer::RasterDepth::Depth8, &mut buf); /// ``` - pub fn new(w: usize, h: usize, depth: RasterDepth, buf: &'a mut [u8]) - -> Self { + pub fn new(w: usize, h: usize, depth: RasterDepth, buf: &'a mut [u8]) -> Self { let bytes_per_pixel = depth.bytes_per_pixel(); let stride = w.checked_mul(bytes_per_pixel).expect("overflow"); Self::with_offset(0, 0, w, h, stride, depth, buf) @@ -43,13 +40,24 @@ impl<'a> RasterMut<'a> { /// let mut buf = [0; 3 * IMG_W * IMG_H]; /// /// bayer::RasterMut::with_offset( - /// 0, 0, IMG_W, IMG_H, 3 * IMG_W, bayer::RasterDepth::Depth8, - /// &mut buf); + /// 0, + /// 0, + /// IMG_W, + /// IMG_H, + /// 3 * IMG_W, + /// bayer::RasterDepth::Depth8, + /// &mut buf, + /// ); /// ``` pub fn with_offset( - x: usize, y: usize, w: usize, h: usize, stride: usize, - depth: RasterDepth, buf: &'a mut [u8]) - -> Self { + x: usize, + y: usize, + w: usize, + h: usize, + stride: usize, + depth: RasterDepth, + buf: &'a mut [u8], + ) -> Self { let x1 = x.checked_add(w).expect("overflow"); let y1 = y.checked_add(h).expect("overflow"); let bytes_per_pixel = depth.bytes_per_pixel(); @@ -58,17 +66,22 @@ impl<'a> RasterMut<'a> { assert_eq!(stride % bytes_per_pixel, 0); RasterMut { - x, y, w, h, stride, depth, buf, + x, + y, + w, + h, + stride, + depth, + buf, } } - /// Borrow a mutable u8 row slice. + /// Borrow a mutable [`u8`] row slice. /// /// # Panics /// - /// Panics if the raster is not 8-bpp. - pub fn borrow_row_u8_mut(&mut self, y: usize) - -> &mut [u8] { + /// Panics if the raster is not 8 bit per pixel. + pub fn borrow_row_u8_mut(&mut self, y: usize) -> &mut [u8] { assert!(self.depth == RasterDepth::Depth8); assert!(y < self.h); @@ -78,13 +91,12 @@ impl<'a> RasterMut<'a> { &mut self.buf[start..end] } - /// Borrow a mutable u16 row slice. + /// Borrow a mutable [`u16`] row slice. /// /// # Panics /// - /// Panics if the raster is not 16-bpp. - pub fn borrow_row_u16_mut(&mut self, y: usize) - -> &mut [u16] { + /// Panics if the raster is not 16 bit per pixel. + pub fn borrow_row_u16_mut(&mut self, y: usize) -> &mut [u16] { assert!(self.depth == RasterDepth::Depth16); assert!(y < self.h); @@ -93,9 +105,7 @@ impl<'a> RasterMut<'a> { let end = start + bytes_per_pixel * self.w; let s = &mut self.buf[start..end]; - unsafe { - slice::from_raw_parts_mut(s.as_mut_ptr() as *mut u16, 3 * self.w) - } + unsafe { slice::from_raw_parts_mut(s.as_mut_ptr() as *mut u16, 3 * self.w) } } } @@ -111,32 +121,34 @@ impl RasterDepth { #[cfg(test)] mod tests { - use ::RasterMut; use super::RasterDepth; + use crate::RasterMut; #[test] #[should_panic] fn test_raster_mut_overflow() { let mut buf = [0; 1]; let _ = RasterMut::new( - ::std::usize::MAX, ::std::usize::MAX, RasterDepth::Depth8, &mut buf); + ::std::usize::MAX, + ::std::usize::MAX, + RasterDepth::Depth8, + &mut buf, + ); } #[test] fn test_borrow_row_u16_mut() { let expected = [ - 0x00,0x00, 0x01,0x01, 0x02,0x02, - 0x03,0x03, 0x04,0x04, 0x05,0x05, - 0x06,0x06, 0x07,0x07, 0x08,0x08, - 0x09,0x09, 0x0A,0x0A, 0x0B,0x0B ]; + 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, + 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, + ]; const IMG_W: usize = 4; const IMG_H: usize = 1; let mut buf = [0u8; 6 * IMG_W * IMG_H]; { - let mut dst = RasterMut::new( - IMG_W, IMG_H, RasterDepth::Depth16, &mut buf); + let mut dst = RasterMut::new(IMG_W, IMG_H, RasterDepth::Depth16, &mut buf); let row = dst.borrow_row_u16_mut(0); for (i, elt) in row.iter_mut().enumerate() {