use crate::decoders::*;
use crate::decoders::cfa::*;
#[derive(Debug, Clone)]
pub struct RawImage {
pub make: String,
pub model: String,
pub clean_make: String,
pub clean_model: String,
pub width: usize,
pub height: usize,
pub cpp: usize,
pub wb_coeffs: [f32;4],
pub whitelevels: [u16;4],
pub blacklevels: [u16;4],
pub xyz_to_cam: [[f32;3];4],
pub cfa: CFA,
pub crops: [usize;4],
pub blackareas: Vec<(u64,u64,u64,u64)>,
pub orientation: Orientation,
pub data: RawImageData,
}
#[derive(Debug, Clone)]
pub enum RawImageData {
Integer(Vec<u16>),
Float(Vec<f32>),
}
impl RawImage {
#[doc(hidden)] pub fn new(camera: Camera, width: usize, height: usize, wb_coeffs: [f32;4], image: Vec<u16>, dummy: bool) -> RawImage {
let blacks = if !dummy && (camera.blackareah.1 != 0 || camera.blackareav.1 != 0) {
let mut avg = [0 as f32; 4];
let mut count = [0 as f32; 4];
for row in camera.blackareah.0 .. camera.blackareah.0+camera.blackareah.1 {
for col in 0..width {
let color = camera.cfa.color_at(row,col);
avg[color] += image[row*width+col] as f32;
count[color] += 1.0;
}
}
for row in 0..height {
for col in camera.blackareav.0 .. camera.blackareav.0+camera.blackareav.1 {
let color = camera.cfa.color_at(row,col);
avg[color] += image[row*width+col] as f32;
count[color] += 1.0;
}
}
[(avg[0]/count[0]) as u16,
(avg[1]/count[1]) as u16,
(avg[2]/count[2]) as u16,
(avg[3]/count[3]) as u16]
} else {
camera.blacklevels
};
let mut blackareas: Vec<(u64,u64,u64,u64)> = Vec::new();
if camera.blackareah.1 != 0 {
blackareas.push((camera.blackareah.0 as u64, width as u64,
(camera.blackareah.0 + camera.blackareah.1) as u64, 0));
}
if camera.blackareav.1 != 0 {
blackareas.push((0, (camera.blackareav.0 + camera.blackareav.1) as u64,
height as u64, camera.blackareav.0 as u64))
}
RawImage {
make: camera.make.clone(),
model: camera.model.clone(),
clean_make: camera.clean_make.clone(),
clean_model: camera.clean_model.clone(),
width: width,
height: height,
cpp: 1,
wb_coeffs: wb_coeffs,
data: RawImageData::Integer(image),
blacklevels: blacks,
whitelevels: camera.whitelevels,
xyz_to_cam: camera.xyz_to_cam,
cfa: camera.cfa.clone(),
crops: camera.crops,
blackareas: blackareas,
orientation: camera.orientation,
}
}
pub fn cam_to_xyz(&self) -> [[f32;4];3] {
Self::pseudoinverse(self.xyz_to_cam)
}
pub fn cam_to_xyz_normalized(&self) -> [[f32;4];3] {
Self::normalized_pseudoinverse(self.xyz_to_cam)
}
pub fn neutralwb(&self) -> [f32;4] {
let rgb_to_xyz = [
[ 0.412453, 0.357580, 0.180423 ],
[ 0.212671, 0.715160, 0.072169 ],
[ 0.019334, 0.119193, 0.950227 ],
];
let mut rgb_to_cam = [[0.0;3];4];
for i in 0..4 {
for j in 0..3 {
rgb_to_cam[i][j] = 0.0;
for k in 0..3 {
rgb_to_cam[i][j] += self.xyz_to_cam[i][k] * rgb_to_xyz[k][j];
}
}
}
let mut neutralwb = [0 as f32; 4];
for i in 0..4 {
let mut num = 0.0;
for j in 0..3 {
num += rgb_to_cam[i][j];
}
neutralwb[i] = 1.0 / num;
}
[neutralwb[0]/neutralwb[1],
neutralwb[1]/neutralwb[1],
neutralwb[2]/neutralwb[1],
neutralwb[3]/neutralwb[1]]
}
pub fn normalized_pseudoinverse(inm: [[f32;3];4]) -> [[f32;4];3] {
let mut xyz_to_cam = inm;
for i in 0..4 {
let mut num = 0.0;
for j in 0..3 {
num += xyz_to_cam[i][j];
}
for j in 0..3 {
xyz_to_cam[i][j] = if num == 0.0 {
0.0
} else {
xyz_to_cam[i][j] / num
};
}
}
Self::pseudoinverse(xyz_to_cam)
}
pub fn pseudoinverse(inm: [[f32;3];4]) -> [[f32;4];3] {
let mut temp: [[f32;6];3] = [[0.0; 6];3];
for i in 0..3 {
for j in 0..6 {
temp[i][j] = if j == i+3 { 1.0 } else { 0.0 };
}
for j in 0..3 {
for k in 0..4 {
temp[i][j] += inm[k][i] * inm[k][j];
}
}
}
for i in 0..3 {
let mut num = temp[i][i];
for j in 0..6 {
temp[i][j] /= num;
}
for k in 0..3 {
if k == i { continue }
num = temp[k][i];
for j in 0..6 {
temp[k][j] -= temp[i][j] * num;
}
}
}
let mut out: [[f32;4];3] = [[0.0; 4];3];
for i in 0..4 {
for j in 0..3 {
out[j][i] = 0.0;
for k in 0..3 {
out[j][i] += temp[j][k+3] * inm[i][k];
}
}
}
out
}
pub fn cropped_cfa(&self) -> CFA {
self.cfa.shift(self.crops[3], self.crops[0])
}
pub fn is_monochrome(&self) -> bool {
self.cpp == 1 && !self.cfa.is_valid()
}
}