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,自动指向.前的对 ...
随机推荐
- 怎么解决Git中出现 "LF will be replaced by CRLF" 警告
Windows中使用CRLF标识一行的结束,而在Linux/UNIX系统中只使用LF标识一行的结束.CRLF即Carriage-Return Line-Feed的缩写.通常情况下,Git库不会自动修改 ...
- 直播APP源码是如何实现音视频同步的
1. 音视频同步原理 1)时间戳 直播APP源码音视频同步主要用于在音视频流的播放过程中,让同一时刻录制的声音和图像在播放的时候尽可能的在同一个时间输出. 解决直播APP源码音视频同步问题的最佳方案 ...
- 测试工具-慢sql日志分析工具pt-query-digest
pt-query-digest分析来自慢速日志文件,常规日志文件和二进制日志文件的MySQL查询.它还可以分析来自tcpdump的查询和MySQL协议数据. 开启慢日志 set global slow ...
- 异常记录-Gradle依赖掉坑之旅
前言 最近在项目中遇到了一个问题,死活拉不下来依赖,耗费了一整天,感觉自己真是菜的抠脚. 没想到今天脑子一清醒,刷刷的问题逐个击破了. 问题描述: 项目成员添加了新的依赖,然后我这边项目拉下来,bui ...
- 通过tuned-adm调整服务器的各种参数
前言 centos7 服务器上面支持通过tuned进行统一的系统参数调整,以前我们可能会通过修改内核配置文件修改内核参数,通过echo去调整磁盘预读,等等很多调整会分散在各处 而系统实际上是可以通过一 ...
- 06 Vue路由简介,原理,实现及嵌套路由,动态路由
路由概念 路由的本质就是一种对应关系,比如说我们在url地址中输入我们要访问的url地址之后,浏览器要去请求这个url地址对应的资源. 那么url地址和真实的资源之间就有一种对应的关系,就是路由. 路 ...
- Elementary OS安装及开发环境配置(一)
前言 假期在家无聊,刚好把六年前的一台笔记本电脑利用起来,原来电脑虽然说配置说不上古董机器,但是运行win系统感觉还是不流畅,所幸给换成Linux桌面版系统,在网上查阅了很多,Linux桌面系统要么推 ...
- Fastjson远程代码执行漏洞复现
fastjson漏洞简介 Fastjson是一个Java库,可用于将Java对象转换为其JSON表示形式.它还可以用于将JSON字符串转换为等效的Java对象,fastjson爆出多个反序列化远程命令 ...
- 查看mongodb状态
netstat -ntlp|grep 27017
- 总是说spring难学?来看完这些spring的注解及其解释,真香!
前言 用过spring的人都知道,spring简单的通过注解就可以完成很多事情,但这些东西是如何实现的呢以及如何应用到我们自己的代码中?接下来,让我们一起开启注解的旅程. 1. @Controller ...