OpenCV-Python setMouseCallback回调函数中图像变量img的传递方法解析
☞ ░ 前往老猿Python博文目录 ░
一、使用全局变量进行变量传递
OpenCV-Python中可以使用setMouseCallback来设置鼠标事件的回调函数,我们来看个样例。
1.1、案例1代码
import numpy as np
import cv2 #freetype
mode = 0
#创建回调函数
def OnMouseAction(event,x,y,flags,param):
global x1, y1
img = img1
if mode == 0 and event == cv2.EVENT_LBUTTONDOWN:
print("左键点击")
cv2.line(img,(0,0),(x,y),(255,255,0),2)
if mode == 1 and event == cv2.EVENT_LBUTTONDOWN:
print("左键点击1")
x1, y1 = x, y
elif mode == 1 and event==cv2.EVENT_MOUSEMOVE and flags ==cv2.EVENT_FLAG_LBUTTON:
print("左鍵拖曳1")
cv2.rectangle(img2,(x1,y1),(x,y),(0,255,0),-1)
img1 = np.zeros((500,500,3),np.uint8)
img2= np.zeros((500,500,3),np.uint8)
cv2.putText(img1,'1',(200,200),cv2.FONT_HERSHEY_SIMPLEX, 4, (255,0,0))
cv2.putText(img2,'2',(200,200),cv2.FONT_HERSHEY_SIMPLEX, 4, (255,0,0))
cv2.namedWindow('image1')
cv2.namedWindow('image2')
cv2.setMouseCallback('image1',OnMouseAction)
while(1):
cv2.imshow('image1',img1)
cv2.imshow('image2', img2)
cbf()
k=cv2.waitKey(1)
if k==ord('l'):
mode = 0
elif k==ord('t'):
mode = 1
elif k==ord('q'):
break
cv2.destroyAllWindows()
1.2、案例1程序功能及运行截图
上面的代码创建了两个图像窗口,在窗口image1中设置了回调函数,当开始运行时,直接在窗口1中画线,当输入‘t’键切换模式后,在窗口中的拖拽却在窗口2中画填充的矩形。运行截图:

