OpenCV学习心得——基础篇——跨平台与Windows系统——highgui原始库的运用(创建窗口并显示图像、鼠标、滑条开关)

OpenCV学习心得——基础篇——跨平台与Windows系统——highgui原始库的运用
FOR THE SIGMA
FOR THE GTINDER
FOR THE ROBOMASTER

简介:

这一系列的学习心得第一轮将参考《学习OpenCV3》一书

操作系统版本:Ubuntu16.04(在这里博主在Linux下进行运行的)
http://www.ubuntu.org.cn/download/desktop 桌面版ubuntu16.04 下载

电子版书籍下载地址
暂无资源

内容:

基于Windows开发
HighGUI工具包不止可以完成视频读取与写入等,还提供了了一些创建窗口、显示图像、处理一些可能操作的特性。尽管使用方便,但是它的UI(用户接口)特性还是有不特别完整的缺陷。所以通过将初始的接口转化为Qt接口来完成现代化UI部分的工作,并将一些新的特性加入进来。

HighGUI原生图形用户接口
HighGUI的图形用户输入工具只支持三个基本的交互,即按键、鼠标在图像区域点击、鼠标滚轮。其优点为速度快,使用简便并不需要安装额外的库;当缺点是对于用户的应用还不太理想。

cv::namedWindow()
最基础的函数,用于在屏幕上创建一个窗口并显示图像或者视频,方便观察者调试。它只需要一个窗口的名称和一个标识符flag作为参数输入。窗口的名字会出现在窗口的顶部,甚至可以作为窗口的句柄传入HighGUI的其他函数。

int cv::namedWindow(
	const string& name,  //窗口的名字
	int	flags = 0        //设置为0(默认值)表示可以调整窗口大小
	);

当然flags也可以设置为cv::WINDOW_AUTOSIZE,可根据加载不同的图像,自动对窗口大小进行自适应调整。
注意:创建窗口并不会显示图片,需要配合cap.open()与imshow()使用才行,具体可以参考
https://blog.csdn.net/whl970831/article/details/97678583
或是查看后面的实例。

cv::destroyWindow()
用于消除(关闭)一个不需要的窗口。

int cv::destroyWindow(
	const string& name,  //窗口的名字
	);

cv::imshow()
作用为将一张图像(或者是持续的视频)加载进入窗口中。

void cv::imshow(
	const string& name,  //窗口的名称(需要跟建立的窗名一样)
	cv::InputArray image  //将要显示的图片
	);

需要注意的是窗口会保存显示图像的一个副本,在需要时从缓存中重画。因此图像显示后对输入的原画的改变并不会影响到显示图像的内容,除非重新调用cv::imshow()。

cv::waitKey()
该函数主要用于键盘按键事件进行特定时长的等待,如果有按键输入,则返回按键值(这就好比刷新率/ms)。

int cv::waitKey(
	int delay = 0 //如果设置为0,cv::waitKey()将无限期地等待按键。
	);

其还有另一个功能便是让任何Opencv窗口进行更新,如果不调用,视频的的一些变化将会表现的很奇怪。

实例:

#include<iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
 
using namespace cv;
 
int main()
{
	Mat img=imread("pic.jpg");  //图片读取并存储在img
	namedWindow("游戏原画");     //新建一个窗口取名为游戏原画
	imshow("游戏原画",img);	    //将游戏原画窗口与图片存储地img链接起来并显示
	waitKey(6000);				//刷新为6000ms
}

鼠标事件
与键盘事件不同的是,鼠标事件是通过更加传统的回调函数的函数机制来完成的。我们需要在触发鼠标事件前,必须先写好一个回调程序,并在Opencv中注册一个函数,以便任何鼠标事件都可以随时调用这个回调程序,以便完成一些操作后得到一定的响应。

这里可能需要介绍一下事件驱动程序,回调其实就是任何以一个参数集作为输入并返回一个正确的类型的函数。这里需要明确告诉程序使用的回调函数发生的事件类型和发生地点,如果用户同时按下Shift或Alt键,也需要明确告诉回调函数。
cv::MouseCallback

void your_mouse_callback(
	int event,      //事件类型(参考鼠标事件类型1)
	int x,          //鼠标事件的X位置(即图像上的像素坐标)
	int y,          //鼠标事件的Y位置(即图像上的像素坐标)
	int flags,      //有关活动的详细信息(参考鼠标事件类型2)
	void* param     //参数来自cv::setMoueCallback()传递信息至任意类型结构
	);

