第八章 表示与描述

第八章 表示与描述

  • 背景
    • 提取区域及其边界的函数
    • 本章中使用的其他MATLAB和工具箱函数
    • 一些基本的实用M函数
  • 表示
    • 链码
    • 使用最小周长多边形的多边形近似
    • 标记
    • 边界线段
    • 骨骼
一.背景
提取区域及其边界的函数

提取边界是建立在分割的基础上的,对分割后的区域进行表示和描述。

  • 单元数组

单元数组能将不同类型、不同维数的数组组合在一起,方便管理使用。其分为一维和多维。

一维单元数组
>> G = image_stats(f);
>> G

G =

  1×4 cell array

    [1×2 double]    [152.8902]    [600×1 double]    [1×600 double]

形成一个1 x 4的单元数组

多维单元数组
>> F = image_stats2(f)

F =

  2×2 cell array

    [  1×2 double]    [    152.8902]
    [600×1 double]    [1×600 double]

形成一个2 x 2的单元数组

四连接和八连接

四连接:上下左右

八连接:在3 x 3的网格里除了最中间的

  • 计算连接分量(区域)

[L, num] = bwlabel(f, conn)

image

计算二值图像的连接分量,conn是四连接或者八连接,num是找到链接分量的个数。

  • 边界像素处理

g = bwperim(f, conn)

返回二值图像g,仅包含f中所有区域的边界像素。

  • 提取边界坐标

g = bwboundaries(f, conn, options)

提取所有区域的真实边界坐标,其中options表示‘holes’和‘noholes’,前一个提取区域和孔洞的边界;后一个仅提取区域及其子区域的边界。

  • 自定义bound2im函数

g = bound2im(b, M, N)

g是包含边界且维持其原始坐标值的最小二值图像,b表示边界,M = size(f, 1) 和 N = size(f, 2)。

  • 连接点坐标点

b = cat(1, B{1})

1表示沿第一维(垂直)连接。

  • 使用函数bwboundaries和bound2im
>> f = zeros(14, 14);
>> f(2:3, 2:13) = 1; f(12:13, 2:13) = 1; f(5:6, 5:10) = 1; f(9:10, 5:10) = 1;
>> f(4:11, 2:3) = 1; f(4:11, 12:13) = 1; f(7:8, 5:6) = 1; f(7:8, 9:10) = 1;
>> B = bwboundaries(f, 'noholes');
>> b = cat(1, B{:});
>> [M, N] = size(f);
>> image = bound2im(b, M, N);
>> [B, L, NR, A] = bwboundaries(f);
>> bR = cat(1, B{1:2}, B{4});
>> imageBoundaries = bound2im(bR, M, N);
>> imageNumberedBoundaries = imageBoundaries.*L;
>> bR2 = cat(1, B{:});
>> imageBoundaries2 = bound2im(bR2, M, N);
>> imageNumberedBoundaries2 = imageBoundaries2.*L;
>> subplot(221), imshow(f), title('原图(两个区域两个孔洞)');
>> subplot(222), imshow(image), title('bwboundaries提取区域边界');
>> subplot(223), imshow(imageNumberedBoundaries), title('区域和最后一个孔洞的边界');
>> subplot(224), imshow(imageNumberedBoundaries2), title('所有已编号的边界');

image

本章中使用的其他MATLAB和工具箱函数
  • imfill函数

gB = imfill(fB, location, conn)

对像素进行填充操作,location确定位置,conn制定背景像素所用的连接性:4(默认)或8连接。

>> gb = imfill(Fig1119);
>> imshow(gb);
>> subplot(121), imshow(Fig1119), title('原图');
>> subplot(122), imshow(gb), title('背景填充');

image

可以看出来图片中的窗户都被填充成灰色的。

gB = imfill(fB ,conn, ‘holes’)

填充二值图像中的孔洞。

>> gB = imfill(f);
>> subplot(121), imshow(f), title('原图');
>> subplot(122), imshow(gB), title('背景填充');

image

二值图像更为清晰看出填充的孔洞。

