OpenCV 学习笔记
March 12, 2010
1. 关于数据基本类型的学习
参见代码:
//2010 年 3 月 12 日, Demo 1 OpenCV 的第一个例子 //author : liuchang #include <cv.h> #include <iostream> using namespace std; int main() { CvPoint p = cvPoint(1,3);// 针对整型的类型 CvPoint ,对应有构造函数 cvPoint ,注意大小写 cout << p.x << " " << p.y << endl; CvPoint2D32f p2 = cvPoint2D32f(12.34,43.45); cout << p2.x << " " << p2.y <<endl; CvPoint3D32f p3 = cvPoint3D32f(12.34,23.45,56.43); cout << p3.x << " " << p3.y << " " << p3.z << endl; //============================================================================= CvSize r = cvSize(3,4); // 长方形维数类型 cout << r.width << " " <<r.height << endl; CvSize2D32f r2 = cvSize2D32f(23.45,34.56); cout << r2.width << " " << r2.height << endl; //============================================================================= CvRect x = cvRect(3,4,12.34,45.56); cout << x.x << " " << x.y << " " << x.width << " " << x.height << endl;
return 0; } |
总结:学习到集中基本的数据类型
1. 点的类型。包括二维和三维,而每一个坐标又可以分为整型和浮点型。其中对于二维,用 2D 来表示,对于三维,用 3D 来表示。具体的见代码上,默认的 CvPoint 类型是一个二维的,整型参数的点。其他的见上。
2. 长方形维数类型。长方形已经固定时二维的类型,于是,形参就只用两个,但是类型可以是整型和浮点型,于是又多了 CvSize2D32f 这种类型了。
3. 有偏移量的长方形维数类型。此时前面两个形参就是偏移量的坐标,分别为 x 和 y 。后面的就是宽和高了。注意,形参的类型都是整型,所以,如果像上面的代码那样,就会发生截断处理,取整数部分,于是输出结果就会有所不同。
4. 注意类型和构造函数的区别。看看,定义一个变量的时候,用的是类型,即: CvPoint,CvSize,CvRect 等等,而对这个类型的变量初始化的时候用的是对应的构造函数,于是是 cvPoint,cvSize,cvRect, 看到规律了吗?类型的第一个首字母大写,而构造函数则是对应的类型名的第一个字母小写就可以了。因此, OpneCV 的这种命名方法还是很科学易记的。
附注: OpenCV 的安装过程以及 Visual C++ 的配置方法:
1. 下载 OpenCV 并安装。由于之前已经下载了 1.0 的版本,所以这里安装的是 1.0 ,默认路径安装,并选择注册环境变量。
2. 检查系统变量是否更改,尽管上面的选项可能会起作用,不过在我的系统中( Windows 7 ),环境变量还是没有更改,于是,选择高级系统设置 --- 环境变量 — 系统变量 —path— 编辑,就是在最后添加路径 ”; C:\Program Files\OpenCV\bin”, 然后点击确定退出。
3. 安装完成后,并不意味着工作就结束了,还需要设定我们的编程环境。具体来说就是 Visual C++ 6.0 的设置。
Visual C++ 6.0 中设置 OpenCV 的步骤:
1. 选择 tools---option, 在弹出的对话框中点击 Directories 标签,在 Show directories for 下拉选择 Include files ,在 Directories 中添加路径:
C:\Program Files\OpenCV\cxcore\include
C:\Program Files\OpenCV\cv\include
C:\Program Files\OpnCV\cvaux\include
C:\Program Files\OpenCV\otherlibs\highgui
C:\Program Files\OpenCV\otherlibs\cvcam\include
2. 在 Show directories for 下拉列表框中选择 Libarary files ,在 Directories 中添加路径:
C:\Program Files\OpenCV\lib
3. 在 Show directories for 下拉列表框中选择 Executable files ,在 Directories 中添加路径:
C:\Program Files\OpenCV\bin
4. 配置完毕,退出。
配置完毕之后的测试程序( Demo1 ),就是前面的测试程序,编译,运行, OK ,完全没有问题,证明配置完毕!
GUI 命令
1. 使用到图片处理,显示,创建窗口等命令的时候,必须要在 Project—Setting 选项中设定相应的参数,否则可能会发生连接错误!这个不同于上面的 Demo1 ,因为 1 中仅仅是用到了一个数据类型,而没有使用 CV 库函数的功能,比如显示,打开一个图片,运用到第三方库的话,肯定要调用 API 来实现功能,所以,链接库的话,必须要加入,为此,可根据提示信息设置,一般的,进行图像处理,都需要使用到这个。
2. 路径的问题。先看看 Demo2 程序 :
#include <cv.h> #include <highgui.h> #include <stdio.h>
int main() { IplImage* image = cvLoadImage("C:\\Users\\liuchang\\test1.bmp"); if(!image){ // 如果加载失败 printf("error: 导入图片出错,很可能是路径出错 !\n"); return 0; } cvNamedWindow("win1",CV_WINDOW_AUTOSIZE); // 创建一个窗口 cvMoveWindow("win1",100,100); // 定位一个窗口 cvShowImage("win1",image); // 在创建的窗口中显示一个图片 // cvWaitKey(0); // 等待用户输入,否则一闪而过 , 看不到图片 cvReleaseImage(&image); // 注意使用完后一定要释放 return 0; } |
此段程序中,功能很简单,就是帮助用户显示一副图片,运行程序,可以显示出来一幅已经存在的图片,而不需要任何的其他 API 来实现。在 OpenCV 中,处理图像的函数很多,此处只是简单的图像显示命令!
另外,上面的注释很清楚的显示了程序的各段代码的功能,这里不再说明。对于具体的说明,后面还会继续!需要注意的一点就是,路径,需要两个斜线,此处很重要,因为对于一个字符串,在作为路径打开的时候,需要 ”\\” 才能够被解释为一个斜线,所以如果像上面直接给出路径的话,需要指定是两个斜线,否则会出错!
OK ,下面试试从客户端来输入数据,即利用 main 函数可以从用户输入数据来编写:
#include <cv.h> #include <highgui.h> #include <stdio.h> #include <string.h>
int main(int argc, char **argv) { char num[20]; char getup[20]; int i ; itoa(argc,num,10); puts(num); puts(argv[0]); puts(argv[1]); strcpy(getup,argv[1]); for(i = 0; i < strlen(getup); i++) putchar(getup[i]); putchar('\\'); // 输出时一个斜线,而如果仅仅一个斜线的话,会报错! IplImage* image = cvLoadImage(argv[1]); if(!image){ // 如果加载失败 printf("error: 导入图片出错,很可能是路径出错 !\n"); return 0; } cvNamedWindow("win1",CV_WINDOW_AUTOSIZE); // 创建一个窗口 cvMoveWindow("win1",100,100); // 定位一个窗口 cvShowImage("win1",image); // 在创建的窗口中显示一个图片 cvWaitKey(0); // 等待用户输入,否则一闪而过 , 看不到图片 cvReleaseImage(&image); // 注意使用完后一定要释放 return 0; } |
关于 main 函数参数的问题,在前面的说明中很清楚,不过这里需要再次说明:
首先, argc 读入的是输入参数的个数,比如这里输入: test2 H:\ray.jpg ,那么读取的 argc 的个数就是 2 ,而 argv 是一个数组,用来存放你输入的参数,既然参数为 2 ,那么该数组就有两个参数,一个 argv[0] ,即前面的那个程序名 test2 ,而后面的那个参数就是你读入的那个路径。注意的一点是:读取后存放的路径和你输入的数据可能不同,具体来说就是,你输入的是 :H:\ray.jpg ,而在机内存储的这个字符串的内容是: H:\\ray.jpg ,也就是说,这个字符串是按照能够正常显示那个斜线符来设计的,也就是转义字符设计的,读入的数据将被转换成正确的能够表示的数据。从上面的验证代码中可以看到。
同时,计算 strlen(argv[1]) 也会发现,两个斜线 ’\\’ 被解释成一个字符!
对于, putchar(‘\\’) ,如果仅仅是一个斜线的话,会报错误,但是两个的话就正常显示一个 ’\’ 了。注意是表示的字符,用的单引号,所以,两个斜线被解释为一个字符。
Tips :如果输入参数是: test2 H:\\ray.jpg ,还是可以正常运行的。
注记:和 C 库函数不同,例如 open 函数,路径是 open(“C:\test.c”,O_RDONLY); 这样的话,里面就是一个斜线哦。所以 OpenCV 是不同的路径写法,一定要注意,还有上面解释的那个输入参数的问题,就 OK 了。
如果路径不对,则会有下面提示信息:
H:\OPENCV\test4\test4.cpp(15) : warning C4129: 'O' : unrecognized character escape sequence
H:\OPENCV\test4\test4.cpp(15) : warning C4129: 'l' : unrecognized character escape sequence
所以,一定要加双下划线!
3. 输入处理:
OpenCV 中如何响应鼠标事件呢?比如,如何响应点击鼠标,如何响应鼠标被按下呢?
其实,只需要你实现下面 mouseHandler 这个方法就可以了:
void mouseHandler(int event,int x,int y,int flags, void *param) { switch (event) { case CV_EVENT_LBUTTONDOWN: if(flags & CV_EVENT_FLAG_CTRLKEY) printf("Left button down with CTRL pressed!\n"); break; case CV_EVENT_LBUTTONUP: printf("Left button up!\n"); break; } } |
那么,如何注册鼠标监听呢?看下面这段代码:
int mouserParam = 5;
cvSetMouseCallback("win1",mouseHandler,&mouserParam);
也就是说,具体的实现监听函数由 mouseHandler 来完成,而要注册,也就是让它何时监听,监听哪一个窗口,则需要用 cvSetMouseCallback 函数来实现,具体的参数,可查阅 API 文档,当然,也可以由上面应用猜测出来。
上面的代码很容易就实现了鼠标被点击并且同时按下 CTRL 键的监听动作和鼠标释放的动作,当然,你还可以实现更多的功能,具体的就是使用 event 的判断,以及和 flags 联合实现的复合键判断!
4. 前面讲到了如何实现监听鼠标事件,那么这里讲下如何监听键盘事件:
看看下面的代码:
int key ;
key = cvWaitKey(0);
if(key == 'q'){
printf("quit\n");
return 0;
}
上面这段代码的意思就是不断的等待输入,如果输入时 q 的话就退出程序,实验之,发现有用。从这里引申下几点:
(1) 对于 cvWaitKey 函数的参数,就是等待的毫秒数,如果是 0 ,则表示不断的等待输入,进入一个循环。而它的返回值,就是你按下的按钮的键值。当然,如果要等待一定的时间,如果没有输入还是退出的话,可以采用 cvWaitKey(1000) 这样的具体参数,这样在等待的过程没有输入的话,还是可以正常退出,而不是想前面的循环在那里。
(2) 如果要实现不断循环的话,可以采用下面的这个形式:
while(1){
key = cvWaitKey(10);
if(key == 27)
break;
switch(key){
case 'h':
break;
case 'i':
break;
}
}
这种方式也很好的实现了循环等待多重输入的形式。
5. 如何处理拖动条事件:
上图即拖动条,如何创建并响应该事件呢?
1. 创建:
int trackbarVal = 25;
int maxVal = 100;
cvCreateTrackbar("bar1","win1",&trackbarVal,maxVal,trackbarHandler);
这样就设置了一个名称为 bar1 的拖动条。
2. 响应事件:利用函数 trackbarHandler 来实现
void trackbarHandler(int pos)
{
printf("Trackbar position: %d\n",pos);
}
注意这个监听是自动的。也就是说不需要自己进行任何的注册,只要创建了,并且写了这个函数,就可以实现自动的监听,因为,在创建的函数中,最后的一个参数就是一个监听的函数。
附记:完整的代码如下:
#include <cv.h> #include <highgui.h> #include <stdio.h> #include <string.h>
void mouseHandler(int event,int x,int y,int flags, void *param) { switch (event) { case CV_EVENT_LBUTTONDOWN: if(flags & CV_EVENT_FLAG_CTRLKEY) printf("Left button down with CTRL pressed!\n"); break; case CV_EVENT_LBUTTONUP: printf("Left button up!\n"); break; } }
void trackbarHandler(int pos) { printf("Trackbar position: %d\n",pos); }
int main(int argc, char **argv) { // char num[20]; // char getup[20]; // int i ; // itoa(argc,num,10); // puts(num); // puts(argv[0]); // puts(argv[1]); // strcpy(getup,argv[1]); // for(i = 0; i < strlen(getup); i++) // putchar(getup[i]); // putchar('\\'); IplImage* image = cvLoadImage(argv[1]); if(!image){ // 如果加载失败 printf("error: 导入图片出错,很可能是路径出错 !\n"); return 0; } cvNamedWindow("win1",CV_WINDOW_AUTOSIZE); // 创建一个窗口 cvMoveWindow("win1",100,100); // 定位一个窗口 cvShowImage("win1",image); // 在创建的窗口中显示一个图片 // int mouserParam = 5; // cvSetMouseCallback("win1",mouseHandler,&mouserParam); // int key ; // key = cvWaitKey(0); // 等待输入,等待时间为 1000ms // if(key == 'q'){ // printf("quit\n"); // return 0; // } int trackbarVal = 25; int maxVal = 100; cvCreateTrackbar("bar1","win1",&trackbarVal,maxVal,trackbarHandler); // int pos = cvGetTrackbarPos("bar1","win1"); // int pos = cvGetTrackbarPos("bar1","win1"); // cvSetTrackbarPos("bar1","win1",25);
cvWaitKey(0); // 等待用户输入,否则一闪而过 , 看不到图片 cvReleaseImage(&image); // 注意使用完后一定要释放 return 0; }
|