数字图像处理实验报告-图像边缘检测和特征提取_第1页
数字图像处理实验报告-图像边缘检测和特征提取_第2页
数字图像处理实验报告-图像边缘检测和特征提取_第3页
数字图像处理实验报告-图像边缘检测和特征提取_第4页
数字图像处理实验报告-图像边缘检测和特征提取_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、华南师范大学实验报告一、实验目的1、.掌握边缘检测的Matlab实现方法2、了解Matlab区域操作函数的使用方法3、了解图像分析和理解的基本方法4、了解纹理特征提取的matlab实现方法二、实验平台计算机和Matlab软件环境三、实验内容1、图像边缘检测2、图像纹理特征提取四、实验原理1、图像边缘检测图像理解是图像处理的一个重要分支,它研究的是为完成某一任务需要从图像中提取哪些有用的信息,以及如何利用这些信息解释图像。边缘检测技术对于处理数字图像非常重要,因为边缘是所要提取目标和背景的分界线,提取出边缘才能将目标和背景区分开来。在图像中,边界表明一个特征区域的终结和另一个特征区域的开始,边界

2、所分开区域的内部特征或属性是一致的,而不同的区域内部的特征或属性是不同的,边缘检测正是利用物体和背景在某种图像特性上的差异来实现的,这些差异包括灰度,颜色或者纹理特征。边缘检测实际上就是检测图像特征发生变化的位置。由于噪声和模糊的存在,检测到的边界可能会变宽或在某些点处发生间断,因此,边界检测包括两个基本内容:首先抽取出反映灰度变化的边缘点,然后剔除某些边界点或填补边界间断点,并将这些边缘连接成完整的线。边缘检测的方法大多数是基于方向导数掩模求卷积的方法。导数算子具有突出灰度变化的作用,对图像运用导数算子,灰度变化较大的点处算得的值比较高,因此可将这些导数值作为相应点的边界强度,通过设置门限的

3、方法,提取边界点集。一阶导数与是最简单的导数算子,它们分别求出了灰度在x和y方向上的变化率,而方向上的灰度变化率可以用下面式子计算:对于数字图像,应该采用差分运算代替求导,相对应的一阶差分为:方向差分为:函数f在某点的方向导数取得最大值的方向是,方向导数的最大值是称为梯度模。利用梯度模算子来检测边缘是一种很好的方法,它不仅具有位移不变性,还具有各向同性。为了运算简便,实际中采用梯度模的近似形式,如:、及等。另外,还有一些常用的算子,如Roberts算子和Sobel算子。Roberts算子的表达式为:Sobel算子的表达式为:X方向算子: y方向算子:其中,由于Sobel算子是滤波算子的形式,用

4、于提取边缘。我们可以利用快速卷积函数,简单有效,因此应用很广泛。拉普拉斯高斯(LoG)算法是一种二阶边缘检测方法。它通过寻找图像灰度值中二阶微分中的过零点(Zero Crossing)来检测边缘点。其原理为,灰度级变形成的边缘经过微分算子形成一个单峰函数,峰值位置对应边缘点;对单峰函数进行微分,则峰值处的微分值为0,峰值两侧符号相反,而原先的极值点对应于二阶微分中的过零点,通过检测过零点即可将图像的边缘提取出来。2、区域简单形状特征2.1 面积S和周长L面积和周长时描述块状图形大小的最基本特征。图像中的图形面积S可用同一标记的区域中像素的个数来表示。图形周长L用图形上相邻边缘间距离之和来表示。

5、3、图像纹理特征提取3.1 基于图像灰度直方图的特征提取图像灰度直方图的形状揭示了图像的特征。例如,分布范围狭窄的直方图表示低对比度的图像;单峰直方图描述图像中所含目标的灰度范围相对背景来说具有较窄的灰度范围。设图像可能的灰度级数为L,其灰度直方图为h(i),i=0,1,L-1,灰度均值为m,则其n阶中心统计矩为 式中,u2也称方差,是对灰度对比度的度量,可以描述直方图的相对平滑程度;u3表示了直方图的偏斜度;u4描述了直方图的相对平坦型。常见的纹理统计度量如下:均值:标准偏差:平滑度:三阶矩:一致性:熵:3.2基于图像灰度共生矩阵的特征提取灰度共生矩阵能反映出图像灰度关于方向、相邻间隔、变化

