climage 0.1.0

Rust implementation of image processing library with OpenCL.
Documentation
use super::context::ClContext;
use super::imageproc::ImageProc;
use ocl::{Buffer, Kernel, Program};

static KERNEL_SRC: &'static str = r#"
__constant sampler_t sampler_const = CLK_NORMALIZED_COORDS_FALSE |
                                    CLK_ADDRESS_NONE |
                                    CLK_FILTER_NEAREST;
__kernel void bilateral_filter(
    __read_only image2d_t src_image,
    __write_only image2d_t dst_image,
    __constant float *weights,
    __private int const sigma_color,
    __private int const sigma_space) {
    int2 gid = (int2)(get_global_id(0), get_global_id(1));
    int2 size = get_image_dim(src_image);

    if(all(gid < size)){
        float4 sum = 0;
        float4 total_w = 0;
        float4 center_p = read_imagef(src_image, sampler_const, gid);
        for(int i = -sigma_space; i < sigma_space + 1; i++) {
            for(int j = -sigma_space; j < sigma_space + 1; j++) {
                if (gid.x + i < 0 || gid.x + i >= size.x || gid.y + j < 0 || gid.y + j >= size.y) {
                    continue;
                }
                float4 cur_p = read_imagef(src_image, sampler_const, gid + (int2)(i, j));
                float4 dp = center_p - cur_p;
                float4 weight = weights[i + sigma_space + (j + sigma_space) * (sigma_space * 2 + 1)] * exp(-(dp * dp) / (float4)(2.0 * sigma_color * sigma_color));
                sum += weight * cur_p;
                total_w += weight;
            }
        }
        sum /= total_w;
        write_imagef(dst_image, gid, sum);
    }
}
"#;

pub struct BilateralFilter<'a> {
    context: &'a ClContext,
    program: Program,
    kernel: Option<Kernel>,
    weight_buf: Buffer<f32>,
    sigma_color: i32,
    sigma_space: i32,
}

impl<'a> BilateralFilter<'a> {
    pub fn new(context: &'a ClContext, sigma_color: i32, sigma_space: i32) -> Self {
        let program = Program::builder()
            .src(KERNEL_SRC)
            .build(&context.context)
            .unwrap();
        let weight_size = (sigma_space * 2 + 1) * (sigma_space * 2 + 1);
        let mut weights: Vec<f32> = vec![0.0; weight_size as usize];
        for i in -sigma_space..(sigma_space + 1) {
            for j in -sigma_space..(sigma_space + 1) {
                let weight = (-((i * i + j * j) as f32)
                    / (2.0 * ((sigma_space * sigma_space) as f32)))
                    .exp();
                weights[(i + sigma_space + (j + sigma_space) * (sigma_space * 2 + 1)) as usize] =
                    weight;
            }
        }
        let sum_weight = weights.iter().sum::<f32>();
        for i in 0..weight_size {
            weights[i as usize] /= sum_weight;
        }
        let weight_buf = Buffer::builder()
            .queue(context.queue.clone())
            .flags(ocl::flags::MEM_READ_ONLY)
            .len(weight_size)
            .copy_host_slice(&weights)
            .build()
            .unwrap();
        BilateralFilter {
            context,
            program,
            kernel: None,
            weight_buf,
            sigma_color,
            sigma_space,
        }
    }
}

impl<'a> ImageProc for BilateralFilter<'a> {
    fn build_kernel(
        &mut self,
        src_img: &crate::ClImageBuffer,
        dst_img: &mut crate::ClImageBuffer,
    ) -> &mut Self {
        let kernel = ocl::Kernel::builder()
            .program(&self.program)
            .name("bilateral_filter")
            .queue(self.context.queue.clone())
            .global_work_size(src_img.dimensions())
            .arg(&src_img.data)
            .arg(&dst_img.data)
            .arg(&self.weight_buf)
            .arg(&self.sigma_color)
            .arg(&self.sigma_space)
            .build()
            .unwrap();
        self.kernel = Some(kernel);
        self
    }
    fn run(&self) {
        unsafe { self.kernel.as_ref().unwrap().enq().unwrap() };
    }
}