图像的边缘检测和缺失修复(附matlab代码)

2023-05-16

       最近在数学建模过程中老师给了个图片分别在清晰、有噪声及模糊状态下对其进行边缘检测的题目,最后一题是将图片中一部分抠出后将图片按照剩余图片的特征进行修复,整个问题涉及到人工智能及计算机视觉的领域较多,和队友三个人三天时间学到了不少东西,在这里对我们三个人的研究成果做一个总结,顺便和各位有需要的程序猿互相交流一波,欢迎评论。

———————————————————

目录:

1. 清晰图片的边缘检测

  1.1 5种边缘检测算子的对比

  1.2 Canny算子边缘检测

2. 噪声干扰下的图片边缘检测

  2.1 5种去噪方式的对比

  2.2 改进的Canny梯度幅值运算进行边缘检测

  2.3 对4种不同种类噪声进行分析

3. 模糊干扰下的图片边缘检测

  3.1 图片7种预处理方式的对比

  3.2 定义模糊度判断最优图片预处理方法

  3.3 对4种不同种类模糊进行分析

4. 基于纹理合成的快速自适应的自然图像缺失补全算法


好~由于整个项目我们是通过MATLAB完成的,那么我们先从如何安装MATLAB这个软件以及如何创建一个工程文件开始慢慢讲起......首先需要去...(不开玩笑,直接步入正题)

1. 清晰图片的边缘检测

  1.1 5种边缘检测算子的对比

    其实每种不同的边缘检测算子都是有模板的,至于他们的模型和原理可以自行上网查找,在这里只对他们做一个效果对比。

目前最流行的几种边缘检测有Roberts算子、Prewitt算子、Sobel算子、Canny算子和Log算子,这几种算子对图像的边缘提取都有着一定的应用,用他们对同一张比较简单的黑白图片进行边缘检测可以看出效果的不同,效果图如下:

                                    

    对比一下就不难发现,canny算子检测效果是明显高于其他几种算子的,保留的信息更多,其它算子对清晰的图片检测都这个diao样就更不用说模糊和加噪声的图片了,所以后面只采用Canny来提取。

各算子具体的matlab代码:

Canny算子:

%Canny算子
close all
clear all
clc
I=imread('timg.jpg');   %导入路径下的图片
U=I;
I=rgb2gray(I);    %如果是灰度图片的话需要注释掉
I=im2double(I);
J=imnoise(I,'gaussian',0,0);
[K,thresh]=edge(J,'canny');
figure;
subplot(121);imshow(U);
xlabel('原图');
subplot(122);imshow(K);
xlabel('Canny检测');

Roberts算子:

clear all; close all;
I=imread('rice.png');  %导入路径下的图片
I=rgb2gray(I);    %如果是灰度图的话需要注释掉
I=im2double(I);
[J, thresh]=edge(I, 'roberts', 35/255);
figure;
subplot(121);  imshow(I);
xlabel('原图');
subplot(122);  imshow(J);
xlabel('roberts检测');

Prewitt算子:

clear all; close all;
I=imread('cameraman.tif');
I=rgb2gray(I);
I=im2double(I);
[J, thresh]=edge(I, 'prewitt', [], 'both');
figure;
subplot(121);  imshow(I);
xlabel('原图');
subplot(122);  imshow(J);
xlabel('Prewitt检测');

Sobel算子:

I=imread('gantrycrane.png');
I=rgb2gray(I);
I=im2double(I);
[J, thresh]=edge(I, 'sobel', [], 'horizontal');
figure;
subplot(121);  imshow(I);
xlabel('原图');
subplot(122);  imshow(J);
xlabel('Sobel检测');

Log算子:

I=imread('cameraman.tif');
I=rgb2double(I);
I=im2double(I);
J=imnoise(I, 'gaussian', 0, 0.005);
[K, thresh]=edge(J, 'log', [], 2.3);
figure;
subplot(121);  imshow(J);
xlabel('原图');
subplot(122);  imshow(K);
xlabel('Log检测');

  1.2Canny算子边缘检测

     在这里对Canny的相关原理做个补充,Canny的原理其实还是很简单的,大致分为下面几步:

    Step1:使用高斯滤波对图像进行降噪处理;

    Step2:使用一阶偏导的有限差分来计算梯度的幅值和方向;

               梯度幅值 M(x,y) 和梯度方向 \theta(x,y) 的计算公式如下:

                                                                    M(x,y)=\sqrt{E_{x}(x,y)^{2}+E_{y}(x,y)^{2}}

                                                                           \theta (x,y)=arctan\frac{E_{y}(x,y)}{E_{x}(x,y)}

        其中,E_{x}(x,y)^E_{y}(x,y)分别为边缘通过点乘Sobel算子的到的不同方向梯度值,其计算公式如下:

                                          

    Step3:对梯度幅值进行非极大值抑制;

       由于在高斯滤波的过程中有将边缘宽度放大的可能,因此为使边缘宽度尽量为一个像素点,我们需要过滤非边缘点。若一个像素点属于边缘点,则此像素点在梯度方向上的梯度值最大,否则其灰度值为0。计算公式如下: 

                                                         

    Step4:使用双阈值算法检测和连接边缘。

        这是该算子最核心的一步,主要思想设置两类阈值,上阈值与下阈值。若梯度幅值小于下阈值,即认为是非边缘信息,将其排除(像素值设为0);若梯度幅值介于下阈值与上阈值之间,若该像素点和边缘相连则认为其是连续边缘的一部分,否则排除掉;若梯度幅值大于上阈值,则认为其是边缘。

       整个算法流程图如下:

                            

       Canny对灰度图的检测效果还ok,那么Canny对彩色图片提取效果咋么样呢。。也进行了尝试,效果还算勉强,但是对于很复杂的彩色图片就不行了,简单的还是ok的,效果图如下:

                                                   

