为什么我的高斯模糊近似强度是一半?

Why is my gaussian blur approximation half strength?

我已经在 Rust 中实现了 stackblur algorithm(Mario Klingemann),并重写了水平传递以使用迭代器而不是索引。然而,与 GIMP 相比,模糊需要 运行 两倍才能达到最大强度。将半径加倍会引入光晕。

/// Performs a horizontal pass of stackblur.
/// Input is expected to be in linear RGB color space.
/// Needs to be ran twice for full effect!
pub fn blur_horiz(src: &mut [u32], width: NonZeroUsize, radius: NonZeroU8) {
    let width = width.get();
    let radius = u32::from(min(radius.get() | 1, 255));
    let r = radius as usize;

    src.chunks_exact_mut(width).for_each(|row| {
        let first = *row.first().unwrap();
        let mut last = *row.last().unwrap();

        let mut queue_r = VecDeque::with_capacity(r);
        let mut queue_g = VecDeque::with_capacity(r);
        let mut queue_b = VecDeque::with_capacity(r);

        // fill with left edge pixel
        for v in iter::repeat(first).take(r / 2 + 1) {
            queue_r.push_back(red(v));
            queue_g.push_back(green(v));
            queue_b.push_back(blue(v));
        }

        // fill with starting pixels
        for v in row.iter().copied().chain(iter::repeat(last)).take(r / 2) {
            queue_r.push_back(red(v));
            queue_g.push_back(green(v));
            queue_b.push_back(blue(v));
        }

        debug_assert_eq!(queue_r.len(), r);

        let mut row_iter = peek_nth(row.iter_mut());

        while let Some(px) = row_iter.next() {
            // set pixel
            *px = pixel(
                queue_r.iter().sum::<u32>() / radius,
                queue_g.iter().sum::<u32>() / radius,
                queue_b.iter().sum::<u32>() / radius,
            );

            // drop left edge of kernel
            let _ = queue_r.pop_front();
            let _ = queue_g.pop_front();
            let _ = queue_b.pop_front();

            // add right edge of kernel
            let next = **row_iter.peek_nth(r / 2).unwrap_or(&&mut last);
            queue_r.push_back(red(next));
            queue_g.push_back(green(next));
            queue_b.push_back(blue(next));
        }
    });
}

[Full Code]

运行宁blur_horiz两次后半径=15的结果:

运行宁blur_horiz一次半径=30后的结果:

请注意,您实现的是常规框过滤器,而不是 stackblur(它使用三角形过滤器)。另外,用一个半径为R的盒子过滤两次相当于用一个半径为2*R的三角形过滤一次,这就解释了为什么在运行 blur_horiz两次时得到预期的结果.