6、幅度的综合信息,它是分析图像的局部模式和它们排列规则的基础。它反映了图像中任意两点灰度的相关性,根据它可以进行纹理特征的抽取及分析。为了能更直观地以共生矩阵描述纹理状况,从共生矩阵导出一些反应矩阵状况的参数,典型的有以下几种:(1)对比度: (2)相关: 其中: (3)能量: (4)逆差矩: 3.3 基于频域的纹理统计方法纹理的频谱度量是基于傅里叶频谱的,适用于描述图像中的周期或近似周期二维模式的方向性。这些在频域中易于识别的全局纹理模式,在空间域中很难检测到。因此,纹理的频谱对于判别周期纹理模式和非周期纹理模式非常有用,对于量化两个周期末时间的差也非常有用。对纹理描述有用的傅里叶频谱的3个特

7、征:(1)频谱中突起的尖峰给出了纹理模式的主要方向;(2)在频谱平面中尖峰的位置给出了模式的基本空间周期;(3)通过过滤除去所有周期性的部分,而留下非周期性的图像元素,然后,这些留下的元素可以通过统计技术进行描述。在用频谱法进行纹理特征提取时常使用函数的极坐标表达比较简单。这里S是频谱函数,r和 是坐标系中的变量。对于每个方向 ,可以看做一维函数。类似的,对每个频率r,也是一个一维函数。对固定的 值分析,可得到沿着自原点的辐射方向上的频谱所表现的特性。繁殖,分析固定r值的,可得到沿着以原点为圆心的圆形上的特性。通过求这些函数的积分(离散变量求和),我们可得到全局描述: 这里R0是以原点为圆心的

