HighGUI 图形用户界面初步

图像的载入、显示和输出到文件

OpenCV 的命名空间

using namespace cv;

Mat 类

Mat 类是用于保存图像以及其他矩阵数据的数据结构,默认情况下尺寸为0。我们也可以指定其初始尺寸。
cv::Mat pic(320,640,cv""Scalar(100);

读取图片文件:Mat scrImage = imread("src.jpg");

图像载入(imread()函数)

函数原型:Mat imread( const String& filename, int flags = IMREAD_COLOR );

  • 第一个参数,对应所需要载入的图片路径名
    在Windows操作系统下,支持的文件格式如下:
    1. Windows位图:bmp, dib ;
    2. JPEG 文件: jpeg, jpg, jpe ;
    3. JPEG 2000 文件:jp2 ;
    4. PNG文件:png ;
    5. 便携文件格式: pbm, pgm, ppm ;
    6. Sun rasters 光栅文件: sr, ras ;
    7. TIFF 文件: tiff, tif 。
  • 第二个参数,为载入标识,它指定一个加载图像的颜色类型,由函数原型可以看到它自带默认值为 IMREAD_COLOR (值为1),所以在调用时可以忽略这个参数。这个参数在OpenCV中标识图像格式的枚举体中取值。
    枚举的定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum ImreadModes {
IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). Ignore EXIF orientation.
IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image (codec internal conversion).
IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image.
IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format.
IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image.
IMREAD_REDUCED_GRAYSCALE_2 = 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2.
IMREAD_REDUCED_COLOR_2 = 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.
IMREAD_REDUCED_GRAYSCALE_4 = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
IMREAD_REDUCED_COLOR_4 = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
IMREAD_REDUCED_GRAYSCALE_8 = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
IMREAD_REDUCED_COLOR_8 = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.
};

所以默认载入三通道的彩色图像,其他参数用途在注释中也已明确。

  • flags > 0 : 返回一个3通道的彩色图像
  • flags = 0 : 返回灰度图像
  • flags < 0 : 返回包含Alpha通道的加载图像

Mat image0=imread("1.jpg", 2 | 4); 载入无损的源图像
Mat image1=imread("1.jpg", 0); 载入灰度图
Mat image2=imread("1.jpg", 199); 载入3通道的彩色图像

图像显示(imshow()函数)

imshow()函数用于在指定的窗口中显示一幅图像。
原型:void imshow(const string& winname, InputArray mat)

  • 第一个参数:填需要显示的窗口标识名称。
  • 第二个参数:填需要显示的图像。

如果窗口是用 CV_WINDOW_AUTOSIZE (默认值)标志创建的,那么显示图像原始大小。否则,将根据图像的深度进行缩放以适合窗口。

创建窗口(namedWindow()函数)

namedWindow用于创建一个窗口。如果是简单地进行图片显示,则不用这个函数创建窗口。但如果需要在显示窗口之前就用到窗口名时,就需要这个函数先创建出窗口,显式地规定窗口名称,比如指定滑动条依附在某个窗口上。

函数原型:void namedWindow(const String& winname, int flags = WINDOW_AUTOSIZE);

  • 第一个参数,填写被用作窗口的标识符的窗口名称
  • 第二个参数,窗口的标识,其enum定义如下:
1
2
3
4
5
6
7
8
9
10
11
enum WindowFlags {
WINDOW_NORMAL = 0x00000000, //!< the user can resize the window (no constraint) / also use to switch a fullscreen window to a normal size.
WINDOW_AUTOSIZE = 0x00000001, //!< the user cannot resize the window, the size is constrainted by the image displayed.
WINDOW_OPENGL = 0x00001000, //!< window with opengl support.

WINDOW_FULLSCREEN = 1, //!< change the window to fullscreen.
WINDOW_FREERATIO = 0x00000100, //!< the image expends as much as it can (no ratio constraint).
WINDOW_KEEPRATIO = 0x00000000, //!< the ratio of the image is respected.
WINDOW_GUI_EXPANDED=0x00000000, //!< status bar and tool bar
WINDOW_GUI_NORMAL = 0x00000010, //!< old fashious way
};

