Ubuntu16.04+OpenCV3.4鼠标滚轮事件获取异常求助
解决Ubuntu 16.04 + OpenCV 3.4下鼠标滚轮方向无法获取的问题
我之前维护旧项目时正好碰到过这个一模一样的坑——OpenCV 3.x对Linux平台的鼠标滚轮事件处理存在缺陷,虽然官方文档标注getMouseWheelDelta()仅支持Windows,但其实是旧版本没做好Linux下的适配,直到OpenCV 4.x才修复了这个问题。下面给你几个可行的解决方案:
方案一:直接通过X11捕获原始滚轮事件(无需修改OpenCV)
因为Ubuntu 16.04基于X11窗口系统,我们可以绕过OpenCV的鼠标回调,直接读取X11的原始事件来获取滚轮方向。这种方法不需要依赖OpenCV的有缺陷的滚轮处理逻辑,兼容性很好。
示例代码
#include "opencv2/core.hpp" #include <opencv2/highgui.hpp> #include <iostream> #include <X11/Xlib.h> using namespace std; using namespace cv; float zoom = 1.0f; // 缩放系数 int main() { Mat mSrc = imread("xxxxx.jpg"); if (mSrc.empty()) { cerr << "无法读取图片,请检查路径!" << endl; return -1; } imshow("src", mSrc); // 初始化X11显示连接 Display* dpy = XOpenDisplay(NULL); if (!dpy) { cerr << "无法打开X11显示连接!" << endl; return -1; } // 创建一个临时窗口用于捕获事件(无需显示) Window temp_win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0, 0); XSelectInput(dpy, temp_win, ButtonPressMask | ButtonReleaseMask); while (true) { int key = waitKey(10); if (key == 27) break; // 按ESC退出 // 检查X11事件队列 XEvent ev; while (XCheckWindowEvent(dpy, temp_win, ButtonPressMask | ButtonReleaseMask, &ev)) { if (ev.type == ButtonPress) { if (ev.xbutton.button == 4) { // 滚轮向上滚动 zoom += 0.1f; cout << "放大,当前缩放系数:" << zoom << endl; } else if (ev.xbutton.button == 5) { // 滚轮向下滚动 zoom = max(0.1f, zoom - 0.1f); // 防止缩放过小 cout << "缩小,当前缩放系数:" << zoom << endl; } // 重新绘制缩放后的图像 Mat zoomed_img; resize(mSrc, zoomed_img, Size(), zoom, zoom); imshow("src", zoomed_img); } } } // 释放X11资源 XCloseDisplay(dpy); return 0; }
编译注意事项
编译时需要链接X11库,命令示例:
g++ your_code.cpp -o zoom_demo `pkg-config opencv --cflags --libs` -lX11
方案二:升级OpenCV到4.x版本(环境允许的话)
如果你的项目可以升级依赖版本,直接把OpenCV从3.4升级到4.x是最省心的办法——OpenCV 4.x已经修复了Linux平台下滚轮事件的处理逻辑,你原来的代码几乎不需要修改就能正常获取滚轮方向。
方案三:修改OpenCV 3.4源码并重新编译(适合有源码编译经验的用户)
如果必须留在OpenCV 3.4环境,可以修改OpenCV源码中处理Linux窗口事件的部分,手动将滚轮的delta值传入回调的flag参数:
- 找到OpenCV源码中对应窗口后端的文件(比如GTK后端是
modules/highgui/src/window_gtk.cpp,QT后端是window_qt.cpp) - 找到处理滚轮事件的函数(比如GTK中的
onScroll回调) - 将滚轮的滚动方向转换为对应的flag值(参考OpenCV4的实现),在调用
cv::setMouseCallback注册的用户回调时,把这个flag值传进去 - 重新编译并安装修改后的OpenCV 3.4
内容的提问来源于stack exchange,提问作者think more
相关产品推荐
相关产品推荐