8、圆的半径。五、思考题1、在边缘提取中,比较边缘提取中LOG、Canny算子的边缘提取效果。答:用canny算子与log算子提取边缘的代码如下:I=double(imread(circles.png); bw4=edge(I,canny); %canny边缘检测 bw5=edge(I,log); %log边缘检测 subplot(2,3,1);imshow(I);title(原图) subplot(2,3,2);imshow(bw4);title(canny边缘检测) subplot(2,3,3);imshow(bw5);title(log边缘检测) 运行结果如下:由上图可以看出,Canny算子

9、提取的边缘的完整与连续性优于Log算子,并且Canny算子对于弱边缘的检测能力也优于Log算子,具有较高的边缘定位精度,边缘较为平滑。2、在纹理的频域特征提取中,分析纹理方向和纹理周期与Fourier变换谱之间的关系?答:利用频谱法提取纹理特征代码如下: f1=imread(texture1.jpg); srad1,sang1,s1=specxture(f1); subplot(2,4,1); imshow(f1); title(原始图像); subplot(2,4,2); imshow(s1,); title(原始图像的频谱); subplot(2,4,3); plot(srad1); ti

10、tle(s(r)曲线); subplot(2,4,4); plot(sang1); title(s(o)曲线); f2=imread(texture2.jpg); srad2,sang2,s2=specxture(f2); subplot(2,4,5); imshow(f2); title(原始图像); subplot(2,4,6); imshow(s2,); title(原始图像的频谱); subplot(2,4,7); plot(srad2); title(s(r)曲线); subplot(2,4,8); plot(sang2); title(s(o)曲线); 运行结果如下:由以上两图可知

11、,当某一纹理图像沿方向的边缘大量存在时,则在频率域内沿+/2方向即与方向成直角的方向上能量集中出现,因此频谱可以反映纹理的方向性。频谱的s(r)曲线反映了能量随半径r的变化曲线。在纹理较粗的情况下,即纹理周期较大的情况下,能量多集中在离原点较近的范围内,而在纹理较细的情况下,即纹理周期较小的情况下,能量分散在离原点较远的范围。3、在共生矩阵中,纹理的粗细是怎样度量的?答:利用角二阶矩阵,即归一化后的灰度共生矩阵。角二阶矩阵是图像灰度分布均匀程度和纹理粗细的一个度量,当图像纹理细致,分布较为均匀时,能量值较大,反之较小。六、实验报告要求1、写出边界提取的原理。答:在图像中,边界表明一个特征区域的

12、终结和另一个特征区域的开始,边界所分开区域的内部特征或属性是一致的,而不同的区域内部的特征或属性是不同的,边缘检测正是利用物体和背景在某种图像特性上的差异来实现的,这些差异包括灰度,颜色或者纹理特征。边缘检测实际上就是检测图像特征发生变化的位置,边缘检测的方法大多数是基于方向导数掩模求卷积的方法。导数算子具有突出灰度变化的作用,对图像运用导数算子,灰度变化较大的点处算得的值比较高,因此可将这些导数值作为相应点的边界强度,通过设置门限的方法,提取边界点集。2、写出区域描述中,二维Fourier变换谱纹理描述原理。答:描述纹理可以从纹理的周期与纹理的方向来描述。设纹理图像的傅里叶变换为F,定义图像

13、的功率谱为|F|2=FF*,F*为F的共轭,如果把傅里叶变换用极坐标形式来表示,则有F(r,)的形式,此时功率谱也变换为半径r与的函数。对实际纹理的研究表明,纹理的粗细,即纹理的周期与功率谱的能量分布与原点的距离有关,而能量沿某个方向的分布也与纹理的方向有关,因此,傅里叶变换谱可以用来描述频谱。附录资料:不需要的可以自行删除Pascal/C/C+语句对比(补充版)一、Hello world 先看三种语言的样例:Pascalbegin writeln(Hello world);end.C#include int main() printf(Hello world!n); return 0;C+#

14、include using namespace std;int main()cout Hello world! endl; return 0; 从这三个程序可以看到一些最基本的东西。在Pascal中的begin和end,在C/C+里就是;Pascal主程序没有返回值,而C/C+返回0(好像在C中可以为NULL)。在C/C+中,main函数以前的是头文件,样例中C为stdio.h,C+除了iostream还有第二行的using namespace std,这个是打开命名空间的,NOIP不会考这个,可以不管,只要知道就行了。 此外说明 注释单行用/,段落的话Pascal为,C/C+为/* */。*

15、 常用头文件(模板)#include #include #include #include #include #include using namespace std;int main() system(“pause”);return 0;二、数据类型及定义 这里只列出常用的类型。1、整型PascalC/C+范围shortint-128 127integershort-32768 32767longintInt -2147483648 2147483647int64long long-9223372036854775808 9223372036854775807byte-0 255wordun

16、signed short0 65535longwordunsigned int0 4294967295qwordunsigned long long0 18446744073709551615 * 当对long long 变量赋值时,后要加LLLong long x=6327844632743269843LL* 如果位移 x2LL* Linux: printf(“%lldn”,x);* Windows: printf(“%I64dn”,x);2、实型PascalC/C+范围realfloat2.9E-39 1.7E38single-1.5E-45 3.4E38doubledouble5.0E-

17、324 1.7E3083、字符即字符串 字符在三种语言中都为char,C里没有字符串,只有用字符数组来代替字符串,Pascal和C+均为string。Pascal中字符串长度有限制,为255,C+则没有。 字符串和字符在Pascal中均用单引号注明,在C/C+中字符用单引号,字符串用双引号。4、布尔类型 Pascal 中为 boolean,C/C+ 为 bool。值均为True 或 False。C/C+中除0外bool都为真。5、定义 常量的定义均为 const,只是在C/C+中必须要注明常量的类型。在C/C+中还可以用宏来定义常量,此时不注明类型。PascalC/C+const a = 60

18、; b = -a + 30; d = ;const int a = 60;const int b = - a + 30;const string d = “”;define MAXN 501 /这个是宏 * 宏定义其实就是直接在程序相应的位置替换: #define randomize srand(unsigned time(NULL) #define wait for(int w=0;w a;cout a;cout a endl;特别说明C+中cin一个字符的话会自动跳过空格和回车,Pascal和C则会读入空格和回车。在Pascal中writeln(a:n:m) 表示在n个字符宽的输出域上输出

19、a保留m位小数。例如:pascal write(a:6) c/c+ printf(“%6d”,a) Pascal write(a:6:2) c/c+ printf(“%6.2f”,a) C+ 如果用 cout ? (繁琐!) 需要加头文件 #inlude cout setprecision(2)a; /作用永久 cout setw(6)a; /作用临时 以下三个进制设定都是永久作用: cout deca; 相当 printf(“%d”,a); /十进制 cout hexa; 相当 printf(“%X”,a); /十六进制 cout octa; 相当 printf(“%o”,a); /八进制例

20、如:cout 12hex12oct1212endl;输出:12c1414 C 的输入输出里面的字符串中%表示变量,%后面的字目表示变量类型。下面是类型表:%hd1个short型整数%d1个int型整数%u1个unsigned int型整数%I64d1个long long型整数%c1个字符%s1个C字符串%f1个float型实数%lf1个double型实数%10.4f输出1个总宽度为10,保留4位小数的实数 文件输入输出:Pascalassign(input, test.in);assign(output, test.out);reset(input);rewrite(output);read(

21、a, b);writeln(a, b);close(input);close(output);CFILE *fin = fopen(“test.in”, “r”);FILE *fout = fopen(“test.out”, “w”);fscanf(fin, “%d%d”, &a, &b);fprintf(fout, “%d%d”, a, b);fclose(fin); fclose(fout);C+#include using namespace std;ifstream fin(“test.in”);ofstream fout(“test.out”);fin a b;fout a b en

22、dl;fin.close(); fout.close();因为C+的读入较慢,个人建议C+的话使用C的输入方式。当然也有人用C的读入,C+的输出的,这种方式我们称之为城乡结合。*中国计算机学会竞赛须知发布的C读写程序:(C+ 也能用,cin,cout,scanf,printf 可混用)#include int main() int a,b; freopen(“sum.in”,”r”,stdin);freopen(“sum.out”,”w”,stdout); scanf(“%d%d”,&a,&b); printf(“%dn”,a+b); return 0; 或者:freopen(“sum.in”

23、,”r”,stdin);freopen(“sum.out”,”w”,stdout);ios:sync_with_stdio(false); 取消同步,cin,cout的速度就不慢了! cinab;couta+bendl; return 0;以下扩充c/c+混用是可行的:#include #include using namespace std;int main() int a,b,c,d; freopen(sum.in,r,stdin); freopen(sum.out,w,stdout); scanf(%d%d,&a,&b); cincd; printf(%dn,a+b); couta+b+