有没有被香蕉君的笑容迷惑到 ,毕竟当代青年必须要在哲♂学中研究学习才有动力~

然后8,其实我有个想法就是通过代码对某段视频的图像进行固定帧数的不断截取,然后不断进行边缘检测,把结果图搞成一个视频,这样子可以对视频进行不断的边缘检测了,,,,好想搞一个某鲲打篮球的线条效果hhh,有时间一定要尝试。

2. 噪声干扰下的图片边缘检测

  2.1 5种去噪方式的对比

       有了噪声干扰以后的图片和普通Canny检测后的效果是啥样子呢。。。

                                             

    超级丑陋,,,多了很多杂七杂八的线,因为噪点本身就是让某个独立的像素点或者某个独立的像素矩阵种的像素值为零造成的,所以不加改进的话机器很容易会将其判断为边缘信息,然后错误提取。因此需要对图片进行预先的去噪处理,在这试用了5种常用的去噪方式,效果图如下:

                                       

       可以看到的是不管哪种滤波方式其实都没有将噪声完全去除,只是一定程度上减少了噪声,可能在这上面看的不是很清楚,但是通过矢量图放大以后感觉中值滤波会稍微好一点,但是其实8,每种滤波方式对不同种类的噪声去噪能力不同,在这里不一一介绍,在2.3里面会对不同去噪方式对不同种类噪声的去噪效果做一个分析,在这里只针对这张图片来进行处理,所以后面对图片选择了中值滤波的处理方式。

  2.2 改进的Canny梯度幅值运算进行边缘检测

      这个模型呢是参考了一份研究生的毕业论文里面的内容:

      文献信息:靳艳红. 基于改进canny算法的图像边缘检测的研究[D].重庆师范大学,2011.

      这份文献里很清楚的把她改进以后的Canny边缘检测模型进行了说明,整个模型变化很大,从双阈值改进为单阈值,但整个模型和算法思想并不是很难,且篇幅不长,我对其进行了算法实现以后,对我们中值滤波以后的图片进行了边缘提取,效果如图:

                                                                  

        这张图和上面的检测图对比一下发现真的是好了很多了,所以当时结果出来以后,还是忍不住大喊了一句“研究生牛逼”。

但是这算法明显有很多可以改进的地方,边缘的线条太粗,如果加一个非极大值抑制其实会更好(这也是我在写这篇博客的时候想到的,当时脑子抽筋居然没想到,wtf.....有兴趣的朋友可以尝试对它进行优化一下)。

        其次就是提取后的图片中剩余的独立存在的噪点还是较多,虽然效果已经很好了,但是很多点点在上面看着就是很难受,于是8,观察了一下这张图的像素矩阵以后发现,那些独立的噪点大多还是以小于等于5×5的矩阵形式存在,于是我对这个算法又做了进一步改进,遍历整个256*256的像素矩阵,对那些5×5的独立像素矩阵进行了排除,只要这个5*5的矩阵周围一圈都没有其他像素点,那么就将整个5*5的矩阵像素值设为0即可。做出的第二次改进的检测效果图如下:

                                                                 

      这次就干净好多了,第一次剩余的大部分噪点都已经排除干净了,但是有些本来属于边缘的由于检测不完整造成的独立的边缘点也一起被排除掉了,不过舍不得羊群套不住狼,这种情况在所难免,所以我还是比较喜欢第二次改进后的结果。

两次改进的Canny算法:

close all
clear all
clc
I=imread('timg.jpg');   %导入路径下的图片
U=I;
I=rgb2gray(I);  %如果是灰度图需要注释掉
 
I=zzlb(I,3);    %3是个常用参数,可以控制滤波的程度,具体内容可自行百度
I=double(I);
%求四个方向的梯度
w=fspecial('sobel');
Fx=imfilter(I,w,'replicate');      %求横边缘
w=w';
Fy=imfilter(I,w,'replicate');      %求竖边缘
for i=1:256
    for j=1:256
        if i-1>0&&j+1<=256&&i+1<=256&&j-1>0
            F45(i,j)=I(i-1,j+1)-I(i+1,j-1);
            F135(i,j)=I(i+1,j+1)-I(i-1,j-1);
        else
            F45(i,j)=I(i,j);
            F135(i,j)=I(i,j);
        end
    end
end
for i=1:256
    for j=1:256
        Ex(i,j)=Fx(i,j)+[F45(i,j)+F135(i,j)]/2;
        Ey(i,j)=Fy(i,j)+[F45(i,j)-F135(i,j)]/2;
        %像素的梯度幅值
        M(i,j)=sqrt(Fx(i,j)^2+Fy(i,j)^2+F45(i,j)^2+F135(i,j)^2);
        %梯度方向
        Q(i,j)=atan(Ey(i,j)/Ex(i,j));
    end
end
 
m=256;n=256;
g=(1/(m*n))*(sum(M(:)));
for i=1:256
    for j=1:256
        M1(i,j)=(M(i,j)-g)^2;
    end
