码迷,mamicode.com
首页 > 其他好文 > 详细

OpenCV 1.x 2.x

时间:2014-10-09 00:32:27      阅读:451      评论:0      收藏:0      [点我收藏+]

标签:style   blog   color   io   os   使用   ar   for   文件   

 

网上现有资料大多基于 OpenCV 1.x 的,其实基于 C++ 的 OpenCV 2.x 使用面向对象的思想,对各种函数库进行了更好的封装,加入了自动内存管理,相比基于 C 的 1.x 版本要好用的多。当然,2.x 版本的 OpenCV (大多数时候)也能向下兼容 1.x 版。1.x 版本的头文件包含在文件夹“includeopencv”中,而 2.x 版本的头文件包含在文件夹“includeopencv2”中。

OpenCV 2.x 同时提供了 C 语言版和 C++ 版,可根据项目需求选择。C++ 版的头文件扩展名一般为“.hpp”,如“core.hpp”,对应的 C 语言版一般扩展名为“.h”,同时文件名末尾一般会加上“_c”,如“core_c.h”。

 

C++ 版本所有类和函数等都包含在命名空间“cv”中。函数命名规则上,一般 C 语言版本以“cv”开头,按照驼峰规则命名,如“cvNamedWindow”,对应的 C++ 版本一般去掉了前面的“cv”(因为使用了命名空间),如“namedWindow”。同样,在一些枚举类型上也有类似规则,如 C 版本中的“CV_WINDOW_AUTOSIZE”,对应 C++ 版本为“WINDOW_AUTOSIZE”,当然,这两个版本下的值一般是相同的,所以即使混用,关系也不大。

1.x 版本到 2.x 版本还有一些变化较大的是,在老版本上,图像的处理一般用 IplImage,矩阵处理一般用 cvMat,新版本上全部统一到了 cv::Mat 类,使用更加方便。凡此种种,不一而足。

使用配置

以 32位系统下 Visual Studio 2010 为例,这里假设 OpenCV 安装在“E:opencv”目录下。

建好项目之后,在项目上右键选择属性,在“配置属性”->“VC++目录”选项中的包含目录添加“E:opencvopencv2.4.5opencvbuildinclude”,“库目录”添加“E:opencvopencv2.4.5opencvbuildx86vc10lib”。如果没有把 OpenCV 目录加入到环境变量的话,运行时会提示缺少 dll,可前往“E:opencvopencv2.4.5opencvbuildx86vc10bin”目录下选择所需的 dll 复制到运行目录下。

下面列举一些 OpenCV 的最基本用法,主要使用 OpenCV 2.4.5 C++ 版本。

显示图像

这个相当于 OpenCV 的 hello world。

首先要包含头文件,然后引用命名空间:

1 #include "opencv2/opencv.hpp"
2 using namespace cv;

然后需要引入两个库文件:

1 const string wnd_name = "Test OpenCV";
2 namedWindow(wnd_name);
3 
4 const string file_name = "D:\a.jpg";
5 Mat img = imread(file_name);
6 imshow(wnd_name, img);

程序能够运行还需要两个对应的 dll:opencv_core245d.dll 和 opencv_highgui245d.dll,将这两个 dll 拷到 Debug 目录下即可。

要显示图像首先需要创建一个窗口,OpenCV 中使用函数 namedWindow() 创建,其原型如下:

void namedWindow(const string& winname, int flags = WINDOW_AUTOSIZE);

第一个参数为标准库 string 类型,表示该窗口的名称,该名称将显示在窗口栏上,OpenCV 用该名称唯一标识一个窗口;
第二个参数表示窗口类型,只有三个可选值:WINDOW_NORMAL、WINDOW_AUTOSIZE、WINDOW_OPENGL,其中 WINDOW_NORMAL 允许用户拖动窗口改变其大小,WINDOW_AUTOSIZE 则自动根据图像尺寸调整大小,不运行用户改变,WINDOW_OPENGL 使用 OpenGL 进行显示。

然后需要读入图像。使用 Mat imread( const string& filename, int flags=1 ); 函数从文件读入图像数据。该函数的第二个参数 flag 有多个取值,默认的为 IMREAD_COLOR,常用的还有 IMREAD_GRAYSCALE 读入为灰度图像。该函数返回值是一个 Mat 类型,具体像素数据存储在 Mat.data 中。

这里有必要说一下 Mat.data。首先,其中的数据是按行存储的,每行占多少个字节由图像的宽度和通道数决定。Mat 中有一个 step 数组,对于二维的图像来说,Mat.step[0] 存储的就是一行(第一维)的步长,也就是一行占用的字节数,Mat.step[1] 存储的为第二维,即一个元素(像素)的宽度,对于 RGB 图像,step[1] 为 3,step[0] 为图像宽度乘以step[1]。其次,Mat.data 中的数据是按照 BGR 存储的。最后,每个像素的数据最好不要直接使用 data 访问,可使用 Mat.at() 等函数访问,这个后面再说。

