mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 02:48:12 +08:00
Raw-rs: Add preprocessing and demosaicing steps (#1796)
* add subtract black step * add scale colors step * add raw to image step * implement linear demosiacing and fix errors in previous code * fix missing variable * make dependencies of tests optional * fix error in raw-rs tests * fix typo in "demosiacing" * use camera data from ADC and remove downloader * cargo fmt * use file_stem instead of file_name * remove old camera data * use equality instead of subtring to find model * store camera_to_xyz in decimal form * Code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
26
libraries/raw-rs/src/preprocessing/camera_data.rs
Normal file
26
libraries/raw-rs/src/preprocessing/camera_data.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use crate::metadata::identify::CameraModel;
|
||||
use build_camera_data::build_camera_data;
|
||||
|
||||
pub struct CameraData {
|
||||
pub black: u16,
|
||||
pub maximum: u16,
|
||||
pub camera_to_xyz: [i16; 9],
|
||||
}
|
||||
|
||||
impl CameraData {
|
||||
const DEFAULT: CameraData = CameraData {
|
||||
black: 0,
|
||||
maximum: 0,
|
||||
camera_to_xyz: [0; 9],
|
||||
};
|
||||
}
|
||||
|
||||
const CAMERA_DATA: [(&str, CameraData); 40] = build_camera_data!();
|
||||
|
||||
pub fn camera_to_xyz(camera_model: &CameraModel) -> Option<[f64; 9]> {
|
||||
let camera_name_needle = camera_model.make.to_owned() + " " + &camera_model.model;
|
||||
CAMERA_DATA
|
||||
.iter()
|
||||
.find(|(camera_name_haystack, _)| camera_name_needle == *camera_name_haystack)
|
||||
.map(|(_, data)| data.camera_to_xyz.map(|x| (x as f64) / 10_000.))
|
||||
}
|
||||
4
libraries/raw-rs/src/preprocessing/mod.rs
Normal file
4
libraries/raw-rs/src/preprocessing/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod camera_data;
|
||||
pub mod raw_to_image;
|
||||
pub mod scale_colors;
|
||||
pub mod subtract_black;
|
||||
17
libraries/raw-rs/src/preprocessing/raw_to_image.rs
Normal file
17
libraries/raw-rs/src/preprocessing/raw_to_image.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use crate::RawImage;
|
||||
|
||||
pub fn raw_to_image(mut raw_image: RawImage) -> RawImage {
|
||||
let mut image = Vec::with_capacity(raw_image.width * raw_image.height * 3);
|
||||
|
||||
for row in 0..raw_image.height {
|
||||
for col in 0..raw_image.width {
|
||||
let mut pixel = [0_u16; 3];
|
||||
let color_index = raw_image.cfa_pattern[2 * (row % 2) + (col % 2)];
|
||||
pixel[color_index as usize] = raw_image.data[row * raw_image.width + col];
|
||||
image.extend_from_slice(&pixel);
|
||||
}
|
||||
}
|
||||
|
||||
raw_image.data = image;
|
||||
raw_image
|
||||
}
|
||||
46
libraries/raw-rs/src/preprocessing/scale_colors.rs
Normal file
46
libraries/raw-rs/src/preprocessing/scale_colors.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use crate::RawImage;
|
||||
|
||||
const XYZ_TO_RGB: [[f64; 3]; 3] = [[0.412453, 0.357580, 0.180423], [0.212671, 0.715160, 0.072169], [0.019334, 0.119193, 0.950227]];
|
||||
|
||||
pub fn scale_colors(mut raw_image: RawImage) -> RawImage {
|
||||
if let Some(camera_to_xyz) = raw_image.camera_to_xyz {
|
||||
let mut camera_to_rgb = [[0.; 3]; 3];
|
||||
for i in 0..3 {
|
||||
for j in 0..3 {
|
||||
for k in 0..3 {
|
||||
camera_to_rgb[i][j] += camera_to_xyz[i * 3 + k] * XYZ_TO_RGB[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut white_balance_multiplier = camera_to_rgb.map(|x| 1. / x.iter().sum::<f64>());
|
||||
|
||||
if white_balance_multiplier[1] == 0. {
|
||||
white_balance_multiplier[1] = 1.;
|
||||
}
|
||||
|
||||
// TODO: Move this at its correct location when highlights are implemented correctly.
|
||||
let highlight = 0;
|
||||
|
||||
let normalize_white_balance = if highlight == 0 {
|
||||
white_balance_multiplier.iter().fold(f64::INFINITY, |a, &b| a.min(b))
|
||||
} else {
|
||||
white_balance_multiplier.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b))
|
||||
};
|
||||
|
||||
let final_multiplier = if normalize_white_balance > 0.00001 && raw_image.maximum > 0 {
|
||||
let scale_to_16bit_multiplier = u16::MAX as f64 / raw_image.maximum as f64;
|
||||
white_balance_multiplier.map(|x| x / normalize_white_balance * scale_to_16bit_multiplier)
|
||||
} else {
|
||||
[1., 1., 1.]
|
||||
};
|
||||
|
||||
for i in 0..(raw_image.height * raw_image.width) {
|
||||
for (c, multiplier) in final_multiplier.iter().enumerate() {
|
||||
raw_image.data[3 * i + c] = ((raw_image.data[3 * i + c] as f64) * multiplier).min(u16::MAX as f64).max(0.) as u16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raw_image
|
||||
}
|
||||
30
libraries/raw-rs/src/preprocessing/subtract_black.rs
Normal file
30
libraries/raw-rs/src/preprocessing/subtract_black.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use crate::{RawImage, SubtractBlack};
|
||||
|
||||
pub fn subtract_black(raw_image: RawImage) -> RawImage {
|
||||
let mut raw_image = match raw_image.black {
|
||||
SubtractBlack::None => raw_image,
|
||||
SubtractBlack::Value(_) => todo!(),
|
||||
SubtractBlack::CfaGrid(_) => subtract_black_cfa_grid(raw_image),
|
||||
};
|
||||
|
||||
raw_image.black = SubtractBlack::None;
|
||||
raw_image
|
||||
}
|
||||
|
||||
pub fn subtract_black_cfa_grid(mut raw_image: RawImage) -> RawImage {
|
||||
let width = raw_image.width;
|
||||
let black_level = match raw_image.black {
|
||||
SubtractBlack::CfaGrid(x) => x,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
for row in 0..raw_image.height {
|
||||
for col in 0..width {
|
||||
raw_image.data[row * width + col] = raw_image.data[row * width + col].saturating_sub(black_level[2 * (row % 2) + (col % 2)]);
|
||||
}
|
||||
}
|
||||
|
||||
raw_image.maximum -= black_level.iter().max().unwrap();
|
||||
|
||||
raw_image
|
||||
}
|
||||
Reference in New Issue
Block a user