Opencv之鼠标事件/窗口交互详解

这篇具有很好参考价值的文章主要介绍了Opencv之鼠标事件/窗口交互详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Opencv之鼠标事件/窗口交互详解

平时在做图像处理demo或者研究测试算法时,经常会用到imshow和鼠标的交互,比如在显示图像的窗口上画点、线、圆、矩形、多边形等操作,故在此做出用法总结。

1.opencv API及参数介绍

cv::setMouseCallback(const string& windowname, MouseCallback onMouse, void* userdata=0)
{
    ....
}
// windowname: 要操作的窗口名称
// onMouse: 鼠标事件函数,鼠标事件发生以后,要执行的回调函数。函数原型是 
// void onMouse(int event, int x, int y, int flags, void * para)
// userdata: 回调函数的参数

鼠标回调函数介绍:

void onMouse(int event, int x, int y, int flags, void *para)
// int event: 鼠标事件,见后续说明
// x, y 是鼠标在图像坐标系中的坐标
// flags :
// para: 是用户传递到回调函数中的参数

截取感兴趣区域ROI:

cv::selectROIs("MultiTracker", frame, bboxes_, showCrosshair, fromCenter);
// “MultiTracker” : windowsName
// frame: 当前画面;格式为cv::Mat
// bboxes: 要存储的框框格式为:std::vector<cv::Rect>
// showCrosshair:默认为True
// fromCenter:从中心点还是从对角点,默认为false,为true时,选框从中心点开始

涉及的相关参数:

// EVENT的参数定义
enum
{
	CV_EVENT_MOUSEMOVE =0,//滑动
	CV_EVENT_LBUTTONDOWN =1,//左键点击
	CV_EVENT_RBUTTONDOWN =2,//右键点击
	CV_EVENT_MBUTTONDOWN =3,//中键点击
	CV_EVENT_LBUTTONUP =4,//左键放开
	CV_EVENT_RBUTTONUP =5,//右键放开
	CV_EVENT_MBUTTONUP =6,//中键放开
	CV_EVENT_LBUTTONDBLCLK =7,//左键双击
	CV_EVENT_RBUTTONDBLCLK =8,//右键双击
	CV_EVENT_MBUTTONDBLCLK =9//中键双击
};
enum
{
CV_EVENT_FLAG_LBUTTON =1,//左键拖拽
CV_EVENT_FLAG_RBUTTON =2,//右键拖拽
CV_EVENT_FLAG_MBUTTON =4,//中键拖拽
CV_EVENT_FLAG_CTRLKEY =8,//按CTRL不放
CV_EVENT_FLAG_SHIFTKEY =16,//按SHIFT不放
CV_EVENT_FLAG_ALTKEY =32//按ALT不放
};

或者python-opencv中的参数也相同:

# mouse callback function
def mouse_event(event, x, y, flags, param):
    '''
    :param event: 点击事件标识
    :param x: 坐标x
    :param y: 坐标y
    :param flags:按键事件标识
    :param param: 携带参数
    :return:
    '''
    if flags == cv2.EVENT_FLAG_ALTKEY:
        print('摁住Alt')
    if flags == cv2.EVENT_FLAG_CTRLKEY:
        print('摁住Ctrl')
    if flags == cv2.EVENT_FLAG_SHIFTKEY:
        print('摁住Shift')
    if flags == cv2.EVENT_FLAG_LBUTTON:
        print('摁住左键')
    if flags == cv2.EVENT_FLAG_MBUTTON:
        print('摁住中键')
    if flags == cv2.EVENT_FLAG_RBUTTON:
        print('摁住右键')
    if event == cv2.EVENT_LBUTTONDBLCLK:
        print('左键双击')
    if event == cv2.EVENT_MBUTTONDBLCLK:
        print('中键双击')
    if event == cv2.EVENT_RBUTTONDBLCLK:
        print('右键双击')
    if event == cv2.EVENT_LBUTTONDOWN:
        print('左键击下')
    if event == cv2.EVENT_LBUTTONUP:
        print('左键弹起')
    if event == cv2.EVENT_MBUTTONDOWN:
        print('中键击下')
    if event == cv2.EVENT_MBUTTONUP:
        print('中键弹起')
    if event == cv2.EVENT_RBUTTONDOWN:
        print('右键击下')
    if event == cv2.EVENT_RBUTTONUP:
        print('右键弹起')
    if event == cv2.EVENT_MOUSEWHEEL:
        if flags > 0:
            print('向前滚动')
        else:
            print('向后滚动')
    if event == cv2.EVENT_MOUSEHWHEEL:
        if flags > 0:
            print('向左滚动')  # 按住Alt
        else:
            print('向右滚动')