鼠标事件类型1

事件数值作用
cv::EVENT_MOUSEMOVE0滑动
cv::EVENT_LBUTTONDOWN1左键点击
cv::EVENT_RBUTTONDOWN2右键点击
cv::EVENT_MBUTTONDOWN3中键点击
cv::EVENT_LBUTTONUP4左键放开
cv::EVENT_RBUTTONUP5右键放开
cv::EVENT_MBUTTONUP6中键放开
cv::EVENT_LBUTTONDBLCLK7左键双击
cv::EVENT_RBUTTONDBLCLK8右键双击
cv::EVENT_MBUTTONDBLCLK9中键双击

鼠标事件类型2

标志数值作用
cv::EVENT_FLAG_LBUTTON1左鍵拖曳
cv::EVENT_FLAG_RBUTTON2右鍵拖曳
cv::EVENT_FLAG_MBUTTON4中鍵拖曳
cv::EVENT_FLAG_CTRLKEY8(8~15)按Ctrl不放事件
cv::EVENT_FLAG_SHIFTKEY16(16~31)按Shift不放事件
cv::EVENT_FLAG_ALTKEY32(32~39)按Alt不放事件

cv::setMouseCallback()

void cv::setMouseCallback(
	const string&	windowName,  //回调函数作用的窗口名称
	cv::MouseCallback on_mouse, //你要注册的回调函数
	void*	param = NULL
	);

实例:使用鼠标回调完成绘制方框的小程序

#include <opencv2/opencv.hpp>
 
 
// 定义回调函数
void my_mouse_callback(int event, int x, int y, int flags, void* param);
 
cv::Rect box;
bool drawing_box = false;
 
// 在图像上画一个方框的子程序
void draw_box(cv::Mat& img, cv::Rect box) {
	cv::rectangle(img, box.tl(), box.br(), cv::Scalar(0x00, 0x00, 0xff)); //红色的
}
 
void help() {
	std::cout << "Call: ./ch4_ex4_1\n" << "show how to use a mouse to draw regions in an image." << std::endl;
}
 
int main()
{
	help();
	box = cv::Rect(-1, -1, 0, 0);
	cv::Mat image(200, 200, CV_8UC3);
	cv::Mat temp;
	image.copyTo(temp);
 
	box = cv::Rect(-1, -1, 0, 0);
	image = cv::Scalar::all(0);
 
	cv::namedWindow("Box Example");
 
	// 注册回调函数
	cv::setMouseCallback("Box Example", my_mouse_callback, (void*)&image);
 
	for (;;)
	{
		image.copyTo(temp);
		if (drawing_box)
		{
			draw_box(temp, box);
		}
		cv::imshow("Box Example", temp);
 
		if (cv::waitKey(15) == 27)
		{
			break;
		}
	}
	cv::destroyWindow("Box Example");
    return 0;
}
 
void my_mouse_callback(int event, int x, int y, int flags, void* param) {
	cv::Mat& image = *(cv::Mat*) param;
 
	switch (event) {
		// 鼠标移动时间,实现左键按下时随鼠标位置改变实时绘图
		case cv::EVENT_MOUSEMOVE: {
			if (drawing_box)
			{	
				box.width = x - box.x;
				box.height = y - box.y;
			}
		}
		break;
 
		// 鼠标左键按下时间,定起点
		case cv::EVENT_LBUTTONDOWN: {
			drawing_box = true;
			box = cv::Rect(x, y, 0, 0);
		}
		break;
 
		// 鼠标左键释放事件,绘制图像
		case cv::EVENT_LBUTTONUP: {
			drawing_box = false;
			if (box.width < 0)
			{
				box.x += box.width;
				box.width *= -1;
			}
			if (box.height < 0)
			{
				box.y += box.height;
				box.height *= -1;
			}
			draw_box(image, box);
		}
		break;
	}
}

上面程序在ubuntu中按Esc退出
实例-多个鼠标事件

#include "opencv2/core.hpp"
#include <opencv2/core/utility.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
 
#include<iostream>
 
using namespace cv;
using namespace std;
 
void OnMouseAction(int event,int x,int y,int flags,void *ustc);  //鼠标回调事件函数
int static times; //记录调用次数
 
Mat  image;
 
