Image deblurring via extreme channels prior 代码解析(二)

三、 2.6调用的threshold_pxpy_v1函数(cho_code文件夹中)

函数格式

function [px, py, threshold]= threshold_pxpy_v1(latent,psf_size,threshold)

三个输入参数潜在图像latent、模糊核大小psf_size和阈值threshold,输出参数px、py和threshold

3.1 判断是否传入threshold参数(2.6 未传入,而4.3传入),如果未传入,则设置为0,并b_estimate_threshold为true,表示之后是否进行threshold的估计,如果传入,则b_estimate_threshold为false。

if ~exist('threshold', 'var')%工作区中是否存在变量threshold %第三个参数有无输入,代码为没有输入
    threshold = 0;
    b_estimate_threshold = true;
else
    b_estimate_threshold = false;
end

3.2 用denoised表示当前图像latent,分别求其水平和垂直梯度px py,将px和py按元平方求和后获得denoised的总梯度大小pm

denoised=latent;

%%
% derivative filters
dx = [-1 1; 0 0];
dy = [-1 0; 1 0];

px = conv2(denoised, dx, 'valid');
py = conv2(denoised, dy, 'valid');
pm = px.^2 + py.^2;%梯度

因为conv2的参数为valid,所以卷积后的px py大小比denoised小一些。

3.3 如果是第一次估计(在3.1中的b_estimate_threshold为true时,表示是第一次被调用,所以要进行初始化为0的threshold进行准确估计):

if b_estimate_threshold
    pd = atan(py./px);%梯度角度
    pm_steps = 0:0.00006:2;
    H1 = cumsum(flipud(histc(pm(pd >= 0 & pd < pi/4), pm_steps)));
    H2 = cumsum(flipud(histc(pm(pd >= pi/4 & pd < pi/2), pm_steps)));
    H3 = cumsum(flipud(histc(pm(pd >= -pi/4 & pd < 0), pm_steps)));
    H4 = cumsum(flipud(histc(pm(pd >= -pi/2 & pd < -pi/4), pm_steps)));

    th = max([max(psf_size)*20, 10]);
    
    for t=1:numel(pm_steps)%numel 数组元素的数目 一维度等于length
        min_h = min([H1(t) H2(t) H3(t) H4(t)]);
        if min_h >= th
            threshold = pm_steps(end-t+1);
            break
        end
    end
end

pd表示梯度方向(角度),pm_steps 表示值从0以0.00006变化到2的列表(长度为33334)。以H1的计算为例,pd >= 0 & pd < pi/4表示梯度方向角是否在第一象限,返回一个逻辑列表,值为1表示对用方向角在第一象限,为0则不在。pm(pd >= 0 & pd < pi/4)得到一个列向量(pm和pd之前为矩阵),取所有方向角在第一象限的所有对应梯度大小。c=histc(a,b)函数统计了列表a中所有的值分布列表b中每段(b相邻两个值界定的值的范围,取前不取后)的数量c,例如:

histc([0.5,1,2,3,3,4],[1,4,5]),返回结果[4,1,0]。表示[0.5,1,2,3,3,4]在大于等于1小于4的范围内有四个(1 2 3 3),大于等于4小于5的范围内有一个(4),大于等于5的为0个。histc(pm(pd >= 0 & pd < pi/4), pm_steps)表示了方向在第一象限的所有梯度值在0~2范围内,每段宽度为0.00006的梯度分布直方图(和灰度直方图类似,灰度直方图范围为0~255,宽度为1)。flipud进行上下翻转,即让分布直方图的取值范围改为从2减小到0,然后通过cumsum统计其累积分布,记作H1(以刚刚为例,[4 1 0]翻转后为[0 1 4],cumsum后为[0 1 5]),H2、3、4同理,分别对应第二三四象限梯度分布的累积。th表示判断阈值估计的终止判断,for循环遍历每个范围段,获得四个象限在该段的累计分布(从1.99996到2开始累计)的最小值,如果该最小是大于指定的th,那么估计的threshold值为pm_steps(end-t+1),t表示遍历次数,然后break出for循环,此时得到了最终估计的threshold(值在0~2之间)

