图像分割

《数字图像处理》 – 冈萨雷斯 读书笔记

点、线和边缘检测

  • 点检测

    点检测在MATLAB中可以用函数imfilter来实现

    点检测方法

    1
    >> g = abs(imfilter(double(f), w)) >= T

    其中f 是输入图像,w是一个合适的点检测掩模, g是结果图像

    • 计算已滤波的图像,即abs(imfilter(double(f),w));

    • 使用来自己滤波的图像的数据找到T的值

    • 将已滤波的图像与T做比较

      点检测举例

    1
    2
    3
    4
    >> w = [-1 -1 -1;-1 8 -1; -1 -1 -1];
    >> g = abs(imfilter(double(f), w));
    >> T = max(g(:));
    >> g = g>=T;

    方法二

    1
    2
    >>g = imsubstract(ordfilt2(f, m*n, ones(m, n)),ordfilt2(f, 1, ones(m, n)));
    >> g = g >= T;
  • 线检测

    线检测中对指定方向的线更感兴趣,这种情况下可以与该方向相关的掩模并对其输出做出阈值处理。

    检测指定方向的线

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >> w = [2 -1 -1 ; -1 2 -1; -1 -1 2];
    >> g = imfilter(double(f), w);
    >> gtop = g(1:120, 1:120);
    >> gtop = pixeldup(gtop, 4);
    >> subplot(1,2,1);
    >> gbot = g(end-119:end, end-119:end);
    >> gbot = pixeldup(gbot, 4);
    >> g = abs(g);
    >> T = max(g(:));
    >> g = g >= T;

    b 图是对a 进行 $-45^.$ 检测器处理后的节刚过,下面两幅分别是它的左上角和右下角的放大图,e 是b 的绝对值 f 是满足条件 g>= T的所有点

    函数pixeldup

    ​ pixeldup(m,n)————%pixeldup函数是将图像扩大mn倍,通过复制每个像素点mn次。

    函数edge

    边缘检测的基本意图是使用如下两个基本准则之一在图像中找到亮度快速变化的地方:

    • 找到亮度的一阶导数在幅度上比指定的阈值大的地方
    • 找到亮度的二阶导数有零交叉的地方
    1
    [g, t] = edge(f, 'method', parameters)

    其中f 是输入图像 , method 是下表中的方法

    输出中 g是一个逻辑数组 ,其值如下决定:

    ​ 在f 中检测到边缘的位置为1, 在其他位置为 0

    t 参数是可选的,它给出edge使用的阈值,以确定那个梯度值足够大到可以称为边缘点。

    Sobel边缘检测器

    1
    [g, t] = edge(f, 'soble', T, dir)
    • 其中f 是输入图像,T 是一个指定的阈值 ,dir指定检测边缘的首选方向:‘horizontal’、’vertical’、 或’both’
    • g 是在被检测到边缘的位置处为 1而在其他位置为0 的逻辑类图像
    • 输出参数t 是可选的,它是函数edge所用的阈值
    • 若指定了T的值,则t = T ; 否则,若T 未被赋值 ,则函数edge会令t 等于它自动确定的一个阈值,然后用于边缘检测。
    • 在输出参量中要包括t的主要原因之一是为了得到一个阈值的初始值
    • 若使用语法 g = edge(f) 或 [g, t] = edge(f) ,则函数edge会默认使用Sobel 检测器

    Prewitt边缘检测器

    1
    [g, t] = edge(f, 'prewitt',T, dir)

    Prewitt 检测器比Sobel 检测器在计算上简单一点,但是比较容易产生一些噪声

    Roberts边缘检测器

    该检测器是最古老的边缘检测器之一,它也是最简单的一种边缘检测器;经常用于硬件的实现,因为既简单又快速。

    Laplacian of a Gaussian 检测器

    1
    [g, t] = edge(f, 'log', T, sigma)

    其中sigma是标准偏差,默认值为2

    零交叉检测器

    该检测器基于与LOG方法相同的概念,但卷积是使用指定的滤波函数H执行的

    1
    [g, t] = edge(f, 'zerocross',T, H)

    Canny边缘检测器

    该检测器是使用函数edge的最有效边缘检测器

    1
    [g, t] = edge(f, 'canny', T, sigma)
    • 其中T 是一个向量, T= [T1,T2]
    • sigma 是平滑滤波器的标准偏差
    • t 是一个二元向量,该向量包含该算法用到的两个阈值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >> [gv, t] = edge(f,'sobel','vertical');
    >> gv = edge(f, 'sobel', 0.15, 'vertical');
    >> gboth = edge(f, 'sobel', 0.15);
    >> w45 = [-2 -1 0;-1 0 1; 0 1 2]
    >> g45 = imfilter(double(f), w45, 'replicate');
    >> T = 0.3 * max(abs(g45(:)));
    >> g45 = g45 >= T;
    >> f45= [0 1 2;-1 0 1;-2 -1 0]
    >> h45= imfilter(double(f), f45,'replicate');
    >> T = 0.3 * max(abs(h45(:)));
    >> h45 = h45 >= T;

    a . 原图像

    b .使用带有自动确定的阈值的一个垂直Sobel 掩模后, 函数edge导致的结果

    c .使用指定阈值后的结果

    d .使用指定阈值来决定垂直边缘和水平边缘的结果

    e .使用函数imfilter 计算 45° 边缘的结果

    f . 使用函数imfilter 计算 -45° 边缘的结果

    Sobel、LOG和Canny 边缘检测器的比较

    1
    2
    3
    4
    5
    6
    >> [g_sobel_default, ts] = edge(f, 'sobel');
    >> [g_log_default, tlog] = edge(f, 'log');
    >> [g_canny_default, tc] = edge(f, 'canny');
    >> g_sobel_best = edge(f, 'sobel', 0.05);
    >> g_log_best = edge(f, 'log', 0.003, 2.25);
    >> g_canny_best = edge(f, 'canny', [0.04 0.10], 1.5);

    ​ 左列: Sobel、LOG 和 Canny 边缘检测器使用默认选项产生的结果