最后使用 imshow() 函数将读入的数据显示在上面创建好的窗口即可。

在 MFC 控件中显示图像

事实上只是把 OpenCV 自动生成的窗口绑定到 MFC 窗口的控件上,如果只是需要显示图像文件的话,建议使用 GDI++ 实现,效果更佳,这里用 OpenCV 实现主要是为了方便在图像处理过程中直接在界面上看到效果。

 1 CWnd* ctl = GetDlgItem(IDC_IMG);
 2 CRect rc;
 3 ctl->GetClientRect(&rc);
 4 
 5 namedWindow(wnd_name, flags);
 6 resizeWindow(wnd_name, rc.Width(), rc.Height());
 7 
 8 HWND hWnd = (HWND)cvGetWindowHandle(wnd_name.c_str());
 9 HWND hParent = ::GetParent(hWnd);
10 ::SetParent(hWnd, ctl->m_hWnd);
11 ::ShowWindow(hParent, SW_HIDE);
12 
13 imshow(wnd_name, img);

随便放一个控件,比如 STATIC_TEXT 控件 IDC_IMG,使用 OpenCV 的方法创建一个名为 wnd_name 的窗口,然后将其大小调整为控件相同大小,再将其绑定到主窗口上,然后隐藏掉 OpenCV 的窗口即可。图像的显示跟平常一样,使用 imshow() 即可。

此法有两个弊端,一是在 OpenCV 创建的窗口隐藏的时候可以看到它闪一下,这个相当不爽,目前还没有找到解决办法;另一个是由于控件大小固定,显示的图像不会自动缩放而是裁剪了,这个在 imshow() 和 namedWindow() 里没有看到解决办法,只能自己进行缩放了。

图像数据修改

这里的修改指的是直接修改像素数据,比如:需要在指定位置画一个绿色的十字叉。

以上面读入的 img 为例,在 cv::Point pt(300, 200) 处画一个单边长度为 len=8 的绿色十字叉,操作如下:

 1 Point pt(300, 200);
 2 const int len = 8;
 3 
 4 int rows = img.rows;
 5 int cols = img.cols;
 6 
 7 for(int i=0; i<len; i++){
 8     // 画横
 9     if((pt.x) + i < cols){
10         img.at<BYTE>(pt.y, ((pt.x) + i) * img.step[1]+0) = 0;
11         img.at<BYTE>(pt.y, ((pt.x) + i) * img.step[1]+1) = 255;
12         img.at<BYTE>(pt.y, ((pt.x) + i) * img.step[1]+2) = 0;
13     }
14 
15     if((pt.x) - i >= 0){
16         img.at<BYTE>(pt.y, ((pt.x) - i) * img.step[1]+1) = 0;
17         img.at<BYTE>(pt.y, ((pt.x) - i) * img.step[1]+1) = 255;
18         img.at<BYTE>(pt.y, ((pt.x) - i) * img.step[1]+2) = 0;
19     }
20 
21     // 画竖
22     if((pt.y) + i < rows){
23         img.at<BYTE>((pt.y) + i, (pt.x) * img.step[1]+0) = 0;
24         img.at<BYTE>((pt.y) + i, (pt.x) * img.step[1]+1) = 255;
25         img.at<BYTE>((pt.y) + i, (pt.x) * img.step[1]+2) = 0;
26     }
27 
28     if((pt.y) - i >= 0){
29         img.at<BYTE>((pt.y) - i, (pt.x) * img.step[1]+0) = 0;
30         img.at<BYTE>((pt.y) - i, (pt.x) * img.step[1]+1) = 255;
31         img.at<BYTE>((pt.y) - i, (pt.x) * img.step[1]+2) = 0;
32     }
33 }
34 imshow(wnd_name, img);

首先,Point 的 x 对应于图像的列,y 对应于行,而 Mat 的访问是按照 (行, 列) 的方式访问,不要搞反了。其次,要注意边界问题。

img.at(pt.y, ((pt.x) – i) * img.step[1]+1) 指按字节访问 img.data 中的第 pt.y 行,第 ((pt.x) – i) * img.step[1]+1 列。列为什么会是这个,在上面 Mat 部分已经讲了,RGB 图像,第 pt.y 行第 pt.x 个像素占了 img.step[1] 个字节,其中第 2 个字节表示“G”通道,将其值修改为 255,其他两个通道修改为 0,则该像素显示为绿色。

TO BE CONTINUED

OpenCV 1.x 2.x

标签:style   blog   color   io   os   使用   ar   for   文件   

原文地址:http://www.cnblogs.com/shiddong/p/4011566.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!