image_conv/
lib.rs

1//! A Rust library for image convolution.
2//!
3//!
4//! ## Example
5//! ```no_run
6//! use image_conv::conv;
7//! use image_conv::{Filter, PaddingType};
8//! use photon_rs::native::{open_image, save_image};
9//!
10//! fn main() {
11//!     // Open an image
12//!     let mut img = open_image("img.jpg").expect("No such file found");
13//!
14//!     // Create a filter
15//!     let sobel_x: Vec<f32> = vec![1.0, 0.0, -1.0, 2.0, 0.0, -2.0, 1.0, 0.0, -1.0];
16//!     let filter = Filter::from(sobel_x, 3, 3);
17//!     
18//!     // Apply convolution    
19//!     let img_conv = conv::convolution(&img, filter, 1, PaddingType::UNIFORM(1));
20//!     save_image(img_conv, "img_conv.jpg");
21//! }
22//! ```
23
24pub mod conv;
25
26use image::{
27    DynamicImage::{self, ImageRgba8},
28    GenericImageView,
29};
30use photon_rs::{helpers, PhotonImage};
31use prettytable::{Cell, Row, Table};
32
33/// Filter is a struct for holding a kernel
34/// and its associated meta-data
35///
36/// # Struct members
37/// * `width` - Holds Filter's width. (usize)
38/// * `height` - Holds Filter's height. (usize)
39/// * `kernel` - Holds Filter's kernel/data. (32-bit floating point Vector)
40pub struct Filter {
41    width: usize,
42    height: usize,
43    kernel: Vec<f32>,
44}
45
46impl Filter {
47    /// Initializes and returns a new Filter object
48    pub fn new(width: usize, height: usize) -> Self {
49        let mut kernel = Vec::<f32>::new();
50        Vec::resize(&mut kernel, width * height, 0_f32);
51        Self { width, height, kernel }
52    }
53    /// Creates and returns a Filter object from a vector of kernel data
54    pub fn from(kernel_buffer: Vec<f32>, width: usize, height: usize) -> Self {
55        let kernel_size = kernel_buffer.len();
56        if width * height != kernel_size {
57            eprintln!("[ERROR]: Invalid dimensions provided");
58            std::process::exit(1);
59        }
60        Self {
61            width,
62            height,
63            kernel: kernel_buffer,
64        }
65    }
66    /// Getter for Filter's width
67    pub fn width(&self) -> usize {
68        self.width
69    }
70    /// Getter for Filter's height
71    pub fn height(&self) -> usize {
72        self.height
73    }
74    /// Getter for Filter's kernel/data
75    pub fn kernel(&self) -> Vec<f32> {
76        self.kernel.clone()
77    }
78    /// Returns data element present at (x, y) location of Filter, as an Option Enum
79    pub fn get_element(&self, x: usize, y: usize) -> Option<f32> {
80        let element_pos = x * self.width + y;
81        if self.kernel.is_empty() || element_pos >= self.kernel.len() {
82            None
83        } else {
84            Some(self.kernel[element_pos])
85        }
86    }
87    /// Sets data element at (x, y) location of Filter.
88    pub fn set_value_at_pos(&mut self, val: f32, position: (usize, usize)) {
89        let element_pos = position.0 * self.width + position.1;
90        if self.kernel.is_empty() || element_pos >= self.kernel.len() {
91            eprintln!("[ERROR]: Index out of bound");
92            std::process::exit(1);
93        } else {
94            self.kernel[element_pos] = val;
95        }
96    }
97    /// Displays the Filter as a pretty 2D-matrix
98    pub fn display(&self) {
99        let mut table = Table::new();
100
101        for x in 0..self.height {
102            let mut row_vec = Vec::<Cell>::new();
103            for y in 0..self.width {
104                let pos = x * self.width + y;
105                let element = &self.kernel[pos];
106                row_vec.push(Cell::new(element.to_string().as_str()));
107            }
108            table.add_row(Row::new(row_vec));
109        }
110        table.printstd();
111    }
112}
113
114/// Enumeration for available padding types
115pub enum PaddingType {
116    UNIFORM(u32),
117    NONE,
118}
119
120/// For convertion of PhotonImage into Dynamic image
121pub fn photon_to_dynamic(photon_image: &PhotonImage) -> DynamicImage {
122    let mut img = helpers::dyn_image_from_raw(photon_image);
123    img = ImageRgba8(img.to_rgba8());
124    img
125}
126
127/// For convertion of Dynamic image into PhotonImage
128pub fn dynamic_to_photon(dynamic_image: &DynamicImage) -> PhotonImage {
129    let image_buffer: Vec<u8> = (*dynamic_image).clone().into_bytes();
130    PhotonImage::new(image_buffer, dynamic_image.width(), dynamic_image.height())
131}