OpenCV(六):TrackBar控件
核心函数
cv2.createTrackbar()
这个函数用于创建一个滑动条并将其附加到指定的窗口上。
函数定义
cv2.createTrackbar(trackbar_name, window_name, value, count, onChange)
参数说明
参数 | 描述 |
---|---|
trackbar_name | (Required) 滑动条的名称(字符串),用于显示在滑动条旁边。 |
window_name | (Required) 绑定滑动条的窗口名称(必须是已通过 cv2.namedWindow() 创建的窗口)。 |
value | (Required) 滑动条的初始位置值(整数)。 |
count | (Required) 滑动条的最大值(整数)。最小值固定为 0。 |
onChange | (Required) 用户自定义的回调函数,当滑动条位置改变时自动调用。注意:如果你不想使用回调函数,可以传入 lambda x: None 或一个空函数。 |
回调函数格式
onChange
回调函数是可选的,但如果提供了,它必须接受一个整数参数:
def onChange(pos):# pos 是当前滑动条的位置值 (0 到 count 之间)# 在这里执行基于新位置值的操作pass
cv2.getTrackbarPos()
这个函数用于获取指定窗口上滑动条的当前位置值。
函数定义
cv2.getTrackbarPos(trackbar_name, window_name)
参数说明
参数 | 描述 |
---|---|
trackbar_name | (Required) 要查询的滑动条的名称。 |
window_name | (Required) 滑动条所在的窗口名称。 |
返回值 | 滑动条的当前整数位置值。 |
示例
示例1:实时调整图像阈值
创建一个 Trackbar 来实时调整图像的二值化阈值。
import numpy as np
import cv2# --- 全局变量和初始化 ---# 窗口名称和滑动条名称
WINDOW_NAME = 'Image Thresholding'
TRACKBAR_NAME = 'Threshold Value'
MAX_VALUE = 255
INITIAL_VALUE = 127# 1. 创建一张示例图像(灰度图)
# 400x600 像素,包含 100x100 的白色方块 (值 255)
img = np.zeros((400, 600), np.uint8)
img[150:250, 250:350] = 255 # 白色方块
img[50:150, 50:150] = 100 # 灰色方块
img = img + 20 # 整体增加 20 的亮度作为背景# 2. 回调函数:滑动条位置改变时自动调用
def on_trackbar_change(pos):"""当滑动条位置改变时执行图像二值化操作:param pos: 滑动条的当前位置值 (0 到 255)"""# 确保阈值不为 0,避免除以零或奇怪的结果if pos == 0:pos = 1# 使用 cv2.threshold 进行二值化处理# cv2.THRESH_BINARY:如果像素值 > pos,则设为 255,否则设为 0# 灰度图 img, 阈值 pos, 最大的输出值 255, 阈值类型_, dst = cv2.threshold(img, pos, 255, cv2.THRESH_BINARY)# 实时显示处理后的图像cv2.imshow(WINDOW_NAME, dst)# 打印当前阈值print(f"Current Threshold: {pos}")# --- 主程序 ---# 3. 创建窗口
cv2.namedWindow(WINDOW_NAME)# 4. 创建滑动条并绑定回调函数
# 参数: 滑动条名称, 窗口名称, 初始值, 最大值, 回调函数
cv2.createTrackbar(TRACKBAR_NAME,WINDOW_NAME,INITIAL_VALUE,MAX_VALUE,on_trackbar_change
)# 5. 首次调用回调函数,显示初始图像
# 必须手动调用一次,以显示初始状态下的图像
on_trackbar_change(INITIAL_VALUE)print(f"窗口名称: {WINDOW_NAME}")
print("滑动条名称: {TRACKBAR_NAME}")
print("请拖动滑动条来实时调整图像的二值化阈值。")
print("按 'ESC' 键退出。")while True:# 6. 等待按键事件# waitKey(1) 保持 GUI 响应性key = cv2.waitKey(1) & 0xFF# 按 ESC 退出if key == 27:break# 7. 清理资源
cv2.destroyAllWindows()
示例2:结合鼠标和 Trackbar 的调色板
使用 三个 Trackbar 来实时调整图像的 BGR 颜色值,然后用 鼠标左键 将选中的颜色绘制到图像上。
核心功能:
- 3 个 Trackbar (B, G, R):实时调整背景色。
- 回调函数:获取 BGR 值并填充背景。
- 鼠标左键:在指定位置用当前选中的 BGR 绘制一个点。
import numpy as np
import cv2 as cv# --- 全局变量和初始化 ---
WINDOW_NAME = 'Color Palette and Drawing'
INITIAL_COLOR = 127
MAX_VALUE = 255# 创建一个 512x512 的黑色画布
img = np.zeros((512, 512, 3), np.uint8)# 存储当前的 BGR 颜色值
current_b = INITIAL_COLOR
current_g = INITIAL_COLOR
current_r = INITIAL_COLOR# --- Trackbar 回调函数 ---
def on_trackbar_change(pos):"""当任一 Trackbar 改变时被调用,用于更新背景色"""global img, current_b, current_g, current_r# 1. 获取三个 Trackbar 的当前位置current_b = cv.getTrackbarPos('B', WINDOW_NAME)current_g = cv.getTrackbarPos('G', WINDOW_NAME)current_r = cv.getTrackbarPos('R', WINDOW_NAME)# 2. 将背景区域(上半部分)填充为当前颜色# 图像的上半部分用于显示背景色img[:256, :] = [current_b, current_g, current_r]# 确保绘制区域不被 Trackbar 更新覆盖cv.imshow(WINDOW_NAME, img)# --- 鼠标回调函数 ---
def mouse_callback(event, x, y, flags, param):"""处理鼠标事件,用于在图像上绘制点"""global img, current_b, current_g, current_rif event == cv.EVENT_LBUTTONDOWN:# 在鼠标点击位置绘制一个圆点# 颜色使用 Trackbar 当前选中的 BGR 值color = (current_b, current_g, current_r)# 半径为 10,填充(-1)cv.circle(img, (x, y), 10, color, -1)# 实时显示更新后的图像cv.imshow(WINDOW_NAME, img)# --- 主程序 ---# 1. 创建窗口
cv.namedWindow(WINDOW_NAME)# 2. 创建并绑定 Trackbar
cv.createTrackbar('B', WINDOW_NAME, INITIAL_COLOR, MAX_VALUE, on_trackbar_change)
cv.createTrackbar('G', WINDOW_NAME, INITIAL_COLOR, MAX_VALUE, on_trackbar_change)
cv.createTrackbar('R', WINDOW_NAME, INITIAL_COLOR, MAX_VALUE, on_trackbar_change)# 3. 绑定鼠标回调函数
cv.setMouseCallback(WINDOW_NAME, mouse_callback)# 4. 首次调用,显示初始背景色
on_trackbar_change(INITIAL_COLOR)print("操作说明:")
print(" - 调整 B/G/R 滑动条:改变背景和画笔颜色。")
print(" - 点击鼠标左键:用当前颜色在图像上绘制圆点。")
print(" - 按 'ESC' 键退出。")while True:# 保持 GUI 响应性key = cv.waitKey(1) & 0xFF# 按 ESC 退出if key == 27:breakcv.destroyAllWindows()
示例3:鼠标拖动实现 ROI (Region of Interest) 选择
利用鼠标的按下、移动和释放事件来实现一个非常实用的功能:用鼠标拖动来选择一个感兴趣的矩形区域 (ROI)。
核心功能:
EVENT_LBUTTONDOWN
:记录矩形起始点。EVENT_MOUSEMOVE
:在拖动过程中实时绘制矩形预览。EVENT_LBUTTONUP
:确认矩形,并对 ROI 区域进行操作(例如,裁剪或反色)。
import numpy as np
import cv2 as cv# --- 全局变量和初始化 ---
WINDOW_NAME = 'ROI Selector'
drawing = False # 标记是否正在拖动
start_x, start_y = -1, -1 # 记录矩形起始点
img = None # 原始图像
img_display = None # 用于实时显示的图像副本# 创建一个带内容的图像 (例如,一张彩色渐变图)
def create_initial_image(height=400, width=600):img = np.zeros((height, width, 3), np.uint8)for i in range(height):# 创建垂直渐变效果img[i, :, 0] = int(i / height * 255) # Blue channel gradientimg[i, :, 1] = 255 - int(i / height * 255) # Green channel gradient# 在中心添加文本cv.putText(img, 'Drag to select ROI', (width // 2 - 100, height // 2), cv.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)return img# 初始化图像
img = create_initial_image()
img_display = img.copy()# --- 鼠标回调函数 ---
def mouse_callback(event, x, y, flags, param):global start_x, start_y, drawing, img, img_display# 1. 鼠标左键按下:开始拖动if event == cv.EVENT_LBUTTONDOWN:drawing = Truestart_x, start_y = x, y# 复制原始图像作为拖动的基础,避免在原图上留下拖影img_display = img.copy()# 2. 鼠标移动:实时绘制矩形预览elif event == cv.EVENT_MOUSEMOVE:if drawing == True:# 每次移动都从原始图像副本 (img_display) 开始绘制,消除上一帧的预览矩形# 必须用 img.copy() 重新加载未修改的原始图像进行预览temp_img = img.copy() # 绘制预览矩形 (线宽为 2, 颜色为白色)cv.rectangle(temp_img, (start_x, start_y), (x, y), (255, 255, 255), 2)# 更新显示窗口cv.imshow(WINDOW_NAME, temp_img)# 3. 鼠标左键释放:完成选择并对 ROI 进行操作elif event == cv.EVENT_LBUTTONUP:if drawing == True:drawing = Falseend_x, end_y = x, y# 确保坐标是正确的 (左上角和右下角)x1 = min(start_x, end_x)y1 = min(start_y, end_y)x2 = max(start_x, end_x)y2 = max(start_y, end_y)# --- 对 ROI 区域进行操作 (例如:反色) ---# 1. 获取 ROI 区域roi = img[y1:y2, x1:x2]# 2. 对 ROI 进行反色处理roi_inverted = cv.bitwise_not(roi)# 3. 将处理后的 ROI 区域放回原图img[y1:y2, x1:x2] = roi_inverted# 4. 更新显示副本img_display = img.copy() print(f"ROI Selected: ({x1}, {y1}) to ({x2}, {y2}), Applied Inversion.")# --- 主程序 ---# 1. 创建窗口
cv.namedWindow(WINDOW_NAME)# 2. 绑定鼠标回调函数
cv.setMouseCallback(WINDOW_NAME, mouse_callback)print("操作说明:")
print(" - 按住鼠标左键拖动:选择一个矩形区域 (ROI)。")
print(" - 释放左键:选中的区域将被反色。")
print(" - 按 'r' 键:重置图像。")
print(" - 按 'ESC' 键退出。")while True:# 实时显示图像cv.imshow(WINDOW_NAME, img_display)key = cv.waitKey(1) & 0xFF# 按 'r' 键重置图像if key == ord('r'):img = create_initial_image()img_display = img.copy()print("Image Reset.")# 按 ESC 退出elif key == 27:breakcv.destroyAllWindows()