use image::{GenericImageView, ImageBuffer, Pixel, Rgba};
use matrix_kit::dynamic::matrix::Matrix;
pub fn read_rgba_matrices(
path: &str
) -> Vec<Matrix<f64>> {
let picture = image::open(path)
.expect(&format!("Unable to open image at path {:?}", path));
let width = picture.width() as usize;
let height = picture.height() as usize;
let mut rgba_raw = vec![
Matrix::<u8>::from_index_def(height, width, &mut |_,_| 0) ; 4
];
for x in 0..width {
for y in 0..height {
let pixel = picture.get_pixel(x as u32, y as u32);
for i in 0..4 {
rgba_raw[i].set(y, x, pixel.channels()[i]);
}
}
}
rgba_raw.iter().map(|byte_matrix|
byte_matrix.applying_to_all(&mut |b|
(b as f64) / (u8::MAX as f64)
)
).collect()
}
pub fn write_rgba_matrices(rgba: Vec<Matrix<f64>>, path: &str) {
let height = rgba[0].row_count();
let width = rgba[0].col_count();
let mut img_buffer = ImageBuffer::new(width as u32, height as u32);
for y in 0..height {
for x in 0..width {
let mut rgba_vec = [0 ; 4];
for i in 0..4 {
rgba_vec[i] = (rgba[i].get(y, x) * (u8::MAX as f64)) as u8;
}
img_buffer.put_pixel(x as u32, y as u32, Rgba(rgba_vec));
}
}
img_buffer
.save(path)
.expect("Failed to save image");
}
#[cfg(test)]
mod test_image_util {
use std::fs::File;
use matrix_kit::dynamic::matrix::Matrix;
use crate::{math::{activation::AFI, svd::{compressed_svd, svd, truncate}}, models::neuralnet::NeuralNet};
use super::{read_rgba_matrices, write_rgba_matrices};
#[test]
fn test_readwrite() {
let channels = read_rgba_matrices("testing/files/sheep.png");
write_rgba_matrices(channels, "testing/files/sheep_new.png");
}
#[test]
fn factor_image() {
let channels = super::read_rgba_matrices("testing/files/sheep.png");
println!("Image is [{} x {}]", channels[0].row_count(), channels[0].col_count());
let image_svd_rgba: Vec<(Matrix<f64>, Matrix<f64>, Matrix<f64>)> = channels.iter().map(|channel|
svd(channel)
).collect();
for i in 0..4 {
let (u, v, s) = image_svd_rgba[i].clone();
let network = NeuralNet::new(vec![
v.transpose(), s.clone(), u.clone()],
vec![
Matrix::new(v.col_count(), 1),
Matrix::new(s.row_count(), 1),
Matrix::new(u.row_count(), 1),
],
vec![AFI::Identity ; 3]
);
let path = format!("testing/files/rgba_sheep_{}.mlk_nn", i);
let mut file = match File::create(path) {
Ok(f) => f,
Err(e) => panic!("Error opening file: {:?}", e),
};
network.write_to_file(&mut file);
}
}
#[test]
fn test_compression() {
let compressed_sizes = vec![240, 200, 150, 100, 10];
let recovered_rgba: Vec<(Matrix<f64>, Matrix<f64>, Matrix<f64>)> = (0..4).map(|i| {
let path = format!("testing/files/rgba_sheep_{}.mlk_nn", i);
let mut file = match File::open(path) {
Ok(f) => f,
Err(e) => panic!("Error writing file: {:?}", e),
};
let network = NeuralNet::from_file(&mut file);
let v = network.weights[0].transpose();
let s = network.weights[1].clone();
let u = network.weights[2].clone();
(u, v, s)
}
).collect();
println!("Singular values for Sheep Picture...");
println!("RED: \t{:?}", recovered_rgba[0].2.get_diagonal());
println!("GREEN:\t{:?}", recovered_rgba[1].2.get_diagonal());
println!("BLUE: \t{:?}", recovered_rgba[2].2.get_diagonal());
println!("ALPHA:\t{:?}", recovered_rgba[3].2.get_diagonal());
for r in compressed_sizes {
let truncated_rgba = recovered_rgba.iter().map(|(u, v, s)| {
let (u_r, v_r, s_r) = truncate(u, v, &s.get_diagonal(), r);
u_r * Matrix::from_diagonal(s_r) * v_r.transpose()
}
).collect();
let path = format!("testing/files/compressed_sheep_{}.png", r);
write_rgba_matrices(truncated_rgba, &path);
}
}
}