1extern crate image;
31extern crate math;
32use std::fmt;
33use image::{GenericImage, ImageBuffer,RGB,GenericImageView, DynamicImage};
34use image::imageops;
35use std::cmp::{min, max};
36
37#[derive(Debug, Copy, Clone)]
39pub enum Pix{
40 R,G,B
41}
42
43pub struct Histogram{
46 r_dist : Vec<f32>,
47 g_dist : Vec<f32>,
48 b_dist : Vec<f32>
49}
50impl fmt::Debug for Histogram {
51 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52 let L = 256;
53 write!(f,"\n----------------- RED -----------------\n");
54 for i in 0..L{
55 if self.r_dist[i] > 0.0{
56 write!(f,"{} => {}\n", i, self.r_dist[i]);
57 }
58 }
59 write!(f,"\n----------------- GREEN -----------------\n");
60 for i in 0..L{
61 if self.g_dist[i] > 0.0{
62 write!(f,"{} => {}\n", i, self.g_dist[i]);
63 }
64 }
65 write!(f,"\n----------------- BLUE -----------------\n");
66 for i in 0..L{
67 if self.b_dist[i] > 0.0{
68 write!(f,"{} => {}\n", i, self.b_dist[i]);
69 }
70 }
71 write!(f,"")
72 }
73}
74
75impl Histogram{
76 pub fn probability(&self,pix_val: u8)->(f32,f32,f32){
77 (self.r_dist[pix_val as usize],self.g_dist[pix_val as usize],self.b_dist[pix_val as usize])
78 }
79 pub fn probability_of(&self,p : Pix, pix_val : u8)->f32{
80 match p{
81 R => self.r_dist[pix_val as usize],
82 G => self.g_dist[pix_val as usize],
83 B => self.b_dist[pix_val as usize],
84 }
85 }
86 pub fn new(img : & DynamicImage)->Self{
87 let (width, height) = img.dimensions();
88 let L = 256;
89 let mut r_dist = vec![0f32;L];
90 let mut g_dist = vec![0f32;L];
91 let mut b_dist = vec![0f32;L];
92 let sum : f32 = (width * height) as f32;
93 for i in 0..width{
94 for j in 0..height{
95 let r_p = img.get_pixel(i,j).data[0];
96 r_dist[r_p as usize] += 1.0;
97 let g_p = img.get_pixel(i,j).data[1];
98 g_dist[g_p as usize] += 1.0;
99 let b_p = img.get_pixel(i,j).data[2];
100 b_dist[b_p as usize] += 1.0;
101 }
102 }
103 let mut sum_distros = 0.0;
104 for i in 0..L{
105 if r_dist[i] >= 1.0{
106 r_dist[i] = r_dist[i] / sum;
107 sum_distros += r_dist[i];
108 }
109 if g_dist[i] >= 1.0{
110 g_dist[i] = g_dist[i] / sum;
111 }
112 if b_dist[i] >= 1.0{
113 b_dist[i] = b_dist[i] / sum;
114 }
115 }
116 Histogram{
117 r_dist: r_dist,
118 g_dist: g_dist,
119 b_dist: b_dist
120 }
121 }
122}
123
124pub fn transform_pixel(original_pixel : u8, colorType : Pix ,histogram :& Histogram)-> u8{
125 let L = 256.0;
126 let new_pixel = 0;
127 let mut distros_sum = 0.0;
128 let mut up_to = original_pixel as u32 +1;
129 for i in 0..up_to{
130 distros_sum += histogram.probability_of(colorType, i as u8);
131 }
132 ((L-1.0) * distros_sum) as u8
133}
134pub fn transform_from_histogram(img : &DynamicImage, hist : &Histogram)->DynamicImage{
145 let (w,h) = img.dimensions();
146 let mut new_img = DynamicImage::new_rgba8(w, h);
147 for i in 0..w{
148 for j in 0..h{
149 let pixel = img.get_pixel(i, j);
150 let mut r = pixel.data[0];
151 let mut g = pixel.data[1];
152 let mut b = pixel.data[2];
153 r = transform_pixel(r, Pix::R, hist);
154 g = transform_pixel(g, Pix::G, hist);
155 b = transform_pixel(b, Pix::B, hist);
156 let transformed_pixel = image::Rgba([r,g,b,pixel.data[3]]);
157 new_img.put_pixel(i,j, transformed_pixel);
158 }
159 }
160 new_img
161}
162pub fn load_img(path : &str)->Result<DynamicImage,image::ImageError>{
169 let im = image::open(path)?;
170 Ok(im)
171}
172pub fn save_img(img : &DynamicImage, path : &str)->Result<(),std::io::Error>{
183 img.save(path)?;
184 Ok(())
185}
186pub fn normalize_brightness(img : &DynamicImage)->Result<DynamicImage,()>{
196 let histogram = Histogram::new(img);
197 let new_image = transform_from_histogram(&img, &histogram);
198 Ok(new_image)
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 fn equals(img1 : &DynamicImage, img2 :& DynamicImage)->bool{
205 let (w1,h1) = img1.dimensions();
206 let (w2,h2) = img2.dimensions();
207 if w1 != w2 || h1 != h2 {
209 return false;
210 }
211 for i in 0..w1{
212 for j in 0..h1{
213 let p1 = img1.get_pixel(i, j);
214 let r1 = p1.data[0];
215 let g1 = p1.data[1];
216 let b1 = p1.data[2];
217 let a1 = p1.data[3];
218 let p2 = img2.get_pixel(i, j);
219 let r2 = p1.data[0];
220 let g2 = p1.data[1];
221 let b2 = p1.data[2];
222 let a2 = p1.data[3];
223 if r1 != r2 || g1 != g2 || b1 != b2 || a1 != a2{
224 return false;
225 }
226 }
227 }
228 true
229 }
230 #[test]
231 fn perform_histogram_equalization() {
232 let path = "./test/bright_miami.jpg";
233 let img = image::open(path).unwrap();
234 let histogram = Histogram::new(&img);
235 let new_image = transform_from_histogram(&img, &histogram);
236 let test_img = image::open("./test/normalized_miami.jpg").unwrap();
238 assert!(equals(&test_img, &new_image),"image not equal");
239 }
240}