if __name__ == '__main__':
    img = np.mat(np.zeros((300, 300, 3), np.uint8))  # 构造一个像素值全为1的图形
    cv2.namedWindow('mouse')    #命名窗口为mouse
    cv2.setMouseCallback('mouse', mouse_event)  # 窗口与回调函数绑定
    while True:
        cv2.imshow('mouse', img)
        if cv2.waitKey(1) & 0xFF == ord('q'):  # 摁下q退出
            break
    cv2.destroyAllWindows()            #销毁所有窗口

2.一个可以绘制矩形和控制缩放的demo

#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

#define WINNAME "画板"

struct MouseParam
{
	Mat img; //用于画好一个后显示
	Mat imgZoomBackup; //用于zoom的还原备份
	Mat imgTmp; //用于实时显示
	Mat imgBackup; //清空,显示最初的图
	Point pt1;
	Point pt2;
	bool mouseLflag;
	float scale;
};


//绘制矩形
void draw_rectangle(Mat& img, const Point& pt1, const Point& pt2)
{
	rectangle(img, pt1, pt2, Scalar(0, 255, 0), 1, 0, 0);
}

//绘制十字线:即过一点的水平、竖直线
void draw_crossline(Mat& img, const Point& pt)
{
	int width = img.cols;
	int height = img.rows;
	cv::Point ptv1;
	cv::Point ptv2;
	cv::Point pth1;
	cv::Point pth2;
	ptv1 = cv::Point(pt.x, 0);
	ptv2 = cv::Point(pt.x, height);
	pth1 = cv::Point(0, pt.y);
	pth2 = cv::Point(width, pt.y);

	cv::line(img, ptv1, ptv2, Scalar(255, 255, 0), 1);
	cv::line(img, pth1, pth2, Scalar(255, 255, 0), 1);
}


/*
* func:实现图像绕某一点进行缩放功能
*/
void zoom(Mat& img, const Mat& srcimg, const Point& pt, const float scale)
{
	int x1, y1, x2, y2;
	int width, height;
	width = (int)(srcimg.cols * scale / 2.0);
	height = (int)(srcimg.rows * scale / 2.0);
	x1 = max(pt.x - width, 0);
	y1 = max(pt.y - height, 0);
	x2 = min(pt.x + width, srcimg.cols);
	y2 = min(pt.y + height, srcimg.rows);
	Rect zoomRect(Point(x1, y1), Point(x2, y2));
	img = srcimg(zoomRect).clone();

}

void on_mouse(int event, int x, int y, int flags, void* param)
{
	MouseParam* par = (MouseParam*)param;
	Point pt(x, y);
	double value;
	float step = 0.05;

	if (event == EVENT_RBUTTONDOWN) //按下右键,重画
	{
		par->img = par->imgBackup.clone();
	}
	else if (event == EVENT_LBUTTONDOWN)  //按下左键
	{
		par->pt1 = pt;
		par->pt2 = pt;
		par->mouseLflag = true;
	}
	else if (event == EVENT_MOUSEMOVE && flags == EVENT_FLAG_LBUTTON) //按下左键并移动
	{
		par->pt2 = pt;
	}
	else if (event == EVENT_LBUTTONUP)//左键放开进行绘制矩形框
	{
		par->pt2 = pt;
		draw_rectangle(par->img, par->pt1, par->pt2);
		//par->imgZoomBackup = par->img.clone();
		par->mouseLflag = false;
	}
	else if (event == EVENT_MOUSEMOVE)  //鼠标移动将显示十字线
	{
		par->pt1 = pt;
	}
	else if (event == EVENT_MOUSEWHEEL) //鼠标滚动
	{
		value = getMouseWheelDelta(flags);
		if (value > 0)             //滚轮向前滚动,设为缩小
			par->scale += step;   
		else if (value < 0)        //鼠标向后滚动,设为放大
			par->scale -= step;
		par->scale = max((float)0.3, par->scale);
		par->scale = min((float)1.0, par->scale);
		zoom(par->img, par->imgZoomBackup, par->pt1, par->scale);
	}
}