end
o=sqrt((1/(m*n))*sum(M1(:)));
%求阈值
k=g+o;
 
for i=2:255
    for j=2:255
        if M(i-1,j)>k||M(i-1,j+1)>k||M(i-1,j-1)>k||M(i,j-1)>k||M(i,j+1)>k||M(i+1,j+1)>k||M(i+1,j-1)>k||M(i+1,j)>k
            M(i,j)=1;
        else
            M(i,j)=0;
        end
    end
end
M2=M;
%第二次改进,剔除掉独立的噪点
for i=4:253
    for j=4:253
        if M(i-3,j-3)==0&&M(i-3,j-2)==0&&M(i-3,j-1)==0&&M(i-3,j)==0&&M(i-3,j+2)==0&&M(i-3,j+1)==0&&M(i-3,j+3)==0&&M(i-2,j-3)==0&&M(i-2,j+3)==0&&M(i-1,j-3)==0&&M(i-1,j+3)==0&&M(i,j-3)==0&&M(i,j+3)==0&&M(i+1,j-3)==0&&M(i+1,j+3)==0&&M(i+2,j-3)==0&&M(i+2,j+3)==0&&M(i+3,j-3)==0&&M(i+3,j-2)==0&&M(i+3,j-1)==0&&M(i+3,j)==0&&M(i+3,j+3)==0&&M(i+3,j+2)==0&&M(i+3,j+1)==0                                        
            M(i,j)=0; M(i-1,j-1)=0;  M(i-1,j)=0; M(i-1,j+1)=0; M(i,j-1)=0; M(i,j+1)=0;M(i+1,j+1)=0;M(i+1,j)=0; M(i+1,j-1)=0; 
           M(i-2,j-2)=0;M(i-2,j-1)=0;M(i-2,j)=0; M(i-2,j+1)=0; M(i-2,j+2)=0;M(i-1,j-2)=0;M(i-1,j+2)=0;M(i,j-2)=0;M(i,j+2)=0;M(i+1,j-2)=0; M(i+1,j+2)=0;
           M(i+2,j-2)=0; M(i+2,j-1)=0;M(i+2,j)=0;M(i+2,j+1)=0; M(i+2,j+2)=0;
        end
    end
end
 
I=U;
I=rgb2gray(I);
I=im2double(I);
J=imnoise(I,'gaussian',0,0);
[K,thresh]=edge(J,'canny');
figure;
subplot(141);imshow(U);
xlabel('原图');
subplot(142);imshow(K);
xlabel('传统canny');
subplot(143);imshow(M2);
xlabel('改进一次canny');
subplot(144);imshow(M);
xlabel('改进两次canny');

中值滤波的函数(zzlb(I,3)):

%------
 I:原图片(灰度图)的像素矩阵
 m:中值滤波参数,不同参数有着不同程度的滤波效果
%------

%中值滤波的函数代码
function [ img ] = zzlb( image, m )
    n = m;
    [ height, width ] = size(image);
    x1 = double(image);
    x2 = x1;
    for i = 1: height-n+1
        for j = 1:width-n+1
            mb = x1( i:(i+n-1),  j:(j+n-1) );
            mb = mb(:);
            mm = median(mb);
            x2( i+(n-1)/2,  j+(n-1)/2 ) = mm;
 
        end
    end
    img = uint8(x2);
end

  2.3 对4种不同种类噪声进行分析

       上面提到过不同的滤波方式其实对不同种类噪声的过滤效果也是不同的,所以改进后的算法的灵敏度和稳定性有待验证,于是我们给同一张图片添加不同种类的噪声并且在不进行任何滤波处理的情况下,分别用传统Canny和改进后的Canny进行边缘检测做出了效果对比图,为了凸显效果的好坏用了另一张比较好检测的图片试了一下:  

                                     

        可见该算法其实稳定性还不错,除了对乘性噪声的抗干扰能力有待增强以外,其它的三种噪声检测效果都还是很满意的了。最后忍不住再喊一句“还是研究生牛逼!”,天气冷(tql),我睡了(wsl)。

3. 模糊干扰下的图片边缘检测

  3.1 图片7种预处理方式的对比

      和上面一样,先给出加了模糊后图片和普通Canny算子检测的效果图,让大家康康是啥鸭子,,,为了增大效果,换了轮廓比较清楚的图:

                                                       

         观察图片像素矩阵可以发现,其实模糊就是让原本差值较大的两个点的像素值更加接近,减少了差值,造成整张图片的模糊效果。而边缘检测其实就是通过判断像素值差距较大的地方,所以对检测造成了干扰,给一个边缘附近的像素矩阵图加深下理解:

                    

        和噪声一样,首先需要对其进行预处理,针对处理后的图片再采用Canny算子对其进行检测,对上面那张图的清晰图进行略微的模糊以后,效果图如下:

                    

         最后几张图有点恐怖,是因为过度提取造成的,把每个轮廓都给提取出来了,不过也应该反应出,最后几种处理方案是对超级模糊的图片进行预处理的最好方式。但是在这种轻微模糊状态下,我们认为还是Prewitt锐化处理比较不错(图中已标红)。

PS:最后三种处理方法是一个层层递进的关系,后面的方法是在前面处理的结果上进一步处理。

这样子的话,对图片分别做一个2倍、5倍和10倍的模糊,然后做一个对比图如下:

                  