3.4 调整threshold

m = pm < threshold;
while all(m(:)==1) %%当pm全部小于thresold(m全为1)
    threshold = threshold * 0.81;%阈值变小
    m = pm < threshold;
end
px(m) = 0;%pm小于threshold的x方向和y方向梯度为0
py(m) = 0;

用m表示pm的每个值是否小于threshold,如果全部小于(即m中所有值都为1),那么循环调整threshold为之前的0.81倍,直到pm有值大于等于threshold为止(m有元素为0),并令梯度大小小于阈值threshold的像素对应的水平和垂直梯度值也为0.px和py即保留了几个比较大的值,其他为0.(2.6)中只需要根据输入的ys大小计算一个阈值threshold即可。

3.5 作者的新的修改,如果这是第一次估计的话,不做操作,而如果不是第一次操作,即输入参数有threshold,则返回的参数threshold是它本身除以1.1.

if b_estimate_threshold
    threshold = threshold;
else
    threshold = threshold./1.1;
end

3.6 至此 函数threshold_pxpy_v1结束

end

四、2.7调用的blind_deconv_mainBDF函数

函数格式

function [k, lambda_dark, lambda_grad, S] = blind_deconv_mainBDF(blur_B, k, ...
                                    lambda_dark, lambda_grad, threshold, opts)

该函数根据输入的参数模糊图像blur_B、初始化的模糊核k、以及lambda_dark, lambda_grad, threshold等参数,计算模糊核k以及中间的潜在图像S,并重新更新lambda_dark和 lambda_grad,即计算:

4.1 首先,对于输入模糊图像blur_B,根据Liu的方法添加边界(Reducing boundary artifacts in image deconvolution.Renting Liu, Jiaya Jia) ,注:只添加了右侧和下侧边界,添加后的图像大小为opt_fft_size([H W]+size(k)-1),将带有边界的模糊图像记作blur_B_w,(该添加边界函数在此不做叙述)则没有添加边界的模糊图像blur_B_tmp等于blur_w的前H行W列(也等于blur_B),求blur_B_tmp的水平和垂直梯度Bx和By。

dx = [-1 1; 0 0];
dy = [-1 0; 1 0];

H = size(blur_B,1);    W = size(blur_B,2);
blur_B_w = wrap_boundary_liu(blur_B, opt_fft_size([H W]+size(k)-1));%添加Liu的边界 只添加了右下
blur_B_tmp = blur_B_w(1:H,1:W,:);%真实图像
Bx = conv2(blur_B_tmp, dx, 'valid');
By = conv2(blur_B_tmp, dy, 'valid');

4.2 迭代,如果lambda_dark为0,表示模型无需考虑暗通道,那么就直接调用自定义函数L0Restoration)即可,传入参数blur_B(没用边界)、k和梯度权值lambda_grad,kappa设为2,返回得到潜在图像S;否则调用自定义函数L0Deblur_dark_chanelBD),传入添加边界的模糊图像blur_B_w、初始化的模糊核k、两个权值参数以及kappa=2。返回得到潜在图像S,并裁剪掉之前添加的边界。

for iter = 1:opts.xk_iter %到4.6迭代结束
    %%
   if lambda_dark~=0
       %S = L0Deblur_dark_chanel(blur_B_w, k, lambda_dark, lambda_grad, 2.0);
       S = L0Deblur_dark_chanelBD(blur_B_w, k, lambda_dark, lambda_grad, 2.0);
       S = S(1:H,1:W,:);
   else
       %% L0 deblurring
       S = L0Restoration(blur_B, k, lambda_grad, 2.0);
   end

4.3 对S调用自定义函数threshold_pxpy_v1),传入之间调用这个函数时已经得到的threshold和S,输出S的水平和垂直梯度lantent_x和lantent_y,只含有大于输入阈值的值,其他为0,同时更新阈值。保存初始化的k为k_prev,然后调用自定义函数estimate_psf),输入带有边界的模糊图像的梯度Bx和By,以及刚刚得到的清晰图像筛选后的梯度lantent_x和lantent_y,置weight为2,进行模糊核的估计,得到模糊核k。

  [latent_x, latent_y, threshold]= threshold_pxpy_v1(S,max(size(k)),threshold); 
  %% 
