数字图像处理实验教程-V3.1-zsj

更新时间:2024-06-03 19:15:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

数字图像处理实验教程 V3.1

青岛科技大学

数字图像处理实验教程

信息学院 张淑军 版本:V3.1

2011年3月试行 2012-2014年修订

1

数字图像处理实验教程 V3.1

编写说明

1. 本书是《数字图像处理》实验教程,配合理论授课内容,巩固所学知识,锻炼学生动手开发能力。 2. 实验课需要学生预习,做好必要的准备,以保证实验效果。每次实验的内容和目标非常明确,实验过程中请同学们认真动手,举一反三,不依赖例程,能掌握编程思想。 3. 为加强学生对于所掌握内容的理解,设计了实验回答问题,环环相扣,使学生在编程实践的同时巩固知识点,对所学知识融会贯通,为进入本次实验内容打下基础。 4. 每次实验由例程和练习两部分组成,例程包含了本次实验的核心内容,要求学生统一掌握。练习部分考虑了学生编程水平的高低,分为:基础练习;扩展练习;高层进阶三个层次,以激励编程好的学生积极主动往更高层次努力,培养、选拔优秀学生;大多数的学生可以完成扩展练习。 5. 每课内容最后罗列了所用到的基本OPENCV函数,方便学生查找使用。未附说明的函数请学生自行查找OPENCV电子书,锻炼自己解决问题的能力。 6. 每次实验完成之后,请学生按要求撰写实验报告,并在最后详细记录“实验收获与总结”,将实验中遇到的问题和解决过程作为经验教训记录下来,训练学生及时总结归纳和反思、记录的习惯。

2

数字图像处理实验教程 V3.1

目 录

目 录 ................................................................................................................................................ 3 实验1 图像文件读入和显示(验证性,第1章) .................................................................... 4 实验2 图像采集与显示(综合性,第2章) .......................................................................... 16 实验3 图像坐标变换(综合性,第2章) .............................................................................. 20 实验4 图像灰度变换(综合性,3.1节) ............................................................................... 25 实验5 直方图均衡化(验证性,3.3节) ............................................................................... 28 实验6 滤波器设计(综合性,3.4节) ................................................................................... 34 实验7 颜色空间转换(综合性,第4章) .............................................................................. 41 实验8 图像傅里叶变换(验证性,第5章) .......................................................................... 47 拓展实验 基于MFC的图像处理程序设计(综合性) ............................................................. 53 参考文献......................................................................................................................................... 53

3

数字图像处理实验教程 V3.1

实验1 图像文件读入和显示(验证性,第1章)

1. 实验目的

(1) 熟悉VC++6.0开发环境。

(2) 了解OpenCV开发库,学会在VC++6.0环境下安装和配置OpenCV。 (3) 掌握开源库的通用安装和配置方法。

(4) 通过运行一个简单的程序,初步了解OpenCV程序的特点。 2. 实验内容

(1) 编写程序掌握OpenCV加载及显示图像的方法。 (2) 查看图像的属性(包括类型、大小、分辨率等),掌握图像的采样和量化、

像素间的联系。

3. 实验步骤(验证性实验)

(1) 检查所用的计算机系统是否已安装了VC++6.0(中英文版本均可)。 (2) 安装OpenCV 1.0并正确配置,配置文档见“9.OpenCV配置文档”。 (3) 创建OpenCV控制台项目。 方法1:新建文件

①在VC6.0下新建一个C++源文件:File->New->Files-> C++ Source File,取名为hello.cpp,指定存储目录。

②在hello.cpp的编辑页面键入hello.cpp所给的代码,并保存。 ③编译、连接,创建所需的工作区,在Debug目录下得到可执行文件hello.exe。 方法2:新建工程

①在VC6.0下创建一个空的控制台项目(Win32 Console Application),取名为hello,指定存储目录。

②给该项目添加(新建)一个C源代码文件(C++ Source File),取名为hello.cpp。键入所给的代码。

③编译、连接该程序,在Debug目录下得到可执行文件hello.exe。 (4) 在工程目录下放入图像文件lena.jpg,运行该项目,得到输出结果。 (5) 按照上述(1)(-3)步骤重新建立一个新的工程hello2.dsw,键入hello2.cpp

的相关代码,编译、连接,调试参数,得到运行结果。

控制台程序有两种方法运行:

①以命令行方式运行:在cmd命令行窗口(开始->运行->打开,cmd->确定,进入命令行窗口)中找到hello.exe所在的文件夹,输入hello.exe lena.jpg(要求lena.jpg与编译连接好的hello.exe在同一个目录下),运行。

②指定输入参数:在项目配置页依次找Project->Settings->Debug->Program arguments,在其中直接输入程序要求的外部输入参数lena.jpg,运行该程序。(要求lena.jpg与工程文件在同一个目录下。)

为更好地理解控制台程序输入参数的问题,请将程序hello.cpp与程序hello2.cpp做仔细的对比,认真体会。

二者的区别在于,hello2.cpp中的main函数带有两个参数,argc和argv,如下面形式: int main(int argc, char** argv) 或 int main(int argc, char* argv[])

这两个参数的作用是:argc 是指命令行输入参数的个数,argv存储了所有的命令行参数。假如程序是hello.exe,如果在命令行运行该程序,运行命令为:hello.exe lena.jpg,则:

4

数字图像处理实验教程 V3.1

argc的值是 2,argv[0]是\,argv[1]是\。

(6) 修改hello2程序,使其可以同时读取、显示多幅图像。 4. 实验回答问题

(1) 什么是OpenCV?

