1use crate::core::traits::*;
2use crate::core::*;
3use ndarray::{prelude::*, s, Data, Zip};
4use num_traits::cast::{FromPrimitive, NumCast};
5use num_traits::{Num, NumAssignOps};
6use std::convert::From;
7use std::fmt::Display;
8
9#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
11pub struct Gray;
12#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
14pub struct RGB;
15#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
18pub struct RGBA;
19#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
21pub struct HSV;
22#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
24pub struct HSI;
25#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
27pub struct HSL;
28#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
31pub struct YCrCb;
32#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
34pub struct CIEXYZ;
35#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
40pub struct CIELAB;
41#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
43pub struct CIELUV;
44#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
46pub struct Generic1;
47#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
49pub struct Generic2;
50#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
52pub struct Generic3;
53#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
55pub struct Generic4;
56#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
58pub struct Generic5;
59
60pub trait ColourModel {
63 fn channels() -> usize {
65 3
66 }
67}
68
69impl RGB {
70 pub fn remove_gamma(v: f64) -> f64 {
72 if v < 0.04045 {
73 v / 12.92
74 } else {
75 ((v + 0.055) / 1.055).powf(2.4)
76 }
77 }
78
79 pub fn apply_gamma(v: f64) -> f64 {
81 if v < 0.0031308 {
82 v * 12.92
83 } else {
84 1.055 * v.powf(1.0 / 2.4) - 0.055
85 }
86 }
87}
88
89fn rescale_pixel<T>(x: f64) -> T
90where
91 T: FromPrimitive + Num + NumCast + PixelBound + Display,
92{
93 let tmax = T::max_pixel().to_f64().unwrap_or(0.0f64);
94 let tmin = T::min_pixel().to_f64().unwrap_or(0.0f64);
95
96 let x = x * (tmax - tmin) + tmin;
97
98 T::from_f64(x).unwrap_or_else(T::zero)
99}
100
101pub fn rgb_to_hsv<T>(r: T, g: T, b: T) -> (T, T, T)
103where
104 T: Copy
105 + Clone
106 + FromPrimitive
107 + Num
108 + NumAssignOps
109 + NumCast
110 + PartialOrd
111 + Display
112 + PixelBound,
113{
114 let r_norm = normalise_pixel_value(r);
115 let g_norm = normalise_pixel_value(g);
116 let b_norm = normalise_pixel_value(b);
117 let cmax = r_norm.max(g_norm.max(b_norm));
118 let cmin = r_norm.min(g_norm.min(b_norm));
119 let delta = cmax - cmin;
120
121 let sat = if cmax > 0.0f64 { delta / cmax } else { 0.0f64 };
122
123 let hue = if delta < std::f64::EPSILON {
124 0.0 } else if cmax <= r_norm {
126 60.0 * (((g_norm - b_norm) / delta) % 6.0)
127 } else if cmax <= g_norm {
128 60.0 * ((b_norm - r_norm) / delta + 2.0)
129 } else {
130 60.0 * ((r_norm - g_norm) / delta + 4.0)
131 };
132 let hue = hue / 360.0f64;
133
134 let hue = rescale_pixel(hue);
135 let sat = rescale_pixel(sat);
136 let val = rescale_pixel(cmax);
137
138 (hue, sat, val)
139}
140
141pub fn hsv_to_rgb<T>(h: T, s: T, v: T) -> (T, T, T)
143where
144 T: Copy
145 + Clone
146 + FromPrimitive
147 + Num
148 + NumAssignOps
149 + NumCast
150 + PartialOrd
151 + Display
152 + PixelBound,
153{
154 let h_deg = normalise_pixel_value(h) * 360.0f64;
155 let s_norm = normalise_pixel_value(s);
156 let v_norm = normalise_pixel_value(v);
157
158 let c = v_norm * s_norm;
159 let x = c * (1.0f64 - ((h_deg / 60.0f64) % 2.0f64 - 1.0f64).abs());
160 let m = v_norm - c;
161
162 let rgb = if (0.0f64..60.0f64).contains(&h_deg) {
163 (c, x, 0.0f64)
164 } else if (60.0f64..120.0f64).contains(&h_deg) {
165 (x, c, 0.0f64)
166 } else if (120.0f64..180.0f64).contains(&h_deg) {
167 (0.0f64, c, x)
168 } else if (180.0f64..240.0f64).contains(&h_deg) {
169 (0.0f64, x, c)
170 } else if (240.0f64..300.0f64).contains(&h_deg) {
171 (x, 0.0f64, c)
172 } else if (300.0f64..360.0f64).contains(&h_deg) {
173 (c, 0.0f64, x)
174 } else {
175 (0.0f64, 0.0f64, 0.0f64)
176 };
177
178 let red = rescale_pixel(rgb.0 + m);
179 let green = rescale_pixel(rgb.1 + m);
180 let blue = rescale_pixel(rgb.2 + m);
181
182 (red, green, blue)
183}
184
185impl<U, T> From<ImageBase<U, RGB>> for Image<T, HSV>
186where
187 U: Data<Elem = T>,
188 T: Copy
189 + Clone
190 + FromPrimitive
191 + Num
192 + NumAssignOps
193 + NumCast
194 + PartialOrd
195 + Display
196 + PixelBound,
197{
198 fn from(image: ImageBase<U, RGB>) -> Self {
199 let mut res = Array3::<_>::zeros((image.rows(), image.cols(), HSV::channels()));
200 let window = image.data.windows((1, 1, image.channels()));
201
202 Zip::indexed(window).for_each(|(i, j, _), pix| {
203 let red = pix[[0, 0, 0]];
204 let green = pix[[0, 0, 1]];
205 let blue = pix[[0, 0, 2]];
206
207 let (hue, sat, val) = rgb_to_hsv(red, green, blue);
208 res.slice_mut(s![i, j, ..]).assign(&arr1(&[hue, sat, val]));
209 });
210 Self::from_data(res)
211 }
212}
213
214impl<T, U> From<ImageBase<U, HSV>> for Image<T, RGB>
215where
216 U: Data<Elem = T>,
217 T: Copy
218 + Clone
219 + FromPrimitive
220 + Num
221 + NumAssignOps
222 + NumCast
223 + PartialOrd
224 + Display
225 + PixelBound,
226{
227 fn from(image: ImageBase<U, HSV>) -> Self {
228 let mut res = Array3::<T>::zeros((image.rows(), image.cols(), RGB::channels()));
229 let window = image.data.windows((1, 1, image.channels()));
230
231 Zip::indexed(window).for_each(|(i, j, _), pix| {
232 let h = pix[[0, 0, 0]];
233 let s = pix[[0, 0, 1]];
234 let v = pix[[0, 0, 2]];
235
236 let (r, g, b) = hsv_to_rgb(h, s, v);
237 res.slice_mut(s![i, j, ..]).assign(&arr1(&[r, g, b]));
238 });
239 Self::from_data(res)
240 }
241}
242
243impl<T, U> From<ImageBase<U, RGB>> for Image<T, Gray>
244where
245 U: Data<Elem = T>,
246 T: Copy
247 + Clone
248 + FromPrimitive
249 + Num
250 + NumAssignOps
251 + NumCast
252 + PartialOrd
253 + Display
254 + PixelBound,
255{
256 fn from(image: ImageBase<U, RGB>) -> Self {
257 let mut res = Array3::<T>::zeros((image.rows(), image.cols(), Gray::channels()));
258 let window = image.data.windows((1, 1, image.channels()));
259
260 Zip::indexed(window).for_each(|(i, j, _), pix| {
261 let r = normalise_pixel_value(pix[[0, 0, 0]]);
262 let g = normalise_pixel_value(pix[[0, 0, 1]]);
263 let b = normalise_pixel_value(pix[[0, 0, 2]]);
264
265 let gray = (0.3 * r) + (0.59 * g) + (0.11 * b);
266 let gray = rescale_pixel(gray);
267
268 res.slice_mut(s![i, j, ..]).assign(&arr1(&[gray]));
269 });
270 Self::from_data(res)
271 }
272}
273
274impl<T, U> From<ImageBase<U, Gray>> for Image<T, RGB>
275where
276 U: Data<Elem = T>,
277 T: Copy
278 + Clone
279 + FromPrimitive
280 + Num
281 + NumAssignOps
282 + NumCast
283 + PartialOrd
284 + Display
285 + PixelBound,
286{
287 fn from(image: ImageBase<U, Gray>) -> Self {
288 let mut res = Array3::<T>::zeros((image.rows(), image.cols(), RGB::channels()));
289 let window = image.data.windows((1, 1, image.channels()));
290
291 Zip::indexed(window).for_each(|(i, j, _), pix| {
292 let gray = pix[[0, 0, 0]];
293
294 res.slice_mut(s![i, j, ..])
295 .assign(&arr1(&[gray, gray, gray]));
296 });
297 Self::from_data(res)
298 }
299}
300
301impl<T, U> From<ImageBase<U, RGB>> for Image<T, CIEXYZ>
302where
303 U: Data<Elem = T>,
304 T: Copy
305 + Clone
306 + FromPrimitive
307 + Num
308 + NumAssignOps
309 + NumCast
310 + PartialOrd
311 + Display
312 + PixelBound,
313{
314 fn from(image: ImageBase<U, RGB>) -> Self {
315 let mut res = Array3::<T>::zeros((image.rows(), image.cols(), CIEXYZ::channels()));
316 let window = image.data.windows((1, 1, image.channels()));
317
318 let m = arr2(&[
319 [0.4360747, 0.3850649, 0.1430804],
320 [0.2225045, 0.7168786, 0.0606169],
321 [0.0139322, 0.0971045, 0.7141733],
322 ]);
323
324 Zip::indexed(window).for_each(|(i, j, _), pix| {
325 let pixel = pix
326 .index_axis(Axis(0), 0)
327 .index_axis(Axis(0), 0)
328 .mapv(normalise_pixel_value)
329 .mapv(RGB::remove_gamma);
330
331 let pixel = m.dot(&pixel);
332 let pixel = pixel.mapv(rescale_pixel);
333
334 res.slice_mut(s![i, j, ..]).assign(&pixel);
335 });
336 Self::from_data(res)
337 }
338}
339
340impl<T, U> From<ImageBase<U, CIEXYZ>> for Image<T, RGB>
341where
342 U: Data<Elem = T>,
343 T: Copy
344 + Clone
345 + FromPrimitive
346 + Num
347 + NumAssignOps
348 + NumCast
349 + PartialOrd
350 + Display
351 + PixelBound,
352{
353 fn from(image: ImageBase<U, CIEXYZ>) -> Self {
354 let mut res = Array3::<T>::zeros((image.rows(), image.cols(), RGB::channels()));
355 let window = image.data.windows((1, 1, image.channels()));
356
357 let m = arr2(&[
358 [3.1338561, -1.6168667, -0.4906146],
359 [-0.9787684, 1.9161415, 0.0334540],
360 [0.0719453, -0.2289914, 1.4052427],
361 ]);
362
363 Zip::indexed(window).for_each(|(i, j, _), pix| {
364 let pixel = pix
365 .index_axis(Axis(0), 0)
366 .index_axis(Axis(0), 0)
367 .mapv(normalise_pixel_value);
368
369 let pixel = m.dot(&pixel);
370
371 let pixel = pixel.mapv(RGB::apply_gamma).mapv(rescale_pixel);
372
373 res.slice_mut(s![i, j, ..]).assign(&pixel);
374 });
375 Self::from_data(res)
376 }
377}
378
379impl<T> From<ImageBase<T, Generic3>> for ImageBase<T, RGB>
380where
381 T: Data,
382{
383 fn from(image: ImageBase<T, Generic3>) -> Self {
384 image.into_type_raw()
385 }
386}
387
388impl<T> From<ImageBase<T, Generic3>> for ImageBase<T, HSV>
389where
390 T: Data,
391{
392 fn from(image: ImageBase<T, Generic3>) -> Self {
393 Self::from_data(image.data)
394 }
395}
396
397impl<T> From<ImageBase<T, Generic3>> for ImageBase<T, HSI>
398where
399 T: Data,
400{
401 fn from(image: ImageBase<T, Generic3>) -> Self {
402 Self::from_data(image.data)
403 }
404}
405
406impl<T> From<ImageBase<T, Generic3>> for ImageBase<T, HSL>
407where
408 T: Data,
409{
410 fn from(image: ImageBase<T, Generic3>) -> Self {
411 Self::from_data(image.data)
412 }
413}
414
415impl<T> From<ImageBase<T, Generic3>> for ImageBase<T, YCrCb>
416where
417 T: Data,
418{
419 fn from(image: ImageBase<T, Generic3>) -> Self {
420 Self::from_data(image.data)
421 }
422}
423
424impl<T> From<ImageBase<T, Generic3>> for ImageBase<T, CIEXYZ>
425where
426 T: Data,
427{
428 fn from(image: ImageBase<T, Generic3>) -> Self {
429 Self::from_data(image.data)
430 }
431}
432
433impl<T> From<ImageBase<T, Generic3>> for ImageBase<T, CIELAB>
434where
435 T: Data,
436{
437 fn from(image: ImageBase<T, Generic3>) -> Self {
438 Self::from_data(image.data)
439 }
440}
441
442impl<T> From<ImageBase<T, Generic3>> for ImageBase<T, CIELUV>
443where
444 T: Data,
445{
446 fn from(image: ImageBase<T, Generic3>) -> Self {
447 Self::from_data(image.data)
448 }
449}
450
451impl<T> From<ImageBase<T, Generic1>> for ImageBase<T, Gray>
452where
453 T: Data,
454{
455 fn from(image: ImageBase<T, Generic1>) -> Self {
456 Self::from_data(image.data)
457 }
458}
459
460impl<T> From<ImageBase<T, Generic4>> for ImageBase<T, RGBA>
461where
462 T: Data,
463{
464 fn from(image: ImageBase<T, Generic4>) -> Self {
465 Self::from_data(image.data)
466 }
467}
468
469impl<T> From<ImageBase<T, RGB>> for ImageBase<T, Generic3>
470where
471 T: Data,
472{
473 fn from(image: ImageBase<T, RGB>) -> Self {
474 Self::from_data(image.data)
475 }
476}
477
478impl<T> From<ImageBase<T, HSV>> for ImageBase<T, Generic3>
479where
480 T: Data,
481{
482 fn from(image: ImageBase<T, HSV>) -> Self {
483 Self::from_data(image.data)
484 }
485}
486
487impl<T> From<ImageBase<T, HSI>> for ImageBase<T, Generic3>
488where
489 T: Data,
490{
491 fn from(image: ImageBase<T, HSI>) -> Self {
492 Self::from_data(image.data)
493 }
494}
495
496impl<T> From<ImageBase<T, HSL>> for ImageBase<T, Generic3>
497where
498 T: Data,
499{
500 fn from(image: ImageBase<T, HSL>) -> Self {
501 Self::from_data(image.data)
502 }
503}
504
505impl<T> From<ImageBase<T, YCrCb>> for ImageBase<T, Generic3>
506where
507 T: Data,
508{
509 fn from(image: ImageBase<T, YCrCb>) -> Self {
510 Self::from_data(image.data)
511 }
512}
513
514impl<T> From<ImageBase<T, CIEXYZ>> for ImageBase<T, Generic3>
515where
516 T: Data,
517{
518 fn from(image: ImageBase<T, CIEXYZ>) -> Self {
519 Self::from_data(image.data)
520 }
521}
522
523impl<T> From<ImageBase<T, CIELAB>> for ImageBase<T, Generic3>
524where
525 T: Data,
526{
527 fn from(image: ImageBase<T, CIELAB>) -> Self {
528 Self::from_data(image.data)
529 }
530}
531
532impl<T> From<ImageBase<T, CIELUV>> for ImageBase<T, Generic3>
533where
534 T: Data,
535{
536 fn from(image: ImageBase<T, CIELUV>) -> Self {
537 Self::from_data(image.data)
538 }
539}
540
541impl<T> From<ImageBase<T, RGBA>> for ImageBase<T, Generic4>
542where
543 T: Data,
544{
545 fn from(image: ImageBase<T, RGBA>) -> Self {
546 Self::from_data(image.data)
547 }
548}
549
550impl<T> From<ImageBase<T, Gray>> for ImageBase<T, Generic1>
551where
552 T: Data,
553{
554 fn from(image: ImageBase<T, Gray>) -> Self {
555 Self::from_data(image.data)
556 }
557}
558
559impl<T, U> From<ImageBase<U, Generic5>> for Image<T, Generic4>
560where
561 U: Data<Elem = T>,
562 T: Copy,
563{
564 fn from(image: ImageBase<U, Generic5>) -> Self {
565 let shape = (image.rows(), image.cols(), Generic4::channels());
566 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
567 Self::from_data(data)
568 }
569}
570
571impl<T, U> From<ImageBase<U, Generic5>> for Image<T, Generic3>
572where
573 U: Data<Elem = T>,
574 T: Copy,
575{
576 fn from(image: ImageBase<U, Generic5>) -> Self {
577 let shape = (image.rows(), image.cols(), Generic3::channels());
578 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
579 Self::from_data(data)
580 }
581}
582
583impl<T, U> From<ImageBase<U, Generic5>> for Image<T, Generic2>
584where
585 U: Data<Elem = T>,
586 T: Copy,
587{
588 fn from(image: ImageBase<U, Generic5>) -> Self {
589 let shape = (image.rows(), image.cols(), Generic2::channels());
590 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
591 Self::from_data(data)
592 }
593}
594
595impl<T, U> From<ImageBase<U, Generic5>> for Image<T, Generic1>
596where
597 U: Data<Elem = T>,
598 T: Copy,
599{
600 fn from(image: ImageBase<U, Generic5>) -> Self {
601 let shape = (image.rows(), image.cols(), Generic1::channels());
602 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
603 Self::from_data(data)
604 }
605}
606
607impl<T, U> From<ImageBase<U, Generic4>> for Image<T, Generic3>
608where
609 U: Data<Elem = T>,
610 T: Copy,
611{
612 fn from(image: ImageBase<U, Generic4>) -> Self {
613 let shape = (image.rows(), image.cols(), Generic3::channels());
614 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
615 Self::from_data(data)
616 }
617}
618
619impl<T, U> From<ImageBase<U, Generic4>> for Image<T, Generic2>
620where
621 U: Data<Elem = T>,
622 T: Copy,
623{
624 fn from(image: ImageBase<U, Generic4>) -> Self {
625 let shape = (image.rows(), image.cols(), Generic2::channels());
626 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
627 Self::from_data(data)
628 }
629}
630
631impl<T, U> From<ImageBase<U, Generic4>> for Image<T, Generic1>
632where
633 U: Data<Elem = T>,
634 T: Copy,
635{
636 fn from(image: ImageBase<U, Generic4>) -> Self {
637 let shape = (image.rows(), image.cols(), Generic1::channels());
638 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
639 Self::from_data(data)
640 }
641}
642
643impl<T, U> From<ImageBase<U, Generic3>> for Image<T, Generic2>
644where
645 U: Data<Elem = T>,
646 T: Copy,
647{
648 fn from(image: ImageBase<U, Generic3>) -> Self {
649 let shape = (image.rows(), image.cols(), Generic2::channels());
650 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
651 Self::from_data(data)
652 }
653}
654
655impl<T, U> From<ImageBase<U, Generic3>> for Image<T, Generic1>
656where
657 U: Data<Elem = T>,
658 T: Copy,
659{
660 fn from(image: ImageBase<U, Generic3>) -> Self {
661 let shape = (image.rows(), image.cols(), Generic1::channels());
662 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
663 Self::from_data(data)
664 }
665}
666
667impl<T, U> From<ImageBase<U, Generic2>> for Image<T, Generic1>
668where
669 U: Data<Elem = T>,
670 T: Copy,
671{
672 fn from(image: ImageBase<U, Generic2>) -> Self {
673 let shape = (image.rows(), image.cols(), Generic1::channels());
674 let data = Array3::from_shape_fn(shape, |(i, j, k)| image.data[[i, j, k]]);
675 Self::from_data(data)
676 }
677}
678
679impl<T, U> From<ImageBase<U, Generic1>> for Image<T, Generic5>
680where
681 U: Data<Elem = T>,
682 T: Copy + Num,
683{
684 fn from(image: ImageBase<U, Generic1>) -> Self {
685 let shape = (image.rows(), image.cols(), Generic5::channels());
686 let mut data = Array3::zeros(shape);
687 data.slice_mut(s![.., .., 0..Generic1::channels()])
688 .assign(&image.data);
689 Self::from_data(data)
690 }
691}
692
693impl<T, U> From<ImageBase<U, Generic2>> for Image<T, Generic5>
694where
695 U: Data<Elem = T>,
696 T: Copy + Num,
697{
698 fn from(image: ImageBase<U, Generic2>) -> Self {
699 let shape = (image.rows(), image.cols(), Generic5::channels());
700 let mut data = Array3::zeros(shape);
701 data.slice_mut(s![.., .., 0..Generic2::channels()])
702 .assign(&image.data);
703 Self::from_data(data)
704 }
705}
706
707impl<T, U> From<ImageBase<U, Generic3>> for Image<T, Generic5>
708where
709 U: Data<Elem = T>,
710 T: Copy + Num,
711{
712 fn from(image: ImageBase<U, Generic3>) -> Self {
713 let shape = (image.rows(), image.cols(), Generic5::channels());
714 let mut data = Array3::zeros(shape);
715 data.slice_mut(s![.., .., 0..Generic3::channels()])
716 .assign(&image.data);
717 Self::from_data(data)
718 }
719}
720
721impl<T, U> From<ImageBase<U, Generic4>> for Image<T, Generic5>
722where
723 U: Data<Elem = T>,
724 T: Copy + Num,
725{
726 fn from(image: ImageBase<U, Generic4>) -> Self {
727 let shape = (image.rows(), image.cols(), Generic5::channels());
728 let mut data = Array3::zeros(shape);
729 data.slice_mut(s![.., .., 0..Generic4::channels()])
730 .assign(&image.data);
731 Self::from_data(data)
732 }
733}
734
735impl<T, U> From<ImageBase<U, Generic1>> for Image<T, Generic4>
736where
737 U: Data<Elem = T>,
738 T: Copy + Num,
739{
740 fn from(image: ImageBase<U, Generic1>) -> Self {
741 let shape = (image.rows(), image.cols(), Generic4::channels());
742 let mut data = Array3::zeros(shape);
743 data.slice_mut(s![.., .., 0..Generic1::channels()])
744 .assign(&image.data);
745 Self::from_data(data)
746 }
747}
748
749impl<T, U> From<ImageBase<U, Generic2>> for Image<T, Generic4>
750where
751 U: Data<Elem = T>,
752 T: Copy + Num,
753{
754 fn from(image: ImageBase<U, Generic2>) -> Self {
755 let shape = (image.rows(), image.cols(), Generic4::channels());
756 let mut data = Array3::zeros(shape);
757 data.slice_mut(s![.., .., 0..Generic2::channels()])
758 .assign(&image.data);
759 Self::from_data(data)
760 }
761}
762
763impl<T, U> From<ImageBase<U, Generic3>> for Image<T, Generic4>
764where
765 U: Data<Elem = T>,
766 T: Copy + Num,
767{
768 fn from(image: ImageBase<U, Generic3>) -> Self {
769 let shape = (image.rows(), image.cols(), Generic4::channels());
770 let mut data = Array3::zeros(shape);
771 data.slice_mut(s![.., .., 0..Generic3::channels()])
772 .assign(&image.data);
773 Self::from_data(data)
774 }
775}
776
777impl<T, U> From<ImageBase<U, Generic1>> for Image<T, Generic3>
778where
779 U: Data<Elem = T>,
780 T: Copy + Num,
781{
782 fn from(image: ImageBase<U, Generic1>) -> Self {
783 let shape = (image.rows(), image.cols(), Generic3::channels());
784 let mut data = Array3::zeros(shape);
785 data.slice_mut(s![.., .., 0..Generic1::channels()])
786 .assign(&image.data);
787 Self::from_data(data)
788 }
789}
790
791impl<T, U> From<ImageBase<U, Generic2>> for Image<T, Generic3>
792where
793 U: Data<Elem = T>,
794 T: Copy + Num,
795{
796 fn from(image: ImageBase<U, Generic2>) -> Self {
797 let shape = (image.rows(), image.cols(), Generic3::channels());
798 let mut data = Array3::zeros(shape);
799 data.slice_mut(s![.., .., 0..Generic2::channels()])
800 .assign(&image.data);
801 Self::from_data(data)
802 }
803}
804
805impl<T, U> From<ImageBase<U, Generic1>> for Image<T, Generic2>
806where
807 U: Data<Elem = T>,
808 T: Copy + Num,
809{
810 fn from(image: ImageBase<U, Generic1>) -> Self {
811 let shape = (image.rows(), image.cols(), Generic2::channels());
812 let mut data = Array3::zeros(shape);
813 data.slice_mut(s![.., .., 0..Generic1::channels()])
814 .assign(&image.data);
815 Self::from_data(data)
816 }
817}
818
819impl ColourModel for RGB {}
820impl ColourModel for HSV {}
821impl ColourModel for HSI {}
822impl ColourModel for HSL {}
823impl ColourModel for YCrCb {}
824impl ColourModel for CIEXYZ {}
825impl ColourModel for CIELAB {}
826impl ColourModel for CIELUV {}
827
828impl ColourModel for Gray {
829 fn channels() -> usize {
830 1
831 }
832}
833
834impl ColourModel for Generic1 {
835 fn channels() -> usize {
836 1
837 }
838}
839impl ColourModel for Generic2 {
840 fn channels() -> usize {
841 2
842 }
843}
844impl ColourModel for Generic3 {
845 fn channels() -> usize {
846 3
847 }
848}
849impl ColourModel for Generic4 {
850 fn channels() -> usize {
851 4
852 }
853}
854impl ColourModel for Generic5 {
855 fn channels() -> usize {
856 5
857 }
858}
859
860impl ColourModel for RGBA {
861 fn channels() -> usize {
862 4
863 }
864}
865
866#[cfg(test)]
867mod tests {
868 use super::*;
869 use ndarray::s;
870 use ndarray_rand::RandomExt;
871 use ndarray_stats::QuantileExt;
872 use rand::distributions::Uniform;
873
874 #[test]
875 fn basic_rgb_hsv_check() {
876 let mut i = Image::<u8, RGB>::new(1, 2);
877 i.pixel_mut(0, 0).assign(&arr1(&[0, 0, 0]));
878 i.pixel_mut(0, 1).assign(&arr1(&[255, 255, 255]));
879
880 let hsv = Image::<u8, HSV>::from(i.clone());
881
882 assert_eq!(hsv.pixel(0, 0)[[2]], 0);
883 assert_eq!(hsv.pixel(0, 1)[[2]], 255);
884
885 let rgb = Image::<u8, RGB>::from(hsv);
886 assert_eq!(i, rgb);
887 }
888
889 #[test]
890 fn gray_to_rgb_test() {
891 let mut image = Image::<u8, Gray>::new(480, 640);
892 let new_data = Array3::<u8>::random(image.data.dim(), Uniform::new(0, 255));
893 image.data = new_data;
894
895 let rgb = Image::<u8, RGB>::from(image.clone());
896 let slice_2d = image.data.slice(s![.., .., 0]);
897
898 assert_eq!(slice_2d, rgb.data.slice(s![.., .., 0]));
899 assert_eq!(slice_2d, rgb.data.slice(s![.., .., 1]));
900 assert_eq!(slice_2d, rgb.data.slice(s![.., .., 2]));
901 }
902
903 #[test]
904 fn rgb_to_gray_basic() {
905 let data = vec![255, 255, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255];
907 let image = Image::<u8, RGB>::from_shape_data(1, 5, data);
908
909 let gray = Image::<u8, Gray>::from(image);
910
911 let expected = vec![255, 0, 77, 150, 28];
913
914 for (act, exp) in gray.data.iter().zip(expected.iter()) {
915 let delta = (*act as i16 - *exp as i16).abs();
916 assert!(delta < 2);
917 }
918 }
919
920 #[test]
921 fn basic_xyz_rgb_checks() {
922 let mut image = Image::<f32, RGB>::new(100, 100);
923 let new_data = Array3::<f32>::random(image.data.dim(), Uniform::new(0.0, 1.0));
924 image.data = new_data;
925
926 let xyz = Image::<f32, CIEXYZ>::from(image.clone());
927
928 let rgb_restored = Image::<f32, RGB>::from(xyz);
929
930 let mut delta = image.data - rgb_restored.data;
931 delta.mapv_inplace(|x| x.abs());
932
933 assert!(*delta.max().unwrap() * 100.0 < 0.5);
935 }
936
937 #[test]
938 fn generic3_checks() {
939 let mut image = Image::<f32, RGB>::new(100, 100);
940 let new_data = Array3::<f32>::random(image.data.dim(), Uniform::new(0.0, 1.0));
941 image.data = new_data;
942 let gen = Image::<_, Generic3>::from(image.clone());
943 assert_eq!(gen.data, image.data);
946
947 let hsv = Image::<_, HSV>::from(gen);
948 assert_eq!(image.data, hsv.data);
949
950 let gen = Image::<_, Generic3>::from(hsv);
951 assert_eq!(image.data, gen.data);
952
953 let hsi = Image::<_, HSI>::from(gen);
954 assert_eq!(image.data, hsi.data);
955
956 let gen = Image::<_, Generic3>::from(hsi);
957 assert_eq!(image.data, gen.data);
958
959 let hsl = Image::<_, HSL>::from(gen);
960 assert_eq!(image.data, hsl.data);
961
962 let gen = Image::<_, Generic3>::from(hsl);
963 assert_eq!(image.data, gen.data);
964
965 let ycrcb = Image::<_, YCrCb>::from(gen);
966 assert_eq!(image.data, ycrcb.data);
967
968 let gen = Image::<_, Generic3>::from(ycrcb);
969 assert_eq!(image.data, gen.data);
970
971 let ciexyz = Image::<_, CIEXYZ>::from(gen);
972 assert_eq!(image.data, ciexyz.data);
973
974 let gen = Image::<_, Generic3>::from(ciexyz);
975 assert_eq!(image.data, gen.data);
976
977 let cieluv = Image::<_, CIELUV>::from(gen);
978 assert_eq!(image.data, cieluv.data);
979
980 let gen = Image::<_, Generic3>::from(cieluv);
981 assert_eq!(image.data, gen.data);
982
983 let cielab = Image::<_, CIELAB>::from(gen);
984 assert_eq!(image.data, cielab.data);
985 }
986
987 #[test]
988 fn generic_model_expand() {
989 let mut image = Image::<f32, Generic1>::new(100, 100);
990 let new_data = Array3::<f32>::random(image.data.dim(), Uniform::new(0.0, 1.0));
991 image.data = new_data;
992
993 let large = Image::<_, Generic5>::from(image.clone());
994
995 assert_eq!(large.channels(), Generic5::channels());
996
997 assert_eq!(
998 large.data.slice(s![.., .., 0]),
999 image.data.slice(s![.., .., 0])
1000 );
1001 let zeros = Array2::<f32>::zeros((100, 100));
1002 for i in 1..Generic5::channels() {
1003 assert_eq!(large.data.slice(s![.., .., i]), zeros);
1004 }
1005 }
1006}