为什么只做这三个方法的对比图呢,,,,见 3.2

  3.2 定义模糊度判断最优图片预处理方法

       上面说过了,图片越模糊像素矩阵中各像素值应该越靠近,如边缘两侧像素值本身应该具有明显的差值,但经过模糊处理以后差值明显变小,因此可以通过计算图片像素矩阵的标准差大小来对图片的模糊程度进行评价。(此处的模糊度是我们自己定义的,不是官方标准),像素矩阵的标准差计算公式就不用给了8,只给出模糊度的计算公式:

                                                                    

其中M_i为第i种程度模糊后的模糊度大小,a_i为第i种程度模糊后图片像素矩阵的标准差大小,b为原图片像素矩阵标准差大小。

         根据该计算公式,用Photoshop对图片不同程度的模糊处理后做出了模糊度大小随模糊程度变化的曲线图如下:

                                                  

       很明显这个模糊度是随着模糊程度增大而增大的,那么根据这个标准,用程序不断的去遍历不同程度模糊下各种处理方法的检测效果,然后根据肉眼判断(没错,就是肉眼判断......没有找到更好的判断标准,只能这鸭子了)选取最好的处理方案,最后给出了方案选取表格如下: 

                                              

        根据这个表格就可以判断什么时候该使用什么方法去处理图片了。

(知道为啥上面只对那三种方法进行对比了吧)

  3.3 对4种不同种类模糊进行分析

         还是和噪声图片一样,不同处理方法对不同种类的模糊有不同的效果。(哈?模糊还有种类?)没错!就是有种类,噪声有不同的种类,模糊也有da,在这里我们共收集了四种常见模糊:马赛克模糊、高斯模糊、运动模糊和径向模糊,每种模糊造成的效果都不同(可以自行查阅相关资料)。这三种算法对四种模糊的处理效果对比图如下:(写到这里突然发现好像这三个没做完整,那就把做了的给出吧,有时间再补充)

                         

                          

                             

       总结就是,,Laplacian锐化算子的效果最好,灵敏度最低,其他三种处理方法灵敏度都还是挺高的,但是8,,,高斯模糊是什么算子都可以搞它,很没有地位的一种模糊,,,

4. 基于纹理合成的快速自适应的自然图像缺失补全算法

          这个还是超好玩的,根据需求从Github找到了一份代码,玩了半天,,,,

          啥叫图像缺失补全呢,其实就是给你一张图片,随便扣掉一块,它可以帮你还原,或者说把图片中的某个人或者物给搞掉,类似于把他(或它)从图片里抹除,,

         上一张图康康,假设原来一张图是这个样子:

                                                     

    然后你看图片里面那个男的不爽,想搞掉他,那,,,,

                                                     

       然后,,,,,,,,,,他就没了,,,,,,

                                                     

       可能非程序猿看到这里很想吐槽,这不就几下PS的事情吗,我手动也可以把他搞掉,甚至可以P的更真实,,,,那你可能无法做到完全让机器来做这个过程,让电脑自动来把这个图像补全可没你想的那么简单,需要设计一个非常高效算法来让计算机自动完成这整个过程,,,,这种算法都是各种大牛研究了很久的东西,反正我是没看懂,就简要提一下它的算法思想好了,,,,它其实就是通过缺失区域的周围的像素点来判断待修复的区域哪个像素点应该是什么颜色,从外往内不断插值的过程,直到所有像素点都被填充完毕。。。给个图理解一下:

                                                    

        当然具体细节肯定没有这么简单啦,最后因为时间问题也没有对算法做出自己的改进,有兴趣的大佬可以去研究下,,

        然后不知道大家有没有注意到,这个算法的名字有个关键词,是对自然图片进行修复的一种算法,上面搞掉小男孩那张图已经可以说明它的效果是非常不错的了,那它对非自然图片的效果如何,,,,也做了试验,这次先给一张做出的最满意的效果图:

                                                     

先卖个关子,你能看出哪里少了点什么吗?

没错,就是少了Tom的女朋友Honey,

                                             

其实原图是这个样子的,,,毕竟Jerry和Tom才是真爱,

                                                       

为了把Jerry搞掉,,程序运行一次以后的效果如下:

                                                      

       和上面那张图对比一下,确实这个算法对非自然图片的修复效果很一般,还残留了很多Jerry身体的某个部分,,,然后继续手动选取需要进一步修复的部分(相当于一个迭代过程),大约是不断修复了5 6次的鸭子,最后得到了上面那张比较满意的效果图。 虽然很笨拙,每次需要人工干预去告诉机器哪里要重新搞,但是也还是能接受的,毕竟对非自然图片不是它的强项,,,,,强人锁男可不太好,这样会男上加男,,造成前后为男,,,

       其实现在很多智能算法也可以对这类问题进行解决,比如用神经网络对图片训练集训练以后来填补空缺,虽然效果肯定是很不错的,但是用这种方法来研究一个数学建模问题没有多大的意义,而且作为一个本科生,那些东西是打死我也研究不出什么东西的,只能是套用套用再套用,,,

基于纹理合成的快速自适应的自然图像补全算法:

main.m:

close all; % closes all figures
clear;
im = im2single(imread('../samples/river.jpg'));
%im = im2single(imread('../samples/water_small.jpg'));
patch_size = 21;
figure(3), hold off, imagesc(im)
[x, y] = ginput;                                                              
target_mask = poly2mask(x, y, size(im, 1), size(im, 2)); 
hole_filling_crimnisi(im, target_mask, patch_size, 0.01, 'river');