gB = imfill(fI, conn)

填充输入灰度图像中的孔洞。

  • 返回像素坐标向量

可以使用组合函数find和bwlabel。

[gB, num] = bwlabel(fB)
[r c] = find(gB == 2)

前一个函数产生多个连接区域gB, 后一个函数表示获得第二个连接区域的坐标。

  • 矩阵或列向量排序

z = sortrows(s)

>> z = sortrows(a)

z =

     1     2
     1     2
     3     4
     5     6
  • 删除重复行

[z, m, n] = unique(s, ‘rows’)

m表示保留原始数据中的哪些行,n表示原始数组排完后的序号

>> a = [1 2; 5 6; 1 2; 3 4];
>> a

a =

     1     2
     5     6
     1     2
     3     4
>> [z, m, n] = unique(a, 'rows');
>> z

z =

     1     2
     3     4
     5     6
  • 移位操作

z = circshift(s, [ud lr])

一些基本的使用M函数
  • 自定义函数bound2eight

b8 = bound2eight(b)

从边界删除4连接像素保留8连接像素

  • 自定义函数bound2four

b4 = bound2four(b)

从边界删除8连接像素保留4连接像素

  • 自定义函数bsubsamp

[s, su] = bsubsamp(b, gridsep)

对边界b进行子取样, 网格的行由gridsep个像素隔开。

  • 自定义函数connectpoly

z = connectpoly(s(:, 1), s(:, 2))

对边界进行子取样后各点就不再连接了,使用这一函数可以重新连接他们。

  • 连接两点的一条直线

[x y] = intline(x1, x2, y1, y2)

二.表示
链码

链码通过托一个指定长度和方向的直线段的连接序列来表示边界。

以方向性数字序列表示的编码称为弗雷曼链码。

image

  • fchcode函数

c = fchcode(b, conn, dir)

dir指定输出链码的方向:若指定为‘same’,则链码方向与b中中点的方向相同;若指定为‘reverse’,将导致链码方向相反。

计算一个存储在数组b中的有序边界点的np x 2集合的弗雷曼链码。

c.fcc = 弗雷曼链码(1 x np)

c.diff = c.ff的一阶差分链码(1 x np)

c.mm = 最小幅度的整数(1 x np)

c.diffmm = 链码c.mm的一阶差分(1 x np)

c.x0y0 = 链码的起点坐标(1 x 2)

  • 弗雷曼链码及变化
>> f = Fig1103;
>> h = fspecial('average', 9);
>> subplot(231), imshow(f), title('带噪原图');
>> g = imfilter(f, h, 'replicate');
>> subplot(232), imshow(g), title('平滑');
>> B = bwboundaries(gB, 'noholes');
>> gB = im2bw(g, 0.5);
>> B = bwboundaries(gB, 'noholes');
>> subplot(233), imshow(gB), title('阈值处理');
>> d = cellfun('length', B);
>> [maxd, k] = max(d);
>> b = B{k};
>> [M N] = size(g);
>> g = bound2im(b, M, N);
>> subplot(234), imshow(g), title('二值图像边界');
>> [s, su] = bsubsamp(b, 50);
>> g2 = bound2im(s, M, N);
>> subplot(235), imshow(g2), title('子取样边界');
>> cn = connectpoly(s(:, 1), s(:, 2));
>> g3 = bound2im(cn, M, N);
>> subplot(236), imshow(g3), title('连接点后的图像');
>> figure, imshow(g2);
>> figure, imshow(g3);

image

后两个图像不清晰,单独显示图片可以清晰看出子取样的边界点和完整的连接图像

image

image

弗雷曼链码c中结构

>> c = fchcode(su);
>> c.x0y0

ans =

     8     3

>> c.fcc

ans =

  Columns 1 through 23

     2     2     2     0     2     2     0     2     0     0     0     0     6     0     6     6     6     6     6     6     6     6     4

  Columns 24 through 32

     4     4     4     4     4     2     4     2     2

>> c.mm