int main()
{
	//Mat img(512, 512, CV_8UC3, Scalar::all(255));
	Mat img = imread("./imgs/1/L.png");
	MouseParam mouseParam;
	mouseParam.img = img.clone();
	mouseParam.imgBackup = img.clone();
	mouseParam.imgZoomBackup = img.clone();
	mouseParam.mouseLflag = false;
	float step = 0.05;
	mouseParam.scale = 1.0;
	namedWindow(WINNAME, 0);
	setMouseCallback(WINNAME, on_mouse, &mouseParam);
	int key;
	while (1)
	{
		mouseParam.imgTmp = mouseParam.img.clone();
		draw_crossline(mouseParam.imgTmp, mouseParam.pt1);
		if (mouseParam.mouseLflag == true)
			draw_rectangle(mouseParam.imgTmp, mouseParam.pt1, mouseParam.pt2);
		imshow(WINNAME, mouseParam.imgTmp);
		key = waitKey(40);
		if (key == 27)
		{
			break;
		}
		else if (key == toascii('q'))
		{
			mouseParam.scale -= step;
			zoom(mouseParam.img, mouseParam.imgZoomBackup, mouseParam.pt1, mouseParam.scale);
		}
		else if (key == toascii('e'))
		{
			mouseParam.scale += step;
			zoom(mouseParam.img, mouseParam.imgZoomBackup, mouseParam.pt1, mouseParam.scale);
		}
	}

	return 0;
}

3.图象中画点

  • 对于拼接后的图像显示窗口,依次绘制左右图中的对应点程序
  • 右键删除尚未调通
std::vector<cv::Point2f>pointsL; //依次存放左右图中的对应点
std::vector<cv::Point2f>pointsR;
cv::Mat mask;
cv::Point2f p_;
//鼠标回调函数
void on_mouse(int event, int x, int y, int flags, void* param)
{
	float cols = mask.cols/2;
	int rad = 6;

	if (event == cv::EVENT_LBUTTONUP || !(flags & cv::EVENT_FLAG_LBUTTON))
		cv::Point2f pt = cv::Point2f(-10, -10);
	else if (event == cv::EVENT_LBUTTONDOWN)
	{
		cv::Point2f pt(x, y);
		if (pt.x>=0&&pt.x <= cols)
		{
			pointsL.push_back(pt);
			cv::circle(mask, pt, rad, cv::Scalar(0, 255, 0), 2);
		}
		else {
			pointsR.push_back(pt);
			cv::circle(mask, pt, rad, cv::Scalar(0, 0, 255), 2);
		}
		//cv::circle(mask, pt, 2, cv::Scalar(0, 255, 0), 2);
		cv::imshow("image", mask);
	}
	else if (event == cv::EVENT_RBUTTONDOWN) //按下右键,重画
	{
		cv::Point2f pt(x, y);
		if (pointsL.size()>0)
		{
			pointsL.pop_back();
		}
		else if (pointsR.size() > 0)
		{
			pointsR.pop_back();
		}
		
	}
	std::cout << "pointsL" << std::endl;
	for (int i = 0; i < pointsL.size(); ++i)
	{
		std::cout << pointsL[i] << std::endl;
	}
	std::cout << "pointsR" << std::endl;
	for (int i = 0; i < pointsR.size(); ++i)
	{
		std::cout << pointsR[i] << std::endl;
	}
}