ssd_patch_2d.m:

function [ ssd_map ] = ssd_patch_2d( I, T )
    mask = T >= 0; % -1 represents empty
    ssd_map = filter2(mask, I .* I, 'valid') + sum(sum(T .* T)) - 2 * filter2(mask .* T, I, 'valid');
end

ssd_patch.m:

function [ ssd_map ] = ssd_patch(I, T)
    ssd_map_r = ssd_patch_2d(I(:, :, 1), T(:, :, 1));
    ssd_map_g = ssd_patch_2d(I(:, :, 2), T(:, :, 2));
    ssd_map_b = ssd_patch_2d(I(:, :, 3), T(:, :, 3));
    ssd_map = ssd_map_r + ssd_map_g + ssd_map_b;
    ssd_map = normalize_2d_matrix(ssd_map);
end

set_forbid_region.m:

function [ ssd_map ] = set_forbid_region( ssd_map, target_mask, patch_size )
    LARGE_CONST = 100;
    hp_size = floor(patch_size / 2);
    forbid_area = imdilate(target_mask, ones(patch_size, patch_size));
    ssd_map = ssd_map + (forbid_area(hp_size + 1 : size(target_mask, 1) - hp_size,...
          hp_size + 1 : size(target_mask, 2) - hp_size) * LARGE_CONST);
end

point_fil.m:

function [ value ] = point_fil( I, h, patch_size, y, x )
hp_size = floor(patch_size / 2);
value = sum(sum(I(y - hp_size : y + hp_size, x - hp_size : x + hp_size) .*  h));
end

normalize_2d_matrix.m:

function [ norm_m ] = normalize_2d_matrix( m )
    norm_m = (m - min(min(m))) / (max(max((m)) - min(min(m))));
end

norm_v.m:

function [ norm_vec ] = norm_v( target_mask, y, x )
    window = target_mask(y - 1 : y + 1, x - 1 : x + 1);
    center_value = window(2, 2);
    window(window == 0) = center_value;
    fx = window(2, 3) - window(2, 1);
    fy = window(3, 2) - window(1, 2);
    if fx == 0 && fy == 0
        norm_vec = [1; 1] / norm([1; 1]); 
    else
        norm_vec = [fx; fy] / norm([fx; fy]);
    end
end

isophote.m:

function [ isoV ] = isophote(im, y, x)
    window = im(y - 1 : y + 1, x - 1 : x + 1);
    center_value = window(2, 2);
    window(window == -1) = center_value;
    fx = window(2, 3) - window(2, 1);
    fy = window(3, 2) - window(1, 2);
    if fx == 0 && fy == 0
       isoV = [0; 0]; 
    else
        I = sqrt(fx^2 + fy^2);
        theta = acot(fy / fx);
        [isoV_x, isoV_y] = pol2cart(theta, I); 
        isoV = [isoV_x; isoV_y];
    end
end

hole_filling_crimnisi.m:

function [ syn_im ] = hole_filling_crimnisi( I, target_mask, patch_size, tol, out_file_name )
    figure(5), imshow(I);
    I = repmat((~target_mask), 1, 1, 3) .* I;
    figure(11), imshow(I);
    out_file_name_mask = strcat('../results/', out_file_name, '_hole_mask.jpg');
    imwrite(I, out_file_name_mask);
    syn_im = I;
    syn_im(syn_im == 0) = -1;
    hp_size = floor(patch_size / 2);
    confidence_map = double(~target_mask);
    i = 1;
    while any(target_mask(:) == 1)
        [t_candi_x, t_candi_y] = fill_front(target_mask);
        [template, y, x, confidence] = choose_template_criminisi(syn_im, t_candi_y, t_candi_x, target_mask, confidence_map, patch_size);
        ssd_map = ssd_patch(syn_im, template);
        ssd_map = set_forbid_region( ssd_map, target_mask, patch_size );
        patch = choose_sample(ssd_map, tol, syn_im, patch_size, 0.0001); 
        %figure(6), imshow(patch); 
        tplt_mask = template >= 0;
        %cut_mask = imdilate((~t_mask), ones(overlap * 2 + 1, overlap * 2 + 1));
        patch = tplt_mask .* template + ~tplt_mask .* patch;
        %figure(7), imshow(patch);
        syn_im(y - hp_size : y + hp_size, x - hp_size : x + hp_size, :) = patch;
        figure(8), imshow(syn_im); 
        target_mask(y - hp_size : y + hp_size, x - hp_size : x + hp_size) = 0;
        %figure(9), imshow(target_mask);
        confidence_map(y - hp_size : y + hp_size, x - hp_size : x + hp_size) =...
            confidence_map(y - hp_size : y + hp_size, x - hp_size : x + hp_size)...
            + ((~tplt_mask(:, :, 1)) * confidence);
        i = i + 1;
    end
figure(10), imshow(syn_im);
out_file_name = strcat('../results/', out_file_name, '_hole.jpg');
imwrite(syn_im, out_file_name);
end

find_err_patch_2D.m:

function [ err_patch ] = find_err_patch_2D( T, patch, overlap)
    diff = T(1 : overlap, :) - patch(1 : overlap, :);
    err_patch = diff .* diff;
end

find_err_patch.m:

function [ err_patch ] = find_err_patch( T, patch, overlap)
    err_patch_r = find_err_patch_2D( T(:, :, 1), patch(:, :, 1), overlap);
    err_patch_g = find_err_patch_2D( T(:, :, 2), patch(:, :, 2), overlap);
    err_patch_b = find_err_patch_2D( T(:, :, 3), patch(:, :, 3), overlap);
    err_patch = err_patch_r + err_patch_g + err_patch_b;
