图像修复中偏微分方程法的有限元法

Using Finite Element Method for Partial Differential Equation Methods in Image Inpainting

如何遍历损坏的灰度图像,在不检查未损坏的像素的情况下修复其中所有损坏的像素?

如有任何帮助,我们将不胜感激。

P.S。我有一个算法可以通过插入周围的像素来修复损坏的像素,但我不能在整个图像上使用这个算法,因为它会花费太长时间。

这是算法(伪代码):

Ek[m, n] = Ik[m − 1, n] + Ik[m + 1, n]+ Ik[m, n − 1] + Ik [m, n + 1] − 4I[m, n]
Ik+1[m, n] = Ik[m, n] + α Ek[m, n]

其中error是Ek,α是系数,Ik是第k次迭代的图像。

据我了解您的问题,您正在寻找一种遍历二维数组的每个像素并在找到 "corrupted" 像素时执行某些操作的方法。不知道你对 "corrupted" 的定义是什么,我会假设 "corrupted" 你的意思是 isnan - 不是数字。那么你的算法就没有意义了(因为你将 NaN 平均到你的校正像素值中,这会给你一个 NaN)。因此,我将假设该算法只是简单地用它最近的非对角线邻居的平均值完全替换像素:

Ak+1[m, n] = 1/4 * ( Ak[m − 1, n] + Ak[m + 1, n]+ Ak[m, n − 1] + Ak [m, n + 1] )

如果我真的误解了你,希望你无论如何都能从我的回答中得到答案。

首先:

% Make a sample 'corrupted' array
A = rand(100,100);
A(A>0.9) = NaN; % ~10% corrupted

现在,问题变得复杂了,因为如果有两个损坏的像素彼此相邻,以及在阵列的边缘,该算法就会失败。我们稍后会担心。

简单(但不起作用)的方法

您可以使用

找到所有损坏的像素
nA = isnan(A); % Boolean array the size of A where each corrupted pixel value is equal to 1

并且,如果您愿意,可以使用

获取它们的索引
I = find(nA); % Finds the indices of the above using linear indexing
[m,n] = find(nA); % Finds the indices using subscript indexing

如果您是 Matlab 的新手,这里的有趣读物可能是:“logical arrays", "find" and "linear indexing”。 我们还需要 A 的大小,所以让我们将其放入工作区

sA = size(A);

然后您遍历所有索引并应用该算法。

for j = 1:length(I)
    i = I(j); %j'th index
    [m,n] = ind2sub(sA,i); % Change linear indices to subscripts
    A(m,n) = 1/4 * ( A(m−1,n) + A(m+1,n)+ A(m,n−1) + A(m,n+1) );
end

更复杂(并且实际有效)的方法

如前所述,当周围有边缘时,以及周围有两个或更多 NaN(您可以将其视为微小的边缘)时,算法会出现问题。为了处理边缘问题,我们将环绕边界,make your image into a torus (although a 1 pixel padding 也可以)。然后我们将迭代 A 根据最近邻方法替换像素。我必须允许 3 和 2 邻居替换,以使其在严重损坏的图像上工作。可以很容易地修改代码来阻止它。无论如何,这是工作示例:

A = peaks(100);
A(rand(size(A))>0.3) = NaN; % 70% corrupted image
sA = size(A);

nrep = [1 1 1]; % Initialise as nonzero
imagesc(A); drawnow; % Show what is happening
while any(isnan(A(:)))
    getA = @(m,n) A(mod(m-1,sA(1)-1)+1,mod(n-1,sA(2)-1)+1); % Wrap the image around the edges
    numA = @(m,n) sum(isnan([getA(m+1,n),getA(m-1,n),getA(m,n+1),getA(m,n-1)])); % Number of neighbouring NaNs
    for j = 1:numel(A);
        if isnan(A(j));
            [m,n] = ind2sub(sA,j);
            switch numA(m,n)
                case 0
                    cA = 1/4 * ( getA(m-1,n) + getA(m+1,n) + getA(m,n-1) + getA(m,n+1) );
                    nrep(1) = nrep(1) + 1;
                case 1
                    cA1 = 1/3 * ( getA(m+1,n) + getA(m,n-1) + getA(m,n+1) );
                    cA2 = 1/3 * ( getA(m-1,n) + getA(m,n-1) + getA(m,n+1) );
                    cA3 = 1/3 * ( getA(m-1,n) + getA(m+1,n) + getA(m,n+1) );
                    cA4 = 1/3 * ( getA(m-1,n) + getA(m+1,n) + getA(m,n-1) );
                    cAs = [cA1 cA2 cA3 cA4];
                    ok = ~isnan(cAs); ok = find(ok,1); % find first cA# which is not a NaN
                    cA = cAs(ok);
                    nrep(2) = nrep(2) + 1;
                case 2
                        cA1 = 1/2 * ( getA(m+1,n) + getA(m,n+1) );
                        cA2 = 1/2 * ( getA(m+1,n) + getA(m,n-1) );
                        cA3 = 1/2 * ( getA(m-1,n) + getA(m,n+1) );
                        cA4 = 1/2 * ( getA(m-1,n) + getA(m,n-1) );
                        cA5 = 1/2 * ( getA(m+1,n) + getA(m-1,n) );
                        cA6 = 1/2 * ( getA(m,n+1) + getA(m,n-1) );
                        cAs = [cA1 cA2 cA3 cA4 cA5 cA6];
                        ok = ~isnan(cAs); ok = find(ok,1); % find first cA# which is not a NaN
                        cA = cAs(ok);
                        nrep(3) = nrep(3) + 1;
                case 3
                    continue
                case 4
                    continue
            end
        A(j) = cA; % Replace element
        end
    end
    imagesc(A); drawnow; pause(0.01); % Show what is happening
end

注释掉带有 imagesc 的行以禁止绘制图形(看起来很酷;))。代码有些摇摇欲坠,可以改进很多,但它运行得很好:

原创

重建形式 50% 腐败

重建形式 70% 腐败

蜂群思维法(我的首选方法)

知道要 google 做什么,因此得出 this 段代码。根据需要进行调整。