4.opencv例程分水岭分割中的界面应用

鼠标时间包含绘制直线的交互操作文章来源地址https://www.toymoban.com/news/detail-622882.html

static void help(char** argv)
{
	cout << "\nThis program demonstrates the famous watershed segmentation algorithm in OpenCV: watershed()\n"
		"Usage:\n" << argv[0] << " [image_name -- default is fruits.jpg]\n" << endl;
	cout << "Hot keys: \n"
		"\tESC - quit the program\n"
		"\tr - restore the original image\n"
		"\tw or SPACE - run watershed segmentation algorithm\n"
		"\t\t(before running it, *roughly* mark the areas to segment on the image)\n"
		"\t  (before that, roughly outline several markers on the image)\n";
}
Mat markerMask, img;
Point prevPt(-1, -1);
static void onMouse(int event, int x, int y, int flags, void*)
{
	if (x < 0 || x >= img.cols || y < 0 || y >= img.rows)
		return;
	if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON))
		prevPt = Point(-1, -1);
	else if (event == EVENT_LBUTTONDOWN)
		prevPt = Point(x, y);
	else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
	{
		Point pt(x, y);
		if (prevPt.x < 0)
			prevPt = pt;
		line(markerMask, prevPt, pt, Scalar(12,234,12), 40, 8, 0);
		line(img, prevPt, pt, Scalar(12,234,12), 40, 8, 0);
		prevPt = pt;
		imshow("image", img);
	}
}
int main(int argc, char** argv)
{
	cv::CommandLineParser parser(argc, argv, "{help h | | }{ @input | fruits.jpg | }");
	if (parser.has("help"))
	{
		help(argv);
		return 0;
	}
	//string filename = samples::findFile(parser.get<string>("@input"));
	Mat img0 = imread("..."), imgGray;
	if (img0.empty())
	{
		cout << "Couldn't open image ";
		help(argv);
		return 0;
	}
	help(argv);
	//img0 = img0(Rect(1000, 1000, 800, 800));
	namedWindow("image", WINDOW_NORMAL);
	img0.copyTo(img);
	cvtColor(img, markerMask, COLOR_BGR2GRAY);
	cvtColor(markerMask, imgGray, COLOR_GRAY2BGR);
	markerMask = Scalar::all(0);
	imshow("image", img);
	setMouseCallback("image", onMouse, 0);
	for (;;)
	{
		char c = (char)waitKey(0);
		if (c == 27)
			break;
		if (c == 'r')
		{
			markerMask = Scalar::all(0);
			img0.copyTo(img);
			namedWindow("image", WINDOW_NORMAL);
			imshow("image", img);
		}
		if (c == 'w' || c == ' ')
		{
			//对绘制完成的图像进行下一步操作
			//须在键入相应按键后执行
		}
	}
	return 0;
}

