1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! A high performance Rust library for image convolution based on.
//!
//!
//! ## Example
//! ```no_run
//! use image_conv::conv;
//! use image_conv::Filter;
//! use photon_rs::native::{open_image, save_image};
//!
//! fn main() {
//!     // Open an image
//!     let mut img = open_image("img.jpg").expect("No such file found");
//!
//!     // Create a filter
//!     let sobel_x: Vec<f32> = vec![1.0, 0.0, -1.0, 2.0, 0.0, -2.0, 1.0, 0.0, -1.0];
//!     let filter = Filter::from(sobel_x, 3, 3);
//!     
//!     // Apply convolution    
//!     let img_conv = conv::convolution(&img, filter, 1, "uniform", 1);
//!     save_image(img_conv, "img_conv.jpg");
//! }
//! ```

use image::{
    DynamicImage::{self, ImageRgba8},
    GenericImageView,
};
use photon_rs::{helpers, PhotonImage};
use prettytable::{Cell, Row, Table};

/// Filter is a struct for holding a kernel
/// and its associated meta-data
///
/// # Struct members
/// * `width` - Holds Filter's width. (usize)
/// * `height` - Holds Filter's height. (usize)
/// * `kernel` - Holds Filter's kernel/data. (32-bit floating point Vector)
pub struct Filter {
    width: usize,
    height: usize,
    kernel: Vec<f32>,
}

impl Filter {
    /// Initializes and returns a new Filter object
    pub fn new(width: usize, height: usize) -> Self {
        let mut kernel = Vec::<f32>::new();
        Vec::resize(&mut kernel, width * height, 0_f32);
        Self {
            width,
            height,
            kernel,
        }
    }
    /// Creates and returns a Filter object from a vector of kernel data
    pub fn from(kernel_buffer: Vec<f32>, width: usize, height: usize) -> Self {
        let kernel_size = kernel_buffer.len();
        if width * height != kernel_size {
            eprintln!("[ERROR]: Invalid dimensions provided");
            std::process::exit(1);
        }
        Self {
            width,
            height,
            kernel: kernel_buffer,
        }
    }
    /// Getter for Filter's width
    pub fn width(&self) -> usize {
        self.width
    }
    /// Getter for Filter's height
    pub fn height(&self) -> usize {
        self.height
    }
    /// Getter for Filter's kernel/data
    pub fn kernel(&self) -> Vec<f32> {
        self.kernel.clone()
    }
    /// Returns data element present at (x, y) location of Filter, as an Option Enum
    pub fn get_element(&self, x: usize, y: usize) -> Option<f32> {
        let element_pos = x * self.width + y;
        if self.kernel.is_empty() || element_pos >= self.kernel.len() {
            None
        } else {
            Some(self.kernel[element_pos])
        }
    }
    /// Sets data element at (x, y) location of Filter.
    pub fn set_value_at_pos(&mut self, val: f32, position: (usize, usize)) {
        let element_pos = position.0 * self.width + position.1;
        if self.kernel.is_empty() || element_pos >= self.kernel.len() {
            eprintln!("[ERROR]: Index out of bound");
            std::process::exit(1);
        } else {
            self.kernel[element_pos] = val;
        }
    }
    /// Displays the Filter as a pretty 2D-matrix
    pub fn display(&self) {
        let mut table = Table::new();

        for x in 0..self.height {
            let mut row_vec = Vec::<Cell>::new();
            for y in 0..self.width {
                let pos = x * self.width + y;
                let element = &self.kernel[pos];
                row_vec.push(Cell::new(element.to_string().as_str()));
            }
            table.add_row(Row::new(row_vec));
        }
        table.printstd();
    }
}

/// For convertion of PhotonImage into Dynamic image
pub fn photon_to_dynamic(photon_image: &PhotonImage) -> DynamicImage {
    let mut img = helpers::dyn_image_from_raw(photon_image);
    img = ImageRgba8(img.to_rgba8());
    img
}

/// For convertion of Dynamic image into PhotonImage
pub fn dynamic_to_photon(dynamic_image: &DynamicImage) -> PhotonImage {
    let image_buffer: Vec<u8> = (*dynamic_image).clone().into_bytes();
    PhotonImage::new(image_buffer, dynamic_image.width(), dynamic_image.height())
}

pub mod conv;
pub mod padding;