24、c+dsn).Cwhile(scanf(%s%d,s,&n)!=EOF).四、赋值语句及运算符号 一一对应的关系PascalC/C+赋值运算赋值:=基本运算加+减-乘*除(实数)/ (double)除法取整div(int) / (int)取余mod%比较等于=不等于!=大于大于等于=小于小于等于=逻辑且and&或or|非not!位运算左移(*2)shl且and&或or|非not异或xor其他增一inc(x)x+减一dec(x)x- 在C/C+中对某个变量自身进行运算可以简写为 变量名 运算符号= 改变量 如 x += 8 就表示 x = x + 8, 即 inc(x, 8)。 在 C/C+里还

25、存在一种三目运算 变量名 = 条件 ? 值A : 值B 如 x = x 0 ? x : -x; /表示若x 0 则取 x, 否则取 x, 同 if x 0 then x := x else x := -x;五、条件语句1、if C/C+中if 语句的条件必须要用括号括起来,后面不使用then。PascalC/C+if a b then flag := true else flag := false;if (a b) flag = true;else flag = false;2、多种分支 C/C+中为switch,Pascal为case:PascalC/C+case x of 1: inc(x

26、); 2: dec(x); else x := x * x;end;switch (x) case 1: x +; break; case 2: x -; break; default: x *= x; 切记C/C+中一定要写break,后果你可以去掉break,运行看看就知道了。六、循环语句1、forPascalC/C+for 变量名 := 初始值 to(downto) 终止值 dofor (变量名=初始值;条件;改变方式)for i := 5 to 10 do dec(a);/终止值大于初始值用 tofor i := 5 downto 1 do dec(a);/终止值小于于初始值用 dow