输出图像到文件(imwrite()函数)

imwrite()函数用于输出图像到文件。

函数原型:bool imwrite( const String& filename, InputArray img, const std::vector<int>& params = std::vector<int>());

  • 第一个参数,填需要写入的文件名,注意要带上后缀。
  • 第二个参数,一般填一个Mat类型的图像数据。
  • 第三个参数,标识为特定格式保存的参数编码,有默认值vector,一般不用填写。如果要填写,需要了解以下内容:
    1. 对于 JPEG 格式的图片,这个参数表示从0到100的图片质量,默认为95;
    2. 对于 PNG 格式的图片,这个参数表示压缩级别,从0到9.较高的值意味着更小的尺寸和更长的压缩时间,默认值为3;
    3. 对于 PPM, PGM 或 PBM 格式的图片,这个参数表示一个二进制格式标志,取值为0或1,默认值为1。

imwrite函数可保存的文件格式 和imread函数可读取格式相同。

创建和使用滑动条

滑动条可以动态调节参数,它依附于窗口而存在。

此外,OpenCV没有实现按钮的功能,所以很多时候,可以用仅含0和1的滑动条来实现按钮的按下和弹起效果。

创建滑动条(createTrackbar()函数)

此函数往往会和一个回调函数配合起来使用。

函数原型:int createTrackbar(const String& trackbarname, const String& winname,int* value, int count, TrackbarCallback onChange = 0, void* userdata = 0);

  • 第一个参数:轨迹条的名字。
  • 第二个参数:窗口的名字,表示这个轨迹条会依附到哪个窗口上(对应前面用namedWindow()创建的窗口)。
  • 第三个参数:一个指向整型的指针,表示滑块的位置。在创建时,滑块的初始位置就是该变量当前的值。
  • 第四个参数:表示滑块可以达到的最大位置的值。滑块最小位置的值始终为0。
  • 第五个参数:一个指向回调函数的指针,默认值为0。每次滑块位置改变时,这个函数都会进行回调。
    回调函数的原型必须为void XXXX(int, void*);,其中第一个参数是轨迹条的位置,第二个参数是用户数据(见下面的第六个参数)。如果回调是NULL指针,则表示没有回调函数的调用,仅第三个参数value有变化。
  • 第六个参数:void*类型的userdata,默认值为0。这个参数是用户传给回调函数的数据,用来处理轨迹条事件。如果使用的第三个参数的value是全局变量的话,完全可以不用管这个userdata参数。

createTrackbar函数要指定回调函数onChange,在轨迹条位置改变的时候来调用这个回调函数,并且创建的轨迹条显示在指定的winname所代表的窗口上。

示例代码:(Code by 毛星云)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序17
// 程序描述:为程序界面添加滑动条
// 开发测试所用IDE版本:Visual Studio 2010
// 开发测试所用OpenCV版本: 3.0 beta
// 2014年11月 Created by @浅墨_毛星云
// 2014年12月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------


//---------------------------------【头文件、命名空间包含部分】-------------------------------
// 描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
#pragma warning(disable:4996)
//-----------------------------------【宏定义部分】--------------------------------------------
// 描述:定义一些辅助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_NAME "【滑动条的创建&线性混合示例】" //为窗口标题定义的宏


//-----------------------------------【全局变量声明部分】--------------------------------------
// 描述:全局变量声明
//-----------------------------------------------------------------------------------------------
const int g_nMaxAlphaValue = 100;//Alpha值的最大值
int g_nAlphaValueSlider;//滑动条对应的变量
double g_dAlphaValue;
double g_dBetaValue;

//声明存储图像的变量
Mat g_srcImage1;
Mat g_srcImage2;
Mat g_dstImage;


