pub fn filter<P, K, F, Q>(image: &Image<P>, kernel: Kernel<K>, mut f: F) -> Image<Q>
where
    P: Pixel,
    <P as Pixel>::Subpixel: Into<K>,
    Q: Pixel,
    F: FnMut(K) -> Q::Subpixel,
    K: Copy + Num,
{
    assert_eq!(P::CHANNEL_COUNT, Q::CHANNEL_COUNT);
    let num_channels = P::CHANNEL_COUNT as usize;
    let zero = K::zero();

    let (width, height) = image.dimensions();
    let mut out = Image::<Q>::new(width, height);
    let mut acc = vec![zero; num_channels];
    let (k_width, k_height) = (kernel.width as i64, kernel.height as i64);
    let (width, height) = (width as i64, height as i64);

    for y in 0..height {
        for x in 0..width {
            for k_y in 0..k_height {
                let y_p = min(height - 1, max(0, y + k_y - k_height / 2)) as u32;
                for k_x in 0..k_width {
                    let x_p = min(width - 1, max(0, x + k_x - k_width / 2)) as u32;

                    debug_assert!(image.in_bounds(x_p, y_p));
                    accumulate(
                        &mut acc,
                        unsafe { &image.unsafe_get_pixel(x_p, y_p) },
                        unsafe { kernel.get_unchecked(k_x as u32, k_y as u32) },
                    );
                }
            }
            let out_channels = out.get_pixel_mut(x as u32, y as u32).channels_mut();
            for (a, c) in acc.iter_mut().zip(out_channels) {
                *c = f(*a);
                *a = zero;
            }
        }
    }
    out
}
Returns 2d correlation of an image. Intermediate calculations are performed
at type K, and the results converted to pixel Q via f. Pads by continuity.

# Panics
If `P::CHANNEL_COUNT != Q::CHANNEL_COUNT`
src/filter/mod.rs