OpenCV 1.x 2.x

网上现有资料大多基于 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

时间: 2024-10-10 15:05:00

OpenCV 1.x 2.x的相关文章

MAC平台下Xcode配置使用OpenCV的具体方法 (2016最新)

1.序言: 1.1 背景 本人小白一枚,不过因为最近在从事机器视觉方面的工作,所以接触到OpenCV. 因为工作需求,本人要在MAC端使用OpenCV实现一些视觉功能,配置环境成了最大的阻碍,网上查了很多相关资料和博客,都因为版本环境问题屡试屡败,不过经历重重尝试,笔者最终还是配置成功并运行了自己的源码.当然成功的关键还是因为笔者站在了巨人的肩膀上,借鉴了很多网上的教程,为了不误导大家配置的过程,参考文章的地址统一放在文章里,望各位大大看见之后能够理解,废话不说进入正题. 1.2 环境说明 如果

Ubuntu16.04安装tensorflow+安装opencv+安装openslide+安装搜狗输入法

Ubuntu16.04在cuda以及cudnn安装好之后,安装tensorflow,tensorflow以及opencv可以到网上下载对应的安装包并且直接在安装包所在的路径下直接通过pip与conda进行安装,如下图所示: 前提是要下载好安装包.安装好tensorflow之后还需要进行在~/.bashrc文件中添加系统路径,如下图所示 Openslide是医学图像一个重要的库,这里给出三条命令进行安装 sudo apt-get install openslide-tools sudo apt-g

关于opencv的文件配置详细内容

原文链接:http://blog.csdn.net/zhuce0001/article/details/21279527 最近在做opencv的一些代码的修修补补的工作: 但在此之前,根本没接触过cpp,更别谈vs,opencv 最近一段时间改代码,感觉自己学习很多东西,在这个过程中一直不断查资料,也没有时间去好好整理一下,但是查资料的过程中发现很多很好的博客,就记录下来方便自己日后查询,很感谢这些热爱分享的大佬 一.只对当前工程起作用的设置1. 设置头文件包含路径   工程上右击,选择"属性&

什么是图像 -- opencv基础

opencv基础篇--到底什么是图像 什么是图像?英语中有两个单词来形容图像,一个是picture,一个是image.这两者虽然是形容同一个东西,但却又有着区别.picture代表实而有物的真实图像:而image代表着计算机中存储的图像,也代表想象中的图像. 而我们更多研究的便是image,计算机图像从广义地可分为矢量图和像素图(位图).矢量图,是由一系列计算机指令描述和记录的一幅图,一幅图可以解为一系列由点.线.面等组成的子图.像素图,则是由很多个点组成的,每个点都是由二进制数据来描述和存储其

OpenCV点滴3

这段时间想稍微系统地学下: 1.Mat-基本图像容器: OpenCV函数中输出图像的内存分配是自动完成的(如果不特别指定的话). 使用OpenCV的C++接口时不需要考虑内存释放问题. 赋值运算符(=)和拷贝构造函数( Mat A,Mat B(A) )只拷贝信息头. 使用函数 clone() 或者 copyTo() 来拷贝一副图像的矩阵. Mat M(2,2, CV_8UC3, Scalar(0,0,255)); 行数,列数,8位,3通道,指定的值初始化: Point2f P(5,1) -->[

OpenCV教程

<OpenCV3编程入门>内容简介&勘误&配套源代码下载 [OpenCV入门教程之十八]OpenCV仿射变换 & SURF特征点描述合辑 [OpenCV入门教程之十七]OpenCV重映射 & SURF特征点检测合辑 [OpenCV入门教程之十六]OpenCV角点检测之Harris角点检测 [OpenCV入门教程之十五]水漫金山:OpenCV漫水填充算法(Floodfill) [OpenCV入门教程之十四]OpenCV霍夫变换:霍夫线变换,霍夫圆变换合辑 [Ope

Kinect2入门+opencv画骨架+骨架数据

////////////////////////////准备工作/////////////////////////////// 首先需要下载安装Kinect2的SDK,下载地址如下: https://www.microsoft.com/en-us/download/details.aspx?id=44561 建议安装时从官网下载,之前有出现过拷贝的文件无法正常安装的情况. //注意V2.0以下版本为一代Kinect所用,一代Kinect推荐V1.8 相对于一代的Kinect,二代由于SDK只出过

基于OpenCV立体视觉标定和校正

这几天学习双目视觉标定,分别使用了两种工具:OpenCV和Matlab.Matlab的效果非常稳定,但是一开始OpenCV的效果很糟糕,要不是出现中断就是标定出来的结果数值很大.经过了几天的不断调试和更改,终于把OpenCV的立体视觉标定和校正的程序写出来了.立体标定时计算空间上的两台摄像机几何关系的过程,立体校正则是对个体图像进行纠正,保证这些图像可以从平面对准的两幅图像获得.程序的框架如下: 1.读取左右相机图片序列 双目相机的图片序列放在Demon的路径下,左右相机的图像的名字分别存放在两

利用颜色和形态学两种方法进行车牌区域提取的OpenCV代码

要想提取车牌号,首先你要定位车牌区域嘛,本文分别两种方法用,即颜色和形态学的方法,对车牌区域进行判定.说得是两种方法,其实两种方法并无多大的区别,只是有一步的判断标准不一样而已,你看了下面整理出的的思路就知道两者的区别真的很小了. 方法一:利用颜色提取车牌区域的思路: ①求得原图像的sobel边缘sobelMat ②在HSV空间内利用车牌颜色阈值对图像进行二值化处理,得到图像bw_blue→ ③由下面的判别标准得到图像bw_blue_edge for (int k = 1; k != heigh

OpenCV与EmguCV中的图像轮廓提取

轮廓是图像中表示边界的一系列点的集合. 虽然边缘检测算法可以根据像素间的差异检查出轮廓边界的像素,但是它并没有把轮廓做为一个整体表示出来.所以下一步工作是把这些边缘检测出来的像素组装成轮廓. openCV中可以用findContours()函数来从二值图像中提取轮廓. openCV中一般用序列来存储轮廓信息.序列中的每一个元素是曲线中一个点的位置. 函数findContours()从二值图像中寻找轮廓.findContours()处理的图像可以是Canny()后得到的有边缘像素的的图像,也可以是