OpenCV3学习笔记(1)
1. 版本
OpenCV Version 3.4.5 CMake Version 3.6.3 MinGW Version x86_64-8.1.0-release-posix-seh-rt_v6-rev0 Clion Version 2018.2.2
2. 图像读入与输出
2.1 命名空间与Mat类
OpenCV的所有类和函数都声明在命名空间cv
,所以代码开头加上using namespace cv
可以方便的使用其中的各种类和函数。否则的话,在使用前还需要加上cv::
这样的领域限定符。
OpenCV中的图像都存储在其的Mat类的对象中,可以认为Mat就是一个矩阵,存储图像个像素的信息。
2.2 图像的载入
图像的载入只需要一行代码
Mat scrImage = imread(string fileName, int flag=1)
其中第二个参数flag默认是1,表示读入的方式,flag不同表示不同种的读入方式。通过查看源代码imgcodecs.hpp,其中的ImreadModes枚举类型如下。
enum ImreadModes {
IMREAD_UNCHANGED = -1, // 原始图像
IMREAD_GRAYSCALE = 0, // 单通道灰度值
IMREAD_COLOR = 1, // 3通道RGB图
IMREAD_ANYDEPTH = 2, // 当图片深度足够时转换为16/32位深度图片,否则为8位深度图片
IMREAD_ANYCOLOR = 4, // 以任何可能的颜色读取图像
IMREAD_REDUCED_GRAYSCALE_2 = 16, // 转换为单通道灰度值并将图片尺寸缩小到原来1/2
IMREAD_REDUCED_COLOR_2 = 17, // 转换为3通道RGB图片并将图片尺寸缩小到原来的1/2
IMREAD_REDUCED_GRAYSCALE_4 = 32, // 转换为单通道灰度值并将图片尺寸缩小到原来1/4
IMREAD_REDUCED_COLOR_4 = 33, // 转换为3通道RGB图片并将图片尺寸缩小到原来的1/4
IMREAD_REDUCED_GRAYSCALE_8 = 64, // 转换为单通道灰度值并将图片尺寸缩小到原来1/8
IMREAD_REDUCED_COLOR_8 = 65, // 转换为3通道RGB图片并将图片尺寸缩小到原来的1/8
IMREAD_IGNORE_ORIENTATION = 128, // 忽略EXIF的旋转标志
};
其中最长用的还属flag=-1,flag=0,flag=1这三种,当图片过大的时候,可以选择适当比例缩放。效果如图1.1所示。
2.3 图像的输出
OpenCV中图像输出一般使用imwirte函数,声明如下
imwrite(const String & filename, InputArray img, const std::vector< int > & params = std::vector< int >() )
filename为文件名,img为要保存的图像变量,params为保存的参数。 可以看到img的格式要求是InputArray类型的,一般我们传入Mat类的变量即可。InputArray和Mat类的关系有必要说明一下。
首先在官方文档中,可以看到
typedef const _InputArray& cv::InputArray
也就是_InputArray
和InputArray
没有什么区别,带下划线的是其引用类型。对InputArray
的定义是// Proxy datatype for passing Mat's and vector<>'s as input parameters class _InputArray。 当我们查看_InputArray
可以看到。其中有个参数为Mat的构造函数,这也就解释的通为什么参数是InputArray
时,传入Mat
类型的变量是可以的了。
class CV_EXPORTS _InputArray
{
......
_InputArray();
_InputArray(const Mat& m); // 构造函数
......
};
......
_InputArray::_InputArray(const Mat& m) : flags(MAT), obj((void*)&m) {}
第三个参数params,一般情况下可以忽略不写,具体介绍可以参见官方文档。
2.4 代码示例
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
Mat srcImage1 = imread("data.jpg", -1);
Mat srcImage2 = imread("data.jpg", 0);
Mat srcImage3 = imread("data.jpg", 1);
if(!srcImage1.empty()) imshow("Image1", srcImage1);
else {
cout << "scrImage is empty! Please check your image dir!" << endl;
return -1;
}
if(!srcImage2.empty()) imshow("Image2", srcImage2);
else {
cout << "scrImage is empty! Please check your image dir!" << endl;
return -1;
}
if(!srcImage3.empty()) imshow("Image3", srcImage3);
else {
cout << "scrImave is empty! Please check your image dir!" << endl;
}
imwrite("dst1.jpg", srcImage1);
imwrite("dst2.jpg", srcImage2);
imwrite("dst3.jpg", srcImage3);
waitKey();
return 0;
}
3. 窗口组件的创建
3.1 窗口的创建
窗口的创建需要用到namedWindow()
函数。当然在使用imshow()
函数的时候,OpenCV会自动创建一个窗口。所以如果只是简单的显示图面,直接调用imshow()
函数即可,没有必要先创建窗口,再显示图片。nameWindow()
的定义如下
void namedWindow ( const String & winname,int flags = WINDOW_AUTOSIZE )
第一个参数为窗口的名称,第二个参数为标志位,默认为自动大小。在官方文档中,给出了一系列的参数,如下所示。
enum WindowFlags {
WINDOW_NORMAL = 0x00000000, // 可以自由更改窗口大小(可拖拽)
WINDOW_AUTOSIZE = 0x00000001, // 窗口大小由图片决定,不可自由更改
WINDOW_OPENGL = 0x00001000, // OpenGL支持的窗口
WINDOW_FULLSCREEN = 1, // 全屏
WINDOW_FREERATIO = 0x00000100, // 最大化,不受图片的纵横比影响
WINDOW_KEEPRATIO = 0x00000000, // 图片纵横比保持不变
WINDOW_GUI_EXPANDED=0x00000000, // 带状态栏和工具栏
WINDOW_GUI_NORMAL = 0x00000010, // 旧式窗口形式
};
这些参数可以根据实际需要进行选择。
3.2 滑动条的创建
在实际的时候,可能经常需要调整成参数,如果使用修改代码再编译运行的方式,会十分繁琐。一个简单的方式是创建一个滑动条,使用滑动条动态修改参数,实时预览。
滑动条创建需要两部分,一部分使用滑动条创建函数创建滑动条,另一部分设置滑动条的回调函数。 创建滑动条需要使用createTrackbar()
函数。函数原型如下。
int createTrackbar ( const String & trackbarname,const String & winname, int * value, int count, TrackbarCallback onChange = 0,void * userdata = 0 )
第一个参数trackbarname为滑动条的名字; 第二个参数winname为窗口的名字; 第三个参数value指针为int型的指针,表示滑动条创建时的初始值,在移动滑动条的过程中也会改变这个值; 第四个参数count为滑动条的最大值; 第五个参数onchange为滑动条的回调函数,回调函数即在改变滑动条的值后会执行何种操作; 第六个参数userdata是用户的其他类型数据,即在回调函数中,还需要什么参数。
在创建滑动条的时候,会默认创建到窗口的最上方,如果有多个,根据窗口宽度选择向右平铺还是向下平铺。 创建完滑动条后,可以就要编写滑动条的回调函数了,回调函数是一个必须以int类型作为第一个参数, void*类型作为第二个参数的函数,分别对应滑动条创建过程中的第三个参数和第六个参数。如:
namedWindow("TrackBarTest");
createTrackbar("TrackBar1", "TrackBarTest", &initPosition1, 10, moveOnTrackBar1, &initPosition2);
void moveOnTrackBar1(int value , void * otherValue) {
int * pOtherValue = (int*)otherValue;
cout << "TrackBar1: " << value << " " << (*pOtherValue) << endl;
}
3.3 代码示例
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
void moveOnTrackBar1(int value , void * otherValue) {
int * pOtherValue = (int*)otherValue;
cout << "TrackBar1: " << value << " " << (*pOtherValue) << endl;
}
void moveOnTrackBar2(int value, void * otherValue) {
int * pOtherValue = (int*)otherValue;
cout << "TrackBar2: " << value << " " << (*pOtherValue) << endl;
}
int main() {
int initPosition1 = 0, initPosition2 = 0;
namedWindow("TrackBarTest", WINDOW_AUTOSIZE);
Mat srcImage = imread("data.jpg");
imshow("TrackBarTest", srcImage);
createTrackbar("TrackBar1", "TrackBarTest", &initPosition1, 5, moveOnTrackBar1, &initPosition2);
createTrackbar("TrackBar2", "TrackBarTest", &initPosition2, 5, moveOnTrackBar2, &initPosition1);
waitKey();
return 0;
}