%   latent_x = conv2(S, dx, 'valid');
%   latent_y = conv2(S, dy, 'valid');
  k_prev = k;
  %
  k = estimate_psf(Bx, By, latent_x, latent_y, 2, size(k_prev));

4.4 获得k的各个连通区域,去掉连通区域的占比小于k总值(此时k所有元素和为1)百分之10的所有连通区域,保留大面积连通区域,然后将k中负值归为0,并重新归一化。

  CC = bwconncomp(k,8);%获得八联通  代替bwlabel,返回的是结构体 包括输入的大小,几个连通区域、每个连通区域的内容等
  for ii=1:CC.NumObjects
      currsum=sum(k(CC.PixelIdxList{ii}));%PixelIdxList{ii}为第ii个连通区域的index(一维)列表
      if currsum<.1 
          k(CC.PixelIdxList{ii}) = 0;%去掉占比小的连通区域
      end
  end
  k(k<0) = 0;
  k=k/sum(k(:));

4.5 权重更新为之前的1/1.1倍

  if lambda_dark~=0
      lambda_dark = max(lambda_dark/1.1, 1e-4);
  else
      lambda_dark = 0;
  end
  %lambda_dark = lambda_dark/1.1;  %% for natural images
  if lambda_grad~=0
      lambda_grad = max(lambda_grad/1.1, 1e-4);
  else
      lambda_grad = 0;
  end

4.6  4.2的迭代结束。对最后得到的k再次去负数后归一化,之后函数blind_deconv_mainBDF结束。

end
k(k<0) = 0;  
k = k ./ sum(k(:));

五  4.2调用的L0Restoration函数(不考虑暗通道)

函数格式

function S = L0Restoration(Im, kernel, lambda, kappa)

输入模糊图像Im、模糊核k、梯度权值lambda,kappa=2,代表ADM(Altetnating Direction Method)的更新步长,返回中间潜在图像S。因为不考虑暗通道,所以模型为:

 5.1 同样首先对模糊图像添加边界,更新为Im,令返回值S初始化为Im,fx和hy分别代表水平和垂直梯度算子,psf2otf是将模糊核从空间域转换为频域的指定大小,类似于fft2变换,betamax设置为1e5(十万)(表示beta循环的上界)。分别将fx fy 和模糊核kernel转到频域,用otfFx、otfFy和KER表示。Den_KER表示KER的模的平方,Denormin2表示otfFx和otfFy的模的平方和,Normin1 表示模糊核的频域的共轭与图像S的频域的点乘,beta初始化为2倍的lambda(对应lambda_grad)

H = size(Im,1);    W = size(Im,2);
Im = wrap_boundary_liu(Im, opt_fft_size([H W]+size(kernel)-1));
%%
S = Im;
betamax = 1e5;
fx = [1, -1];
fy = [1; -1];
[N,M,D] = size(Im);
sizeI2D = [N,M];
otfFx = psf2otf(fx,sizeI2D);
otfFy = psf2otf(fy,sizeI2D);
%%
KER = psf2otf(kernel,sizeI2D);
Den_KER = abs(KER).^2;
Denormin2 = abs(otfFx).^2 + abs(otfFy ).^2;
Normin1 = conj(KER).*fft2(S);
%% 
beta = 2*lambda;

5.2 循环,Denormin为Den_KER与beta乘以Denormin2的和,用h和v表示S的水平和垂直方向上的差分(diff),和梯度类似,h^2+v^2表示总差分大小,t表示总差分大小是否小于lambda/beta,并置总差分小于lambda/beta的对应的水平和垂直差分值为0.

while beta < betamax %到5.3结束
    Denormin   = Den_KER + beta*Denormin2;
    h = [diff(S,1,2), S(:,1,:) - S(:,end,:)];
    v = [diff(S,1,1); S(1,:,:) - S(end,:,:)];
    if D==1
        t = (h.^2+v.^2)<lambda/beta;
    else
        t = sum((h.^2+v.^2),3)<lambda/beta;
        t = repmat(t,[1,1,D]);
    end
    h(t)=0; v(t)=0;