//-----------------------------------【on_Trackbar( )函数】--------------------------------
// 描述:响应滑动条的回调函数
//------------------------------------------------------------------------------------------
void on_Trackbar(int, void*)
{
//求出当前alpha值相对于最大值的比例
g_dAlphaValue = (double)g_nAlphaValueSlider / g_nMaxAlphaValue;
//则beta值为1减去alpha值
g_dBetaValue = (1.0 - g_dAlphaValue);

//根据alpha和beta值进行线性混合
addWeighted(g_srcImage1, g_dAlphaValue, g_srcImage2, g_dBetaValue, 0.0, g_dstImage);

//显示效果图
imshow(WINDOW_NAME, g_dstImage);
}


//-----------------------------【ShowHelpText( )函数】--------------------------------------
// 描述:输出帮助信息
//-------------------------------------------------------------------------------------------------
//-----------------------------------【ShowHelpText( )函数】----------------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
void ShowHelpText()
{
//输出欢迎信息和OpenCV版本
printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
printf("\n\n\t\t\t此为本书OpenCV3版的第17个配套示例程序\n");
printf("\n\n\t\t\t 当前使用的OpenCV版本为:" CV_VERSION);
printf("\n\n ----------------------------------------------------------------------------\n");
}


//--------------------------------------【main( )函数】-----------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{

//显示帮助信息
ShowHelpText();

//加载图像 (两图像的尺寸需相同)
g_srcImage1 = imread("1.jpg");
g_srcImage2 = imread("2.jpg");
if (!g_srcImage1.data) { printf("读取第一幅图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return -1; }
if (!g_srcImage2.data) { printf("读取第二幅图片错误,请确定目录下是否有imread函数指定图片存在~!\n"); return -1; }

//设置滑动条初值为70
g_nAlphaValueSlider = 70;

//创建窗体
namedWindow(WINDOW_NAME, 1);

//在创建的窗体中创建一个滑动条控件
char TrackbarName[50];
sprintf(TrackbarName, "透明值 %d", g_nMaxAlphaValue);

createTrackbar(TrackbarName, WINDOW_NAME, &g_nAlphaValueSlider, g_nMaxAlphaValue, on_Trackbar);

//结果在回调函数中显示
on_Trackbar(g_nAlphaValueSlider, 0);

//按任意键退出
waitKey(0);

return 0;
}

运行效果:(分别为透明度0%、50%、100%的情况)
trackbar2trackbar1trackbar3

获取当前轨迹条的位置(getTrackbarPos()函数)

函数原型:int getTrackbarPos(const String& trackbarname, const String& winname);

  • 第一个参数:表示轨迹条的名字。
  • 第二个参数:表示轨迹条的父窗口的名称。

鼠标操作

和创建滑动条的函数类似,指定鼠标操作消息回调函数的函数为setMouseCallback

函数原型:setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);

  • 第一个参数:窗口的名字。
  • 第二个参数:指定窗口里每次鼠标事件发生的时候,被调用的函数指针。
    这个函数的原型大概是void Foo(int event, int x, int y, int flags, void *param);其中event变量enum值的定义见后文,x和y是鼠标指针在图像坐标系中的坐标值,flag是的enum值的定义见后文。param是用户定义的传递到setMouseCallback函数调用的参数。
  • 第三个参数:用户定义的传递到回调函数的参数,默认值为0。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//! Mouse Events see cv::MouseCallback
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.
};
1
2
3
4
5
6
7
8
9
//! 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.
};

示例代码:(Code by 毛星云)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//--------------------------------------【程序说明】-------------------------------------------
// 程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序18
// 程序描述:HelloOpenCV
// 开发测试所用IDE版本:Visual Studio 2010
// 开发测试所用OpenCV版本: 3.0 beta
// 2014年11月 Created by @浅墨_毛星云
// 2014年12月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------

//---------------------------------【头文件、命名空间包含部分】-----------------------------
// 描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
using namespace cv;

//-----------------------------------【宏定义部分】--------------------------------------------
// 描述:定义一些辅助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_NAME "【程序窗口】" //为窗口标题定义的宏


//-----------------------------------【全局函数声明部分】------------------------------------
// 描述:全局函数的声明
//------------------------------------------------------------------------------------------------
void on_MouseHandle(int event, int x, int y, int flags, void* param);
void DrawRectangle(cv::Mat& img, cv::Rect box);
void ShowHelpText();

