OpenCV快速入门三:鼠标事件

上一节我们学会了如何读取摄像头,今天我们来学习一下opencv的鼠标事件

一:相关api

Windows摁住Ctrl后鼠标点击相关api可跳转到封装页面:
如果api有看不懂的建议直接去OpenCV官网,然后可以再看看网友怎么解释的。

1.设置鼠标事件

setMouseCallback(const String & 	winname,  #要设置鼠标事件的窗口名
				 MouseCallback 	onMouse,      #回调函数,当窗口产生鼠标事件时,调用的函数名
				 void* userdata = 0)          #传递给回调函数的可选参数

2.鼠标滚轮响应:


value = getMouseWheelDelta(flags);   // value > 0 向上  value < 0 向下
void resize( InputArray src,
 			 OutputArray dst,  
			 Size dsize,            //输出图像的尺寸
			 double fx = 0,         //水平方向上的缩放系数,当fx为0时,将由公式 (double)dsize.width/src.cols 计算得到
			 double fy = 0,         //垂直方向上的缩放系数,如果fy为0,将由公式 (double)dsize.height/src.rows 计算得到
			 int interpolation = INTER_LINEAR );//图像缩放的插值算法类型

3.回调函数原型

void MouseCallback(int event,        #鼠标基础事件
             int x, int y,           #鼠标在x轴y轴方向上的坐标值,窗口左上角为原点(0,0)
             int flags,              #flags的值代表鼠标拖拽事件和Ctrl、Shift、Alt按键事件的代号
             void *userdata)         #用户数据

即你想要用你的鼠标实现什么功能的函数

def mcallback(event,x,y,flags,userdata):#输出鼠标坐标
    print(event,x,y,flags,userdata)

4.鼠标事件

import cv2
mouse_shijian=[i for i in dir(cv2) if 'EVENT'in i]  #将全部鼠标事件保存在列表中
print (mouse_shijian)                               #打印列表

结果

#鼠标拖拽事件和Ctrl、Shift、Alt按键事件
EVENT_FLAG_LBUTTON 1 #左鍵拖曳
EVENT_FLAG_RBUTTON 2 #右鍵拖曳
EVENT_FLAG_MBUTTON 4 #中鍵(滚轮)拖曳
EVENT_FLAG_CTRLKEY 8 #(8~15)按下Ctrl不放
EVENT_FLAG_SHIFTKEY 16 #(16~31)按下Shift不放
EVENT_FLAG_ALTKEY 32 #(32~39)按下Alt不放

#鼠标基础事件
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 #中键双击

二:代码演示

1.输出鼠标坐标

#python
import cv2
import numpy as np

#鼠标回调函数
def mcallback(event,x,y,flags,userdata):
    print(x,y)

cv2.namedWindow('mouse', cv2.WINDOW_AUTOSIZE)
cv2.resizeWindow('mouse', 640, 480)

#设置鼠标回调
cv2.setMouseCallback('mouse',mcallback,"123")

img=np.zeros((480,640,3),np.uint8)#全黑图片
while True:
    cv2.imshow('mouse',img)
    key=cv2.waitKey(0)#为0则只显示一帧
    if(key&0xff==ord('q')):
        break

cv2.destroyAllWindows()

结果如下
在这里aa插入图片描述

2.框选图像

//C++
Point sp(-1, -1);	//起始点(初始值-1,-1)
Point ep(-1, -1);	//结束点(初始值-1,-1)
Mat temp;			//原图的克隆,用于实时刷新图片

static void on_draw(int event, int x, int y, int flags, void* userdata) {
	Mat bg = *(Mat*)userdata;	//回调函数传过来的图像数据
	if (event == EVENT_LBUTTONDOWN) {	//如果左键被按下
		sp.x = x;	//保存左键按下时的xy值
		sp.y = y;
		std::cout << "Start point: " << sp << std::endl;
	}
	else if (event == EVENT_LBUTTONUP) {//如果左键被抬起
		ep.x = x;	//保存左键抬起时的xy值
		ep.y = y;
		int dx = ep.x - sp.x;	//计算矩形长宽
		int dy = ep.y - sp.y;
		if (dx > 0 && dy > 0) {	//当矩形长宽都为正数时
			Rect box(sp.x, sp.y, dx, dy);
            temp.copyTo(bg);
			rectangle(bg, box, Scalar(0, 0, 255), 2, 8, 0);	//绘制矩形
			imshow("Mouse Drawing", bg);
			imshow("ROI", temp(box));	//显示ROI区域(被框选的区域)
			sp.x = -1;	//起始点坐标复位
			sp.y = -1;
		}
	}
	else if (event == EVENT_MOUSEMOVE) {
		if (sp.x > 0 && sp.y > 0) {		//当起始点坐标不是初始值,且鼠标移动时
			ep.x = x;
			ep.y = y;
			int dx = ep.x - sp.x;
			int dy = ep.y - sp.y;
			if (dx > 0 && dy > 0) {
				Rect box(sp.x, sp.y, dx, dy);
				temp.copyTo(bg);	//刷新屏幕,清除上一循环绘制的矩形
				rectangle(bg, box, Scalar(0, 0, 255), 2, 8, 0);	//绘制新矩形
				imshow("Mouse Drawing", bg);
			}
		}
	}
}