5.3 Normin2为h和v的负差分之和,FS为频域结果,分子为Normin1 + beta*fft2(Normin2),分母为Denormin,将FS逆傅里叶变换并取实部得到S,beta更新为beta*kappa,直至beta>betamax。

    Normin2 = [h(:,end,:) - h(:, 1,:), -diff(h,1,2)];
    Normin2 = Normin2 + [v(end,:,:) - v(1, :,:); -diff(v,1,1)];
    FS = (Normin1 + beta*fft2(Normin2))./Denormin;
    S = real(ifft2(FS));
    beta = beta*kappa;
end

5.4 裁剪S,将S返回,函数L0Restoration结束。

S = S(1:H, 1:W, :);
end

5.5 ()和论文《Deblurring Text Images via L0-Regularized Intensity and Gradient Prior》方法进行对照。论文中,正则化项包括保真项和两个惩罚项(梯度l0正则化和图像像素l0正则化),该函数不考虑图像像素正则化。对于模型

求解过程为:

    输入:模糊图像I,模糊核k。

    输出:清晰图像S。

    初始化:beta=2*lambda,kappa=2.

           重复:(1)求解g。

                   (2)求解S。

                   (3) beta=beta*kappa.

           直至 beta>betamax。

    输出S。

g的解和S的解如下:

∇代表梯度算子,gh和gv分别代表g的差分。

回到函数L0Restoration。对输入图像添加边界后(抑制复原时产生的振铃),Im相当于I,先初始化结果S为I,betamax为beta迭代的上界(求解过程中重复的终止条件),fx和fy对应梯度算子∇={∇h,∇v},otfFx和otfFy分别代表其频域F(∇h)和F(∇v)。KER为k的频域,即F(k)。Den_KER为KER的模的的点平方,实质上就是,即分母的第一项;同理,Denormin2为,简单表示为,对应分母第二项(不考虑β)。Normin1为k的频域的共轭与I的频域的点乘,即公式中分子的第一项。变量h和v代表S的差分,即∇I。将∇I中小于lambda/beta的值置为0,得到的h和v即g在水平和垂直方向的分量表示,g={h,v}。

代码块对应

然后将解得的g带入。Normin2为h的负水平差分和v的负水平差分,将其转为频域表示即为。自此将代码和公式全部对应起来了:

六 4.2调用的L0Deblur_dark_chanelBD函数(考虑暗通道)

函数格式

function S = L0Deblur_dark_chanelBD(Im, kernel, lambda, wei_grad, kappa)

相比于(),多输入了一个参数,当然在这个代码中,lambda表示的是暗通道的权值lambda_dark,而wei_grad代表梯度权值。因为比()多了一个要考虑的因素,很多地方和()相同,就略过。

S = Im;
betamax = 1e5;
fx = [1, -1];
fy = [1; -1];
[N,M,D] = size(Im);
sizeI2D = [N,M];
otfFx = psf2otf(fx,sizeI2D);
otfFy = psf2otf(fy,sizeI2D);
%%
KER = psf2otf(kernel,sizeI2D); %第s层的核函数
Den_KER = abs(KER).^2;
%%
Denormin2 = abs(otfFx).^2 + abs(otfFy ).^2;
if D>1
    Denormin2 = repmat(Denormin2,[1,1,D]);%复制成三层
    KER = repmat(KER,[1,1,D]);
    Den_KER = repmat(Den_KER,[1,1,D]);
end
Normin1 = conj(KER).*fft2(S);%原始图像S*模糊核K

6.1 dark_r = 45 表示以某像素点为中心的暗通道计算区域大小为45像素,mybeta_pixel和maxbeta_pixel分别为迭代的初始值和上界。

dark_r = 45; %% Fixed size!
%mybeta_pixel = 2*lambda;
%[J, J_idx] = dark_channel(S, dark_r);
mybeta_pixel = lambda/(graythresh((S).^2));%graythresh计算全局阈值,使阈值化的黑白像素的类内方差最小化
maxbeta_pixel = 8;%2^3;