1.3、简析
回调函数OnMouseAction中使用了两个全局变量img1、img2,因此回调函数中对图像的操作是通过全局变量来实现的。关于该使用方法请参考《第5.4节 Python函数中的变量及作用域》的介绍。
二、使用回调函数参数param进行变量传递
当回调函数要操作的对象不是全局变量时,回调函数就不能使用第一种方法传递变量,此时只能通过回调函数参数param进行变量传递。
2.1、案例2:将案例1中的img1传值改成param进行传递
import numpy as np
import cv2 #freetype
mode = 0
#创建回调函数
def OnMouseAction(event,x,y,flags,param):
global x1, y1
img = param
if mode == 0 and event == cv2.EVENT_LBUTTONDOWN:
print("左键点击")
cv2.line(img,(0,0),(x,y),(255,255,0),2)
if mode == 1 and event == cv2.EVENT_LBUTTONDOWN:
print("左键点击1")
x1, y1 = x, y
elif mode == 1 and event==cv2.EVENT_MOUSEMOVE and flags ==cv2.EVENT_FLAG_LBUTTON:
print("左鍵拖曳1")
cv2.rectangle(img2,(x1,y1),(x,y),(0,255,0),-1)
img1 = np.zeros((500,500,3),np.uint8)
img2= np.zeros((500,500,3),np.uint8)
cv2.putText(img1,'1',(200,200),cv2.FONT_HERSHEY_SIMPLEX, 4, (255,0,0))
cv2.putText(img2,'2',(200,200),cv2.FONT_HERSHEY_SIMPLEX, 4, (255,0,0))
cv2.namedWindow('image1')
cv2.namedWindow('image2')
cv2.setMouseCallback('image1',OnMouseAction,img1)
while(1):
cv2.imshow('image1',img1)
cv2.imshow('image2', img2)
k=cv2.waitKey(1)
if k==ord('l'):
mode = 0
elif k==ord('t'):
mode = 1
elif k==ord('q'):
break
cv2.destroyAllWindows()
上面的代码和案例1的代码相比,只修改了第11行和32行的代码,但程序功能完全相同,这证明了param传值的可行性。
2.2、案例3
# -*- coding: utf-8 -*-
import cv2
def OnMouseLBUTTONDOWN(event,x,y,flags,param):
frame = param
if frame is not None:
if event == cv2.EVENT_LBUTTONDOWN:
cv2.putText(frame,'Mouse left button Pressed',(x,y), cv2.FONT_HERSHEY_SIMPLEX,1, (255,0,0))
cv2.imshow('video', frame)
else:
print("frame is None")
def playVideoFile():
cap = cv2.VideoCapture(r'f:\video\zbl1.mp4')
fps = 1
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
# 逐帧捕获
ret, frame = cap.read()
if not ret:
if frame is None :
print("The video has end.")
else:
print("Read video error!")
break
# 显示结果帧e
cv2.imshow('video', frame)
cv2.setMouseCallback('video', OnMouseLBUTTONDOWN, frame)
if cv2.waitKey(int(1000/fps)) == ord('q'): break
# 完成所有操作后,释放捕获器
cap.release()
cv2.destroyAllWindows()
playVideoFile()
上面的代码读取某个视频文件逐帧显示,并在显示后设置回调函数,回调函数就是当鼠标按下时,在当前帧图片上鼠标按下位置显示’Mouse left button Pressed’。在实现上述代码时有几点需要注意:
- fps设置要小,否则后面的帧在屏幕上覆盖了前面加了字符的帧图像,无法看清字符;
- setMouseCallback 必须在每次读到新帧后设置,否则回调函数中收到的参数param就不是指向当前帧,而是调用回调函数时frame变量对应帧,有可能frame还没定义或者定义的初始值如None,这样后面的鼠标点击无法触发对当前帧的操作;
- setMouseCallback调用时必须在窗口已经通过cv2.namedWindow或cv2.imshow定义了窗口名字之后,否则窗口没有定义回调函数设置没有作用;
- 回调函数对当前帧添加了字符之后,需要再次调用cv2.imshow该帧才会刷新显示。
更多OpenCV-Python的介绍请参考《OpenCV-Python图形图像处理》。
关于老猿的付费专栏
老猿的付费专栏《使用PyQt开发图形界面Python应用》专门介绍基于Python的PyQt图形界面开发基础教程,付费专栏《moviepy音视频开发专栏》详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,两个专栏加起来只需要19.9元,都适合有一定Python基础但无相关专利知识的小白读者学习。
收费专栏文章目录:《moviepy音视频开发专栏文章目录》、《使用PyQt开发图形界面Python应用专栏目录》。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《专栏:Python基础教程目录》从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