end

find_cut_mask.m:

function [ mask ] = find_cut_mask(template, patch, overlap)
    t_size = size(template, 1);
    mask = zeros(t_size);
    mask_up = zeros(overlap, t_size);
    mask_left = zeros(t_size, overlap);
    is_up = nnz(template(1 : overlap, ceil(t_size / 2), 1) >= 0);
    is_left = nnz(template(ceil(t_size / 2), 1 : overlap, 1) >= 0);
    if is_up > 0
        err_patch = find_err_patch(template, patch, overlap);
        mask_up = cut_dp(err_patch);
    end
    if is_left > 0
        err_patch = find_err_patch(permute(template, [2 1 3]), permute(patch, [2 1 3]), overlap);
        mask_left = cut_dp(err_patch)';
    end
    mask(1 : overlap, :) = mask(1 : overlap, :) | mask_up;
    mask(:, 1 : overlap) = mask(:, 1 : overlap) | mask_left;
    mask;
end

fill_front.m:

function [ front_x, front_y ] = fill_front( target_mask )
    front = imdilate(target_mask, ones(3,3)) & ~target_mask;
    [front_y, front_x] = find(front);
end

choose_template_criminisi.m:

function [ template, y, x, conf] = choose_template_criminisi(I, t_candi_y, t_candi_x, target_mask, confidence_map,  patch_size)
   
    data = zeros(size(t_candi_y));
    confidence = zeros(size(t_candi_y));
    hp_size = floor(patch_size / 2);
    
    for i = 1 : size(t_candi_y, 1)
        yy = t_candi_y(i); xx = t_candi_x(i);
        if xx == 121 && yy == 253
            xx;
        end
        norm_vec = norm_v(target_mask, yy, xx);
        iso_v = isophote(I(:, :, 1), yy, xx);
        confidence(i) = point_fil(confidence_map, ones(size(patch_size)), patch_size, yy, xx) / (patch_size^2);
        data(i) = abs(dot(iso_v, norm_vec(:, 1)));
    end
    priority = confidence + data;
    [priority, sorted_id] = sort(priority, 'descend');
    t_candi_y = t_candi_y(sorted_id);
    t_candi_x = t_candi_x(sorted_id);
    confidence = confidence(sorted_id);
    data = data(sorted_id);
    y = t_candi_y(1); x = t_candi_x(1);
    conf = confidence(1);
    template = I(y - hp_size : y + hp_size, x - hp_size : x + hp_size, : );
end

choose_sample.m:

function [patch] = choose_sample( ssd_map, tol, I, patch_size, small_cost_value)
    min_c = min(min(ssd_map));
    min_c = max(min_c,small_cost_value);
    [y, x] = find(ssd_map <= min_c * (1 + tol));
    index = randi(size(y, 1));
    hp_size = floor(patch_size / 2);
    y = y(index) + hp_size; % transfrom to I coordinate
    x = x(index) + hp_size;
    patch = I((y - hp_size) : (y + hp_size), (x - hp_size) : (x + hp_size), :);
end

最后给大家推荐一本书,,,

                                                    

       这本书对类似问题还是很有帮助的,整个建模过程也参考了很多,,网上也有电子版和对应的配套源文件,给大家安利一波,,,

       估计以后没什么时间再去专门长时间的研究这方面的东西了,,,不过还是感觉这个领域还是很有意思的,也没有深到理解不透的程度,感觉本科生也是可以对现有成果进行设计和改进的,,,欢迎各位大佬在评论内一起讨论交流,有不对的地方欢迎指出,顺便可以一起研究下哲♂学。

如有侵权请联系删除,转载请附上本文链接,尊重原创,谢谢!!

      

                                                       

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