6.2 在迭代中,调用自定义函数dark_channel()获得图像S的按通道图像J,以及每个像素到其暗通道像素的映射J_idx。令u等于J,并使u中值小于给定大小的像素值置为0.

while mybeta_pixel< maxbeta_pixel %到6.6结束
    %% 
    [J, J_idx] = dark_channel(S, dark_r);
    u = J;
    if D==1
        t = u.^2<lambda/mybeta_pixel;%u<thre
    else
        t = sum(u.^2,3)<lambda/mybeta_pixel;
        t = repmat(t,[1,1,D]);
    end
    u(t) = 0;%灰度通道中小于阈值的置为0

6.3 调用自定义函数assign_dark_channel_to_pixel),对S进行调整得到u。

u = assign_dark_channel_to_pixel(S, u, J_idx, dark_r);

6.4 对I进行亮通道即对1-I进行暗通道(I范围为0~1),用BS表示1-S,进行和S相似的操作:

    BS=1-S;
    [BJ, BJ_idx] = dark_channel(BS, dark_r);%亮通道
    bu = BJ;
    if D==1
        t = bu.^2<lambda/mybeta_pixel;
    else
        t = sum(bu.^2,3)<lambda/mybeta_pixel;
        t = repmat(t,[1,1,D]);
    end
    bu(t) = 0;
    %
    clear t;
    bu = assign_dark_channel_to_pixel(BS, bu, BJ_idx, dark_r);

6.5 进行和5.2-5.3相同的操作(此时在6.2的循环中)

    while beta < betamax
        Denormin   = Den_KER + beta*Denormin2 + 2*mybeta_pixel;
        %
        h = [diff(S,1,2), S(:,1,:) - S(:,end,:)];%diff(S,n,dim) :沿 dim 指定的维计算的第 n 个差分
        %前n-1列为列的差分,最后一列为第一列与最后一列的差值,相当于全差值
        
        v = [diff(S,1,1); S(1,:,:) - S(end,:,:)];
        if D==1
            t = (h.^2+v.^2)<wei_grad/beta;
        else
            t = sum((h.^2+v.^2),3)<wei_grad/beta;
            t = repmat(t,[1,1,D]);
        end
        h(t)=0; v(t)=0;
        clear t;
        %
        Normin2 = [h(:,end,:) - h(:, 1,:), -diff(h,1,2)];%二阶差分?
        Normin2 = Normin2 + [v(end,:,:) - v(1, :,:); -diff(v,1,1)];
        %
        FS = (Normin1 + beta*fft2(Normin2) + mybeta_pixel*fft2(u)+mybeta_pixel*fft2(1-bu))./Denormin;
        S = real(ifft2(FS));
        %%
        beta = beta*kappa;
        if wei_grad==0
            break;
        end
    end

6.6 更新mybeta_pixel,直至大于mybeta_pixel跳出,函数L0Deblur_dark_chanelBD结束。

    mybeta_pixel = mybeta_pixel*kappa;
end
%
end

6.7 参考本文的论文:根据代码,对应的模型为

求解过程为:

    输入:模糊图像I,模糊核k。

    输出:清晰图像S。

    初始化:kappa=2,w,(w代表代码中的mybeta_pixel)=lambda/thre,wmax(maxbeta_pixel)=8,kappa=2.

           重复:(1)计算图像S的暗通道J和亮通道BJ。

                   (2)求解p和q。

                   (3)重复:(1)  初始化:beta=2*lambda。

                                     (2)求解g。

                                     (3) 求解S。

                                     (4)beta=beta*kappa。

                      直至 beta>betamax。

                   (4)w=w*kappa.

           直至 w>wmax。

    输出S。

和5.5相似,g的求解公式相同。p和q的求解公式为:

代码中的u和bu分别对应q和p。

S的求解公式为:

相比于5.5 ,分子只多了红色部分,分母多了2w。其他变量含义和5.5相同。

猜你喜欢

转载自blog.csdn.net/qq_36614557/article/details/111722173
今日推荐