void MyDemo::mouseDrawing_Demo(Mat& image) {
	namedWindow("Mouse Drawing", WINDOW_AUTOSIZE);	//创建一个窗口
	setMouseCallback("Mouse Drawing", on_draw,(void*)(&image));	//调用鼠标回调函数
	imshow("Mouse Drawing", image);
	temp = image.clone();
}
import cv2


img_path = r"C:\Users\DMr\Pictures\text\wenben1.jpg"

def on_mouse(event, x, y, flags, param):
    global img, point1, point2, cut_img
    img2 = img.copy()
    if event == cv2.EVENT_LBUTTONDOWN:  # 左键点击
        point1 = (x, y)
        cv2.circle(img2, point1, 10, (0, 255, 0), 3)
        cv2.imshow('image', img2)
    elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON):  # 按住左键拖曳
        cv2.rectangle(img2, point1, (x, y), (255, 0, 0), 3)
        cv2.imshow('image', img2)
    elif event == cv2.EVENT_LBUTTONUP:  # 左键释放
        point2 = (x, y)
        cv2.rectangle(img2, point1, point2, (0, 255, 255), 3)
        cv2.imshow('image', img2)
        min_x = min(point1[0], point2[0])
        min_y = min(point1[1], point2[1])
        width = abs(point1[0] - point2[0])
        height = abs(point1[1] - point2[1])
        cut_img = img[min_y:min_y + height, min_x:min_x + width]

        cv2.imshow('jietu', cut_img)
        
img = cv2.imread(img_path,0)
#img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)

cv2.namedWindow('image')
cv2.setMouseCallback('image', on_mouse)
cv2.imshow('image', img)
key = cv2.waitKey(0)  # 接收按键信息---16位
if (key & 0xff == ord('q')):  # esc退出--取key的最后八位
    cv2.destroyAllWindows()
else:
    print(key)
cv2.destroyAllWindows()

输出
aaa

3.鼠标滚轮放缩图像

//C++
static void on_Mouse(int event, int x, int y, int flags, void* userdata)
{
    // 获得图像
    Mat image = *(Mat*)userdata;
    Mat imgzoom;
    int value;
 
    // 判断鼠标事件
    if (event == EVENT_MOUSEWHEEL)
    {
        // 获取鼠标滚轮的方向
        value = getMouseWheelDelta(flags);
        if (value > 0)   // 向上
        {
            // 放大
            cout <<"h:"<<h <<"  w:"<<w<< "鼠标向上";
            resize(image, imgzoom,Size(h * 2,w * 2),0,0,INTER_LINEAR);
            h = h * 2;
            w = w * 2;
        }
        else if(value < 0 )  // 向下
        {
            cout << "h:" << h << "  w:" << w << "鼠标向下";
            //缩小
            resize(image,imgzoom,Size(h / 2, w / 2),0,0,INTER_LINEAR);
            h = h / 2;
            w = w / 2;
        }
        if (!image.empty())
        {
            // 显示
            imshow("缩放图像", imgzoom);;
        }
    }
}
 
 
void ControllSize(Mat &img)
{
    namedWindow("缩放图像");
    h = img.rows;
    w = img.cols;
 
    setMouseCallback("缩放图像", on_Mouse,(void*)(&img));
 
    imshow("缩放图像",img);
}

每日“大饼”:
自古英雄出少年
少年时 唤起一天明月 照我满杯冰雪
少年时 算平生肝胆 因人常热
虽然 韶华不为少年留 但不论我们行走多远 归来仍是少年

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氿 柒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值