到了这里,关于Opencv之鼠标事件/窗口交互详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenCV9-窗口交互操作

    图像窗口滑动条就是显示在图像的窗口中,能够通过滑动改变数值的滑动条。OpenCV中使用createTrackbar函数在显示图像的窗口中创建滑动条: 下面是拖动滑动条改变图像亮度的代码: OpenCV提供了鼠标响应相关函数setMouseCallback: 鼠标响应的回调函数: event鼠标响应事件:EVENT_

    2024年02月07日
    浏览(32)
  • js常用点击、鼠标、键盘事件--详解

    JavaScript 提供了多种事件类型,包括点击事件、鼠标事件和键盘事件。您可以通过监听这些事件来响应用户的交互动作。以下是一些常见事件及其相应的 JavaScript 代码示例: 1. 点击事件: 2. 鼠标事件(例如鼠标移入、移出、移动等): 3. 键盘事件(例如按下按键、释放按键

    2024年02月12日
    浏览(47)
  • opencv进阶03-图像与鼠标的交互示例

    在处理图像时,可能需要与当前正在处理的图像进行交互。OpenCV 提供了鼠标事件,使用户可以通过鼠标与图像交互。鼠标事件能够识别常用的鼠标操作,例如:针对不同按键的单击、双击,鼠标的滑动、拖曳等。 例如,用户单击鼠标,我们就画一个圆。通常的做法是,创建

    2024年02月12日
    浏览(52)
  • C++OpenCV(3):基础交互(视频与鼠标操作)

    🔆 文章首发于我的个人博客:欢迎大佬们来逛逛 🔆 OpenCV项目地址及源代码:点击这里 openCV中使用鼠标的交互的函数是: setMouseCallback 可以使得 激活 对 winname 为标题的窗口进行 onMouse 回调函数执行的鼠标交互操作,并且可以传递用户自定义变量给 userdata 关于MouseCallBack回调

    2024年02月16日
    浏览(27)
  • C++ opencv鼠标事件,在图像上画矩形

    opencv中常用的除了TrackBar滑动条事件,还有丰富的鼠标事件,与TrackBar类似,鼠标事件也是使用回调函数判断动作的发生,并执行相关的操作。整个行为与QT的信号与槽类似。 在图像中画出矩形,需要使用setMouseCallback()和MouseCallback()函数。 本文使用的头文件及命名空间: 设

    2024年02月11日
    浏览(25)
  • 【opencv-python使用鼠标点击图片显示该点坐标和像素值】

    注:本篇仅用以记录本人日常学习内容📙 实现获取像素点的功能主要基于OpenCV的内置函数cv2.setMouseCallback(),即鼠标事件回调 winname: 接收鼠标事件的窗口名称 onMouse: 处理鼠标事件的回调函数指针 userdata: 传给回调函数的用户数据 🌈我们来看看可以处理的鼠标事件有哪些:

    2024年02月09日
    浏览(42)
  • 基于WPF Opencv实现一个图像可移动、缩放和可交互的显示窗口

    学习Halcon的HSmartWindowControl窗口控件,用WPF和Opencv仿照了一个。 显示控件的主体是两个Canvas: Root Canvas是背景,刷上了网格; 把要显示的图像作为Image Canvas的图像背景, 后面图像的移动,缩放,实质都是Image Canvas。 可交互,学习的是Halcon的绘图对象,WPF的Path来实现的,Path类

    2023年04月09日
    浏览(31)
  • 可视可交互!在全志H618上用OpenCV读取图像显示到PyQt5窗口上

    OpenCV能够处理图像、视频、深度图像等各种类型的视觉数据,在某些情况下,尽管OpenCV可以显示窗口,但PyQt5可能更适合用于创建复杂的交互式应用程序,而自带GPU的H618就成为了这些图像显示的最佳载体。 这里分享一个代码,功能是使用图像处理库opencv从摄像头获取数据,缩

    2024年02月01日
    浏览(35)
  • Opencv C++图像处理:矩阵Mat + 随机数RNG + 计算耗时 + 鼠标事件

    数据类型 字节数 取值范围 bool型(布尔型) 1 [0 or 1] BOOL型(int型) 4 [TRUE or FALSE] sbyte型(有符号8位整数) 1 [128 ~ 127] bytet型(无符号8位整数) 8U 2 [0 ~ 255] short型(有符号16位整数) 16S 2 [-32,768 ~ 32,767] ushort型(无符号16位整数) 16U 2 [0 ~ 65,535] int型(有符号32位整数) 32S 4 [

    2024年02月03日
    浏览(39)
  • Opencv C++ 三、通过鼠标点击操作获取图像的像素坐标和像素值 四、生成一个简单的灰度图像。

    该操作首先需要创建一个头文件 在该头文件内进行编写: 而后双击打开源文件: 在源文件内编写: 执行该程序: 显示内容为上图,而后在右侧image窗口内任意点击一个位置: 就会显示该位置的坐标信息和像素值。 由于该图像为RBG彩色图像,不是单通道的灰度影像,不能显

    2024年04月28日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包