在 opencv 回调函数之外访问变量

Access variable outside of opencv callback fuction

我正在使用 OpenCV 根据其 RGB 值跟踪图像的一部分并使用 cv2.setMouseCallback

这是我的代码:

def track_ground():
    b_min, g_min, r_min = 255, 255, 255
    b_max, g_max, r_max = 0, 0, 0
    
    ##########################################
    # mouse callback function
    def get_pixel(event,x,y,flags,param):

        if event == cv2.EVENT_MOUSEMOVE:
            b, g, r = img[x, y]
            # We are moving around the mouse to find the range of values for rgb
            # of the background; we will use them for thresholding later.

            b_min = min(b, b_min)
            g_min = min(g, g_min)
            r_min = min(r, r_min)
            b_max = max(b, b_max)
            g_max = max(g, g_max)
            r_max = max(r, r_max)

    
    img = cv2.imread('data/my_image.jpg')
    cv2.namedWindow('image')
    cv2.setMouseCallback('image',get_pixel)
    while True:
        cv2.imshow('image',img)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cv2.destroyAllWindows()
    
    ###########################################
    
    print('min:', b_min, g_min, r_min)
    print('max:', b_max, g_max, r_max)
    
    return (b_min, g_min, r_min), (b_max, g_max, r_max)

我的想法是,我想获得变量 b_ming_minr_minb_max、[的最小值和最大值 R、G、B 像素=16=], r_max 当我在图像的特定部分移动鼠标时。为此,我正在使用'cv2.setMouseCallbackand the callback functionget_pixel`,它应该将 RGB 像素的 minimum/maximum 值保持在移动鼠标的 x、y 位置。

现在有一个与回调函数外的变量可访问性相关的错误,它说: UnboundLocalError: local variable 'b_min' referenced before assignment.

我如何访问和修改这些变量?

一个解决方案是使用 param 参数到 get_pixel 回调函数,以便将数据传递给主函数 track_ground:

import cv2
import numpy as np
from pprint import pprint


# mouse callback function
def get_pixel(event,x,y,flags,param):

    if event == cv2.EVENT_MOUSEMOVE:
        img = param['img']
        b, g, r = img[x, y]
        # We are moving around the mouse to find the range of values for rgb
        # of the background; we will use them for thresholding later.
        
        cv2.circle(img, (x, y), 1, (0, 0, 255), 2)
        
        param['b_min'] = min(b, param['b_min'])
        param['g_min'] = min(g, param['g_min'])
        param['r_min'] = min(r, param['r_min'])
        param['b_max'] = max(b, param['b_max'])
        param['g_max'] = max(g, param['g_max'])
        param['r_max'] = max(r, param['r_max'])
        
        rgb_minmax = param.copy()
        del rgb_minmax['img']
        pprint(rgb_minmax)

def track_ground():
    
    ##########################################

    
    img = cv2.imread('data/my_image.jpg')
    cv2.namedWindow('image')
    param = {
        'img': img,
        'b_min': 255,
        'g_min': 255,
        'r_min': 255,
        'b_max': 0,
        'g_max': 0,
        'r_max': 0
    }
    cv2.setMouseCallback('image',get_pixel, param)
    while True:
        cv2.imshow('image',img)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cv2.destroyAllWindows()
    
    ###########################################
    
    print('min:', param['b_min'], param['g_min'], param['r_min'])
    print('max:', param['b_max'], param['g_max'], param['r_max'])
    
    return param

是否还有其他更好的解决方案?

我将 bgr minmax 变量放在函数之外,并使用 global 关键字在 track_groundget_pixel 函数的范围内使用它们。我还更改了您的显示代码以仅显示一次图像,在 window 打开时打印最小最大值,并在 window.[=15 上按下“X”时结束 while 循环=]

代码:

import cv2

def track_ground():
    b_min, g_min, r_min = 255, 255, 255
    b_max, g_max, r_max = 0, 0, 0
    
    ##########################################
    # mouse callback function
    def get_pixel(event,x,y,flags,param):
        nonlocal b_min, g_min, r_min, b_max, g_max, r_max

        if event == cv2.EVENT_MOUSEMOVE:
            b, g, r = img[x, y]
            # We are moving around the mouse to find the range of values for rgb
            # of the background; we will use them for thresholding later.

            b_min = min(b, b_min)
            g_min = min(g, g_min)
            r_min = min(r, r_min)
            b_max = max(b, b_max)
            g_max = max(g, g_max)
            r_max = max(r, r_max)

    
    img = cv2.imread('test.jpg')
    cv2.namedWindow('image')
    cv2.setMouseCallback('image',get_pixel)
    cv2.imshow('image',img)
    while cv2.getWindowProperty('image', 1) >= 0:
        print(b_min, g_min, r_min)
        print(b_max, g_max, r_max)
        k = cv2.waitKey(30)
    cv2.destroyAllWindows()
    
    
    ###########################################
    return (b_min, g_min, r_min), (b_max, g_max, r_max)

print(track_ground())
    

我在这张图片上测试了它,它似乎有效: