1extern crate smlm_sig_proc as sig_proc;
2extern crate smlm_tiff as tiff_wrap;
3
4#[cfg(feature = "plot")]
5extern crate gnuplot;
6
7pub use self::stats::Stats;
8pub use self::images::{OwnedImage, BorrowedImage};
9
10use tiff_wrap::{Tiff};
11
12pub use sig_proc::fft::c64;
13use sig_proc::fft::{fft_2d, fft_shift};
14
15#[cfg(feature = "plot")]
16use gnuplot::{Figure, AxesCommon, DataType};
17
18use std::ops::{AddAssign, Mul, Div};
19use std::path::Path;
20
21pub mod circles;
23pub mod filter;
24pub mod images;
25pub mod stats;
26pub mod utils;
27
28pub trait Image
29{
30 type Data;
31 fn n_rows(&self) -> usize;
32 fn n_cols(&self) -> usize;
33 fn data(&self) -> &[Self::Data];
34
35 fn width(&self) -> usize
36 {
37 self.n_cols()
38 }
39
40 fn height(&self) -> usize
41 {
42 self.n_rows()
43 }
44
45 fn shape(&self) -> (usize, usize)
47 {
48 (self.n_rows(), self.n_cols())
49 }
50
51 fn size(&self) -> usize
53 {
54 self.n_rows() * self.n_cols()
55 }
56
57 fn get_at(&self, row: usize, col: usize) -> &Self::Data
60 {
61 let index = self.get_index(row, col);
62 self.get(index)
63 }
64
65 fn get(&self, idx: usize) -> &Self::Data
68 {
69 &self.data()[idx]
70 }
71
72 fn get_data(&self, indicies: &[usize]) -> Vec<&Self::Data>
75 {
76 indicies.iter().map(|x| self.get(*x)).collect()
77 }
78
79 fn get_index(&self, row: usize, col: usize) -> usize
81 {
82 utils::get_index(row, col, self.n_cols())
83 }
84
85 fn get_coords(&self, index: usize) -> (usize, usize)
87 {
88 utils::get_coords(index, self.n_cols())
89 }
90
91
92 fn is_square(&self) -> bool
94 {
95 self.n_rows() == self.n_cols()
96 }
97
98 fn centre_index(&self) -> usize
100 {
101 let (row, col) = self.centre_position();
102 utils::get_index(row, col, self.n_cols())
103 }
104
105 fn centre_row(&self) -> usize
107 {
108 self.n_rows() / 2
109 }
110
111 fn centre_col(&self) -> usize
113 {
114 self.n_cols() / 2
115 }
116
117 fn centre_position(&self) -> (usize, usize)
119 {
120 (self.centre_row(), self.centre_col())
121 }
122
123 fn square_centre(&self) -> bool
126 {
127 self.n_rows() % 2 == 0 && self.n_rows() == self.n_cols()
128 }
129
130 fn perimimeter_indicies_using<P: circles::Perimeter>(&self, radius: usize) -> Vec<usize>
132 where Self: Sized
133 {
134 P::get(self, radius as f64)
135 }
136
137 fn perimimeter_indicies_with(&self, method: circles::Method, radius: usize) -> Vec<usize>
139 where Self: Sized
140 {
141 method.get_perimeter(self, radius as f64)
142 }
143
144 fn perimimeter_indicies(&self, radius: usize) -> Vec<usize>
147 where Self: Sized
148 {
149 circles::angle_carve(self, radius as f64)
150 }
151
152 fn perimimeter_pixels(&self, radius: usize) -> Vec<&Self::Data>
154 where Self: Sized
155 {
156 let data = self.data();
157 self.perimimeter_indicies(radius)
158 .into_iter()
159 .map(|i| &data[i])
160 .collect()
161 }
162
163 fn apply_index_mask(&self, indicies: &[usize]) -> Vec<Self::Data>
164 where Self::Data: Copy
165 {
166 indicies.iter().map(|i| self.data()[*i]).collect()
167 }
168
169 fn apply_mask<I: Image<Data=bool>>(&self, mask_image: I) -> Vec<Self::Data>
170 where Self::Data: Copy
171 {
172 let mut iter = mask_image.data().iter();
173 self.data().iter().filter(|_| *iter.next().unwrap()).map(|v| *v).collect()
174 }
175
176 fn mul<I: Image<Data=Self::Data>>(&self, rhs: I) -> OwnedImage<Self::Data>
177 where Self::Data : Mul<Self::Data, Output = Self::Data> + Copy,
178 {
179 let data = self.data().iter().zip(rhs.data().iter()).map(|(a, b)| (*a) * (*b)).collect();
180 OwnedImage::new(self.shape(), data)
181 }
182
183 fn div<I: Image<Data=Self::Data>>(&self, rhs: I) -> OwnedImage<Self::Data>
184 where Self::Data : Div<Self::Data, Output = Self::Data> + Copy,
185 {
186 let data = self.data().iter().zip(rhs.data().iter()).map(|(a, b)| (*a) / (*b)).collect();
187 OwnedImage::new(self.shape(), data)
188 }
189
190 fn map<T, F: FnMut(&Self::Data) -> T>(&self, f: F) -> OwnedImage<T>
191 {
192 let mut image : OwnedImage<_> = self.data().iter().map(f).collect();
193 image.reshape(self.shape());
194 image
195 }
196
197 #[cfg(feature = "plot")]
198 fn plot(&self, title: Option<&str>) -> ()
199 where Self::Data : DataType + Copy
200 {
201 let mut figure = Figure::new();
202 figure.axes2d()
203 .set_title(title.unwrap_or(""), &[])
204 .image(self.data().iter().map(|x| *x), self.n_rows(), self.n_cols(), None, &[]);
205 figure.show_and_keep_running().unwrap();
206 }
207
208 fn write_tiff<P: AsRef<Path>>(&self, path: P) -> Result<(), String>
209 where Self::Data : tiff_wrap::writer::ToColourType, [Self::Data]: tiff_wrap::writer::TiffValue
210 {
211 let (width, height) = self.get_tiff_writer_shape()?;
212 let mut writer = tiff_wrap::writer::StandardTiffWriter::from_disk(path, width, height).map_err(|e| e.to_string())?;
213 writer.write_image_for(self.data()).map_err(|e| e.to_string())
214 }
215
216 fn write_big_tiff<P: AsRef<Path>>(&self, path: P) -> Result<(), String>
217 where Self::Data : tiff_wrap::writer::ToColourType, [Self::Data]: tiff_wrap::writer::TiffValue
218 {
219 let (width, height) = self.get_tiff_writer_shape()?;
220 let mut writer = tiff_wrap::writer::BigTiffWriter::from_disk(path, width, height).map_err(|e| e.to_string())?;
221 writer.write_image_for(self.data()).map_err(|e| e.to_string())
222 }
223
224 fn get_tiff_writer_shape(&self) -> Result<(u32, u32), String>
225 {
226 let (rows, cols) = self.shape();
227 let width = cols.try_into().map_err(|e: std::num::TryFromIntError| e.to_string())?;
228 let height = rows.try_into().map_err(|e: std::num::TryFromIntError| e.to_string())?;
229 Ok((width, height))
230 }
231}
232
233impl<I : Image> Image for &I
234{
235 type Data = I::Data;
236
237 fn n_rows(&self) -> usize
238 {
239 (*self).n_rows()
240 }
241
242 fn n_cols(&self) -> usize
243 {
244 (*self).n_cols()
245 }
246
247 fn data(&self) -> &[I::Data]
248 {
249 (*self).data()
250 }
251}
252
253impl<I : Image> Image for &mut I
254{
255 type Data = I::Data;
256
257 fn n_rows(&self) -> usize
258 {
259 Image::n_rows(*self)
260 }
261
262 fn n_cols(&self) -> usize
263 {
264 Image::n_cols(*self)
265 }
266
267 fn data(&self) -> &[I::Data]
268 {
269 Image::data(*self)
270 }
271}
272
273pub trait ImageMut: Image
274{
275 fn data_mut(&mut self) -> &mut [Self::Data];
276
277 fn get_at_mut(&mut self, row: usize, col: usize) -> &mut Self::Data
280 {
281 let index = self.get_index(row, col);
283 self.get_mut(index)
284 }
285
286 fn get_mut(&mut self, idx: usize) -> &mut Self::Data
289 {
290 &mut self.data_mut()[idx]
291 }
292
293 fn add_to<'a, I: Image<Data=Self::Data> + 'a>(&'a mut self, other: I) -> ()
294 where <Self as Image>::Data: Copy,
295 <Self as Image>::Data: AddAssign
296 {
297 for (value, other_value) in self.data_mut().iter_mut().zip(other.data().iter().copied())
298 {
299 *value += other_value;
300 }
301 }
302}
303
304impl<I: ImageMut> ImageMut for &mut I
305{
306 fn data_mut(&mut self) -> &mut [<Self as Image>::Data]
307 {
308 <I as ImageMut>::data_mut(*self)
309 }
310}
311
312pub trait Crop : Image
313{
314 fn take_rows(&mut self, n_rows: usize) -> Result<(), ()>;
315 fn drop_rows(&mut self, n_rows: usize) -> Result<(), ()>;
316 fn take_cols(&mut self, n: usize) -> Result<(), ()>;
317 fn drop_cols(&mut self, n_cols: usize) -> Result<(), ()>;
318
319 fn central_row_crop(&mut self, n_rows: usize) -> Result<(), ()>
320 {
321 let is_even = n_rows % 2 == 0;
322 let half = n_rows / 2;
323 let n_take = if is_even {half} else{half + 1};
324 self.take_rows(n_take).and_then(|_| self.drop_rows(half))
325 }
326
327 fn central_col_crop(&mut self, n_cols: usize) -> Result<(), ()>
328 {
329 let is_even = n_cols % 2 == 0;
330 let half = n_cols / 2;
331 let n_take = if is_even {half} else{half + 1};
332 self.take_cols(n_take).and_then(|_| self.drop_cols(half))
333 }
334
335 fn central_crop(&mut self, n_rows: usize, n_cols: usize) -> Result<(), ()>
336 {
337 self.central_row_crop(n_rows).and_then(|_| self.central_col_crop(n_cols))
338 }
339}
340
341impl<C : Crop> Crop for &mut C
344{
345 fn take_rows(&mut self, n_rows: usize) -> Result<(), ()>
346 {
347 Crop::take_rows(*self, n_rows)
348 }
349
350 fn drop_rows(&mut self, n: usize) -> Result<(), ()>
351 {
352 Crop::drop_rows(*self, n)
353 }
354
355 fn take_cols(&mut self, n: usize) -> Result<(), ()>
356 {
357 Crop::take_cols(*self, n)
358 }
359
360 fn drop_cols(&mut self, n: usize) -> Result<(), ()>
361 {
362 Crop::drop_cols(*self, n)
363 }
364
365 fn central_row_crop(&mut self, n_rows: usize) -> Result<(), ()>
366 {
367 Crop::central_row_crop(*self, n_rows)
368 }
369
370 fn central_col_crop(&mut self, n_cols: usize) -> Result<(), ()>
371 {
372 Crop::central_col_crop(*self, n_cols)
373 }
374
375 fn central_crop(&mut self, n_rows: usize, n_cols: usize) -> Result<(), ()>
376 {
377 Crop::central_crop(*self, n_rows, n_cols)
378 }
379}
380
381pub trait Pad : Image
382{
383 fn pad_rows_start(&mut self, n_rows: usize) -> Result<(), ()>;
384 fn pad_rows_end(&mut self, n_rows: usize) -> Result<(), ()>;
385 fn pad_cols_start(&mut self, n_cols: usize) -> Result<(), ()>;
386 fn pad_cols_end(&mut self, n_cols: usize) -> Result<(), ()>;
387
388 fn central_row_pad(&mut self, n_rows: usize) -> Result<(), ()>
389 {
390 let is_even = n_rows % 2 == 0;
391 let half = n_rows / 2;
392 let start = if is_even {half} else{half + 1};
393 self.pad_rows_start(start).and_then(|_| self.pad_rows_end(half))
394 }
395
396 fn central_col_pad(&mut self, n_cols: usize) -> Result<(), ()>
397 {
398 let is_even = n_cols % 2 == 0;
399 let half = n_cols / 2;
400 let start = if is_even {half} else{half + 1};
401 self.pad_cols_start(start).and_then(|_| self.pad_cols_end(half))
402 }
403
404 fn central_pad(&mut self, n_rows: usize, n_cols: usize) -> Result<(), ()>
405 {
406 self.central_row_pad(n_rows).and_then(|_| self.central_col_pad(n_cols))
407 }
408
409 fn pad_to(&mut self, rows: usize, cols: usize) -> Result<(), ()>
410 {
411 let n_rows = rows - self.n_rows();
412 let n_cols = cols - self.n_cols();
413 self.central_pad(n_rows, n_cols)
414 }
415}
416
417impl<P : Pad> Pad for &mut P
418{
419 fn pad_rows_start(&mut self, n_rows: usize) -> Result<(), ()>
420 {
421 Pad::pad_rows_start(*self, n_rows)
422 }
423
424 fn pad_rows_end(&mut self, n: usize) -> Result<(), ()>
425 {
426 Pad::pad_rows_end(*self, n)
427 }
428
429 fn pad_cols_start(&mut self, n: usize) -> Result<(), ()>
430 {
431 Pad::pad_cols_start(*self, n)
432 }
433
434 fn pad_cols_end(&mut self, n: usize) -> Result<(), ()>
435 {
436 Pad::pad_cols_end(*self, n)
437 }
438
439 fn central_row_pad(&mut self, n_rows: usize) -> Result<(), ()>
440 {
441 Pad::central_row_pad(*self, n_rows)
442 }
443
444 fn central_col_pad(&mut self, n_cols: usize) -> Result<(), ()>
445 {
446 Pad::central_col_pad(*self, n_cols)
447 }
448
449 fn central_pad(&mut self, n_rows: usize, n_cols: usize) -> Result<(), ()>
450 {
451 Pad::central_pad(*self, n_rows, n_cols)
452 }
453
454 fn pad_to(&mut self, rows: usize, cols: usize) -> Result<(), ()>
455 {
456 Pad::pad_to(*self, rows, cols)
457 }
458}
459
460pub trait Fft
461{
462 type Output;
463 fn fft(&self) -> Self::Output;
464 fn shifted_fft(&self) -> Self::Output;
465}
466
467impl<I> Fft for I
468where I: Image<Data=f64>
469{
470 type Output = OwnedImage<c64>;
471 fn fft(&self) -> Self::Output
472 {
473 let n_rows = self.n_rows();
474 let n_cols = self.n_cols();
475 let output_data = fft_2d(self.data(), n_rows, n_cols); Self::Output::new((n_rows, n_cols), output_data)
477 }
478
479 fn shifted_fft(&self) -> Self::Output
480 {
481 let mut new_data = vec![c64::ZERO; self.size()];
482 fft_shift(self.fft().data(), &mut new_data, self.n_rows(), self.n_cols());
483 OwnedImage::new((self.n_rows(), self.n_cols()), new_data)
484 }
485}
486
487pub fn read_tiff_image_64<P: AsRef<Path>>(tiff_file: P) -> Result<OwnedImage<f64>, String>
488{
489 let mut reader = Tiff::read(tiff_file).map_err(|e| e.to_string())?;
490 let (width, height) = reader.dimensions().map_err(|e| e.to_string())?;
491 let image = reader.current_image().map_err(|e| e.to_string())?;
492 let data = image.to_f64().map_err(|e| e.to_string())?;
493 Ok(OwnedImage::new((height as usize, width as usize), data))
494}
495
496#[cfg(test)]
497mod tests
498{
499 use super::*;
500
501 use crate::images::BorrowedImage;
502
503 fn generate(n_rows: usize, n_cols: usize) -> ((usize, usize),Vec<usize>)
504 {
505 ((n_rows, n_cols), (0..(n_rows * n_cols)).collect())
506 }
507
508 #[test]
509 fn centre_index_test()
510 {
511 test_centre_index(4, 4, 10);
512 test_centre_index(3, 4, 6);
513 test_centre_index(3, 3, 4);
514 test_centre_index(5, 5, 12);
515 }
516
517 fn test_centre_index(n_rows: usize, n_cols: usize, expected: usize) -> ()
518 {
519 let (shape, data) = generate(n_rows, n_cols);
520 let image = BorrowedImage::new(shape, &data);
521 assert_eq!(image.centre_index(), expected);
522 }
523
524 #[test]
525 fn square_centre_test()
526 {
527 test_square_centre(4, 4, true);
528 test_square_centre(5, 5, false);
529 }
530
531 fn test_square_centre(n_rows: usize, n_cols: usize, expected: bool) -> ()
532 {
533 let (shape, data) = generate(n_rows, n_cols);
534 let image = BorrowedImage::new(shape, &data);
535 assert_eq!(image.square_centre(), expected);
536 }
537
538 #[test]
539 fn basic_fft()
540 {
541 let shape = (1, 4);
542 let data = vec![0.0, 1.0, 2.0, 3.0];
543 let image = BorrowedImage::new(shape, &data);
544 let fft_data = image.fft();
545
546 let expected = [ [6.0, 0.0], [-2.0, 2.0], [-2.0, 0.0], [-2.0, -2.0] ].map(|a| c64::new(a[0], a[1]));
547 assert_eq!(fft_data.data(), expected);
548 }
549
550 #[test]
551 fn shifted_fft()
552 {
553 let shape = (1, 4);
554 let data = vec![0.0, 1.0, 2.0, 3.0];
555 let image = BorrowedImage::new(shape, &data);
556 let fft_data = image.shifted_fft();
557
558 let expected = [ [-2.0, 0.0], [-2.0, -2.0], [6.0, 0.0], [-2.0, 2.0]].map(|a| c64::new(a[0], a[1]));
559 assert_eq!(fft_data.data(), expected);
560 }
561
562 #[test]
563 fn multiply()
564 {
565 let shape = (1, 4);
566 let data = vec![0.0, 1.0, 2.0, 3.0];
567 let image_1 = BorrowedImage::new(shape, &data);
568 let image_2 = BorrowedImage::new(shape, &data);
569 let m_image = image_1.mul(image_2);
570 let expected = [ 0.0, 1.0, 4.0, 9.0];
571 assert_eq!(m_image.data(), expected);
572 }
573
574 #[test]
599 fn perimenter_pixels()
600 {
601 let (shape, data) = generate(14, 14);
602 let image = BorrowedImage::new(shape, &data);
603 let expected = [61, 62, 63, 64, 65, 74, 75, 79, 80, 88, 94, 102, 108, 116, 122, 130, 131, 135, 136, 145, 146, 147, 148, 149];
606 let mut result = image.perimimeter_pixels(3);
607 result.sort();
608
609 assert_eq!(result.into_iter().map(|x| *x).collect::<Vec<usize>>().as_slice(), expected);
610 }
611
612 #[test]
613 fn drop_rows_test()
614 {
615 let (shape, data) = generate(5, 5);
616 let mut image = OwnedImage::new(shape, data);
617 assert_eq!(image.drop_rows(2).is_ok(), true);
618 assert_eq!(image.shape(), (3, 5));
619 assert_eq!(image.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
620 }
621
622 #[test]
623 fn drop_cols_test()
624 {
625 let (shape, data) = generate(5, 5);
626 let mut image = OwnedImage::new(shape, data);
627 assert_eq!(image.drop_cols(2).is_ok(), true);
628 assert_eq!(image.shape(), (5, 3));
629 assert_eq!(image.data(), [0, 1, 2, 5, 6, 7, 10, 11, 12, 15, 16, 17, 20, 21, 22])
630 }
631
632 #[test]
633 fn mut_image_is_image()
634 {
635 let (shape, data) = generate(5, 5);
636 let mut image = OwnedImage::new(shape, data);
637 let image_ref = &mut image;
638 assert_eq!(image_ref.n_rows(), 5);
639 assert_eq!(image_ref.n_cols(), 5);
640 assert_eq!(image_ref.shape(), (5, 5));
641 }
642
643 #[test]
644 fn mapped_image_is_correct_shape()
645 {
646 let (shape, data) = generate(5, 5);
647 let image = OwnedImage::new(shape, data);
648 let new_image = image.map(|_| 0);
649 assert_eq!(new_image.data(), vec![0; 25]);
650 assert_eq!(new_image.shape(), image.shape())
651 }
652}