int main(int argc,char*argv[])
{
	image=imread("pic.jpg", IMREAD_GRAYSCALE);
	imshow("image",image);
	setMouseCallback("image",OnMouseAction);
	waitKey();
	system("pause");
}
 

//鼠标回调函数
void OnMouseAction(int event,int x,int y,int flags,void *ustc)
{	
	//cout<<"第 "<<times<<" 次回调鼠标事件"<<endl;
 
	if(event==CV_EVENT_LBUTTONDOWN)
	{
		cout<<"触发左键按下事件"<<endl;
		cout<<"location: "<<x<<", "<<y<<endl;
 
		unsigned char* row_ptr = image.ptr<unsigned char> ( y );  // row_ptr是第y行的头指针
		unsigned char* data_ptr = &row_ptr[ x*image.channels() ]; // data_ptr 指向待访问的像素数据
		// 输出该像素的每个通道,如果是灰度图就只有一个通道
		for ( int c = 0; c != image.channels(); c++ )
		{
			unsigned char data = data_ptr[c]; // data为I(x,y)第c个通道的值
			cout << (int)data << endl;
		}		
	}
	
	if(event==CV_EVENT_MOUSEMOVE)
	{
		cout<<"触发鼠标移动事件"<<endl;
	}
	if(event==CV_EVENT_LBUTTONUP)
	{
		cout<<"触发左键抬起事件"<<endl;
	}
	if(event==CV_EVENT_RBUTTONDOWN)
	{
		cout<<"触发右键按下事件"<<endl;
	}
	if(event==CV_EVENT_RBUTTONUP)
	{
		cout<<"触发右键抬起事件"<<endl;
	}
	if(event==CV_EVENT_LBUTTONDBLCLK)
	{
		cout<<"触发左键双击事件"<<endl;
	}
	if(event==CV_EVENT_RBUTTONDBLCLK)
	{
		cout<<"触发右键双击事件"<<endl;
	}
}

滑动条、滚动条和开关
HighGUI中提供了一种方便的滑动条(slider)单元。在HighGUI中,滑动条也叫“滚动条”(trackbar)。

int cv::createTrackbar(
	const string&	trackbarName,    //滑动条的名称
	const string& 	windowName,	     //滑动条将要添加到的父窗口的名称,放置在窗口顶部或是底部
	int*	value, 					 //指向整数的指针,随着滑动钮的移动而自动变化
	int 	count,  				 //滑动条可以滑动的最大值
	cv::TrackbarCallback onChange = NULL,
	void*	param = NULL
	);

这里有两种方法来获取或设置滑动条的位置值

int cv::getTrackbarPos(
	const string& trackbarName,
	const string& windowName,
	);
void cv::setTrackbarPos(
	const string& trackbarName,
	const string& windowname,
	int pos
	);

注意:可以通过滑动条来模拟开关(0-关;1-开)

实例:为视频添加控制视频的播放功能(滑条)

#include <opencv2/opencv.hpp>
#include <iostream>
 
using namespace std;
 
int g_switch_value = 1;
void switch_off_function() {  //关闭
	cout << "暂停\n";
}
 
void switch_on_function(){    //打开
	cout << "播放\n";
}

//创建的回调函数
void switch_callback(int position, void*) {
	if (position == 0)
	{
		switch_off_function();
	}
	else
	{
		switch_on_function();
	}
}
 
void help() {
	cout << "Call: my.avi" << endl;
	cout << "Shows putting a pause button in a video." << endl;
}
// 使用滚动条来创建一个“开关”,用来控制视频的播放功能
int main()
{
	cv::Mat frame; //frame存点
	cv::VideoCapture g_capture; //直接创建一个VideoCapture对象-g_capture
	g_capture.open("/home/whl970831/sdad/150/Windmills-master/wind.mp4");//打开视频地址
	help();
	cv::namedWindow("example", 1);//新建窗口名为example,大小为1.
	cv::createTrackbar("switch", "example", &g_switch_value, 1, switch_callback);
 	//滑动条的名称:switch ;要添加的父窗口的名称,顶部或底部:example;指向整数值;可滑动最大值;创建的回调函数-switch_callback
	for (;;)
	{
		if (g_switch_value)
		{
			g_capture >> frame;
			if (frame.empty())
			{
				break;
			}
			cv::imshow("example", frame);
		}
		if (cv::waitKey(10) == 27)
		{
			break;
		}
	}
	cv::destroyWindow("example");
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值