OpenCV的全称是:Open Source Computer Vision Library 。OpenCV是一个基于BSD许可证授权(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

(2) 通过实验,查看IplImage结构体的数据结构。请给出IplImage结构体

的数据结构。

nt nSize; /* IplImage大小 */ int ID; /* 版本 (=0)*/

int nChannels; /* 大多数OPENCV函数支持1,2,3 或 4 个通道 */ int alphaChannel; /* 被OpenCV忽略 */ int depth; /* 像素的位深度

char colorModel[4]; /* 被OpenCV忽略 */ char channelSeq[4]; /* 同上 */

int dataOrder; /* 0 - 交叉存取颜色通道, 1 - 分开的颜色通道. */ int origin; /* 0 - 顶—左结构, 1 - 底—左结构

int align; /* 图像行排列 (4 or 8). OpenCV 忽略它,使用 widthStep 代替 */ int width; /* 图像宽像素数 */ int height; /* 图像高像素数*/

struct _IplROI *roi;/* 图像感兴趣区域. 当该值非空只对该区域进行处理 */ struct _IplImage *maskROI; /* 在 OpenCV中必须置NULL */ void *imageId; /* 同上*/

struct _IplTileInfo *tileInfo; /*同上*/

int imageSize; /* 图像数据大小(在交叉存取格式下imageSize=image->height*image->widthStep),单位字节*/ char *imageData; /* 指向排列的图像数据 */

int widthStep; /* 排列的图像行大小,以字节为单位 */ int BorderMode[4]; /* 边际结束模式, 被OpenCV忽略 */ int BorderConst[4]; /* 同上 */

char *imageDataOrigin; /* 指针指向一个不同的图像数据结构(不是必须排列的),是为了纠正图像内存分配准备的 */

(3) 请说明OpenCV配置过程中,各个步骤的意义。

配置VC++6.0环境

下面需要设置VC6.0环境,使得VC6.0在编译OpenCV程序时,能够知道从何处找到头文件和库文件。 (1)配置头文件目录

依次打开Tools->Options->Directories: 在

Include files中,添加如下目录(6个,通常用前面的4个即可): (2)配置库文件目录

5

数字图像处理实验教程 V3.1

依次打开Tools->Options->Directories: 在Library files中,添加如下目录: (三)配置项目

要使得VC6.0项目能够支持OpenCV,需要在项目中添加

OpenCV的库文件链接,使程序能够知道所用的函数是来自哪个库。 依次打开Project->Settings->Link,在Object/library modules中,添加所需要的lib文件,以空格分开。通常包括(6个):

cxcore.lib cv.lib cvaux.lib highgui.lib cvcam.lib ml.lib

(4) 如何修改程序,使得程序可以显示多幅图像? 5. 练习

【基础练习】试着不用参考给定例程,自己写出本次实验的代码,掌握OpenCV图像处理程序的基本流程和框架。

【扩展练习】编程实现加载并显示三幅图像,其中一幅通过指定文件名的方式读取,另外两幅通过外部输入参数读取。

1. #include 2. #include 3. #include 4.

5. using namespace std; 6.

7. #pragma comment(lib, \ 8. #pragma comment(lib, \ 9. #pragma comment(lib, \ 10.

11. void imshowMany(const std::string& _winName, const vector& _imgs)

; 12.

13. int main(void) 14. {

15. std::vector imgs(6); 16. imgs[0] = cvLoadImage(\); 17. imgs[1] = cvLoadImage(\); 18. imgs[2] = cvLoadImage(\); 19. imgs[3] = cvLoadImage(\); 20. imgs[4] = cvLoadImage(\); 21. imgs[5] = cvLoadImage(\); 22.

23. imshowMany(\, imgs); 24. cvWaitKey(); 25.

6

数字图像处理实验教程 V3.1

26. return 0; 27. } 28.

29. void imshowMany(const std::string& _winName, const vector& _imgs)

30. {

31. int nImg = (int)_imgs.size(); 32.

33. IplImage* dispImg; 34.

35. int size; 36. int x, y; 37.

38. // w - Maximum number of images in a row 39. // h - Maximum number of images in a column 40. int w, h;

41. // scale - How much we have to resize the image 42. float scale; 43. int max; 44.

45. if (nImg <= 0) 46. {

47. printf(\); 48. return; 49. }

50. else if (nImg > 12) 51. {

52. printf(\); 53. return; 54. } 55.

56. else if (nImg == 1) 57. {

58. w = h = 1; 59. size = 300; 60. }

61. else if (nImg == 2) 62. {

63. w = 2; h = 1; 64. size = 300; 65. }

66. else if (nImg == 3 || nImg == 4) 67. {

68. w = 2; h = 2;

7

数字图像处理实验教程 V3.1

69. size = 300; 70. }

71. else if (nImg == 5 || nImg == 6) 72. {

73. w = 3; h = 2; 74. size = 200; 75. }

76. else if (nImg == 7 || nImg == 8) 77. {

78. w = 4; h = 2; 79. size = 200; 80. } 81. else 82. {

83. w = 4; h = 3; 84. size = 150; 85. } 86.

87. dispImg = cvCreateImage(cvSize(100 + size*w, 60 + size*h), IPL_DEPTH_8U,

3); 88.

89. for (int i= 0, m=20, n=20; i

91. x = _imgs[i]->height; 92. y = _imgs[i]->width; 93.

94. max = (x > y)? x: y;

95. scale = (float) ( (float) max / size ); 96.

97. if (i%w==0 && m!=20) 98. {

99. m = 20; 100. n += 20+size; 101. }

102. cvSetImageROI(dispImg,cvRect(m, n, (int)(x/scale), (int)(y/scale)))

;

103. cvResize(_imgs[i], dispImg); 104. cvResetImageROI(dispImg); 105. } 106.

107. cvNamedWindow(_winName.c_str()); 108. cvShowImage(_winName.c_str(), dispImg); 109. }

8

数字图像处理实验教程 V3.1

6. 实验报告要求

实验报告要求写明以下7方面内容: (1) 写明实验目的。

(2) 写明实验内容和步骤。

(3) 写出完整的控制台程序代码,并加详细的注释。(仅对hello.c) (4) 描绘并解释实验结果,并对实验结果进行分析。 (5) 写明实验中存在的不足,以及改进的方法。 (6) 回答实验中涉及到的问题。 (7) 写出本次实验的体会。 7. 预习内容

(1)如何用摄像头采集图像并进行显示? (2)OpenCV功能的进一步了解。 8. 参考程序代码 /* 程序名:hello.cpp

功 能:读入指定文件,并在屏幕上显示 */

#include \

#include \

#define FILENAME \使用宏定义,指定图像文件名

void main() {

IplImage* pImg;//定义图像结构变量指针

pImg=cvLoadImage(FILENAME,1);//加载指定文件

cvNamedWindow(\创建窗口,第2个参数为1表示固定大小,0表示可变大小

cvShowImage(\在指定窗口显示图像文件

cvWaitKey(0);//等待按键,若无此句,程序运行时看不到结果 cvDestroyWindow(\销毁窗口 cvReleaseImage(&pImg);//释放图像文件 }

/* 程序名:hello2.cpp

功 能:从磁盘中读入任意图像文件,并将图像显示在屏幕上 */

#include \

#include \

//在main函数中,argc表示主程序接收的参数个数,argv数组接收程序参数 //如:当argc=2时,argv[0]表示第0个参数(可执行程序本身),argv[1]表示第1个参数(需人为输入)

9

数字图像处理实验教程 V3.1

//当argc=1时,表示不需要从外界接收参数 int main(int argc, char** argv) {

IplImage* pImg;//声明IplImage指针

//载入图像

if (argc==2 改为1&& (pImg=cvLoadImage(argv[1],1))!=0) { cvNamedWindow(\创建窗口 cvShowImage(\显示图像 cvWaitKey(0);//等待按键 cvDestroyWindow(\销毁窗口 cvReleaseImage(&pImg);//释放图像 return 0; }

return -1; }

9. OpenCV函数解释

OpenCV的函数和数据类型命名规则如下:

(1) 宏全部使用大写字符,字间用下划线分隔,如:CV_MAX_DIM,

IPL_DEPTH_32F。

(2) 数据类型以Cv开头,如:CvSize,CvPoint3D64f等。 (3) 函数以cv开头,如:cvLoadImage、cvSaveImage等。

需要包含的OpenCV头文件:

\:OpenCV的基本函数头文件。

\:用于用户GUI界面设计的OpenCV专用库,包括很多Windows API接口函数。

OpenCV基本函数:

cvLoadImage从文件读取图像

语法:IplImage* cvLoadImage(const char* filename,int flag=1) 参数:

filename:待载入的文件名,包括扩展名。可以载入BMP,DIB,JPEG,PNG,PBM,PGM,PPM,SR,RAS和TIFF等文件格式。 flag表示是否是彩色图像(多通道),默认为1,表示读入的图像被强制为3通道的彩色图像

flag=0,表示载入图像强制为单通道灰度图像

flag<0,表示载入图像由文件中的图像通道数决定。 返回值为IplImage结构指针。

10

数字图像处理实验教程 V3.1

cvNamedWindow窗口定义函数

语法:int cvNamedWindow(const char* name,unsigned long flags) 参数Name:窗口名。 flags:窗口属性值,可以选择CV_WINDOW_AUTOSIZE1(表示固定大小)和0(或其他大于1的整数:表示可变大小)两种值。

cvShowImage图像显示函数

语法:void cvShowImage(const char * name, const CvArr* image)

参数:name:窗口名称。image:图像类型指针,一般为IplImage型。

说明:CvArr *仅仅被用作函数的参数,用来指明函数接收的数组类型不止一个,如类型IplImage*,CvMat *,甚至是CvSeq *,最终的数组类型是在运行时通过分析数组头的前4个字来判断。

cvWaitKey按键等待函数

语法:int cvWaitKey(int delay=0) 参数:

delay:等待按键毫秒数。 返回值为按键的键号。

cvDestroyWindow窗口注销函数

语法:void cvDestroyWindow(const char* Name); 参数:Name:要注销的窗口名称。

cvReleaseImage图像注销函数

语法:cvReleaseImage(CvArr* image); 参数:image:要注销的IplImage指针 10. OpenCV配置文档 以VC++6.0为例:

(假定OpenCV的安装目录为C:\\PROGRAM FILES\\OPENCV) (1)配置头文件目录

依次打开Tools->Options->Directories: 在Include files中,添加如下目录: C:\\PROGRAM FILES\\OPENCV\\CV\\INCLUDE

C:\\PROGRAM FILES\\OPENCV\\CVAUX\\INCLUDE C:\\PROGRAM FILES\\OPENCV\\CXCORE\\INCLUDE C:\\PROGRAM FILES\\OPENCV\\OTHERLIBS\\HIGHGUI

C:\\PROGRAM FILES\\OPENCV\\OTHERLIBS\\CVCAM\\INCLUDE

11

数字图像处理实验教程 V3.1

点击Options之后页面如下:

配置完之后,页面如下:

12

数字图像处理实验教程 V3.1

(2)配置库文件目录

依次打开Tools->Options->Directories: 在Library files中,添加如下目录: C:\\PROGRAM FILES\\OPENCV\\LIB

配置完之后页面如下:

13

数字图像处理实验教程 V3.1

(3)添加库文件链接

这一步对于每一个工程都要配置一次,在新建工程之后,依次打开Project->Settings->Link,在Object/library modules中,添加所需要的lib文件,以空格分开。通常包括:

cxcore.lib cv.lib cvaux.lib highgui.lib cvcam.lib ml.lib

点击Settings->Link,添加6个库之后的页面如下:

14

数字图像处理实验教程 V3.1

程序在链接、运行时,需要OpenCV的动态链接库的支持,如果程序提示找不到dll文件,则需将OpenCV的所有动态链接库文件(OpenCV->bin目录下的8个dll文件)直接拷到系统安装目录system32下,这样OpenCV的程序无论在本机的何处运行,都没有问题了。

15

数字图像处理实验教程 V3.1

实验2 图像采集与显示(综合性,第2章)

1. 实验目的

(1) 了解OpenCV中使用摄像头采集图像的方法。

(2) 掌握OpenCV进行图像采集、存储与显示的实现方法。 2. 实验内容

编写程序,用摄像头采集彩色图像并进行彩色和灰度显示。

3. 实验步骤(验证性实验)

(1) 首先保证计算机安装了某个摄像头(webcam)及其驱动程序,摄像头能

正常采集。

(2) 创建OpenCV控制台项目。

(3) 添加源文件gray.cpp,并输入相关代码。 (4) 编译、连接、运行,得到实验结果。 4. 实验回答问题

(1) IplImage结构体中imageData的格式是什么样的?Char* (2) 函数cvCreateImage的最后一个参数的含义是什么? channels每个图元的颜色通道数。 可以是 1, 2, 3 或 4.通道是交叉存取的

(3) 画出示例代码gray.cpp程序的流程图。 5. 练习

【基础练习】修改程序,使得程序能读取硬盘上的AVI视频文件并逐帧显示。 【扩展练习】自己编写完整程序实现以下功能: (1) 创建一个窗口 (2) 载入图像 (3) 显示图像

(4) 创建一幅新图像

(5) 将原图像转换为灰度图像赋给新图像 (6) 在新窗口显示新图像 (7) 销毁窗口,释放图像 6. 实验报告要求

实验报告要求写明以下7方面内容: (1) 写明实验目的。

(2) 写明实验内容和步骤。

(3) 写出完整的控制台程序代码,并加详细的注释。 (4) 描绘并解释实验结果,并对实验结果进行分析。 (5) 写明实验中存在的不足,以及改进的方法。 (6) 回答实验中涉及到的问题。 (7) 写出本次实验的体会。 7. 预习内容

(1) 图像坐标变换有哪些?掌握每种变换的公式。 (2) 图像坐标变换的级联。 8. 参考程序代码 /* 程序名:gray.cpp

16

数字图像处理实验教程 V3.1

说 明:从摄像头采集图像,并转化为灰度图显示 */

#include #include #include #include

int main( int argc, char** argv ) {

//声明IplImage指针

IplImage* pFrame = NULL; IplImage* pFrImg = NULL; CvCapture* pCapture = NULL;

int nFrmNum = 0;

//创建窗口

cvNamedWindow(\ cvMoveWindow(\ cvNamedWindow(\ cvMoveWindow(\

if( !(pCapture = cvCaptureFromCAM(-1)))//从摄像头获取图像

//if( !(pCapture = cvCaptureFromAVI(“sea.avi”))) //从视频文件获取图像 { fprintf(stderr, \报错 return -2; }

//逐帧读取视频

while(pFrame = cvQueryFrame( pCapture )) { nFrmNum++;

//如果是第一帧,需要申请内存,并初始化 if(nFrmNum == 1) { pFrImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U,1);

pFrImg->origin=1;//设置图像数据起点为左下角,可设0查看不同结果 }

cvCvtColor(pFrame, pFrImg, CV_RGB2GRAY); //转化成单通道图像(灰度图像)

17

数字图像处理实验教程 V3.1

//显示图像

cvShowImage(\ cvShowImage(\ //等待按键事件 cvWaitKey(2);//当前帧采集到之后延迟2毫秒,以便能实现连续显示视频的效果 //cvWaitKey(0);//若参数为0,则无限制等待按键,只能显示第一帧图像 }

//销毁窗口

cvDestroyWindow(\ cvDestroyWindow(\ //释放图像和矩阵

cvReleaseImage(&pFrame); cvReleaseImage(&pFrImg); cvReleaseCapture(&pCapture); return 0; }

9. OpenCV函数解释

需要包含的OpenCV头文件 #include \#include \#include \

cxcore.h:OpenCV核函数头文件

OpenCV基本函数:

OpenCV支持从摄像头和视频文件(AVI)中捕捉图像,使用的两个函数是: cvCaptureFromCAM从摄像头捕捉图像 cvCaptureFromAVI从视频获取图像 返回值均为CvCapture结构体

cvCaptureFromCAM

功能:给从摄像头得到的视频流分配和初始化CvCapture结构。 语法:CvCapture* cvCaptureFromCAM( int index ); 参数:index 要使用的摄像头索引,默认为-1。

cvQueryFrame获取视频序列帧的每一帧

语法:IplImage* cvQueryFrame( CvCapture* capture ); 参数:capture 视频获取结构。

cvCreateImage创建图像函数

语法:IplImage *cvCreateImage(CvSize size, int depth, int channels)

18

数字图像处理实验教程 V3.1

参数:size:图像的宽、高。depth:图像图元深度。channels每个图元的颜色通道数。

返回值:IplImage结构体。

cvMoveWindow移动窗口函数

语法:void cvMoveWindows(name,int x,int y)

参数:name:窗口的名称。X:窗口左上角的x坐标。Y:窗口左上角的Y坐标。

cvGetWindowHandle获取窗口句柄函数 传入参数为窗口名称。 返回值为窗口的句柄。

cvCvtColor色彩空间转换函数

语法:void cvCvtColor(const CvArr* src, CvArr* dst, int code) 参数:src为源图像的不定数组,CvArr*指针,一般情况为IplImage型指针。Dst:目的地址的CvArr指针,一般为IplImage型结构体。Code:色彩转换空间, 常数定义为CV_2

19

数字图像处理实验教程 V3.1

实验3 图像坐标变换(综合性,第2章)

1. 实验目的

(1) 掌握图像坐标变换的原理和方法。

(2) 能设计相应代码实现图像的旋转与缩放变换。 2. 实验内容

编写程序用OpenCV实现对图像的各种空间变换。需要实现的功能有:旋转与缩放。

3. 实验步骤(综合性实验) (1) 新建源文件rotate.cpp。

(2) 编写程序代码,使程序可以对图像进行旋转与缩放。 (3) 编译、连接(生成工作区)、运行该文件,得到实验结果。

(4) 通过给定的函数,理解所给代码的功能进而改写程序代码,使程序可以

对图像实现指定的空间变换,包括平移、旋转、缩放。 4. 实验回答问题

(1) 请给出图像坐标变换的基本公式和实现原理,并着重说明例程中的算法。 (2) 写出平移矩阵、缩放矩阵、旋转(绕z轴)矩阵。 5. 练习

【基础练习】

(1) 修改例程,使得程序可以每次按键旋转一次图像。(这个修改在现在的代

码上比较困难,需要把rotate函数解开,直接在main函数里写) (2) 修改例程,使得程序可以连续循环地旋转图像。

答:将 if( cvWaitKey(5) == 27 )//如果按键为Escape键,则退出循环 break;

angle =(int) (angle + delta) % 360; 中的break注释掉

【扩展练习】

(1)使用cvFlip函数实现图像绕x,y轴或中心旋转。

(2)修改例程,使得程序可以在旋转图像的同时缩放图像。 【高层进阶】

(1) 使用cvResize函数实现图像的缩放功能。

(2) 编写程序,实现图像的平移、旋转和缩放综合功能。 6. 实验报告要求

实验报告要求写明以下7方面内容: (1) 写明实验目的。

(2) 写明实验内容和步骤。

(3) 写出空间变换所涉及的图像处理函数,并加详细的注释。 (4) 描绘并解释实验结果,并对实验结果进行分析。 (5) 写明实验中存在的不足,以及改进的方法。 (6) 回答实验中涉及到的问题。 (7) 写出本次实验的体会。 7. 预习内容

20

数字图像处理实验教程 V3.1

(1) 空域图像增强的概念是什么?有哪些分类? (2) 给出几种常见的图像灰度映射函数。 8. 参考程序代码 /* 程序名:rotate.cpp

功 能:使用OpenCV函数实现图像的旋转(平移和缩放)。 */

#include #include #include

#include #include

void myRotate(IplImage* ,int); //声明自定义的图像旋转函数

int main() {

IplImage *src;

src=cvLoadImage(\ if(!src) { printf(\加载图片失败!\\n\ return -1; }

cvNamedWindow(\窗口固定大小

cvMoveWindow(\设定窗口左上角坐标位置 cvShowImage(\

int ang=45;

cvRotate(src, ang);//旋转图像

cvWaitKey(0);

cvReleaseImage(&src); cvDestroyWindow(\ return 0; }

void myRotate(IplImage* src,int angle)//自定义图像旋转函数 {

IplImage *dst=0;

dst = cvCloneImage (src);

float m[6];

int w = src->width;

21

数字图像处理实验教程 V3.1

int h = src->height;

m[0] = cos(angle * CV_PI/180); m[1] = sin(angle * CV_PI/180); m[2] = w*0.5f; m[3] = -m[1]; m[4] = m[0]; m[5] = h*0.5f;

CvMat M = cvMat( 2, 3, CV_32F, m );//初始化一个2行3列的矩阵M(矩阵元素的数据类型为32位float型)

cvGetQuadrangleSubPix( src, dst, &M);//以M矩阵变换src图像为dst图像

cvNamedWindow(\ cvMoveWindow(\ cvShowImage(\}

9. OpenCV数据结构与基本函数

CvMat结构定义多通道矩阵,如下(在cxcore/cxarray.cpp中): typedef struct CvMat {

int type; //元素类型和标记

int step; //以字节为单位的行数据长度 /* for internal use only */ int* refcount; int hdr_refcount; union {

uchar* ptr; short* s; int* i; float* fl; double* db; } data; //data指针 #ifdef __cplusplus union {

int rows; int height; }; union {

int cols; int width;

22

数字图像处理实验教程 V3.1

}; #else

int rows; //行数 int cols; //列数 #endif }CvMat;

函数说明:

cvMat初始化矩阵函数

语法:CvMat cvMat(int rows, int cols, int type, void *data=NULL)

参数:rows矩阵行数,cols矩阵列数,type元素类型,data可选项,指向分配给矩阵头的数据指针。

OpenCV中重要的矩阵变换函数,使用方法为cvMat* cvCreateMat ( int rows, int cols, int type ); 这里type可以是任何预定义类型,预定义类型的结构如下:CV_ (S|U|F)C。于是,矩阵的元素可以是32位浮点型数据(CV_32FC1),或者是无符号的8位三元组的整型数据(CV_8UC3),或者是无数的其他类型的元素。一个CvMat的元素不一定就是个单一的数字。在矩阵中可以通过单一(简单)的输入来表示多值,这样我们可以在一个三原色图像上描绘多重色彩通道。对于一个包含RGB通道的简单图像,大多数的图像操作将分别应用于每一个通道(除非另有说明)。

cvGetQuadrangleSubPix 使用子像素精度提取像素四边形。该函数通过指定的变换矩阵对原图像进行相应的变换。

语法:void cvGetQuadrangleSubPix( const CvArr *src, CvArr *dst, const CvMat *map_matrix)

参数:src 输入图像 dst 提取的四边形

map_matrix 为2*3的变换矩阵[A | b]

说明:此函数以子像素精度从图像src中提取四边形,并将结果存储于dst,计算公式如下:

dst[x + width(dst)/2, y+height(dst)/2] = src(A11x?A12y?b1,A21x?A22y?b2) 其中,A和b为几何形变参数,均来自映射矩阵map_matrix。映射矩阵为:

?Amap_matrix=?11?A21A12A22b1? ?b2?此处,非整数坐标A?(x,y)T?b的像素点值通过双线性插值得到。多通道图像的每一个通道都单独计算。

这个函数旋转图像后,超出原图像部分,默认的是重复边界模式。

23

数字图像处理实验教程 V3.1

cvResize图像大小变换函数

功能:函数 cvResize 将图像 src 改变尺寸得到与 dst 同样大小。若设定 ROI,函数将按常规支持 ROI.

语法:void cvResize( const CvArr* src, CvArr* dst, int interpolation= CV_INTER_LINEAR ); 参数:src 输入图像

dst 输出图像

interpolation 插值方法,包括: (1) CV_INTER_NN - 最近邻插值

(2)CV_INTER_LINEAR - 双线性插值(默认时使用)

(3)CV_INTER_AREA - 使用像素关系重采样。当图像缩小时,该方法可以避免波纹出现。当图像放大时,类似于 CV_INTER_NN 方法。 (4)CV_INTER_CUBIC - 立方插值

cvFlip垂直,水平或既垂直又水平地翻转二维数组

语法:void cvFlip( const CvArr* src, CvArr* dst=NULL, int flip_mode=0) 参数:src 输入数组

dst 输出数组,若dst = NULL,则翻转是在内部替换。

flip_mode 指定怎样翻转数组。若=0,则绕x轴翻转;若>0,则绕y轴翻转;若<0,则绕x轴和y轴翻转。 说明:函数cvFlip以下面三种方式之一翻转数组(行和列下标是以0为基点的): if flip_mode = 0,则dst(i,j)=src(rows(src)-i-1,j),绕x轴旋转 if flip_mode > 0,则dst(i,j)=src(i,cols(src1)-j-1),绕y轴旋转

if flip_mode < 0,则dst(i,j)=src(rows(src)-i-1,cols(src)-j-1),绕x轴和y轴旋转

24

数字图像处理实验教程 V3.1

实验4 图像灰度变换(综合性,3.1节)

1. 实验目的

(1) 了解空域图像增强的概念与分类。 (2) 掌握不同的灰度变换方法。 (3) 能设计相应代码实现灰度变换。 2. 实验内容

编写程序用OpenCV实现对图像的各种灰度变换。需要实现的功能有:对比度增强;图像求反;动态范围压缩;灰度切分。 3. 实验步骤(综合性实验)

(1) 创建控制台项目,添加源文件imadjust.cpp。

(2) 编写程序代码,使程序可以对图像进行对比度增强。 (3) 编译连接,运行该文件,做出实验结果一。

(4) 改写程序代码,使程序可以对图像求反,做出实验结果二。 (5) 改写程序代码,使程序可以对动态范围压缩,做出实验结果三。 (6) 改写程序代码,使程序可以对灰度切分,做出实验结果四。 4. 实验回答问题

(1) 如何获取一幅图像中某个像素点的灰度值?

val= (uchar) src->imageData [ src->widthStep*y + x]; //得到该像素点的灰度值 (2) 如何给目标图像中的像素点重新赋灰度值? dst->imageData[ dst->widthStep*y + x] = val;//对像素点重新赋灰度值

(3) 如何修改程序,使得图像能够对彩色图像(三通道)进行幅值的映射? 5. 练习

【基础练习】根据例程,自己编写实验步骤中所提到的四种灰度变换功能。 【扩展练习】

(1) 试着不用例程的指导,自己独立编写实验步骤中所提到的四种灰度变换功

能,要求程序清晰,无冗余代码。

(2) 给定一个灰度映射函数曲线,要求编程实现指定图像的灰度映射,并显示

原图像和目标图像。

(3) 对两幅尺寸均为M*N的图像,通过获取各对应像素的灰度值进行图像相

加,显示叠加后的图像。 【高层进阶】

(1) 修改程序,实现对彩色图像三通道幅值的变换。 (2) 实现尺寸相同的彩色图像相加功能。 6. 实验报告要求

实验报告要求写明以下7方面内容: (1) 写明实验目的。

(2) 写明实验内容和步骤。

(3) 写出每种灰度变换的图像处理函数,并加详细的注释。 (4) 描绘并解释实验结果,并对实验结果进行分析。 (5) 写明实验中存在的不足,以及改进的方法。 (6) 回答实验中涉及到的问题。 (7) 写出本次实验的体会。

25

数字图像处理实验教程 V3.1

7. 预习内容

图像直方图的概念;直方图均衡化的计算方法。 8. 参考程序代码

/* 程序名:imadjust.cpp

功 能:读入图像,强制转换为灰度图,对其进行灰度变换 */

#include \

#include \/*

灰度变换函数ImageAdjust

其中,源图像src和目标图像dst均为8比特的灰度图像 默认的参数值有:

[low, high] = [0,1]; [bottom, top] = [0,1];

线性变换:将源灰度值的[low, high]区间线性变换到[bottom, top]区间 如果变换成功,返回0,否则返回非零值。 */

int ImageAdjust(IplImage* src, IplImage* dst, double low, double high, double bottom, double top) {

if( low<0 || low>1 || high <0 || high>1 || bottom<0 || bottom>1 || top<0 || top>1 || low>=high)

return -1;//输入参数值不符合函数要求,则返回失败值

//将输入参数缩放到8比特图像的灰度级别[0, 255]上 double low2 = low*255; double high2 = high*255;

double bottom2 = bottom*255; double top2 = top*255;

double k = (top2 - bottom2)/(high2 - low2);//计算直线斜率

int x,y; double val;

//对图像中的像素逐个进行灰度变换

for( y = 0; y < src->height; y++)//y为像素的纵坐标 {

for (x = 0; x < src->width; x++)//x为像素的横坐标 {

val= (uchar) src->imageData [ src->widthStep*y + x]; //得到源图像中像素点的灰度值

val = (val - low2)* k + bottom2;//计算变换后的灰度值 if(val>255) val=255;

26

数字图像处理实验教程 V3.1

if(val<0) val=0;//保证灰度值落在有效的灰度级别内

dst->imageData[ dst->widthStep*y + x] = val;//对目标图像的像素

点重新赋灰度值 } }

return 0; }

int main( int argc, char** argv ) {

IplImage *src = 0, *dst = 0;

if( argc != 2 || (src=cvLoadImage(argv[1], 0)) == NULL)//参数0表示强制转换为单通道灰度图像

return -1;//指定读取灰度图像,否则程序退出

cvNamedWindow( \ cvNamedWindow( \

//以下为图像增强过程 //先复制源图像

dst = cvCloneImage(src);

//输入参数 [0,0.5] 和 [0.5,1]进行灰度变换 if( ImageAdjust( src, dst, 0, 0.5, 0.5, 1)!=0) return -1;

cvShowImage( \ cvShowImage( \ cvWaitKey(0);

cvDestroyWindow(\ cvDestroyWindow(\ cvReleaseImage( &src ); cvReleaseImage( &dst );

return 0; }

9. OpenCV函数解释

cvCloneImage复制图像函数

语法:IplImage* cvCloneImage(const IplImage* image)

输入参数为源图像IplImage指针,返回值为目的IplImage指针。

27

数字图像处理实验教程 V3.1

实验5 直方图均衡化(验证性,3.3节)

1. 实验目的

(1)熟悉直方图均衡化处理的理论基础; (2)掌握直方图均衡化处理的实现方法; (3)学习VC++6.0和OpenCV的编程方法; (4)验证直方图均衡化处理理论; (5)观察直方图均衡化处理的结果。 2. 实验内容

(1) 使用VC++6.0编译OpenCV程序histeq.c的代码,使程序显示直方图均衡

化后的图像。观察并记录实验结果。

(2) OpenCV已经封装了对图像进行均衡化的算法(cvEqualizeHist函数),试

修改histeq.c的代码,直接使用函数cvEqualizeHist对图像进行均衡化。 (3) 选做实验:参考提供的代码imhist.c,建立相应工程,实现图像直方图的

显示。了解在OpenCV中画图形的方法。 3. 实验回答问题

简述图像直方图均衡化的计算步骤。 1.累积 2.取整 3,映射 4.计算 4. 练习

【基础练习】

(1) 熟练使用快捷键及C程序调试方法:F9加断点,F10单步执行,F5调试

等。

(2) 练习使用printf打印语句用来检测局部结果。 5. 实验报告要求

实验报告要求写明以下7方面内容: (1) 写明实验目的。

(2) 写明实验内容和步骤。

(3) 写出图像处理函数代码,并对算法程序部分加详细的注释。 (4) 描绘并解释实验结果,并对实验结果进行分析。 (5) 写明实验中存在的不足,以及改进的方法。 (6) 回答实验中涉及到的问题。 (7) 写出本次实验的体会。 6. 预习内容

预习空域滤波器的分类;平滑、锐化滤波器的实现方法。 7. 参考程序代码 /* 程序名:histeq.c

功 能:读入图像,实现直方图的均衡化并显示 */

#include \

#include \

#define HDIM 256 // bin of HIST, default = 256

28

数字图像处理实验教程 V3.1

int main( int argc, char** argv ) {

IplImage *src = 0, *dst = 0; CvHistogram *hist = 0;

int n = HDIM; double nn[HDIM]; uchar T[HDIM]; CvMat *T_mat;

int x;

int sum = 0; // sum of pixels of the source image 图像中像素点总数 double val = 0;

if( argc != 2 || (src=cvLoadImage(argv[1], 0)) == NULL) // force to gray image return -1;

cvNamedWindow( \ cvNamedWindow( \

// 计算直方图

hist = cvCreateHist( 1, &n, CV_HIST_ARRAY, 0, 1 ); cvCalcHist( &src, hist, 0, 0 );

// Create Accumulative Distribute Function of histgram val = 0;

for ( x = 0; x < n; x++) {

val = val + cvGetReal1D (hist->bins, x);//计算累积直方图 nn[x] = val; }

// 归一化直方图

sum = src->height * src->width; for( x = 0; x < n; x++ ) {

T[x] = (uchar) (255 * nn[x] / sum); // range is [0,255] 取整扩展 }

// Using look-up table to perform intensity transform for source image dst = cvCloneImage( src );

T_mat = cvCreateMatHeader( 1, 256, CV_8UC1 );

cvSetData( T_mat, T, 0 ); //用取整扩展后的新的灰度值填充数组T_mat

29

数字图像处理实验教程 V3.1

// 直接调用内部函数完成 look-up-table 的过程 cvLUT( src, dst, T_mat ); //完成灰度映射

cvShowImage( \ cvShowImage( \ cvWaitKey(0);

cvDestroyWindow(\ cvDestroyWindow(\ cvReleaseImage( &src ); cvReleaseImage( &dst ); cvReleaseHist ( &hist );

return 0; }

/* 程序名:hist.c

功 能:读入图像,计算并显示直方图。 */

#include \

#include \#include #include

int main( int argc, char** argv ) {

IplImage *src = 0; IplImage *histimg = 0; CvHistogram *hist = 0;

int hdims = 50; // 划分HIST的个数,越高越精确 float hranges_arr[] = {0,255}; float* hranges = hranges_arr; int bin_w; float max_val; int i;

if( argc != 2 || (src=cvLoadImage(argv[1], 0)) == NULL) // force to gray image return -1;

cvNamedWindow( \ cvNamedWindow( \

hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 ); // 计算直

30

数字图像处理实验教程 V3.1

方图

histimg = cvCreateImage( cvSize(320,200), 8, 3 ); cvZero( histimg );

cvCalcHist( &src, hist, 0, 0 ); // 计算直方图

cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 ); // 只找最大值

cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 ); // 缩放 bin 到区间 [0,255] cvZero( histimg );

bin_w = histimg->width / hdims; // hdims: 条的个数,则 bin_w 为条的宽度

// 画直方图

for( i = 0; i < hdims; i++ ) {

double val = ( cvGetReal1D(hist->bins,i)*histimg->height/255 ); CvScalar color = CV_RGB(255,255,0); //(hsv2rgb(i*180.f/hdims); cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),

cvPoint((i+1)*bin_w,(int)(histimg->height - val)), color, 1, 8, 0 ); }

cvShowImage( \

cvShowImage( \ cvWaitKey(0);

cvDestroyWindow(\

cvDestroyWindow(\ cvReleaseImage( &src ); cvReleaseImage( &histimg ); cvReleaseHist ( &hist );

return 0; }

8. OpenCV函数解释 数据结构:

CvHistogram 定义多维直方图,其结构如下: Typedef struct CvHistogram {

int type;

CvArr* bins; //存储计算的结果

float thresh[CV_MAX_IDM][2];//对于归一化的直方图 float** thresh2; //对于未归一化的直方图 CvMatND mat; } CvHistogram;

CvHistogram使用Look-up table(LUT)的方式,也就是查表法,开一个256大小

31

数字图像处理实验教程 V3.1

空间的数组,利用比例的缩放,缩放的数据存入Look-up table里面,再利用索引的方式对应。

函数:

cvCreateHist 创建直方图函数

功能:创建一个指定尺寸的直方图,并返回创建的直方图指针。

格式:CvHistgram *cvCreatHist(int dims, int *sizes, int type, float **ranges=NULL, int uniform=1);

参数:dims 直方图维数

sizes 直方图维数尺寸的数组

type 直方图的表示格式,为下列值之一:

——CV_HIST_ARRAY 直方图数据表示为多维密集数组CvMatND ——CV_HIST_TREE 直方图数据表示为多维稀疏数组CvSparseMat ranges 和 uniform一般取默认值。

cvCalcHist计算图像直方图函数

格式:void cvCalcHist( IplImage **image, CvHistGram *hist, int accumulate=0, const CvArr *mask=NULL);

参数:image:输入图像(也可使用结构CvMat**)。

hist 直方图指针。

accumulate:累计标志,默认为0。 mask:操作掩码,默认为0(NULL)。

cvLUT使用查表的值填充输出数组。

格式:void cvLUT(const CvArr *src, CvArr *dst, const CvArr *lut); 参数:src:元素为8位的输入数组。

dst:输出数组。

lut:有256个元素的查找表。

查找表的索引来自于输入数组,即函数按如下方式计算每个元素:

dst[i] = lut[src(i) + DELTA]

这里,当src的深度是CV_8U时,DELTA=0;当src的深度是CV_8S时,DELTA=128。

cvGetReal1D返回单通道数组的指定元素

格式:double cvGetReal1D(const CvArr* arr, int index); 参数:arr 输入数组,必须是单通道。 index 数组下标,从0开始

cvCreateMatHeader创建数组矩阵头部函数。 功能:分配新的矩阵头并返回指向它的指针

格式:CvMat* cvCreateMatHeader(int rows, int cols, int type); 参数:rows 矩阵行数;cols 矩阵列数;type矩阵元素类型。

矩阵头创建之后,矩阵的数据可以使用函数cvCreateData被进一步分配,或利用函数cvSetData由用户明确指定。

32

数字图像处理实验教程 V3.1

故:cvCreateMatHeader与cvSetData这两个函数经常连用创建数组。

cvSetData分配数据给数组

格式:void cvSetData(CvArr* arr, void* data, int step); 参数:arr 数组头;data 用户数据;step 整行字节长。 说明:在调用此函数时,数组头arr应该已经使用函数cvCreateMatHeader或cvMat(对于矩阵)初始化。

cvEqualizeHist直方图均衡化函数

格式:void cvEqualizeHist( const CvArr* src, CvArr* dst); 参数:src 输入的8位单通道图像;

dst 输出的均衡化之后的图像,与输入图像的数据类型和大小一致。 说明:函数cvEqualizeHist对输入图像进行直方图均衡化,采用如下算法: (1) 计算输入图像src的直方图H。

(2) 归一化直方图,使直方图之和为256。 (3) 计算累计直方图,即H/(i)?0?j?i?H(j)。

(4) 用H’作为索引表,对输入图像进行灰度变换,得到输出图像dst,即

dst(x,y)?H'[src(x,y)]。

直方图均衡化算法可以归一化图像的亮度,增强图像的对比度。

cvZero清零数组函数。

cvSize产生尺寸函数。

cvGetMinMaxHistValue返回最大最小值方块函数以及他们的位置。

cvConvertScale使用线性变换转换数组

参数:src 输入数组。Dst:输出数组。Scale:比例因子。Shift 将输入数组元素案比例缩放后添加的值。Dst=src*scale+shift。

cvRectangle矩形填充图像函数

参数:image:图像。Pt1:矩形的第一个顶点。Pt2:矩形的对角线顶点。Color:线条颜色。Thickness:线条的粗细程度。Line_type:线条类型。Shift:坐标小数点后位数。

cvReleaseHist注销直方图指针。

33

数字图像处理实验教程 V3.1

实验6 滤波器设计(综合性,3.4节)

1. 实验目的

(1) 掌握空域滤波器的种类和特点。

(2) 掌握均值滤波器、中值滤波器的设计方法。 (3) 提高解决实际问题的能力。 2. 实验内容和步骤

(1) 思考如何根据实验4(图像灰度变换),自己编写均值滤波器?试着去写

代码。

(2) 对照给出的第一个例程filter1.c,检查自己编程结果与问题所在。 (3) 调试运行第二个例程filter2.c,观察实验结果。

(4) 对比两个例程,总结并掌握自己从底层编写滤波器及调用OpenCV现有

函数实现滤波器的方法与不同。

(5) 思考并设计中值滤波器的实现方法。 3. 实验回答问题

简述空域滤波器的分类及各种滤波器的算法原理。

⑴ 从数学形态上可以把空域滤波器分为线性滤波器和非线性滤波器:线性滤波器又分为高通,低通和带通滤波器,非线性滤波器又可分为中值滤波,最大值,最小值滤波器。

⑵ 从处理效果上可以把空域滤波器分为平滑空间滤波器和锐化空间滤波器 平滑空间滤波器又可分为线性平滑滤波器即均值滤波器,非线性平滑滤波器包括中值滤波器,最大值滤波器,最小值滤波器。

? 低通滤波器原理算法--边缘的计算

1)相邻近似计算法 2)不完整模板近似法

中值滤波器的原理

? 用模板区域内象素的中值,作为结果值

R = mid {zk | k = 1,2,…,9}

– 中值滤波算法的实现

? 将模板区域内的象素排序,求出中值。

例如:3x3的模板,第5大的是中值, 5x5的模板,第13大的是中值, 7x7的模板,第25大的是中值, 9x9的模板,第41大的是中值。

? 对于同值象素,连续排列。

如(10,15,20,20,20,20,20,25,100

高频补偿过滤的原理

? 弥补高通滤波的缺陷,在增强边和细节的同时,不丢失原图

像的低频成分。

高通滤波可看作为: 高通 = 原图 – 低通 在上式原图上乘一个扩大因子A, 有高频补偿过滤: 高频补偿 = A原图 – 低通

34

数字图像处理实验教程 V3.1

= (A – 1)原图 + (原图 – 低通) = (A – 1)原图 + 高通

? 当A = 1时,高频补偿就是高通过滤, ? 当A >1 时,原图像的一部分被加到高通中

4. 练习

【基础练习】

(1) 使用滤波器时,对于图像的边界,一般有两种处理方法:边界扩展和不处

理。例程1采用的是边界不处理,请修改此例程,实现边界扩展的均值滤波器。

(2) 对例程2进行修改,使程序能够实现各种不同的线性滤波算法。包括:均

值滤波器、加权均值滤波器、锐化滤波器(Prewitt算子、Sobel算子、Laplace算子)等。

(3) #include \ (4) #include \ (5) #include \ (6) #include \ (7) #include \

(8) int main(int argc, char ** argv) (9) {

(10) IplImage * src, *dst ; (11)

(12) src = cvLoadImage(\Panda1.bmp\);

(13) dst = cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,3) ; (14) cvNamedWindow(\,0) ; (15) cvShowImage(\,src); (16) cvNamedWindow(\,0) ; (17)

(18) cvSobel(src,dst,0,1,5); (19) cvShowImage(\,dst); (20) cvWaitKey(0) ;

(21) cvReleaseImage(&src) ; (22) cvReleaseImage(&dst); (23) return 0; (24) }

(25) 已知OpenCV函数cvSmooth(src, dst, CV_GAUSSIAN, 3,0,0,0); 可直接实

现高斯低通滤波,请用此函数改写例程,实现不同尺寸的高斯滤波功能。 【扩展练习】

中值滤波是一种非线性平滑法,它对一个滑动窗口内的像素灰度值排序,并用其中值代替窗口中心像素的灰度值。请自己动手编写阶数为n的方形中值滤波器及十字叉中值滤波器,

35

数字图像处理实验教程 V3.1

IplImage* MedianFilter_5_5(IplImage* src){ IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels); cvSmooth(src,dst,CV_MEDIAN,5); return dst;

} 对比其处理效果。

1. int sum(int val[N]) 2. {

3. int i,j;// 循环变量 4. char bTemp; 5.

6. // 用冒泡法对数组进行排序 7. for (j = 0; j < N- 1; j ++) 8. {

9. for (i = 0; i < N - j - 1; i ++) 10. {

11. if (val[i] > val[i + 1]) 12. {

13. // 互换

14. bTemp = val[i];

15. val [i] = val [i + 1]; 16. val [i + 1] = bTemp; 17. } 18. } 19. } 20.

21. // 计算中值 22. if ((N & 1) > 0) 23. {

24. // 数组有奇数个元素,返回中间一个元素 25. bTemp = val[(N + 1) / 2]; 26. } 27. else 28. {

29. // 数组有偶数个元素,返回中间两个元素平均值 30. bTemp = ( val [N / 2] + val [N / 2 + 1]) / 2; 31. } 32.

33. return bTemp; 34. }

【高层进阶】

请编写程序,实现用户可选多种滤波器的功能,将不同类型的滤波器分别用函数实现,在主程序中增加用户交互,如用户可选用某种滤波器、可选择滤波器

36

数字图像处理实验教程 V3.1

不同尺寸等。此题目旨在训练代码模块化及集成开发能力。 5. 实验报告要求

实验报告要求写明以下7方面内容: (1) 写明实验目的。

(2) 写明实验内容和步骤。

(3) 写出图像处理函数代码,并对算法程序部分加详细的注释。 (4) 描绘并解释实验结果,并对实验结果进行分析。 (5) 写明实验中存在的不足,以及改进的方法。 (6) 回答实验中涉及到的问题。 (7) 写出本次实验的体会。 6. 预习内容

(1) 自己查阅资料,学习图像分割的概念,了解图像边界、区域检测的原理并

预习图像边缘提取的基本算法。

(2) 请预习图像颜色空间的分类和特点以及颜色空间的转换方法。 7. 参考程序代码 /* 程序名:filter1.c

功 能:编程实现均值滤波器,对图像进行滤波 */

#include

#include #include

#define FILENAME \

#define N 9//滤波器的阶数(模板尺寸,N=9时表示模板大小为 3*3)

int sum(int val[N])//求平均值 {

int s=0,i;

for (i=0;i

int main( int argc, char** argv ) {

IplImage *src = 0, *dst = 0; int x,y,val[N],value;

src = cvLoadImage(FILENAME, 0);// 0:强制转化为灰度图再处理,否则下面的滤波无效

dst = cvCloneImage( src ); cvNamedWindow(\ cvShowImage(\

for (y=1;yheight-1;y++)//边界不处理 for (x=1;xwidth-1;x++)

37

数字图像处理实验教程 V3.1

{ val[0]=(uchar)src->imageData[src->widthStep * (y-2) + (x-2)];

val[1]=(uchar)src->imageData[src->widthStep * (y-2) + (x -1) ]; val[2]=(uchar)src->imageData[src->widthStep * (y-2) + x];

val[3]=(uchar)src->imageData[src->widthStep * (y-2) + (x +1) ]; val[4]=(uchar)src->imageData[src->widthStep * (y-1) + (x+2)]; val[5]=(uchar)src->imageData[src->widthStep * (y-1) + (x-2)]; val[6]=(uchar)src->imageData[src->widthStep * (y-1) + ( x -1 ) ]; val[7]=(uchar)src->imageData[src->widthStep * (y-1) + x];

val[8]=(uchar)src->imageData[src->widthStep * (y-1) + (x +1) ];

val[9]=(uchar)src->imageData[src->widthStep * (y-1) + (x +2) ];

val[10]=(uchar)src->imageData[src->widthStep * y + (x-2)]; val[11]=(uchar)src->imageData[src->widthStep * y + (x -1) ]; val[12]=(uchar)src->imageData[src->widthStep * y + x];

val[13]=(uchar)src->imageData[src->widthStep * y + (x +1) ]; val[14]=(uchar)src->imageData[src->widthStep * y + (x+2)]; val[15]=(uchar)src->imageData[src->widthStep * (y+1) + (x-2)]; val[16]=(uchar)src->imageData[src->widthStep * (y+1) + (x -1) ]; val[17]=(uchar)src->imageData[src->widthStep * (y+1) + x];

val[18]=(uchar)src->imageData[src->widthStep * (y+1) +( x+1)]; val[19]=(uchar)src->imageData[src->widthStep * (y+1) + (x +2) ]; val[20]=(uchar)src->imageData[src->widthStep * (y+2) + (x-2)];

val[21]=(uchar)src->imageData[src->widthStep * (y+2) + (x -1) ]; val[22]=(uchar)src->imageData[src->widthStep * (y+2) + x];

val[23]=(uchar)src->imageData[src->widthStep * (y+2) +( x+1)]; val[24]=(uchar)src->imageData[src->widthStep * (y+2) + (x +2) ];

value = sum(val);

dst->imageData[dst->widthStep * y +x]=value;//给目标图像中对应像素赋灰度值 }

cvNamedWindow(\ cvShowImage(\

cvSaveImage(\保存图像 cvWaitKey(0);

cvReleaseImage( &src ); cvReleaseImage( &dst ); return 0; }

/* 程序名:filter2.c

功 能:使用不同的模板(滤波器)对图像进行滤波 */

#include

#include

38

数字图像处理实验教程 V3.1

#include

#define FILENAME \

int main( int argc, char** argv ) {

IplImage *src = 0, *dst = 0, *dst2 = 0; float k[9] = { 1, 1, 1, 0, 0, 0, -1,-1,-1}; /* float g[9] = { 1, 0, -1, 1, 0, -1,

1, 0, -1}; */ CvMat Km;

Km = cvMat( 3, 3, CV_32F, k );

src = cvLoadImage(FILENAME, 0);// 0: force to gray image dst = cvCloneImage( src ); cvNamedWindow(\ cvShowImage(\

cvNamedWindow(\

cvFilter2D( src, dst, &Km, cvPoint(-1,-1));//使用模板Km对图像进行二维滤波 cvShowImage(\cvSaveImage(“filter2.jpg”, dst); cvWaitKey(0);

cvReleaseImage( &src ); cvReleaseImage( &dst ); return 0; }

8. OpenCV函数解释

cvInitMatHeader初始化矩阵头函数 cvMat给矩阵赋值函数。

cvFilter2D对图像做卷积运算

语法:void cvFilter2D( const CvArr *src, CvArr *dst, const CvMat *kernel, CvPoint anchor=cvPoint(-1,-1)); 参数:src 输入图像。

dst 输出图像。

kernel 卷积核(即滤波器的模板),单通道浮点矩阵。

anchor:核的锚点,表示一个被滤波的点在核内的位置。默认为(-1,-1)表示锚点在核中心。

cvSmooth 低通滤波(去噪声)

39

数字图像处理实验教程 V3.1

语法:CVAPI(void) cvSmooth( const CvArr* src, CvArr* dst,

int smoothtype CV_DEFAULT(CV_GAUSSIAN), int param1 CV_DEFAULT(3), int param2 CV_DEFAULT(0), double param3 CV_DEFAULT(0), double param4 CV_DEFAULT(0));

cvLaplace计算图像的 Laplacian 变换(拉普拉斯锐化)

语法:void cvLaplace( const CvArr* src, CvArr* dst, int aperture_size=3 ); 参数: src 输入图像.

dst 输出图像.

aperture_size 核大小 (与 cvSobel 中定义一样).

功能:函数 cvLaplace 计算输入图像的 Laplacian变换,方法是先用 sobel 算子计算二阶 x- 和 y- 差分,再求和:

对 aperture_size=1 则给出最快计算结果,相当于对图像采用如下内核做卷积:

类似于 cvSobel 函数,该函数也不作图像的尺度变换,所支持的输入、输出图像类型的组合和cvSobel一致。

40

本文来源:https://www.bwwdw.com/article/l646.html

Top