imageproc/
map.rs

1//! Functions for mapping over pixels, colors or subpixels of images.
2
3use image::{GenericImage, ImageBuffer, Luma, LumaA, Pixel, Primitive, Rgb, Rgba};
4
5use crate::definitions::Image;
6
7/// The type obtained by replacing the channel type of a given `Pixel` type.
8/// The output type must have the same name of channels as the input type, or
9/// several algorithms will produce incorrect results or panic.
10pub trait WithChannel<C: Primitive>: Pixel {
11    /// The new pixel type.
12    type Pixel: Pixel<Subpixel = C>;
13}
14
15/// Alias to make uses of `WithChannel` less syntactically noisy.
16pub type ChannelMap<Pix, Sub> = <Pix as WithChannel<Sub>>::Pixel;
17
18impl<T, U> WithChannel<U> for Rgb<T>
19where
20    Rgb<T>: Pixel<Subpixel = T>,
21    Rgb<U>: Pixel<Subpixel = U>,
22    T: Primitive,
23    U: Primitive,
24{
25    type Pixel = Rgb<U>;
26}
27
28impl<T, U> WithChannel<U> for Rgba<T>
29where
30    Rgba<T>: Pixel<Subpixel = T>,
31    Rgba<U>: Pixel<Subpixel = U>,
32    T: Primitive,
33    U: Primitive,
34{
35    type Pixel = Rgba<U>;
36}
37
38impl<T, U> WithChannel<U> for Luma<T>
39where
40    T: Primitive,
41    U: Primitive,
42{
43    type Pixel = Luma<U>;
44}
45
46impl<T, U> WithChannel<U> for LumaA<T>
47where
48    T: Primitive,
49    U: Primitive,
50{
51    type Pixel = LumaA<U>;
52}
53
54/// Applies `f` to each subpixel of the input image.
55///
56/// # Examples
57/// ```
58/// # extern crate image;
59/// # #[macro_use]
60/// # extern crate imageproc;
61/// # fn main() {
62/// use imageproc::map::map_subpixels;
63///
64/// let image = gray_image!(
65///     1, 2;
66///     3, 4);
67///
68/// let scaled = gray_image!(type: i16,
69///     -2, -4;
70///     -6, -8);
71///
72/// assert_pixels_eq!(
73///     map_subpixels(&image, |x| -2 * (x as i16)),
74///     scaled);
75/// # }
76/// ```
77pub fn map_subpixels<I, P, F, S>(image: &I, f: F) -> Image<ChannelMap<P, S>>
78where
79    I: GenericImage<Pixel = P>,
80    P: WithChannel<S>,
81    S: Primitive,
82    F: Fn(P::Subpixel) -> S,
83{
84    let (width, height) = image.dimensions();
85    let mut out: ImageBuffer<ChannelMap<P, S>, Vec<S>> = ImageBuffer::new(width, height);
86
87    for y in 0..height {
88        for x in 0..width {
89            let out_channels = out.get_pixel_mut(x, y).channels_mut();
90            for c in 0..P::CHANNEL_COUNT {
91                out_channels[c as usize] = f(unsafe {
92                    *image
93                        .unsafe_get_pixel(x, y)
94                        .channels()
95                        .get_unchecked(c as usize)
96                });
97            }
98        }
99    }
100
101    out
102}
103
104/// Applies `f` to each subpixel of the input image in place.
105///
106/// # Examples
107/// ```
108/// # extern crate image;
109/// # #[macro_use]
110/// # extern crate imageproc;
111/// # fn main() {
112/// use imageproc::map::map_subpixels_mut;
113///
114/// let mut image = gray_image!(
115///     1, 2;
116///     3, 4);
117///
118/// let want = gray_image!(
119///     2, 4;
120///     6, 8);
121///
122/// map_subpixels_mut(&mut image, |x| 2 * x);
123///
124/// assert_pixels_eq!(
125///     image,
126///     want);
127/// # }
128/// ```
129pub fn map_subpixels_mut<I, P, F>(image: &mut I, f: F)
130where
131    I: GenericImage<Pixel = P>,
132    P: Pixel,
133    F: Fn(P::Subpixel) -> P::Subpixel,
134{
135    let (width, height) = image.dimensions();
136
137    for y in 0..height {
138        for x in 0..width {
139            let mut pixel = image.get_pixel(x, y);
140            let channels = pixel.channels_mut();
141            for c in 0..P::CHANNEL_COUNT as usize {
142                channels[c] =
143                    f(unsafe { *image.unsafe_get_pixel(x, y).channels().get_unchecked(c) });
144            }
145            image.put_pixel(x, y, pixel);
146        }
147    }
148}
149
150/// Applies `f` to the color of each pixel in the input image.
151///
152/// # Examples
153/// ```
154/// # extern crate image;
155/// # #[macro_use]
156/// # extern crate imageproc;
157/// # fn main() {
158/// use image::Rgb;
159/// use imageproc::map::map_colors;
160///
161/// let image = gray_image!(
162///     1, 2;
163///     3, 4);
164///
165/// let rgb = rgb_image!(
166///     [1, 2, 3], [2, 4, 6];
167///     [3, 6, 9], [4, 8, 12]);
168///
169/// assert_pixels_eq!(
170///     map_colors(&image, |p| { Rgb([p[0], (2 * p[0]), (3 * p[0])]) }),
171///     rgb);
172/// # }
173/// ```
174pub fn map_colors<I, P, Q, F>(image: &I, f: F) -> Image<Q>
175where
176    I: GenericImage<Pixel = P>,
177    P: Pixel,
178    Q: Pixel,
179    F: Fn(P) -> Q,
180{
181    let (width, height) = image.dimensions();
182    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);
183
184    for y in 0..height {
185        for x in 0..width {
186            unsafe {
187                let pix = image.unsafe_get_pixel(x, y);
188                out.unsafe_put_pixel(x, y, f(pix));
189            }
190        }
191    }
192
193    out
194}
195
196/// Applies `f` to the color of each pixel in the input image in place.
197///
198/// # Examples
199/// ```
200/// # extern crate image;
201/// # #[macro_use]
202/// # extern crate imageproc;
203/// # fn main() {
204/// use image::Luma;
205/// use imageproc::map::map_colors_mut;
206///
207/// let mut image = gray_image!(
208///     1, 2;
209///     3, 4);
210///
211/// let want = gray_image!(
212///     2, 4;
213///     6, 8);
214///
215/// map_colors_mut(&mut image, |p| Luma([2 * p[0]]));
216///
217/// assert_pixels_eq!(
218///     image,
219///     want);
220/// # }
221/// ```
222pub fn map_colors_mut<I, P, F>(image: &mut I, f: F)
223where
224    I: GenericImage<Pixel = P>,
225    P: Pixel,
226    F: Fn(P) -> P,
227{
228    let (width, height) = image.dimensions();
229
230    for y in 0..height {
231        for x in 0..width {
232            unsafe {
233                let pix = image.unsafe_get_pixel(x, y);
234                image.unsafe_put_pixel(x, y, f(pix));
235            }
236        }
237    }
238}
239
240/// Applies `f` to the colors of the pixels in the input images.
241///
242/// Requires `image1` and `image2` to have the same dimensions.
243/// # Examples
244/// ```
245/// # extern crate image;
246/// # #[macro_use]
247/// # extern crate imageproc;
248/// # fn main() {
249/// use image::Luma;
250/// use imageproc::map::map_colors2;
251///
252/// let image1 = gray_image!(
253///     1, 2,
254///     3, 4
255/// );
256///
257/// let image2 = gray_image!(
258///     10, 20,
259///     30, 40
260/// );
261///
262/// let sum = gray_image!(
263///     11, 22,
264///     33, 44
265/// );
266///
267/// assert_pixels_eq!(
268///     map_colors2(&image1, &image2, |p, q| Luma([p[0] + q[0]])),
269///     sum
270/// );
271/// # }
272/// ```
273pub fn map_colors2<I, J, P, Q, R, F>(image1: &I, image2: &J, f: F) -> Image<R>
274where
275    I: GenericImage<Pixel = P>,
276    J: GenericImage<Pixel = Q>,
277    P: Pixel,
278    Q: Pixel,
279    R: Pixel,
280    F: Fn(P, Q) -> R,
281{
282    assert_eq!(image1.dimensions(), image2.dimensions());
283
284    let (width, height) = image1.dimensions();
285    let mut out: ImageBuffer<R, Vec<R::Subpixel>> = ImageBuffer::new(width, height);
286
287    for y in 0..height {
288        for x in 0..width {
289            unsafe {
290                let p = image1.unsafe_get_pixel(x, y);
291                let q = image2.unsafe_get_pixel(x, y);
292                out.unsafe_put_pixel(x, y, f(p, q));
293            }
294        }
295    }
296
297    out
298}
299
300/// Applies `f` to each pixel in the input image.
301///
302/// # Examples
303/// ```
304/// # extern crate image;
305/// # #[macro_use]
306/// # extern crate imageproc;
307/// # fn main() {
308/// use image::Rgb;
309/// use imageproc::map::map_pixels;
310///
311/// let image = gray_image!(
312///     1, 2;
313///     3, 4);
314///
315/// let rgb = rgb_image!(
316///     [1, 0, 0], [2, 1, 0];
317///     [3, 0, 1], [4, 1, 1]);
318///
319/// assert_pixels_eq!(
320///     map_pixels(&image, |x, y, p| {
321///         Rgb([p[0], x as u8, y as u8])
322///     }),
323///     rgb);
324/// # }
325/// ```
326pub fn map_pixels<I, P, Q, F>(image: &I, f: F) -> Image<Q>
327where
328    I: GenericImage<Pixel = P>,
329    P: Pixel,
330    Q: Pixel,
331    F: Fn(u32, u32, P) -> Q,
332{
333    let (width, height) = image.dimensions();
334    let mut out: ImageBuffer<Q, Vec<Q::Subpixel>> = ImageBuffer::new(width, height);
335
336    for y in 0..height {
337        for x in 0..width {
338            unsafe {
339                let pix = image.unsafe_get_pixel(x, y);
340                out.unsafe_put_pixel(x, y, f(x, y, pix));
341            }
342        }
343    }
344
345    out
346}
347
348/// Applies `f` to each pixel in the input image in place.
349///
350/// # Examples
351/// ```
352/// # extern crate image;
353/// # #[macro_use]
354/// # extern crate imageproc;
355/// # fn main() {
356/// use image::Luma;
357/// use imageproc::map::map_pixels_mut;
358///
359/// let mut image = gray_image!(
360///     1, 2;
361///     3, 4);
362///
363/// let want = gray_image!(
364///     1, 3;
365///     4, 6);
366///
367/// map_pixels_mut(&mut image, |x, y, p| {
368///     Luma([p[0] + x as u8 + y as u8])
369/// });
370///
371/// assert_pixels_eq!(
372///     image,
373///     want);
374/// # }
375/// ```
376pub fn map_pixels_mut<I, P, F>(image: &mut I, f: F)
377where
378    I: GenericImage<Pixel = P>,
379    P: Pixel,
380    F: Fn(u32, u32, P) -> P,
381{
382    let (width, height) = image.dimensions();
383
384    for y in 0..height {
385        for x in 0..width {
386            unsafe {
387                let pix = image.unsafe_get_pixel(x, y);
388                image.unsafe_put_pixel(x, y, f(x, y, pix));
389            }
390        }
391    }
392}
393
394/// Creates a grayscale image by extracting the red channel of an RGB image.
395///
396/// # Examples
397/// ```
398/// # extern crate image;
399/// # #[macro_use]
400/// # extern crate imageproc;
401/// # fn main() {
402/// use image::Luma;
403/// use imageproc::map::red_channel;
404///
405/// let image = rgb_image!(
406///     [1, 2, 3], [2, 4, 6];
407///     [3, 6, 9], [4, 8, 12]);
408///
409/// let expected = gray_image!(
410///     1, 2;
411///     3, 4);
412///
413/// let actual = red_channel(&image);
414/// assert_pixels_eq!(actual, expected);
415/// # }
416/// ```
417pub fn red_channel<I, C>(image: &I) -> Image<Luma<C>>
418where
419    I: GenericImage<Pixel = Rgb<C>>,
420    Rgb<C>: Pixel<Subpixel = C>,
421    C: Primitive,
422{
423    map_colors(image, |p| Luma([p[0]]))
424}
425
426/// Creates an RGB image by embedding a grayscale image in its red channel.
427///
428/// # Examples
429/// ```
430/// # extern crate image;
431/// # #[macro_use]
432/// # extern crate imageproc;
433/// # fn main() {
434/// use image::Luma;
435/// use imageproc::map::as_red_channel;
436///
437/// let image = gray_image!(
438///     1, 2;
439///     3, 4);
440///
441/// let expected = rgb_image!(
442///     [1, 0, 0], [2, 0, 0];
443///     [3, 0, 0], [4, 0, 0]);
444///
445/// let actual = as_red_channel(&image);
446/// assert_pixels_eq!(actual, expected);
447/// # }
448/// ```
449pub fn as_red_channel<I, C>(image: &I) -> Image<Rgb<C>>
450where
451    I: GenericImage<Pixel = Luma<C>>,
452    Rgb<C>: Pixel<Subpixel = C>,
453    C: Primitive,
454{
455    map_colors(image, |p| {
456        let mut cs = [C::zero(); 3];
457        cs[0] = p[0];
458        Rgb(cs)
459    })
460}
461
462/// Creates a grayscale image by extracting the green channel of an RGB image.
463///
464/// # Examples
465/// ```
466/// # extern crate image;
467/// # #[macro_use]
468/// # extern crate imageproc;
469/// # fn main() {
470/// use image::Luma;
471/// use imageproc::map::green_channel;
472///
473/// let image = rgb_image!(
474///     [1, 2, 3], [2, 4, 6];
475///     [3, 6, 9], [4, 8, 12]);
476///
477/// let expected = gray_image!(
478///     2, 4;
479///     6, 8);
480///
481/// let actual = green_channel(&image);
482/// assert_pixels_eq!(actual, expected);
483/// # }
484/// ```
485pub fn green_channel<I, C>(image: &I) -> Image<Luma<C>>
486where
487    I: GenericImage<Pixel = Rgb<C>>,
488    Rgb<C>: Pixel<Subpixel = C>,
489    C: Primitive,
490{
491    map_colors(image, |p| Luma([p[1]]))
492}
493
494/// Creates an RGB image by embedding a grayscale image in its green channel.
495///
496/// # Examples
497/// ```
498/// # extern crate image;
499/// # #[macro_use]
500/// # extern crate imageproc;
501/// # fn main() {
502/// use image::Luma;
503/// use imageproc::map::as_green_channel;
504///
505/// let image = gray_image!(
506///     1, 2;
507///     3, 4);
508///
509/// let expected = rgb_image!(
510///     [0, 1, 0], [0, 2, 0];
511///     [0, 3, 0], [0, 4, 0]);
512///
513/// let actual = as_green_channel(&image);
514/// assert_pixels_eq!(actual, expected);
515/// # }
516/// ```
517pub fn as_green_channel<I, C>(image: &I) -> Image<Rgb<C>>
518where
519    I: GenericImage<Pixel = Luma<C>>,
520    Rgb<C>: Pixel<Subpixel = C>,
521    C: Primitive,
522{
523    map_colors(image, |p| {
524        let mut cs = [C::zero(); 3];
525        cs[1] = p[0];
526        Rgb(cs)
527    })
528}
529
530/// Creates a grayscale image by extracting the blue channel of an RGB image.
531///
532/// # Examples
533/// ```
534/// # extern crate image;
535/// # #[macro_use]
536/// # extern crate imageproc;
537/// # fn main() {
538/// use image::Luma;
539/// use imageproc::map::blue_channel;
540///
541/// let image = rgb_image!(
542///     [1, 2, 3], [2, 4, 6];
543///     [3, 6, 9], [4, 8, 12]);
544///
545/// let expected = gray_image!(
546///     3, 6;
547///     9, 12);
548///
549/// let actual = blue_channel(&image);
550/// assert_pixels_eq!(actual, expected);
551/// # }
552/// ```
553pub fn blue_channel<I, C>(image: &I) -> Image<Luma<C>>
554where
555    I: GenericImage<Pixel = Rgb<C>>,
556    Rgb<C>: Pixel<Subpixel = C>,
557    C: Primitive,
558{
559    map_colors(image, |p| Luma([p[2]]))
560}
561
562/// Creates an RGB image by embedding a grayscale image in its blue channel.
563///
564/// # Examples
565/// ```
566/// # extern crate image;
567/// # #[macro_use]
568/// # extern crate imageproc;
569/// # fn main() {
570/// use image::Luma;
571/// use imageproc::map::as_blue_channel;
572///
573/// let image = gray_image!(
574///     1, 2;
575///     3, 4);
576///
577/// let expected = rgb_image!(
578///     [0, 0, 1], [0, 0, 2];
579///     [0, 0, 3], [0, 0, 4]);
580///
581/// let actual = as_blue_channel(&image);
582/// assert_pixels_eq!(actual, expected);
583/// # }
584/// ```
585pub fn as_blue_channel<I, C>(image: &I) -> Image<Rgb<C>>
586where
587    I: GenericImage<Pixel = Luma<C>>,
588    Rgb<C>: Pixel<Subpixel = C>,
589    C: Primitive,
590{
591    map_colors(image, |p| {
592        let mut cs = [C::zero(); 3];
593        cs[2] = p[0];
594        Rgb(cs)
595    })
596}