前言
何凯明文章引导图像滤波的源代码中的行方向盒子滤波函数如下
function imDst = rowboxfilter(imSrc, w)
[hei, wid] = size(imSrc);
imDst = zeros(hei,wid);
imCum = cumsum(imSrc, 2);
imDst(:, 1:w+1) = imCum(:, 1+w:2*w+1);
imDst(:, w+2:wid-w) = imCum(:, 2*w+2:wid) - imCum(:, 1:wid-2*w-1);
imDst(:, wid-w+1:wid) = repmat(imCum(:, wid), [1, w]) - imCum(:, wid-2*w:wid-w-1);
end
这段代码在
function q = rowguidedfilter(I, p, r, eps)
[hei, wid] = size(I);
N = rowboxfilter(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels.
mean_I = rowboxfilter(I, r) ./ N;
mean_p = rowboxfilter(p, r) ./ N;
mean_Ip = rowboxfilter(I.*p, r) ./ N;
cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch.
mean_II = rowboxfilter(I.*I, r) ./ N;
var_I = mean_II - mean_I .* mean_I;
a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper;
b = mean_p - a .* mean_I; % Eqn. (6) in the paper;
mean_a = rowboxfilter(a, r) ./ N;
mean_b = rowboxfilter(b, r) ./ N;
q = mean_a .* I + mean_b; % Eqn. (8) in the paper;
end
函数中多处出现,代码中仅仅提到其作用与
colfilt(imSrc, [2*r+1, 2*r+1], 'sliding', @sum);
相同,此外并无过多解释,不便于理解,故写此篇。
解析
假设有M行N列的原图像矩阵如下,这里我们设置为10行20列
根据代码
N = rowboxfilter(ones(hei, wid), r)
我们可以知道作者生成了一个与原图相同尺寸的全一矩阵,并对其实施行方向的方盒滤波,方盒半径为r,也即尺寸为(2r+1)X(2r+1)的方盒滤波框。代码中r=4,即尺寸为9*9。
然而在rowboxfilter中仅仅执行横向的方盒滤波,这时方盒滤波框变成了1X(2*r+1)的矩形滤波框。如下所示
滤波过程
对于I(1,1),由于是行滤波,故以坐标为(1,1)处为滤波器中心(红色框),r=4为半径(绿色框)进行求和,结果为5。
对于I(1,2),此时滤波器向右移动一格,以坐标为(1,2)处为滤波器中心(红色框),r=4为半径(绿色框)进行求和,结果为6。
中间部分结果从7到8
直到滤波器的全部方格均加入运算
对于I(1,5),此时滤波器向右移动一格,以坐标为(1,5)处为滤波器中心(红色框),r=4为半径(绿色框)进行求和,结果为9。
此后只要滤波器右翼未触碰到末尾列,结果均为9。而从接触到末尾列开始的情况与首列正好对称。
因此我们可以得到完整结果如下
然而,对于代码
colfilt(imSrc, [2*r+1, 2*r+1], 'sliding', @sum);
以相同的输入得到的结果如下
我们可以发现结果变成了原来的结果矩阵的每个元素乘以5。因为这段代码中的滤波框变成了方框,如下所示。
总结
这段代码
N = rowboxfilter(ones(hei, wid), r);
的作用是提前计算滑动窗口内像素块的总数N。
在之后的代码
mean_I = rowboxfilter(I, r) ./ N;
mean_p = rowboxfilter(p, r) ./ N;
mean_Ip = rowboxfilter(I.*p, r) ./ N;
mean_II = rowboxfilter(I.*I, r) ./ N;
mean_a = rowboxfilter(a, r) ./ N;
mean_b = rowboxfilter(b, r) ./ N;
中都有使用到N。