随笔-145  评论-173  文章-70  trackbacks-0

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;

}

 

posted on 2010-03-16 13:21 deercoder 阅读(10796) 评论(7)  编辑 收藏 引用 所属分类: OpenCV

评论:
# re: OpenCV学习笔记(一) 2010-03-16 17:03 | anon
建议支持学2.0  回复  更多评论
  
# re: OpenCV学习笔记(一) 2010-03-16 22:03 | 刘畅
@anon
谢谢,以前装过2.0,不过嫌配置比较复杂就没有做了,貌似最近官方网站有说明,有时间去看看。  回复  更多评论
  
# re: OpenCV学习笔记(一) 2010-03-29 00:30 | df
建议使用VC Express, 2005,2008,2010都好,因为VC6和C++标准不相容,编译调试过程中可能会出现一些不可预知的问题。另外,新的OpenCV对C++增强不少,建议看看。  回复  更多评论
  
# re: OpenCV学习笔记(一) 2010-03-29 11:50 | 刘畅
@df
谢谢,有时间一定看看。  回复  更多评论
  
# re: OpenCV学习笔记(一) 2010-06-09 16:17 | Forsure
你好,文章写得非常的好,虽然很早就学习了这些基础内容,不过今天看了你的觉得还是收获不少,我最近又回来搞opencv,希望可以一起讨论交流。我的邮箱luanwpp#163.com,#号换成@。期待  回复  更多评论
  
# re: OpenCV学习笔记(一) 2011-04-29 23:55 | 郑郑郑
"
4. 注意类型和构造函数的区别。看看,定义一个变量的时候,用的是类型,即: CvPoint,CvSize,CvRect 等等,而对这个类型的变量初始化的时候用的是对应的构造函数,于是是 cvPoint,cvSize,cvRect, 看到规律了吗?类型的第一个首字母大写,而构造函数则是对应的类型名的第一个字母小写就可以了。因此, OpneCV 的这种命名方法还是很科学易记的。
"
cvPoint,cvSize,cvRect是构造函数?应该是结构体吧  回复  更多评论
  
# re: OpenCV学习笔记(一) 2011-05-25 10:38 | 刘畅
@郑郑郑
CvPoint Point1; //类型
cvPoint() //构造函数
初始化CvPoint资料结构,为OpenCV常用资料结构
cvPoint(int型别row,int型别colunm)   回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理