参考学习书籍:《OpenCV3 编程入门》
环境:OpenCV4.1.1+VS2019
上一篇博客梳理了OpenCV的一些常用函数,imread(),imshow(),waitKey(),namedWindow(),inwrite(),addWeighted(),但都是静态函数。
这一篇博客学习一些常用的动态函数,包括滑动条和鼠标操作。
一.滑动条的创建和使用
createTrackbar函数用于创建滑动条,并将这一滑动条依附在一个窗口中。常常需要与一个回调函数搭配使用。
int createTrackbar(conststring& trackbarname, conststring& winname, int* value, int count, TrackbarCallback onChange = 0, void* userdata = 0);
/* 第一个参数 conststring& 类型的 trackbarname 创建的轨迹条名称
第二个参数 conststring& 类型的 winname 轨迹条所依附的窗口的名字
第三个参数 int* 类型的 value 表示滑块的位置 在创建时,value的值就是滑块的初始位置
第四个参数 int 类型的 count 表示滑块可以达到的最大位置的值(最小位置的值始终为0)
第五个参数 TrackbarCallback 类型的 onChange 默认值为0 这是一个指向回调函数的指针
第六个参数 void* 类型的 userdata 默认值为0 是用户传给回调函数的数据用来处理轨迹条事件 */
例如:
createTrackbar("透明度:", "【效果图】", &g_nAlphaValueSlider, 300, on_Change);
例程:
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <iostream>
#define WINDOW_NAME "线性混合示例" //为窗口标题定义的宏
using namespace cv;
const int g_nMaxAlphaValue = 100; //Alpha的最大值
int g_nAlphaValueSlider; //滑动条对应变量
double g_dAlphaValue;
double g_dBetaValue;
char* TrackbarName;
//声明存储图像的变量
Mat dst;
Mat src1;
Mat src2;
//响应滑动条的回调函数
void on_Trackbar(int ,void*)
{
g_dAlphaValue = (double) (g_nAlphaValueSlider/g_nMaxAlphaValue);
g_dBetaValue = (1.0 - g_dAlphaValue);
addWeighted(src1, g_dAlphaValue, src2, g_dBetaValue, 0.0, dst);
imshow(WINDOW_NAME,dst); //显示效果图
}
int main()
{
//加载图像(两幅图尺寸需相同)
src1 = imread("1.jpg");
src2 = imread("2.jpg");
if ( !src1.data)
{
printf("读取第一幅图片错误,请确定目录是否有imread函数指定图片存在\n");
return -1;
}
if ( !src2.data)
{
printf("读取第二幅图片错误,请确定目录是否有imread函数指定图片存在\n");
return -1;
}
//设置滑动条初值为70
g_nAlphaValueSlider = 70;
//创建窗体
namedWindow(WINDOW_NAME);
//在创建的窗体中创建一个滑动条控件
//char TrackbarName[50];
TrackbarName = new char[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;
}
在项目生成时,可能会遇到一个问题:
这是因为VS中,sprintf的安全性较低,所以微软提供了sprintf_s来代替,我们可以进行下面几步操作,规避这一错误。
在属性管理器中,选择Debud|x64(∵我们的调试环境是这一个),右击Microsoft.Cpp.x64.use,选择属性,在C/C++中的预处理器中的预处理器定义添加_CRT_SECURE_NO_DEPRECATE,点击确认。
再次生成项目就不会有这一错误了。
二.鼠标操作
与滑动条类似,鼠标操作也有一个创建函数setMouseCallback
void setMouseCallback(conststring& winname, MouseCallback onMouse, void* userdata = 0)
/* 第一个参数 conststring& 类型的 winname 窗口名
第二个参数 MouseCallback 类型的 onMouse 窗口里每次鼠标事件发生时被调用的函数指针
第三个参数 void* 类型的 userdata 默认值为0 */
例程:
#include <opencv2/opencv.hpp>
using namespace cv;
#define WINDOW_NAME "【鼠标操作】"
void on_MouseHandle(int event, int x, int y, int flags, void* param);
void DrawRactangle(Mat& img, Rect box);
Rect g_rectangle;
bool g_bDrawingBox = false;//是否进行绘制
RNG g_rng(12345);
int main(int argc, char** argv)
{
//准备参数
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);
// 设置鼠标操作回调函数
namedWindow(WINDOW_NAME);
setMouseCallback(WINDOW_NAME, on_MouseHandle, (void*)&srcImage);
// 程序主循环,当进行绘制的标识符为真的时候进行绘制
while (1)
{
srcImage.copyTo(tempImage); // 复制源图到临时变量
if (g_bDrawingBox)
{
DrawRactangle(tempImage, g_rectangle); //进行绘制
}
imshow(WINDOW_NAME, tempImage);
if (waitKey(10) == 27) // 按下ESC键,程序退出
break;
}
return 0;
}
// 鼠标回调函数,根据不同的鼠标事件进行不同的操作
void on_MouseHandle(int event, int x, int y, int flags, void* param)
{
Mat& image = *(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:
{
// 标识符为false
g_bDrawingBox = 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;
}
//调用函数进行绘制
DrawRactangle(image, g_rectangle);
}
break;
}
}
// 画矩形
void DrawRactangle(Mat& img, Rect box)
{
rectangle(img, box.tl(), box.br(), Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255)));
}
效果图:
在窗口中点击鼠标左键画矩形,窗口中就会出现所画矩形。