1
右列:交互地显示原图像的主要特征,减少了无关的细节
1
综合所有,Canny 边缘检测器产生的最好结果

使用Hough变换的线检测

寻找并链接图像中线段的处理方式

  • 函数sparse

    给是一个矩阵,用函数sparse把他转换成稀疏矩阵

1
S = sparse(A)

更常用的方法:

1
S = sparse(r, c, s, m, n)
  • r 和 c 分别是我们希望转换为稀疏矩阵的矩阵中非零元素的行和列索引向量

  • S 是一个向量,它包含有相应于索引对(r, c) 的值

  • m n 是结果矩阵的行维数和列维数

  • 函数full

    给出任意一个稀疏矩阵,用full 函数来获得完整的矩阵

1
A = full(S)
  • 使用hough变换做峰值检测

    • 找到包含有最大值的hough变换单元并记下它的位置
    • 把第一步中找到的最大值点的邻域中的hough变换单元设为零
    • 重复该步骤,直到找到需要的峰值数时为止,或者达到一个指定的阈值时为止
  • 函数houghpeaks

    解决上述所讲的问题

  • 使用hough变换做先检测和链接

    一旦hough变换中识别出了一组候选的峰被,则他们还要留待确定是否存在与这些峰值相关的线段以及它们的起始和结束为止。对每一个峰值来说,第一步是找到图像中影响到峰值的每一个非零值点的位置。因此,编写了函数houghpixels

    这里使用该函数来找到的位置相关的像素必须结合成线段,

  • 函数houghlines采用下面的策略

  • 使用hough变换做先检测和链接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    [H, theta, rho] = hough(f, 0.5);
    imshow(imadjust(mat2gray(H)),'XData',theta,'YData',rho,'InitialMagnification','fit'),axis on, axis normal
    xlabel('\theta'),ylabel('\rho')
    [r, c] = houghpeaks(H, 5);
    hold on
    plot(theta(c), rho(r), 'linestyle', 'none', 'marker', 's', 'color', 'w')
    lines = houghlines(f, theta,rho,r,c)
    figure, imshow(f),hold on
    In images.internal.initSize (line 71)
    In imshow (line 309)
    for k = 1:length(lines)
    xy = [lines(k).point1 ; lines(k).point2];
    plot(xy(:, 2),xy(:,1),'LineWidth', 4, 'Color', [.6 .6 .6]);
    end

阈值处理

  • 全局阈值处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
T = 0.5*(double(min(f(:))) + double(max(f(:))));
done = false;
while~done
g = f >= T;
Tnext = 0.5*(mean(f(g))+mean(f(~g)));
done = abs(T - Tnext) < 0.5;
T = Tnext;
end
T2 = graythresh(f);
T2 * 255
bw = im2bw(f, T2);

  • 局部阈值处理

    全局阈值处理方法在背景照明不均匀时有可能失效,在这种情况下

    • 针对照明问题做预处理以补偿图像,然后再对预处理后的图像采用全局阈值处理