Skip to content

Commit

Permalink
Fix LAB/LUV normalization
Browse files Browse the repository at this point in the history
  • Loading branch information
awxkee committed Jun 8, 2024
1 parent 12abab5 commit b0d4144
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 24 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ workspace = { members = ["./src/app"] }

[package]
name = "histogram_equalization"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
description = "Histogram equalization"
readme = "README.md"
Expand Down
3 changes: 2 additions & 1 deletion src/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ edition = "2021"

[dependencies]
image = "0.25.1"
histogram_equalization = {path = "../../"}
histogram_equalization = {path = "../../"}
colorutils-rs = "0.3.1"
31 changes: 24 additions & 7 deletions src/app/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,49 @@
use colorutils_rs::rgb_to_rgba;
use image::GenericImageView;
use image::io::Reader as ImageReader;

use histogram_equalization::hist_equal_luv_rgb;
use histogram_equalization::{clahe_hsl_rgba, clahe_lab_rgb, clahe_lab_rgba, ClaheGridSize, hist_equal_luv_rgb};

fn main() {
let img = ImageReader::open("assets/asset_1.jpg")
let img = ImageReader::open("assets/asset_2.jpg")
.unwrap()
.decode()
.unwrap();
let dimensions = img.dimensions();
let channels = 3;
let mut src_bytes = img.as_bytes();

let mut dst_rgba = vec![];
dst_rgba.resize(4usize * dimensions.0 as usize * dimensions.1 as usize, 0u8);
rgb_to_rgba(
&src_bytes,
3u32 * dimensions.0,
&mut dst_rgba,
4u32 * dimensions.0,
dimensions.0,
dimensions.1,
255,
);
src_bytes = &dst_rgba;

let channels = 4;
let stride = dimensions.0 as usize * channels;
let mut dst_bytes: Vec<u8> = vec![0; stride * dimensions.1 as usize];
let src_bytes = img.as_bytes();

hist_equal_luv_rgb(
clahe_lab_rgba(
src_bytes,
stride as u32,
&mut dst_bytes,
stride as u32,
dimensions.0,
dimensions.1,
3f32,
ClaheGridSize::new(8, 8),
128,
);

if channels == 4 {
image::save_buffer(
"converted_eq_luv.png",
"converted_luv.png",
&dst_bytes,
dimensions.0,
dimensions.1,
Expand All @@ -35,7 +52,7 @@ fn main() {
.unwrap();
} else {
image::save_buffer(
"converted_eq_luv.jpg",
"converted_luv.jpg",
&dst_bytes,
dimensions.0,
dimensions.1,
Expand Down
30 changes: 16 additions & 14 deletions src/lab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub(crate) fn generic_image_to_lab<const IMAGE: u8>(
let image_configuration: ImageConfiguration = IMAGE.into();
let channels = image_configuration.get_channels_count();

let full_scale = 1f32 / 100f32 * scale;
let full_scale = scale / 100f32;

let mut src_offset = 0usize;
let mut lab_offset = 0usize;
Expand All @@ -26,7 +26,6 @@ pub(crate) fn generic_image_to_lab<const IMAGE: u8>(
let new_slice = unsafe { slice::from_raw_parts_mut(dst_ptr, width as usize * channels) };
for x in 0..width as usize {
let px = x * channels;
let h_px = x * channels;

let rgb = Rgb::<u8>::new(
unsafe {
Expand All @@ -41,14 +40,15 @@ pub(crate) fn generic_image_to_lab<const IMAGE: u8>(
);
let luv = rgb.to_lab();
unsafe {
*new_slice.get_unchecked_mut(h_px) = (luv.l * full_scale).round().min(scale) as u16;
*new_slice.get_unchecked_mut(h_px + 1) = luv.a as u16;
*new_slice.get_unchecked_mut(h_px + 2) = luv.b as u16;
*new_slice.get_unchecked_mut(px) = (luv.l * full_scale).round().min(scale) as u16;
// Just for storing in u16 adding 500 to subtract 500 after to keep values in positive range
*new_slice.get_unchecked_mut(px + 1) = (luv.a + 500f32) as u16;
*new_slice.get_unchecked_mut(px + 2) = (luv.b + 500f32) as u16;
if image_configuration.has_alpha() {
let a = *src.get_unchecked(
src_offset + px + image_configuration.get_a_channel_offset(),
);
*new_slice.get_unchecked_mut(h_px + 3) = a as u16;
*new_slice.get_unchecked_mut(px + 3) = a as u16;
}
}
}
Expand All @@ -70,7 +70,7 @@ pub(crate) fn lab_to_generic_image<const IMAGE: u8>(
let image_configuration: ImageConfiguration = IMAGE.into();
let channels = image_configuration.get_channels_count();

let full_scale = 1f32 / scale * 100f32;
let full_scale = 100f32 / scale;

let mut src_offset = 0usize;
let mut dst_offset = 0usize;
Expand All @@ -79,30 +79,32 @@ pub(crate) fn lab_to_generic_image<const IMAGE: u8>(
let source_slice = unsafe { slice::from_raw_parts(src_ptr, width as usize * channels) };
for x in 0..width as usize {
let px = x * channels;
let h_px = x * channels;

let l = unsafe { *source_slice.get_unchecked(px) } as f32 * full_scale;

let a = unsafe { *source_slice.get_unchecked(px + 1) } as f32 - 500f32;
let b = unsafe { *source_slice.get_unchecked(px + 2) } as f32 - 500f32;

let rgb = Lab::new(
l,
unsafe { *source_slice.get_unchecked(px + 1) } as f32,
unsafe { *source_slice.get_unchecked(px + 2) } as f32,
a,
b,
);
let rgb = rgb.to_rgb();
unsafe {
*dst.get_unchecked_mut(
dst_offset + h_px + image_configuration.get_r_channel_offset(),
dst_offset + px + image_configuration.get_r_channel_offset(),
) = rgb.r;
*dst.get_unchecked_mut(
dst_offset + h_px + image_configuration.get_g_channel_offset(),
dst_offset + px + image_configuration.get_g_channel_offset(),
) = rgb.g;
*dst.get_unchecked_mut(
dst_offset + h_px + image_configuration.get_b_channel_offset(),
dst_offset + px + image_configuration.get_b_channel_offset(),
) = rgb.b;
if image_configuration.has_alpha() {
let a = *source_slice.get_unchecked(px + 3);
*dst.get_unchecked_mut(
dst_offset + h_px + image_configuration.get_a_channel_offset(),
dst_offset + px + image_configuration.get_a_channel_offset(),
) = a as u8;
}
}
Expand Down

0 comments on commit b0d4144

Please sign in to comment.