图像的边缘检测和缺失修复(附matlab代码) 的相关文章

  • docker删除无用的镜像等操作

    提供 prune命令 xff0c 用于移除不使用的镜像 容器 卷 网络 Prune images docker image prune移除没有标签并且没有被容器引用的镜像 xff0c 这种镜像称为 dangling 摇晃的 镜像 示例1 x
  • Python之requests模块-session

    http协议本身是无状态的 xff0c 为了让请求之间保持状态 xff0c 有了session和cookie机制 requests也提供了相应的方法去操纵它们 requests中的session对象能够让我们跨http请求保持某些参数 xf
  • git 对比两个分支差异

    1 显示出branch1和branch2中差异的部分 git diff branch1 branch2 stat 2 显示指定文件的详细差异 git diff branch1 branch2 具体文件路径 3 显示出所有有差异的文件的详细差
  • 操作系统中cpu如何工作

    扩充小知识 xff1a 这些硬件设备在一条总线上链接 xff0c 他们通过这条线进行数据交互 xff0c 里面的带头大哥就是CPU xff0c 拥有最高指挥权 那么它是如何工作的呢 xff1f A 取指单元 xff08 从内存中取得指令 x
  • dev/mapper的解释

    二 dev mapper目录的解释 为了方便叙述 xff0c 假设一台服务器有三块硬盘分别为a xff0c b xff0c c xff0c 每块硬盘的容量为1T 在安装Linux的时候 xff0c 先根据系统及自身的需要建立基本的分区 xf
  • Centos安装python39(其他版本也是一样的流程)

    Centos安装python39 其他版本也是一样的流程 centos安装python39 其他版本也是一样的流程 1 下载python39 可以去官网下载 xff0c 也可以去华为云下载 华为云 xff1a Index of python
  • centos 中如何启动两个rabbitmq 服务

    启动两个rabbitmq 服务 sudo RABBITMQ NODE PORT 61 5672 RABBITMQ DIST PORT 61 15672 RABBITMQ SERVER START ARGS 61 34 rabbitmq ma
  • 【码农本色】用数据解读我的2014

    转眼2014就过去了 xff0c 不禁感叹又老了一岁的同时 xff0c 却发现已经快研究生毕业了 xff0c 趁着这个活动简单总结下2014 1 实习篇 2014年一月份拿到了人生第一个实习offer xff0c 在sony这样的大公司做a
  • 出现Permission denied (publickey)的解决方法

    ssh root 64 10 240 1 161 报错 1 发现问题 在Linux终端使用ssh root 64 server ip来连接到远程服务器时 xff0c 出现Permission denied publickey 提示 2 分析
  • 23年4月开发语言最新排行榜公布

    随着时代的发展 xff0c 编程语言也在不断演化和发展 xff0c 每一种编程语言都有着其独特的特性和适用场景 在这篇博客中 xff0c 我们将来探讨一下各大编程语言的排行榜 xff0c 以及它们各自的优缺点和应用场景 下面是最新的 Tio
  • CommandNotFoundError: No command ‘conda activate‘

    前言 xff0c 在windows下使用coda 虚拟环境时 xff0c 在激活环境 conda activate env name 时 xff0c 报错找不到 conda activate 的命令 浪费了好久的时间 xff0c 找到了合适
  • Spring、SpringMVC常用注解总结

    一 Spring常用注解 64 Component xff1a 标注一个普通的Spring Bean类 64 Controller xff1a 标注一个控制器组件类 64 Service xff1a 标注一个业务层组件类 64 Reposi
  • 关于Ubuntu fix-broken 的使用

    执行命令 xff1a sudo apt fix broken install sudo apt get update sudo apt get upgrade 运行后可以解决由于依赖包缺失或错误引起的无法通过apt get来安装应用
  • java看书规划

    Java编程思想 大话设计模式 重构 改善既有代码的设计 effective java 深入理解Java虚拟机 Java并发编程实战 深入理解计算机系统 xff0c tcp ip详解 卷一 二 三 xff0c 数据结构与算法 xff08 三
  • 粗读Targeted Supervised Contrastive Learning for Long-Tailed Recognition

    相比于直接对图像进行分类 xff0c 本文更关注特征提取部分 xff0c 通过令提取的不同类特征在超球面上尽可能远离 xff0c 让属于同一类的特征尽可能靠近 xff0c 来提高模型面对样本不平衡时的分类性能 这是本文的方法和效果示意图 第
  • 运行 npm install 报错 command failed npm ERR! command C:\Windows\system32\cmd.exe /d /s /c node build.js

    运行 npm install 报错 command failed npm ERR command C Windows system32 cmd exe d s c node build js nodejs build js 具体看图片 xf
  • e2fsprogs : 预依赖: e2fslibs (= 1.42.13-1ubuntu1) 但是 1.42.13-1ubuntu1.1 正要被安装 E: 有未能满足的依赖关系

    问题 1 E 无法获得锁 var lib dpkg lock open 11 资源暂时不可用 E 无法锁定管理目录 var lib dpkg xff0c 是否有其他进程正占用它 xff1f 2 下列软件包有未满足的依赖关系 xff1a e2
  • 操原上机(二) 模拟实现“生产者-消费者”问题

    实验内容 在 windows 环境下 xff0c 利用高级语言编程环境 xff08 限定为 VS 环境或 VC 环境 xff09 调用 CreateThread 函数和相关的同步函数 xff0c 模拟实现 生产者 消费者 问题 实验过程 首
  • 普通程序员如何入门AI

    毫无疑问 xff0c 人工智能是目前整个互联网领域最火的行业 xff0c 随着AlphaGo战胜世界围棋冠军 xff0c 以及各种无人驾驶 智能家居项目的布道 xff0c 人们已经意识到了AI就是下一个风口 当然 xff0c 程序员是我见过
  • Arch Linux 安装简明流程

    Arch Linux 安装简明流程 这是一篇为 GPT EFI 引导 的电脑安装 Arch Linux xff08 双系统 xff09 的中文简明流程 xff0c 尽可能省略了可以省略的流程与文字以使得篇幅尽量短小 xff0c 基本上基于