27、ntofor (i = 5; i = 1; i-) a-;/*只要i 满足条件就会一直循环。C/C+中i是实数、指针都可以*/C/C+中for的特殊用法:/变量为实数for (double i = 1; i 符号为间接引用,后面会提到。for (type1 *p = head - next; p; p = p - next) printf(“%d”, p - k);2、whilePascalC/C+while 条件 dowhile (条件)while i 0 do dec(i);while (i != 0) i-;/也可写作 while (i) i-;/在C/C+中非0即为真。3、repeat

28、-until & do-whilePascalC/C+repeat 语句 until 结束条件;do while (运行条件)repeat int(i) until i 100;do i+; while (i = 100);七、数组 Pascal中数组的下标可以随意定义,而C/C+下标始终为从0开始到(数组大小1)。PascalC/C+定义a : array 1.100 of integer;b :array 1.10,1.10 of int64;int a100;int b1010;含义a 为大小为100的integer数组,合法下标为1到100b 为大小为10*10的int64数组,合法下

29、标为1,1到10,10a 为大小为100的int数组,合法下标为0到99b 为大小为10*10的int数组,合法下标为0,0到9,9;使用inc(a21);b2,2:=b1,1+b1,2+b2,1;a21+;b11=b01+b00+b10; 数组清零PascalC/C+Fillchar(a, sizeof(a), 0);memset(a, 0, sizeof(a);/头文件包含 string.h*如果要填最大: memset(a,127,sizeof(a) (但达不到 INT_MAX) 如果要填最小: memset(a,128,sizeof(a) (但达不到 INT_MIN) 如果填0: me

30、mset(a,0,sizeof(a) 如果填-1: memset(a,-1,sizeof(a)八、字符串 C风格的字符串就是字符数组。 C+和Pascal的字符串使用基本相同,只是C+中字符串下标以0开始,Pascal以1开始。字符串处理很多这里不一一列举,只写最常用的几个。PascalC (包含)定义用:char sC+(包含)定义用:string s输入输出Readln(s);Writeln(s);Scanf(“%s”,s);Printf(“%sn”,s);注:不能输入输出c+的字符串Cins;Couts = s 的区别: getline(cin,s)cins一次性整行读入,直至行末尾。只

31、读入一个“单词”,遇空格和行末停止。例如输入;How are you?s=” How are you?”读入整串含空格例如输入;How are you?s=”How”如果三个都读:cins1s2s3*C+ 数字与数值之间的转换:#include #include #include /必须加入using namespace std;int main() string text = 152; int number; stringstream ss;ss number; /string - int coutnumber+100endl; ss string string str = ss.str()

32、; return 0;九、过程和函数1、过程 在C/C+中没有过程,但可以把返回值为“空”的函数理解为过程。PascalC/C+无参过程procedure 过程名;说明部分begin 语句部分 end;/说明部分、begin、end语句部分统称为过程体void 函数名(); 主体部分; return ;带参过程procedure 过程名(形参表)过程体void 函数名(形参表)过程体 值传和址传:当一个参数是值传时,形参在子过程中相当于一个局部变量,对它的改变不影响实在的参数值。址传则会影响。下例中a为值传,b为址传。初始a = 5,b = 5,运行后a = 5,b = 10;PascalC/

33、C+var a, b:integer;procedure doit(a:integer; var b:integer);begin b := a + b; a := a + b;end;begina := 5;b := 5;doit(a, b);writeln(a, , b);end.void doit(int a, int &b) HYPERLINK a a认为值参,b认为变量传参 b += a; a += b; return ;int main()int a = 5, b = 5;doit(a, b);cout a b;return 0;* 用若干地址传参可以给调用者传回若干值 Void

34、tryit(int &x,int &y,int &z) 调用时: tryit(a,b,c) ,可以传回 a,b,c的值。* 用数组名(也是地址)传参可以传回整组的数据 Void tryit( int a) 调用时: tryit(x),可以传回整个数组。例如:void tryit(int a) for(int i=0;i=10;i+) ai=i*2; return; int main() int x10; tryit(x); for(int i=0;i=10;i+) coutxiendl; system(pause); return 0;*用指向函数的指针作为参数,可以执行指定的函数。(略)ST

35、L 的两个应用:* C+ 快排函数#include Bool com(int a,int b) Return ab;Int main() Int a10=5,7,3,2,6,8,4,3,5,7;Sort(a,a+10,com); /如果升序可以省略com.For(int i=0;i10;i+) Coutai” “;* 优先队列(以堆排为例)#include #include using namespace std;priority_queue Q;int main() int n,a; cinn; while (n-) cina; Q.push(a); while (!Q.empty() co

36、ut Q.top() ; Q.pop(); return 0;* 队列、栈、优先队列 三种数据结构汇总:#include #include priority_queue Q;queue Q1;stack S;int main()Q.push(5); x = Q.top(); Q.pop();Q.empty();Q.size()Q1.push(5); Q1.size(); Q1.front(); Q1.empty(); Q1.pop();S.push(5); S.size(); S.top(); S.emtpy(); S.pop();2、函数 . PascalC/C+funtion 函数名(形参表):返回值类型;函数体返回值类型 函数名(形参表) 主体; return 返回值; 注意在Pascal中: 在函数体的语句部分中,必须有对应的函数标识符赋值的语句,并且这些语句在函数被引用时至少要有一句被执行,最后赋给函数标识符的值就是函数值。或者exit(返回值);下面为求n阶乘的样例:PascalC/C+function fac(n:integer):longint;var sum, i:lon

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论