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:
Elbert Ronnie
2024-08-11 14:06:50 +05:30
committed by GitHub
parent 1b6d45ad30
commit a9cfeeb219
62 changed files with 688 additions and 56 deletions

View 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.))
}

View File

@@ -0,0 +1,4 @@
pub mod camera_data;
pub mod raw_to_image;
pub mod scale_colors;
pub mod subtract_black;

View 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
}

View 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
}

View 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
}