跟老猿学Python、学OpenCV!
☞ ░ 前往老猿Python博文目录 ░
OpenCV-Python setMouseCallback回调函数中图像变量img的传递方法解析的更多相关文章
- 第5.4节 Python函数中的变量及作用域
一.函数中的变量使用规则 函数执行时,使用的全局空间是调用方的全局空间,参数及函数使用的局部变量存储在函数单独的局部名字空间内: 函数的形参在函数中修改了值时,并不影响调用方本身的数据,但如果形参是一 ...
- 使用匿名函数在回调函数中正确访问JS循环变量
有时候, 需要以不同的参数调用某个URL,并且在回调函数中仍然可以访问正在使用的参数, 这时候, 需要使用闭包保存当前参数, 否则, 当回调函数执行时, 之前的参数很可能早已被修改为最后一个参数了. ...
- 回调函数中使用MFC类的成员或对话框控件的简单方法
在MFC的很多程序中,常常需要在回调函数中调用MFC类的类成员变量.类成员函数,亦或者对话框控件的句柄.由于回调函数是基于C编程的Windows SDK的技术,而类成员又有this指针客观条件限制.. ...
- JavaScript 回调函数中的 return false 问题
今天一个同事问了我一个问题,就是在 Ajax 方法中,请求成功后(success)的回调函数中根据响应的值来判断程序是否继续执行,他不解的是在回调函数中已经 return false 了,但是 Aja ...
- Javascript回调函数中的this指向问题
使用js中的定时器(setInterval,setTimeout),很容易会遇到this指向的问题. 直接上例子: 1 var name = 'my name is window'; 2 var ob ...
- django变量使用-在模板中使用视图函数中的变量
DTL语言,即django template language 第一次使用时,需要修改项目的setting.py文件,将其中TEMPLATES中的DIRS修改为os.path.join(BASE_DI ...
- vue中this在回调函数中的使用
this在各类回调中使用: 如果是普通函数是没法使用的 所以需要先将this.变量赋值给新的变量,然后才能在回调函数中使用 例如: refund: function (id) { if (!this. ...
- 【spring 后台跳转前台】使用ajax访问的后台,后台正常执行,返回数据,但是不能进入前台的ajax回调函数中
问题: 使用ajax访问的后台,后台正常执行,并且正常返回数据,但是不能进入前台的ajax回调函数中 问题展示: 问题解决: 最后发现是因为后台的方法并未加注解:@ResponseBody,导致方法 ...
- JS回调函数中的this指向(详细)
首先先说下正常的this指向问题 什么是this:自动引用正在调用当前方法的.前的对象. this指向的三种情况 1. obj.fun() fun中的this->obj,自动指向.前的对 ...
随机推荐
- 用spring-retry注解自动触发重试方法
原文地址:https://www.jianshu.com/p/ee02d6125113 需求背景: 有些时候我们再调用一些第三方服务的时候,从第三方那边拉数据. 但是第三方服务不是100%稳定的,有些 ...
- Luogu P1856 [USACO5.5]矩形周长Picture
线段树+扫描线 经典的扫描线问题 首先将一个矩形看作由竖着的两条边和横着的两条边构成 那分成两次考虑,一次考虑竖边,一次考虑横边 首先考虑横边 如图两个矩形,现将横边擦去,留下竖边,将平面划分成3个区 ...
- Vue3教程:一个基于 Vue 3 + Vant 3 的商城项目开源啦!
之前发布过一篇文章,告诉大家我要开发一个 Vue3 的商城项目并开源到 GitHub 上,供大家练手和学习,随后也一直有收到留言和反馈,问我开发到哪里了,什么时候开源之类的问题,今天终于可以通知大家, ...
- git commit后如何取消commit
在git使用中要如何取消commit但是还未push的操作? 通常,我们对修改的文件会先git add .,然后git commmit -m "注释",但是如果commit错了,想 ...
- 关于多线程--网络编程 -- 注解反射的一点笔记(JAVA篇)
一 . 线程 java开启一个线程的方法(三种) 方法一:继承Thread类并New一个线程对象 步骤: 1):定义一个类A继承于Java.lang.Thread类. class TestThread ...
- SQL IsNull函数详解
IsNull,计算机语言函数,意思是返回 Boolean 值,指明表达式是否不包含任何有效数据 (Null). ISNULL 使用指定的替换值替换 NULL. IS NULL经常用于组成一个逻辑表达式 ...
- FTP的PORT(主动模式)和PASV(被动模式)
最近做一个项目用到FTP和其它系统进行文件传输,结果在FTP网络连接的问题上花了很多时间,由于太久没搞多FTP,忘记了FTP不单单开放21端口,客户端采用不同连接模式对网络有不同.在此重温一下FTP的 ...
- 学习笔记:[算法分析]数据结构与算法Python版[基本的数据结构-上]
线性结构Linear Structure ❖线性结构是一种有序数据项的集合,其中 每个数据项都有唯一的前驱和后继 除了第一个没有前驱,最后一个没有后继 新的数据项加入到数据集中时,只会加入到原有 某个 ...
- MQ消息中间件,面试能问些什么?
MQ消息中间件,面试能问些什么? 为什么使用消息队列?消息队列的优点和缺点? kafka.activemq.rabbitmq.rocketmq都有什么优缺点? 面试官角度分析: (1)你知不知道你们系 ...
- 打包错误:Failed to execute goal org.scala-tools:maven-scala-plugin:2.15.2:compile (default) on project MusicProject: wrap: org.apache.commons.exec.ExecuteException:
错误:Failed to execute goal org.scala-tools:maven-scala-plugin:2.15.2:compile (default) on project Mus ...