ans =

  Columns 1 through 23

     0     0     0     0     6     0     6     6     6     6     6     6     6     6     4     4     4     4     4     4     2     4     2

  Columns 24 through 32

     2     2     2     2     0     2     2     0     2

>> c.diff

ans =

  Columns 1 through 23

     0     0     6     2     0     6     2     6     0     0     0     6     2     6     0     0     0     0     0     0     0     6     0

  Columns 24 through 32

     0     0     0     0     6     2     6     0     0

>> c.diffmm

ans =

  Columns 1 through 23

     0     0     0     6     2     6     0     0     0     0     0     0     0     6     0     0     0     0     0     6     2     6     0

  Columns 24 through 32

     0     0     0     6     2     0     6     2     6

==cellfun函数==:该函数就是专门对cell数组进行操作的,我觉得与for循环相似,对行列化矩阵进行一次处理。

使用最小周长多边形的多边形近似
  • 基础知识

将图像边缘收缩,产生一个最小周长的多边形,连接周长边界单元。MPP的顶点不是与内墙中的凸顶点一致,就是与外墙中的凹顶点的镜像顶点一致。

  • 实现MPP的函数

Q = qtdecomp(B, threshold, [mindim maxdim])

[vals, r, c] = qtgetblk(B, Q, mindim)

threshold(阈值)在0和1之间,r和c是一个包含块的左上角的行和列坐标的向量。

==qtgetblk和qtsetblk==

qtgetblk 获取四叉树分解的块值

语法:[vals,r,c]=qtgetblk(I,S,dim)

[vals,idx]=qtgetblk(I,S,dim)

qtsetblk 设置四叉树分解中的块值

语法:J=qtsetblk(I,S,dim,vals)

  • 计算MPP的M函数

[X, Y, R] = im2minperpoly(f,cellsize)

cellsize指定细胞组合体中用于包围边界的方形单元的大小。

>> f = Fig1107;
>> subplot(231), imshow(f), title('原图')
>> b = boundaries(f, 4, 'noholes');
>> b = b{1};
>> [M, N] = size(f);
>> bim = bound2im(b, M, N);
>> subplot(232), imshow(bim), title('4连接');
>> [x, y] = minperpoly(f, 2);
>> b2 = connectpoly(x, y);
>> B2 = bound2im(b2, M, N);
>> subplot(233), imshow(B2), title('单元大小为2');
>> [x, y] = minperpoly(f, 3);
>> b3 = connectpoly(x, y);
>> B3 = bound2im(b3, M, N);
>> subplot(234), imshow(B3), title('单元大小为3');
>> [x, y] = minperpoly(f, 4);
>> b4 = connectpoly(x, y);
>> B4 = bound2im(b4, M, N);
>> subplot(235), imshow(B4), title('单元大小为4');
>> [x, y] = minperpoly(f, 8);
>> b8 = connectpoly(x, y);
>> B8 = bound2im(b8, M, N);
>> subplot(236), imshow(B8), title('单元大小为8');

image

使用更大的方形边界单元得到的MPP

>> [x, y] = minperpoly(f, 10);
>> b10 = connectpoly(x, y);
>> B10 = bound2im(b10, M, N, xmin, ymin);
>> subplot(221), imshow(B10), title('单元大小为10');
>> [x, y] = minperpoly(f, 16);
>> b16 = connectpoly(x, y);
>> B16 = bound2im(b16, M, N, xmin, ymin);
>> subplot(222), imshow(B16), title('单元大小为16');
>> [x, y] = minperpoly(f, 20);
>> b20 = connectpoly(x, y);
>> B20 = bound2im(b20, M, N, xmin, ymin);
>> subplot(223), imshow(B20), title('单元大小为20');
>> [x, y] = minperpoly(f, 32);
>> b32 = connectpoly(x, y);
>> B32 = bound2im(b32, M, N, xmin, ymin);
>> subplot(224), imshow(B32), title('单元大小为32');

image

标记
  • 自定义函数signature

[dist, angle] = signature(b, x0, y0)

