窗口交互操作
交互操作可以实现在程序运行过程中改变参数数值的作用
避免重复运行程序,节省时间,同时能够增强结果的对比效果
图像窗口滑动条createTrackbar()
OpenCV4提供了createTrackbar()函数实现在显示图像的窗口中创建滑动条
createTrackbar()函数原型:
int createTrackbar(const String& trackbarname,
const String& winname,
int* value,
int count,
TrackbarCallback onChange = 0,
void* userdata = 0
)
- trackbarname:滑动条的名称
- winname:创建滑动条窗口的名称
- value:指向整数变量的指针,该指针指向的值反映滑块的位置,创建后,滑动位置由此变量定义
- count:滑动条的最大值
onChange:每次滑块更改位置时要调用的函数的指针,函数原型为void Foo(int,void*);
其中第一个参数是轨迹栏位置,第二个参数是用户数据,如果回调是NULL指针,则不会调用任何回调,而只是更新数值
- userdata:传递给回调函数的可选参数
该函数能够在图像窗口上方创建一个从0开始的整数滑动条,滑动条默认只能输出整数,因此,如果需要小数,就需要进行后续处理
例如输出值/10得到含有一位小数的数据
该函数第一个参数是滑动条的名称,第二个参数是创建滑动条的图像窗口的名称,第三个参数是指向整数变量的指针
该指针指向的值反映滑块的位置,创建滑动条时,该参数确定了滑块的初始位置,滑动条创建完成后,指针指向的整数随滑块移动而改变
第四个参数是滑块条的最大取值,第五个参数是每次滑块更改位置时要调用的函数的指针,最后一个是传递给回调函数的void*类型数据
如果使用的第三个参数是全局变量,则可以不用修改最后一个参数,使用参数的默认值就可以
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//为了能在被调用函数中使用,设置成全局
int value;
static void callBack(int,void*); //滑动条回调函数
Mat img1,img2;
int main()
{
img1 = imread("E:\\CLion\\opencv_xin\\SG\\SG_0.jpg");
if (img1.empty()) {
cout << "Error" << endl;
return -1;
}
namedWindow("滑动条改变图像亮度");
imshow("滑动条改变图像亮度",img1);
value = 100; //滑动条创建时的初始值
//创建滑动条
createTrackbar("亮度值百分比","滑动条改变图像亮度",&value,600,callBack,0);
waitKey(0);
}
static void callBack(int,void*)
{
float a = value/100.0;
img2 = img1*a;
imshow("滑动条改变图像亮度",img2);
}
鼠标响应setMouseCallback()
OpenCV4提供了鼠标响应相关函数setMouseCallback()函数
setMouseCallback()函数原型:
void setMouseCallback(const String& winname,
MouseCallback onMouse,
void * userdata = 0
)
- winname:添加鼠标响应的窗口的名字
- onMouse:鼠标响应的回调函数
- userdata:传递给回调函数的可选参数
该函数能够为指定的图像窗口创建鼠标响应,第一个参数是需要创建鼠标响应的图像窗口的名字
第二个参数为鼠标响应的回调函数,该函数是鼠标状态发生改变时调用,是MouseCallback类型函数
最后一个参数是传递给回调函数的可选参数,一般情况下,使用默认值0即可
MouseCallback()回调函数原型:
typedef void(*cv::MouseCallback)(int event,
int x,
int y,
int flags,
void *userdata
)
- event:鼠标响应事件标志,参数为EVENT_*形式
- x:鼠标指针在图像坐标系中的x坐标
- y:鼠标指针在图像坐标系中的y坐标
- flags:鼠标响应标志,参数为EVENT_FLAG_*形式
- userdata:传递给回调函数的可选参数
MouseCallback类型的回调函数是一个无返回值的函数,函数名可以任意设置
最后一个参数是传递给回调函数的可选参数,一般情况下,使用void*默认即可
MouseCallback类型回调函数鼠标响应事件标志
| 标志参数 | 简记 | 含义 |
|---|---|---|
| EVENT_MOUSEMOVE | 0 | 表示鼠标指针在窗口上移动 |
| EVENT_LBUTTONDOWN | 1 | 表示按下鼠标左键 |
| EVENT_RBUTTONDOWN | 2 | 表示按下鼠标右键 |
| EVENT_MBUTTONDOWN | 3 | 表示按下鼠标中键 |
| EVENT_LBUTTONUP | 4 | 表示释放鼠标左键 |
| EVENT_RBUTTONUP | 5 | 表示释放鼠标右键 |
| EVENT_MBUTTONUP | 6 | 表示释放鼠标中键 |
| EVENT_LBUTTONDBLCLK | 7 | 表示双击鼠标左键 |
| EVENT_RBUTTONDBLCLK | 8 | 表示双击鼠标右键 |
| EVENT_MBUTTONDBLCLK | 9 | 表示双击鼠标中键 |
| EVENT_MOUSEWHEEL | 10 | 正值表示向前滚动,负值表示向后滚动 |
| EVENT_MOUSEHWHEEL | 11 | 正值表示向左滚动,负值表示向右滚动 |
MouseCallback类型回调函数鼠标响应标志
| 标志参数 | 简记 | 含义 |
|---|---|---|
| EVENT_FLAG_LBUTTON | 1 | 按住左键拖拽 |
| EVENT_FLAG_RBUTTON | 2 | 按住右键拖拽 |
| EVENT_FLAG_MBUTTON | 4 | 按住中键拖拽 |
| EVENT_FLAG_CTRLKEY | 8 | 按“Ctrl”键 |
| EVENT_FLAG_SHIFTKEY | 16 | 按“Shift”键 |
| EVENT_FLAG_ALTKEY | 32 | 按“Alt”键 |
鼠标响应就是当鼠标位于对应的图像窗口内时,时刻检测鼠标状态,当鼠标状态发生改变时,调用回调函数的判断逻辑选择相应的操作
示例程序:如果鼠标右键被按下,就会提示“点击鼠标左键才可以绘制轨迹”,若单击左键,就会输出当前鼠标的坐标
并将该点坐标定义为某段轨迹的起始位置。之后按住左键移动鼠标,会绘制鼠标的移动轨迹
该程序中提供了两种绘制轨迹的方式:
第一种是每次调用回调函数获得鼠标位置时更改周围图像像素值,但是由于回调函数有一定执行时间
当鼠标移动过快,就会出现断点
第二种是在前一时刻和当前时刻鼠标位置间绘制直线,可以避免因鼠标移动过快出现断点的问题
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
Mat img,imgPoint; //全局的图像
Point prePoint; //前一时刻鼠标的坐标,用于绘制直线
void mouse(int event,int x,int y,int flags, void*);
int main()
{
img = imread("E:\\CLion\\opencv_xin\\SG\\SG_0.jpg");
if (img.empty()) {
cout << "Error" << endl;
return -1;
}
img.copyTo(imgPoint);
imshow("图像窗口1",img);
imshow("图像窗口2",imgPoint);
setMouseCallback("图像窗口1",mouse,0); //鼠标响应
waitKey(0);
return 0;
}
void mouse(int event,int x,int y,int flags, void*)
{
if (event == EVENT_RBUTTONDOWN) //单击右键
{
cout << "点击鼠标左键才可以绘制轨迹" << endl;
}
if (event == EVENT_LBUTTONDOWN) //单击左键,输出坐标
{
prePoint = Point(x,y);
cout << "轨迹起始坐标" << prePoint << endl;
}
if (flags == EVENT_FLAG_LBUTTON && event == EVENT_MOUSEMOVE ) //按住鼠标左键移动
{
//通过改变图像像素显示鼠标移动轨迹
imgPoint.at<Vec3b>(y,x) = Vec3b(0,0,255);
imgPoint.at<Vec3b>(y,x-1) = Vec3b(0,0,255);
imgPoint.at<Vec3b>(y,x+1) = Vec3b(0,0,255);
imgPoint.at<Vec3b>(y+1,x) = Vec3b(0,0,255);
imgPoint.at<Vec3b>(y+1,x) = Vec3b(0,0,255);
imshow("图像窗口2",imgPoint);
//通过绘制直线显示鼠标移动轨迹
Point pt(x,y);
line(img,prePoint,pt,Scalar(0,0,255),2,5,0);
prePoint = pt;
imshow("图像窗口1",img);
}
}
Opencv提供了直线函数line()
line()函数原型:
void line(Mat& img,
Point pt1,
Point pt2,
const Scalar& color,
int thickness=1,
int lineType=8,
int shift=0
)
- img: 要绘制线段的图像。
- pt1: 线段的起点。
- pt2: 线段的终点。
- color: 线段的颜色,通过一个Scalar对象定义。
- thickness: 线条的宽度。
- lineType: 线段的类型。可以取值8, 4, 和CV_AA, 分别代表8邻接连接线,4邻接连接线和反锯齿连接线。默认值为8邻接。为了获得更好地效果可以选用CV_AA(采用了高斯滤波)。
- shift: 坐标点小数点位数