image_toolbox/
lib.rs

1//! Quick to start, different and random Image operations. 
2//! Feel free to contribute and add new features via a Pull Request.
3//! # How to use
4//! In Cargo.toml 
5//! ```ignore
6//! [dependencies]
7//! image-toolbox = "*"
8//! ```
9//! # The histogram struct 
10//! ```
11//! use image_toolbox::{Histogram, load_img};
12//! use image::{DynamicImage};
13//! 
14//! // load img 
15//! let img = load_img("./test/bright_miami.jpg").unwrap();
16//! let histogram = Histogram::new(&img);
17//! println!("{:?}",histogram);
18//! // get the r,g,b probability of some pixel value 
19//! let (p_r,p_g,p_b) : (f32,f32,f32) = histogram.probability(200);
20//! ```
21//! # turn a TOO bright image into normal colors
22//! ```ignore
23//! use image_toolbox::{load_img,normalize_brightness,save_img};
24//! 
25//! let img = load_img("./test/bright_miami.jpg").unwrap();
26//! let new_image = normalize_brightness(&img).unwrap();
27//! save_img(&new_image,"./test/result.jpg").unwrap();
28//! ```
29
30extern 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/// used to represent pixel color type in Histogram struct
38#[derive(Debug, Copy, Clone)]
39pub enum Pix{
40    R,G,B
41}
42
43/// Histogram representation of an image 
44/// represents the distribution of Red,Green,Blue pixels in an image. 
45pub 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}
134/// turn a very bright image into a normal looking one by using histogram equalization.
135/// ```
136/// use image_toolbox::{transform_from_histogram,Histogram};
137/// use image::{DynamicImage};
138/// 
139/// // make a new 500X500 image 
140/// let img = DynamicImage::new_rgba8(500,500); 
141/// let histogram = Histogram::new(&img);
142/// let new_image = transform_from_histogram(&img, &histogram);
143/// ```
144pub 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}
162/// Load any type of image uses `DynamicImage` type. 
163/// ```
164/// use image_toolbox::{load_img};
165/// 
166/// let img = load_img("./test/bright_miami.jpg").unwrap();
167/// ```
168pub fn load_img(path : &str)->Result<DynamicImage,image::ImageError>{
169    let im = image::open(path)?;
170    Ok(im)
171}
172/// Save an image to disk 
173/// ```
174/// use image_toolbox::{save_img};
175/// use image::{DynamicImage};
176/// 
177/// // make a new 500X500 image 
178/// let img = DynamicImage::new_rgba8(500,500); 
179/// // save the image 
180/// save_img(&img,"./test/empty_img.jpg").unwrap();
181/// ```
182pub fn save_img(img : &DynamicImage, path : &str)->Result<(),std::io::Error>{
183    img.save(path)?;
184    Ok(())
185}
186/// transform a very bright image into normal brightness based on histogram equalization
187/// wrapper for `transform_from_histogram` function. 
188/// ```
189/// use image_toolbox::{load_img,normalize_brightness};
190/// 
191/// let img = load_img("./test/bright_miami.jpg").unwrap();
192/// let new_image = normalize_brightness(&img).unwrap();
193/// // save_img(&new_image,"./test/result.jpg").unwrap();
194/// ```
195pub 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        // compare image dimensions 
208        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        // verify 
237        let test_img = image::open("./test/normalized_miami.jpg").unwrap();
238        assert!(equals(&test_img, &new_image),"image not equal");
239    }
240}