//-----------------------------------【全局变量声明部分】-----------------------------------
// 描述:全局变量的声明
//-----------------------------------------------------------------------------------------------
Rect g_rectangle;
bool g_bDrawingBox = false;//是否进行绘制
RNG g_rng(12345);



//-----------------------------------【main( )函数】--------------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-------------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{
//【0】改变console字体颜色
system("color 9F");

//【0】显示欢迎和帮助文字
ShowHelpText();

//【1】准备参数
g_rectangle = Rect(-1, -1, 0, 0);
Mat srcImage(600, 800, CV_8UC3), tempImage;
srcImage.copyTo(tempImage);
g_rectangle = Rect(-1, -1, 0, 0);
srcImage = Scalar::all(0);

//【2】设置鼠标操作回调函数
namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME, on_MouseHandle, (void*)&srcImage);

//【3】程序主循环,当进行绘制的标识符为真时,进行绘制
while (1)
{
srcImage.copyTo(tempImage);//拷贝源图到临时变量
if (g_bDrawingBox) DrawRectangle(tempImage, g_rectangle);//当进行绘制的标识符为真,则进行绘制
imshow(WINDOW_NAME, tempImage);
if (waitKey(10) == 27) break;//按下ESC键,程序退出
}
return 0;
}



//--------------------------------【on_MouseHandle( )函数】-----------------------------
// 描述:鼠标回调函数,根据不同的鼠标事件进行不同的操作
//-----------------------------------------------------------------------------------------------
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{

Mat& image = *(cv::Mat*) param;
switch (event)
{
//鼠标移动消息
case EVENT_MOUSEMOVE:
{
if (g_bDrawingBox)//如果是否进行绘制的标识符为真,则记录下长和宽到RECT型变量中
{
g_rectangle.width = x - g_rectangle.x;
g_rectangle.height = y - g_rectangle.y;
}
}
break;

//左键按下消息
case EVENT_LBUTTONDOWN:
{
g_bDrawingBox = true;
g_rectangle = Rect(x, y, 0, 0);//记录起始点
}
break;

//左键抬起消息
case EVENT_LBUTTONUP:
{
g_bDrawingBox = false;//置标识符为false
//对宽和高小于0的处理
if (g_rectangle.width < 0)
{
g_rectangle.x += g_rectangle.width;
g_rectangle.width *= -1;
}

if (g_rectangle.height < 0)
{
g_rectangle.y += g_rectangle.height;
g_rectangle.height *= -1;
}
//调用函数进行绘制
DrawRectangle(image, g_rectangle);
}
break;

}
}



//-----------------------------------【DrawRectangle( )函数】------------------------------
// 描述:自定义的矩形绘制函数
//-----------------------------------------------------------------------------------------------
void DrawRectangle(cv::Mat& img, cv::Rect box)
{
cv::rectangle(img, box.tl(), box.br(), cv::Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255)));//随机颜色
}


//-----------------------------------【ShowHelpText( )函数】-----------------------------
// 描述:输出一些帮助信息
//----------------------------------------------------------------------------------------------
void ShowHelpText()
{
//输出欢迎信息和OpenCV版本
printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
printf("\n\n\t\t\t此为本书OpenCV3版的第18个配套示例程序\n");
printf("\n\n\t\t\t 当前使用的OpenCV版本为:" CV_VERSION);
printf("\n\n ----------------------------------------------------------------------------\n");
//输出一些帮助信息
printf("\n\n\n\t欢迎来到【鼠标交互演示】示例程序\n");
printf("\n\n\t请在窗口中点击鼠标左键并拖动以绘制矩形\n");

}

运行结果:
mouse

总结

前面几张比较基础,学得比较细致。虽然现在还在入门,但是已经学到了许多其他的知识,比如C++的一些以前没有理解或者不知道的操作。学习,重在坚持,希望能够坚持下去。后面要看算法了,可能花在这上面的时间不会太多。