寻找边界的标记,b是一个np x 2数组,它的行包含顺时针或逆时针方向排列的边界点的x和y坐标。(x0, y0)是一个点的坐标,测量该点到边界的距离。

  • 笛卡儿积坐标与极坐标转换

[THETA, RHO] = cart2pol(X, Y)

X、Y是包含笛卡儿坐标点的坐标的向量

[X, Y] = pol2cart(THETA, RHO)

  • 标记应用(查找边界并区分)
>> f = Fig1111;
>> g = Fig11111;
>> subplot(221), imshow(f), title('不规则方形');
>> subplot(222), imshow(g), title('三角形边界');
>> bsq = bwboundaries(f, 'noholes');
>> [distsq, anglesq] = signature(bsq{1});
>> subplot(223), plot(anglesq, distsq);
>> bsq = bwboundaries(g, 'noholes');
>> [distsq, anglesq] = signature(bsq{1});
>> subplot(224), plot(anglesq, distsq);

image

从下面的标记可以清晰地区分出两张图像边界的不同。

边界线段

将边界分解为线段降低了边界的复杂性。

骨骼

表示一个平面区域的结构形状的一种方法是将它简化为图形,这种细化也成为骨骼化。

  • 自定义函数bwmorph

skeletonImage = bwmorph(B, ‘skel’, Inf)

>> f = Fig1113;
>> subplot(231), imshow(f), title('原图');
>> h = fspecial('gaussian', 25, 15);
>> f = im2double(f);
>> g = imfilter(f, h, 'replicate');
>> subplot(232), imshow(g), title('高斯模板平滑后');
>> g = im2bw(g, 1.5 * graythresh(g));
>> subplot(233), imshow(g), title('阈值处理');
>> s = bwmorph(g, 'skel', Inf);
>> subplot(234), imshow(s), title('骨骼');
>> s1 = bwmorph(s, 'spur', 8);
>> subplot(235), imshow(s1), title('去除刺状突起8次');
>> s2 = bwmorph(s1, 'spur', 7);
>> subplot(236), imshow(s2), title('额外去除剌状突起7次');

image

使用高斯模板来平滑图像,其中函数graythresh()为自动阈值,处理后g为二值图像,乘以1.5是表示增加50%的阈值处理总量。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构与算法分析-C语言描述(原书第二版)是一本经典的计算机科学教材,它涵盖了数据结构和算法的基本概念和实现方法。下面是第五章的练习题答案: 1. 编写一个递归算法,计算一个整数n的阶乘。 ```c #include <stdio.h> int factorial(int n) { if (n == 0) { return 1; } else { return n * factorial(n-1); } } int main() { int n = 5; printf("Factorial of %d is %d\n", n, factorial(n)); return 0; } ``` 2. 编写一个递归算法,输出一个整数n的二进制表示。 ```c #include <stdio.h> void decimalToBinary(int n) { if (n > 0) { decimalToBinary(n / 2); printf("%d", n % 2); } } int main() { int n = 10; printf("Decimal %d is binary ", n); decimalToBinary(n); printf("\n"); return 0; } ``` 3. 编写一个非递归算法,求一个数组的最大值。 ```c #include <stdio.h> int findMax(int arr[], int size) { int max = arr[0]; for (int i = 1; i < size; i++) { if (arr[i] > max) { max = arr[i]; } } return max; } int main() { int arr[] = {2, 8, 4, 1, 6}; int size = sizeof(arr) / sizeof(arr[0]); printf("The maximum value in the array is %d\n", findMax(arr, size)); return 0; } ``` 4. 编写一个非递归算法,将一个字符串进行反转。 ```c #include <stdio.h> #include <string.h> void reverseString(char str[]) { int len = strlen(str); for (int i = 0, j = len - 1; i < len / 2; i++, j--) { char temp = str[i]; str[i] = str[j]; str[j] = temp; } } int main() { char str[] = "Hello World"; printf("Original string: %s\n", str); reverseString(str); printf("Reversed string: %s\n", str); return 0; } ``` 以上是第五章的练习题答案,希望对您有帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值