鼠标指针是图形用户界面(GUI)中的一个关键组件。没有它,您就无法真正考虑与GUI交互。那么,让我们深入了解一下OpenCV中用于鼠标和滑动条的内置函数。我们将演示如何使用鼠标来注释图像,以及如何使用滑动条来控制图像的大小。
我们将使用下面的图片来演示在OpenCV中使用鼠标指针和滑动条功能。
1.使用鼠标注释图像
OpenCV提供了一个鼠标事件检测功能来检测各种鼠标操作,如左键单击和右键单击。在第一个例子中,我们将向您展示如何使用鼠标在一个指定窗口中显示的图像上渲染一个矩形。
(1)Python
# 导入库
import cv2
# 列表来存储边界框坐标
top_left_corner=[]
bottom_right_corner=[]
# 函数将在鼠标输入时被调用
def drawRectangle(action, x, y, flags, *userdata):
# 引用全局变量
global top_left_corner, bottom_right_corner
# 当按下鼠标左键时,标记左上角
if action == cv2.EVENT_LBUTTONDOWN:
top_left_corner = [(x,y)]
# 当松开鼠标左键时,标记右下角
elif action == cv2.EVENT_LBUTTONUP:
bottom_right_corner = [(x,y)]
# 画矩形
cv2.rectangle(image, top_left_corner[0], bottom_right_corner[0], (0,255,0),2, 8)
cv2.imshow("Window",image)
# 读取图片
image = cv2.imread("../Input/sample.jpg")
# 制作临时图像
temp = image.copy()
# 创建命名窗口
cv2.namedWindow("Window")
# 鼠标事件发生时调用的Highgui函数
cv2.setMouseCallback("Window", drawRectangle)
k=0
# 按下q键关闭窗口
while k!=113:
# 显示图像
cv2.imshow("Window", image)
k = cv2.waitKey(0)
# 如果按下c,使用虚拟图像清除窗口
if (k == 99):
image= temp.copy()
cv2.imshow("Window", image)
cv2.destroyAllWindows()
(2)C++
// 导入库
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
//命名空间
using namespace cv;
using namespace std;
// Points来存储边界框坐标
Point top_left_corner, bottom_right_corner;
// 初始化一个矩阵来存储图像数据
Mat image;
// 函数将在鼠标输入时被调用
void drawRectangle(int action, int x, int y, int flags, void *userdata)
{
// 当按下鼠标左键时,标记左上角
if( action == EVENT_LBUTTONDOWN )
{
top_left_corner = Point(x,y);
}
// 当松开鼠标左键时,标记右下角
else if( action == EVENT_LBUTTONUP)
{
bottom_right_corner = Point(x,y);
// 绘制矩形
rectangle(image, top_left_corner, bottom_right_corner, Scalar(0,255,0), 2, 8 );
// 显示
imshow("Window", image);
}
}
// Main function
int main()
{
image = imread("../../Input/sample.jpg");
// 制作一个临时图像
Mat temp = image.clone();
// 创建命名窗口
namedWindow("Window");
// 鼠标事件发生时调用的Highgui函数
setMouseCallback("Window", drawRectangle);
int k=0;
// 循环,直到按下q字符
while(k!=113)
{
imshow("Window", image );
k= waitKey(0);
// 如果按下c,清除窗口
if(k == 99)
{
temp.copyTo(image);
}
}
destroyAllWindows();
return 0;
}
2.代码解析
首先定义一个特殊的回调函数,它将在指定窗口中显示的图像上绘制一个矩形。只有在检测到某些用户界面事件时才调用这种类型的函数,它后来被称为“Callback”函数。在这里,这个特殊的函数与鼠标事件相关联,因此我们将它定义为MouseCallback
函数。但是,您可以任意命名函数。在本例中,我们将其命名为drawRectangle()
。这是因为我们要注册这个函数名,以便与鼠标事件相关联。您不需要为函数指定任何输入参数,这些参数将在用户与鼠标交互时自动填充。
让我们了解如何将这个函数与特定的鼠标事件关联起来。我们创建了基于特定鼠标事件绘制矩形的逻辑。这里记录了可用的事件列表。当用户与鼠标交互时,当鼠标在显示的图像上时:鼠标事件类型和事件标志将被记录,以及鼠标的x和y坐标。然后将这些信息传递给函数进行处理。*userdata
是一个可选参数,它可以为回调函数提供进一步的输入(不过在本例中我们不需要它)。当操作LEFTBUTTONDOWN
和LEFTBUTTONUP
被触发时,我们将坐标存储在各自的变量中,并使用它们来绘制矩形。
定义这个鼠标回调函数后,我们继续执行以下操作:
- 使用imread()从磁盘读取示例图像
- 保存图像的副本,
c++
使用clone()
,Python使用copy()
- 创建命名窗口
调用setMouseCallback()
来注册我们上面定义的鼠标回调函数,以及(drawRectangle())
来注册在指定窗口中发生的鼠标事件。
在Python中,cv2.setMouseCallback(winname, onm ouse, userdata)
;在C++中,void cv::setMouseCallback(const String & winname, MouseCallback onm ouse, void * userdata = 0);
-
winname
:窗口名称 -
onMouse
:用于鼠标事件的回调函数 -
userdata
:传递给回调函数的可选参数
在最后一步中,我们需要创建一个允许用户与指定窗口交互的显示循环。因此,在下面的代码中,我们:
- 创建一个while循环,持续显示图像,直到用户按下
' q '
键(ASCII码:113)退出应用程序脚本。 - 在循环中为用户提供清除之前所有注释的功能。用户可以将命名窗口中的图像重置为读取原始图像时生成的副本。这只需通过检查键盘输入
' c '
(ASCII代码:99)即可完成。 - 当用户退出循环时,我们使用destroyAllWindows()销毁窗口。
3.使用滑动条调整图像大小
现在,我们将演示如何使用滑动条来调整图像的大小。看看这段代码:
(1)Python
# 导入库
import cv2
maxScaleUp = 100
scaleFactor = 1
windowName = "Resize Image"
trackbarValue = "Scale"
# 读取图片
image = cv2.imread("../Input/sample.jpg")
# 创建一个显示结果的窗口,并将标志设置为“cv2.WINDOW_AUTOSIZE”
cv2.namedWindow(windowName, cv2.WINDOW_AUTOSIZE)
# 回调函数
def scaleImage(*args):
# 从滑动条得到比例因子
scaleFactor = 1+ args[0]/100.0
# 调整图像大小
scaledImage = cv2.resize(image, None, fx=scaleFactor, fy = scaleFactor, interpolation = cv2.INTER_LINEAR)
cv2.imshow(windowName, scaledImage)
# 创建滑动条并关联回调函数
cv2.createTrackbar(trackbarValue, windowName, scaleFactor, maxScaleUp, scaleImage)
# 显示图像
cv2.imshow(windowName, image)
c = cv2.waitKey(0)
cv2.destroyAllWindows()
(2)C++
// 导入包
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
// 命名空间
using namespace std;
using namespace cv;
int maxScaleUp = 100;
int scaleFactor = 1;
string windowName = "Resize Image";
string trackbarValue = "Scale";
// 回调函数
void scaleImage(int, void*)
{
// 读取图像
Mat image = imread("../../Input/sample.jpg");
// 从滑动条得到缩放因子
double scaleFactorDouble = 1 + scaleFactor/100.0;
// 如果变成0,将因子设为1
if (scaleFactorDouble == 0)
{
scaleFactorDouble = 1;
}
Mat scaledImage;
// 调整图像大小
resize(image, scaledImage, Size(), scaleFactorDouble, scaleFactorDouble, INTER_LINEAR);
// 显示图像
imshow(windowName, scaledImage);
}
int main()
{
// 加载图像
Mat image = imread("../../Input/sample.jpg");
// 创建一个显示结果的窗口,并将标志设置为“自动大小”
namedWindow(windowName, WINDOW_AUTOSIZE);
// 创建Trackbars并关联回调函数
createTrackbar(trackbarValue, windowName, &scaleFactor, maxScaleUp, scaleImage);
scaleImage(25,0);
// 显示图像
imshow(windowName, image);
waitKey(0);
destroyAllWindows();
return 0;
}
你已经学会了在OpenCV中调整图像的大小。在这里,我们将重点讨论如何使用OpenCV中的trackbar函数来创建一个自定义回调函数。这个例子很像上面描述的鼠标指针的例子,所以我们将主要指出与滑动条相关的细节。
- 从导入包开始
- 接下来,我们初始化一些变量和字符串。我们将需要这些来创建trackbar和实现我们的回调函数。
-
scaleFactor
定义的缩放因子,将在图像的回调函数中使用。 -
maxScaleUp
滑动条位置将记录的最大值。最好将100作为最大值,这样我们就可以使用滑动条位置来直接缩放百分比。
-
- 现在,让我们使用
imread()
读取一个示例图像,并创建一个命名窗口。在namedWindow()
函数中,我们传递了WINDOW_AUTOSIZE
标志。这很重要,因为它可以让我们调整图像的大小。 - 我们现在准备讨论回调函数,它将在用户与trackbar交互时被调用。定义trackbar回调函数与定义鼠标回调函数非常相似。只需遵循TrackbarCallback函数签名,然后将该回调函数与trackbar关联起来。
- 用函数签名定义回调函数。
- 和以前一样,可以随意命名函数。在本例中,我们将其命名为
scaleImage()
。 - 在Python代码中,从
args[0]
检索滑动条位置,范围从0到100。 - 根据滑动条位置计算
scaleFactor
,并将该scaleFactor
输入到resize()
函数以调整图像的大小。 - 在Python代码中,不需要为图像指定任何数据类型。但在c++中,你必须将它初始化为Mat。
- 要创建使用回调函数的trackbar,我们需要调用createTrackbar()函数,如下所示。在下面的代码中查看它的语法。在Python中,
cv2.createTrackbar( trackbarName, windowName, value, count, onChange)
;在C++中,int cv::createTrackbar (const String & trackbarname, const String & winname, int * value, int count, TrackbarCallback onChange = 0, void * userdata = 0)
-
trackbarname
:创建的滑动条的名称。 -
winname
:创建的滑动条的父窗口的名称。 -
value
:滑块的默认位置。这是可选的。 -
count
:滑块的最大值。 -
onChange
:回调函数 -
userdata
:传递给回调函数的用户数据。它可以用来处理滑动条事件,而不需要使用全局变量。
-
- 最后,我们简单地调用
imshow()
来在指定的窗口中显示图像。然后是waitKey(0)
,参数为0,它无限期地显示窗口。
总结
您不仅学习了创建可与用户发起的鼠标事件关联的回调函数。还可以使用setMouseCallback()
和createTrackbar()
来注册它们。使用这些基本组件,您可以创建许多有趣的应用程序。为什么不尝试使用滑动条来改变显示图像的强度!
参考目录
https://learnopencv.com/mouse-and-trackbar-in-opencv-gui/