OpenCV滑动条的创建和使用(非常详细)
在 OpenCV 中,滑动条设计的主要目的是在视频播放帧中选择特定帧。在和父窗口使用时,需要给滑动条赋予一个特别的名字(通常是一个字符串),接下来直接通过那个名字进行引用。
创建滑动条的函数是 createTrackbar(),该函数声明如下:
回调函数类型 TrackbarCallback 的定义如下:
这个回调函数不是必需的,如果赋值为 NULL,就没有回调函数,移动滑动按钮的唯一响应就是 createTrackbar 的参数 value 指向的变量值的变化。
除了创建滑动条的函数外,OpenCV 还提供了函数 getTrackbarPos()(用于获取滑动块的位置)和函数 setTrackbarPos()(用于设置滑动条的位置)。
getTrackbarPos() 函数的声明如下:
setTrackbarPos() 函数的声明如下:
下面我们看一个专业的例子,利用滑动块调节参数。
在回调函数中,np.uint8() 是专门用于存储各种图像的(包括 RGB、灰度图像等),范围是 0~255。该函数接收的参数是一个数组。需要注意的是,clip() 函数的返回值是 uint8() 的参数,但是这个函数仅仅是对原数据和 0xff 相与(和最低 2 字节数据相与),这就容易导致如果原数据大于 255,那么在直接使用 np.uint8() 后,比第 8 位大的数据都被截断了。
clip() 函数将数组中的元素限制在 a_min 与 a_max 之间,大于 a_max 的就使得它等于 a_max,小于 a_min 的就使得它等于 a_min。它的原型是:
在上述代码中,首先读取 test.jpg,然后定义滑动块的两个回调函数 updateAlpha() 和 updateBeta(),接着利用函数 namedWindow() 创建一个窗口,并利用函数 createTrackbar() 创建两个滑动条,这样窗口上就有两个滑动条。updateAlpha() 和 updateBeta() 都是滑动条的回调函数,用于响应用户滑动滑块这个事件。最后一个 while 循环,等待用户按 Q 键退出。
在回调函数中,函数 np.uint8() 专门用于存储各种图像的数据(包括 RGB、灰度图像等),它用于将输入数据转换为 8 位无符号整数类型,即将输入数据的值限制在 0~255,并将其存储为 8 位无符号整数。
NumPy 中的 np.uint8() 函数是将原数据和 0xff 做与运算,这就容易导致如果原数据是大于 255 的,那么在直接使用 np.uint8() 函数后,比第 8 位更大的数据都被截断了。
例如,数字 2000 在转换为 np.uint8() 的时候,就会被转换成 208(2000&0xff=208),这样就会导致数据不准确,区分不出原来的数据是大于 255 的还是本来就是 208。为了解决这个问题,我们可以使用 np.clip() 函数,用于将数组中的元素限制在一个指定的范围内,而且它可以给定一个范围,范围外的值将被剪裁到范围边界。
np.clip() 函数原型如下:
该函数返回一个与输入数组形状相同的数组,其中元素值被限制在 lower 和 upper 之间。
下面是一个简单的示例,展示如何使用 clip() 函数将数组中的元素限制在 0~1:
创建滑动条的函数是 createTrackbar(),该函数声明如下:
CreateTrackbar(trackbarName, windowName, value, count, onChange) -> None
- trackbarName 是滑动条的名称;
- windowName 是滑动条将要添加到父窗口的名称,一旦滑动条创建好,它就将被添加到窗口的顶部或底部,滑动条不会挡住任何已经在窗口中的图像,只会让窗口变大,窗口的名称将作为一个窗口的标记,至于滑动条上滑动按钮的确切位置,则由操作系统决定,一般都是最左边;
- value 是一个指向整数的指针,这个整数值会随着滑动按钮的移动而自动变化;
- count 是滑动条可以滑动的最大值;
- onChange 是一个指向回调函数的指针,当滑动按钮移动时,回调函数就会被自动调用。
回调函数类型 TrackbarCallback 的定义如下:
def TrackbarCallback(pos,userdata)
- pos 表示滚动块的当前位置;
- userdata 是传给回调函数的可选参数。
这个回调函数不是必需的,如果赋值为 NULL,就没有回调函数,移动滑动按钮的唯一响应就是 createTrackbar 的参数 value 指向的变量值的变化。
除了创建滑动条的函数外,OpenCV 还提供了函数 getTrackbarPos()(用于获取滑动块的位置)和函数 setTrackbarPos()(用于设置滑动条的位置)。
getTrackbarPos() 函数的声明如下:
GetTrackbarPos(trackbarName, windowName) -> retval参数 trackbarName 是滑动条的名称;windowName 是滑动条将要添加到父窗口的名称。函数返回滑动块的当前位置。
setTrackbarPos() 函数的声明如下:
SetTrackbarPos(trackbarName, windowName, pos) -> None其中,参数 trackName 表示滚动条的名称;windowName 是滑动条将要添加到父窗口的名称;pos 表示要设置的滑动块位置。
下面我们看一个专业的例子,利用滑动块调节参数。
import cv2 as cv import numpy as np import cv2 import numpy as np alpha = 0.3 beta = 80 img_path = "test.jpg" img = cv2.imread(img_path) img2 = cv2.imread(img_path) def updateAlpha(x): global alpha, img, img2 # 得到数值 alpha = cv2.getTrackbarPos('Alpha', 'image') alpha = alpha * 0.01 img = np.uint8(np.clip((alpha * img2 + beta), 0, 255)) def updateBeta(x): global beta, img, img2 beta = cv2.getTrackbarPos('Beta', 'image') img = np.uint8(np.clip((alpha * img2 + beta), 0, 255)) # 创建窗口 cv2.namedWindow('image') cv2.createTrackbar('Alpha', 'image', 0, 300, updateAlpha) cv2.createTrackbar('Beta', 'image', 0, 255, updateBeta) # 设置默认值 cv2.setTrackbarPos('Alpha', 'image', 100) cv2.setTrackbarPos('Beta', 'image', 10) while (True): cv2.imshow('image', img) if cv2.waitKey(1) == ord('q'): break cv2.destroyAllWindows()在上述代码中,首先读取 test.jpg,然后定义滑动块的两个回调函数 updateAlpha() 和 updateBeta(),接着利用函数 namedWindow() 创建 1 个窗口,并利用函数 createTrackbar() 创建 2 个滑动条,这样窗口上就有 2 个滑动条。updateAlpha() 和 updateBeta() 都是滑动条的回调函数,用于响应用户滑动滑块这个事件。最后一个 while 循环,等待用户按 Q 键退出。
在回调函数中,np.uint8() 是专门用于存储各种图像的(包括 RGB、灰度图像等),范围是 0~255。该函数接收的参数是一个数组。需要注意的是,clip() 函数的返回值是 uint8() 的参数,但是这个函数仅仅是对原数据和 0xff 相与(和最低 2 字节数据相与),这就容易导致如果原数据大于 255,那么在直接使用 np.uint8() 后,比第 8 位大的数据都被截断了。
clip() 函数将数组中的元素限制在 a_min 与 a_max 之间,大于 a_max 的就使得它等于 a_max,小于 a_min 的就使得它等于 a_min。它的原型是:
numpy.clip(a, a_min, a_max, out=None)其中,a 是一个数组,后面两个参数分别表示最小值和最大值。
在上述代码中,首先读取 test.jpg,然后定义滑动块的两个回调函数 updateAlpha() 和 updateBeta(),接着利用函数 namedWindow() 创建一个窗口,并利用函数 createTrackbar() 创建两个滑动条,这样窗口上就有两个滑动条。updateAlpha() 和 updateBeta() 都是滑动条的回调函数,用于响应用户滑动滑块这个事件。最后一个 while 循环,等待用户按 Q 键退出。
在回调函数中,函数 np.uint8() 专门用于存储各种图像的数据(包括 RGB、灰度图像等),它用于将输入数据转换为 8 位无符号整数类型,即将输入数据的值限制在 0~255,并将其存储为 8 位无符号整数。
NumPy 中的 np.uint8() 函数是将原数据和 0xff 做与运算,这就容易导致如果原数据是大于 255 的,那么在直接使用 np.uint8() 函数后,比第 8 位更大的数据都被截断了。
例如,数字 2000 在转换为 np.uint8() 的时候,就会被转换成 208(2000&0xff=208),这样就会导致数据不准确,区分不出原来的数据是大于 255 的还是本来就是 208。为了解决这个问题,我们可以使用 np.clip() 函数,用于将数组中的元素限制在一个指定的范围内,而且它可以给定一个范围,范围外的值将被剪裁到范围边界。
np.clip() 函数原型如下:
numpy.clip(a, lower, upper)
- a 是输入数组;
- lower 表示元素的下限,所有小于下限的元素将被限制为下限值;
- upper 表示元素的上限,所有大于上限的元素将被限制为上限值。
该函数返回一个与输入数组形状相同的数组,其中元素值被限制在 lower 和 upper 之间。
下面是一个简单的示例,展示如何使用 clip() 函数将数组中的元素限制在 0~1:
import numpy as np arr = np.array([-2, -1, 0, 1, 2]) clipped_arr = np.clip(arr, 0, 1) print(clipped_arr) # 输出:[ 0. 0. 0. 1. 1.]运行工程,结果如下图所示:
