第一件事:HighGUI 模块学习
1. OpenCV 命名空间
之前的代码每一个 OpenCV 类和函数之前都会加上 cv:: ,这是因为 OpenCV 的代码都是定义在命名空间 cv 之内的,需要通过在类和函数之前加上 cv:: 对 cv 命名空间内的类和函数进行调用。但是还有一种更方便的用法,是在代码开头的适当位置加上 using namespace cv;
这句代码。规定之后的程序都位于此命名空间之内。
比如:
#include <opencv2/opencv.cpp>
using namespace cv;
这样,之后的程序都不需要再加 cv:: 前缀。
2. 图像载入: imread 函数
imread 函数用于读取文件中的图片到 OpenCV 中。原型如下:
Mat imread(const string& filename, int flags = 1);
- 第一个参数,const string& 类型的变量,需要填入图片的路径名。
支持如下类型的图像输入:
类型 | 后缀 |
---|---|
位图 | *.bmp,*.dib |
JPEG文件 | *.jpeg,*.jpg,*.jpe |
JPEG 2000 文件 | *.jp2 |
PNG图片 | *.png |
便携文件格式 | *.pbm,*.pgm,*ppm |
Sun rasters 光栅文件 | *.sr,*.ras |
TIFF 文件 | *.tiff,*.tif |
- 第二个参数,int 类型的变量,指定一个加载图像的显示颜色类型。默认值为 1,表示载入三通道的彩色图。我们可以在 imgcodecs_c.h( OpenCV2 中,被定义在 higui_c.h 文件中) 文件中找到这个枚举的定义:
enum
{
/* 8bit, color or not */
CV_LOAD_IMAGE_UNCHANGED =-1,
/* 8bit, gray */
CV_LOAD_IMAGE_GRAYSCALE =0,
/* ?, color */
CV_LOAD_IMAGE_COLOR =1,
/* any depth, ? */
CV_LOAD_IMAGE_ANYDEPTH =2,
/* ?, any color */
CV_LOAD_IMAGE_ANYCOLOR =4,
/* ?, no rotate */
CV_LOAD_IMAGE_IGNORE_ORIENTATION =128
};
参数名 | 介绍 |
---|---|
CV_LOAD_IMAGE_UNCHANGED | 和 CV_LOAD_IMAGE_ANYCOLOR 相比,除了会载入Alpha通道外基本是同等效果的,所以这个参数渐渐使用的很少了。 |
CV_LOAD_IMAGE_GRAYSCALE | 将图像转为灰度再返回。 |
CV_LOAD_IMAGE_COLOR | 将图像转换为3通道彩色再返回。 |
CV_LOAD_IMAGE_ANYDEPTH | 若载入图像深度为 16 位 或 32 位,就返回对应深度的图像,否则将图像深度转为8位再返回。 |
CV_LOAD_IMAGE_ANYCOLOR | 保持颜色通道不变 |
CV_LOAD_IMAGE_IGNORE_ORIENTATION | 忽略图片文件中的 orientation 旋转参数载入 |
注意:如果输入的参数之间有冲突,则会采用较小的值。如 CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYCOLOR
将按照 CV_LOAD_IMAGE_COLOR
载入三通道图。
若这个参数不取这个枚举值,那么将会按照:
- flags > 0 返回 3 通道彩色图(CV_LOAD_IMAGE_COLOR);
- flags = 0 返回灰度图(CV_LOAD_IMAGE_GRAYSCALE);
- flags < 0 返回包含Alpha通道的彩色图(CV_LOAD_IMAGE_UNCHANGED);
这个规则载入图像。
3.图像显示: imshow 函数
imshow 用于在指定窗口显示图像,原型如下:
void imshow(const string& winname, InputArray Mat);
- 第一个参数:const string& 类型的变量,需要显示的窗口名。
- 第二个参数:InputArray 类型的变量,需要显示的图像。如果窗口是用 CV_WINDOW_AUTOSIZE(默认值) 创建的,那么就按图像原始大小显示(窗口会自动适应图片大小)。否则缩放图像适应窗口大小。而 imshow 函数对图像深度的缩放会规范到[0,255] 区间,即 8 位深度。
InputArray 类型:
在 opencv_core 模块中的 mat.hpp 头文件中可以找到该类型定义:
typedef const _InputArray& InputArray;
class CV_EXPORTS _InputArray
{
public:
enum {
KIND_SHIFT = 16,
FIXED_TYPE = 0x8000 << KIND_SHIFT,
FIXED_SIZE = 0x4000 << KIND_SHIFT,
KIND_MASK = 31 << KIND_SHIFT,
NONE = 0 << KIND_SHIFT,
MAT = 1 << KIND_SHIFT,
MATX = 2 << KIND_SHIFT,
STD_VECTOR = 3 << KIND_SHIFT,
STD_VECTOR_VECTOR = 4 << KIND_SHIFT,
STD_VECTOR_MAT = 5 << KIND_SHIFT,
EXPR = 6 << KIND_SHIFT,
OPENGL_BUFFER = 7 << KIND_SHIFT,
CUDA_HOST_MEM = 8 << KIND_SHIFT,
CUDA_GPU_MAT = 9 << KIND_SHIFT,
UMAT =10 << KIND_SHIFT,
STD_VECTOR_UMAT =11 << KIND_SHIFT,
STD_BOOL_VECTOR =12 << KIND_SHIFT,
STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT
};
_InputArray();
_InputArray(int _flags, void* _obj);
_InputArray(const Mat& m);
_InputArray(const MatExpr& expr);
_InputArray(const std::vector<Mat>& vec);
template<typename _Tp> _InputArray(const Mat_<_Tp>& m);
template<typename _Tp> _InputArray(const std::vector<_Tp>& vec);
_InputArray(const std::vector<bool>& vec);
template<typename _Tp> _InputArray(const std::vector<std::vector<_Tp> >& vec);
template<typename _Tp> _InputArray(const std::vector<Mat_<_Tp> >& vec);
template<typename _Tp> _InputArray(const _Tp* vec, int n);
template<typename _Tp, int m, int n> _InputArray(const Matx<_Tp, m, n>& matx);
_InputArray(const double& val);
_InputArray(const cuda::GpuMat& d_mat);
_InputArray(const std::vector<cuda::GpuMat>& d_mat_array);
_InputArray(const ogl::Buffer& buf);
_InputArray(const cuda::HostMem& cuda_mem);
template<typename _Tp> _InputArray(const cudev::GpuMat_<_Tp>& m);
_InputArray(const UMat& um);
_InputArray(const std::vector<UMat>& umv);
Mat getMat(int idx=-1) const;//常成员函数,不能改变成员变量值的函数
Mat getMat_(int idx=-1) const;
UMat getUMat(int idx=-1) const;
void getMatVector(std::vector<Mat>& mv) const;
void getUMatVector(std::vector<UMat>& umv) const;
void getGpuMatVector(std::vector<cuda::GpuMat>& gpumv) const;
cuda::GpuMat getGpuMat() const;
ogl::Buffer getOGlBuffer() const;
int getFlags() const;
void* getObj() const;
Size getSz() const;
int kind() const;
int dims(int i=-1) const;
int cols(int i=-1) const;
int rows(int i=-1) const;
Size size(int i=-1) const;
int sizend(int* sz, int i=-1) const;
bool sameSize(const _InputArray& arr) const;
size_t total(int i=-1) const;
int type(int i=-1) const;
int depth(int i=-1) const;
int channels(int i=-1) const;
bool isContinuous(int i=-1) const;
bool isSubmatrix(int i=-1) const;
bool empty() const;
void copyTo(const _OutputArray& arr) const;
void copyTo(const _OutputArray& arr, const _InputArray & mask) const;
size_t offset(int i=-1) const;
size_t step(int i=-1) const;
bool isMat() const;
bool isUMat() const;
bool isMatVector() const;
bool isUMatVector() const;
bool isMatx() const;
bool isVector() const;
bool isGpuMatVector() const;
~_InputArray();
protected:
int flags;
void* obj;
Size sz;
void init(int _flags, const void* _obj);
void init(int _flags, const void* _obj, Size _sz);
};
可以看出这是一个代理类并通过 c++ 的转换构造函数机制,实现传入 Mat 类型并转为 InputArray 的相应构造函数 _InputArray(const Mat& m);
,构造出一个 InputArray 类型的对象。
代理类:目标类(可多个)为其内部的 private、protected 类型成员变量,并通过创建同名方法以及对目标类相应方法的调用,完成对目标类的代理行为。
简而言之,就是替目标类传话的一个类。
4. 创建窗口:namedWindow 函数
namedWindow 的函数原型如下:
void namedWindow(const string& winname, int flags=WINDOW_AUTOSIZE);
- 第一个参数,const string& 类型的变量,窗口标识符。
- 第二个参数,int 类型的变量,窗口类型。
类型 | 介绍 |
---|---|
WINDOW_NORMAL | 用户可以改变窗口的大小 |
WINDOW_AUTOSIZE | 窗口自动调整,以显示所显示的图像。用户不可以手动设置。 |
WINDOW_OPENGL | 使创建的窗口支持OpenGL |
5. 输出图像到文件:imwrite 函数
imwrite 函数原型如下:
bool imwrite(const string& filename,InputArray img, vector<int> params=vector<int>());
- 第一个参数:const string& 类型的变量,文件名(需要后缀)。
- 第二个参数:InputArray 类型的数据,一般是 Mat 类型的图像数据。
- 第三个参数:vector<int> 类型的变量,特定格式保存的参数编码。它有默认值。
图片格式 | 介绍 |
---|---|
JPEG | 这个参数表示从 0 到 100 的图片质量,默认值95。 |
PNG | 这个参数表示压缩级别(CV_IMWRITE_PNG)从 0 到 9。值越高意味着,尺寸越小,压缩时间越长。 默认值是 3 |
PPM,PGM,PBM | 表示二进制格式标志(CV_IMWRITE_PXM_BINARY),取值为 0 或者 1。 |
支持保存的几种图片格式与支持读取的几种图片格式一致。
6. 图像载入、显示与输出的综合程序
#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, const char * argv[]) {
//载入图像
cv::Mat image = cv::imread("1.jpg");
cv::Mat logo = cv::imread("Code_r_Wang.jpg");
//显示原图像
cv::namedWindow("1.jpg");
cv::imshow("1.jpg", image);
//显示logo图像
cv::namedWindow("Code_r_Wang.jpg");
cv::imshow("Code_r_Wang.jpg", logo);
//选取部分图像
cv::Mat imageROI;
imageROI = image(cv::Rect(image.cols - logo.cols - 10, image.rows - logo.rows - 10, logo.cols, logo.rows));
//混合图像(这个函数放到后面学)
cv::addWeighted(imageROI, 0.5, logo, 0.5, 0.0, imageROI);
//展示结果图
cv::namedWindow("result");
cv::imshow("result", image);
//图像输出到文件
cv::imwrite("叠加的结果图像.jpg", image);
cv::waitKey();
return 0;
}
7. 滑动条
- 创建滑动条
createTrackbar 函数,用于创建一个可以调整数值的滑动条,并将滑动条依附至指定窗口。函数原型如下:
int createTrackbar(const String& trackbarname, const String& winname, int *value, int count, TrackbarCallback onChange = 0, void* userdata = 0);
第一个参数:const String& 类型变量,滑动条的标识符。
第二个参数:const String& 类型变量,要依附的窗口的标识符。
第三个参数:int* 类型变量,一个指向整型的指针,表示滑块的位置。
第四个参数:int 类型变量,表示滑块滑块可以到达的最大位置。滑块最小位置为 0。
第五个参数:TrackbarCallback 类型的 onChange,默认值为 0。一个指向回调函数的指针。每次滑动条位置改变,都会回调这个函数。可以在 highgui.hpp 头文件中找到定义 typedef void (*TrackbarCallback)(int pos, void* userdata);
指向的指针必须为 void (int ,void*)类型。第一个参数为滑块的位置,第二个参数为用户想要传递的数据。
第六个参数:void* 类型的变量,默认值为 0。这个参数会作为回调函数的第二个参数。
- 测试程序
#include <iostream>
#include <opencv2/opencv.hpp>
//窗口宏
#define WINDOW_NAME "Trackbar Demo"
//滑动条最大值
const int g_nMaxAlphaValue = 100;
//滑动条对应变量
int g_nAlphaValueSlider;
double g_dAlphaValue;
double g_dBetaValue;
//图像
cv::Mat g_srcImage1;
cv::Mat g_srcImage2;
cv::Mat g_dstImage;
void on_Trackbar(int count, void* userdata){
//计算 alpha 值
g_dAlphaValue = (double) g_nAlphaValueSlider/g_nMaxAlphaValue;
//计算 beta 值
g_dBetaValue = 1 - g_dAlphaValue;
//线性混合(这个函数放到后面学)
cv::addWeighted(g_srcImage1, g_dAlphaValue, g_srcImage2, g_dBetaValue, 0.0, g_dstImage);
//显示效果图
cv::imshow(WINDOW_NAME, g_dstImage);
}
int main(int argc, const char * argv[]) {
//载入图像
g_srcImage1 = cv::imread("1.jpg");
g_srcImage2 = cv::imread("2.jpg");
//判断是否载入成功,失败返回 -1
if ( !g_srcImage1.data || !g_srcImage2.data) {
return -1;
}
//赋最大参数值
g_nAlphaValueSlider = 70;
//创建窗口
cv::namedWindow(WINDOW_NAME);
//创建滑动条
cv::createTrackbar("TrackBar", WINDOW_NAME, &g_nAlphaValueSlider, g_nMaxAlphaValue, on_Trackbar);
//初次混合
on_Trackbar(g_nAlphaValueSlider, NULL);
cv::waitKey();
return 0;
}
8. 鼠标操作:setMouseCallback 函数
鼠标操作的消息传递和滑动条的消息传递方式很类似。setMouseCallback 函数原型如下:
void setMouseCallback(const String &winname, MouseCallBack onMouse, void* userdata);
- 第一个参数窗口标识符。
- 第二个参数 MouseCallback 类型函数指针
//highgui.hpp 头文件中
/** @brief Callback function for mouse events. see cv::setMouseCallback
@param event one of the cv::MouseEventTypes constants.
@param x The x-coordinate of the mouse event.
@param y The y-coordinate of the mouse event.
@param flags one of the cv::MouseEventFlags constants.
@param userdata The optional parameter.
*/
typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);
第一个参数:int 类型变量对应枚举值
enum MouseEventTypes {
EVENT_MOUSEMOVE = 0, //!< indicates that the mouse pointer has moved over the window.
EVENT_LBUTTONDOWN = 1, //!< indicates that the left mouse button is pressed.
EVENT_RBUTTONDOWN = 2, //!< indicates that the right mouse button is pressed.
EVENT_MBUTTONDOWN = 3, //!< indicates that the middle mouse button is pressed.
EVENT_LBUTTONUP = 4, //!< indicates that left mouse button is released.
EVENT_RBUTTONUP = 5, //!< indicates that right mouse button is released.
EVENT_MBUTTONUP = 6, //!< indicates that middle mouse button is released.
EVENT_LBUTTONDBLCLK = 7, //!< indicates that left mouse button is double clicked.
EVENT_RBUTTONDBLCLK = 8, //!< indicates that right mouse button is double clicked.
EVENT_MBUTTONDBLCLK = 9, //!< indicates that middle mouse button is double clicked.
EVENT_MOUSEWHEEL = 10,//!< positive and negative values mean forward and backward scrolling, respectively.
EVENT_MOUSEHWHEEL = 11 //!< positive and negative values mean right and left scrolling, respectively.
};
从枚举的名称不难看出其所代表的意义。
int x, int y 参数代表鼠标指针在图像坐标系中的坐标。
int flags 参数代表物理按键类型。对应枚举值如下:
//! Mouse Event Flags see cv::MouseCallback
enum MouseEventFlags {
EVENT_FLAG_LBUTTON = 1, //!< indicates that the left mouse button is down.
EVENT_FLAG_RBUTTON = 2, //!< indicates that the right mouse button is down.
EVENT_FLAG_MBUTTON = 4, //!< indicates that the middle mouse button is down.
EVENT_FLAG_CTRLKEY = 8, //!< indicates that CTRL Key is pressed.
EVENT_FLAG_SHIFTKEY = 16,//!< indicates that SHIFT Key is pressed.
EVENT_FLAG_ALTKEY = 32 //!< indicates that ALT Key is pressed.
};
*void userdata 参数代表自定义参数。
- 第三个参数:*void userdata 参数代表自定义参数。