随机推荐

  • python 数据文件上传到ftp服务器

    场景 xff1a 客户的某数据文件需要定时推送到一个第三方平台的ftp服务器上 xff0c 第三方平台会对上传过来的数据文件进行解析 一 通过FTP将文件上传到服务器 xff0c 需要满足以下几个条件 xff1a 本服务器和ftp服务器是联
  • 基于web系统的一个小型简单管理系统

    系统简介 本系统提供给暮云办公室的工作人员使用 权限包含 xff1a 检索信息 更新信息 删除信息技术路线 1 前端 xff1a html 43 ccs 43 js 采用框架 xff1a jquery 43 bootstrap 2 后端 x
  • 修改 Ubuntu 系统用户名和登录名

    在终端中 xff0c 命令行前面的字符串格式为用户名 64 主机名 路径 若要将老用户名user改为新用户名robot xff0c 请按照下面的顺序修改 xff08 0步骤可以跳过 xff09 xff1a 修改主机名 xff08 如果需要的
  • BT下载磁力下载工具,这几款,不限速

    想看个电影 xff0c 迅雷限速 xff0c 经常还因为某些原因下不了 xff0c 下载电影 xff0c BT下载工具总少不了 xff0c 今天给大家推荐这几款BT下载磁力链接下载工具 不限速下载 xff0c 超爽 xff01 一 Motr
  • ubuntu22.04桌面图标不显示的可能情况之一

    我自己的ubuntu突然不显示桌面图标了 xff0c 但文件管理器可以看到desktop目录下其实有文件的 xff0c 在网上找了很多方法也无济于事 xff0c 最后无意中点了下gnome插件里的一个选项 xff0c 问题就解决了 xff0
  • QT开发笔记(Serial Port )

    Serial Port Qt 提供了串口类 xff0c 可以直接对串口访问 我们可以直接使用 Qt 的串口类编程即可 xff0c 十分 方便 Qt 串口类不仅在 Windows 能用 xff0c 还能在 Linux 下用 xff0c 虽然串
  • ubuntu14.04版本下在目录下快捷打开终端

    在Ubuntu 14中 xff0c 您可以通过Nautilus文件管理器的右键菜单来快速打开终端窗口 xff0c 而无需切换到终端模式 具体的操作步骤如下 xff1a 打开Nautilus文件管理器 xff0c 并进入要打开终端窗口的目录
  • SQL SERVER添加注释的快捷键

    SQL SERVER添加注释 添加注释删除注释 添加注释 Ctrl 43 K xff0c C xff08 按住Ctrl xff0c 然后按K xff0c 接着按C xff09 删除注释 Ctrl 43 K xff0c U xff08 按住C
  • 多线程经典题目

    多线程编程 目录 文章目录 多线程编程目录work1work2work3work4work5work6work7work8锁的实现线程间同步唤醒 阻塞交替打印方式相关blogLambda原子类型理论锁模型Java锁底层实现 work1 sp
  • 抖音短视频脚本制作的一些技巧,快快收藏起来!

    在抖音上发布一个成功的短视频需要多方面的考虑 xff0c 其中最重要的是脚本的制作 一个好的脚本不仅可以吸引用户观看 xff0c 还可以让用户产生共鸣 xff0c 从而提高视频的传播效果 以下是不若与众科技一些关于抖音短视频脚本制作的技巧
  • java中http请求带cookie

    span class hljs built in String span urlPath 61 span class hljs string 34 你的请求链接 34 span span class hljs built in String
  • Linux系统下使用rpm安装时失败 出现错误:“依赖检测失败” 解决方法

    今天长青在重新安装yum的时候出现了这种错误 xff0c 提示 依赖检测失败 解决方法 xff1a 在命令末尾加上 nodeps force 参数意思 xff1a nodeps xff1a 不检测依赖关系 force xff1a 强制安装
  • springboot的sql日志打印与AOP实现接口调用日志打印

    Springboot的sql日志打印与AOP实现接口调用日志打印 96 1 Springboot与mybatis或者mybatisplus 打印sql执行语句 使用的是springboot中内部嵌入的日志框架 2 接口调用日志 xff0c
  • 双一流博士整理的71个OpenCV实战项目教程开放下载!

    点击上方 小白学视觉 xff0c 选择加 34 星标 34 或 置顶 重磅干货 xff0c 第一时间送达 近期小白学视觉公众号推出了多篇Python 43 OpenCV实战项目的文章 xff0c 深受小伙伴们的喜爱 最近有小伙伴推荐 xff
  • 资料分析之增长量

    一 增长量的计算 识别 xff1a 增长 43 单位 公式 xff1a 1 给出现期 基期 xff1a 增长量 61 现期 基期 2 给出现期 增长率 xff1a 增长量 61 r 现期 1 43 r 速算 xff1a 1 尾数法法 xff
  • Manjaro 基础配置及常用软件安装

    更新源 获取key https mirrors tuna tsinghua edu cn help archlinux https mirrors tuna tsinghua edu cn help archlinuxcn 安装常用工具 x
  • JS中new Date().format("YYYY-mm-dd")提示format is not a function的解决办法

    format方法已经被移除了 xff0c 赶快换个组件 xff01 如果是个懒人 xff0c 就不要再看那些自己写方法大神给的函数了 xff01 xff01 用moment xff0c npm一下子就能装好 xff0c 很好用 xff01
  • python去掉字符串中的指定字符的方法

    我们在使用 Python处理字符串的时候 xff0c 经常会遇到一些字符串中出现了指定字符 xff0c 比如以下代码 xff1a 上面代码中的 就是一个指定字符 xff0c 在 python中 xff0c 如果使用 替换为指定字符 xff0
  • linux使用yum安装JDK8

    安装步骤 xff1a 1 查看是否已安装JDK yum list installed span class token operator span grep java 2 卸载CentOS系统Java环境 yum span class to
  • 图像的边缘检测和缺失修复(附matlab代码)

    最近在数学建模过程中老师给了个图片分别在清晰 有噪声及模糊状态下对其进行边缘检测的题目 xff0c 最后一题是将图片中一部分抠出后将图片按照剩余图片的特征进行修复 xff0c 整个问题涉及到人工智能及计算机视觉的领域较多 xff0c 和队友