首页 > 解决方案 > 如何使用回调函数避免全局变量

问题描述

我想将label_image()代码放入一个用图像初始化的函数中,label_image(image). 现在,如果我不将图像声明为全局变量,它不会正确更新,因为回调函数具有image全局label_image(image)而不是image. 此外,尽管在click()内部初始化了回调函数,但除非全局声明,否则它label_image()无法看到变量。image我想我的问题会很容易解决,如果我可以传递imageclick()which 然后将能够更新label_image(image)收到的相同副本。到目前为止,我还没有找到这样做,因为回调函数需要 5 个参数event, x, y, flags, param......

def click(event, x, y, flags, param):
        global click_pts, image_storage, image
        if event == cv2.EVENT_LBUTTONDOWN:
            click_pts.append((x, y, 1))
            cv2.circle(image, (x, y), 5, (255, 0, 0), -1)
            image_storage = lshift(image_storage, image)
            cv2.imshow("image", image_storage[-1])
            print('added %(n)s, size %(s)s, type %(t)s' % {'n': (x, y), 's': len(click_pts), 't': 1})
        elif event == cv2.EVENT_RBUTTONDOWN:
            click_pts.append((x, y, 2))
            cv2.circle(image, (x, y), 5, (0, 255, 255), -1)
            image_storage = lshift(image_storage, image)
            cv2.imshow("image", image_storage[-1])
            print('added %(n)s, size %(s)s, type %(t)s' % {'n': (x, y), 's': len(click_pts), 't': 2})


def label_image() -> list:
    global click_pts, image_storage, image
    click_pts = []
    image_storage = np.zeros((10,) + image.shape, np.uint8)
    image_storage[:] = np.ndarray.copy(image)
    cv2.namedWindow('image', cv2.WINDOW_NORMAL)
    cv2.resizeWindow('image', 1400, 1400)
    cv2.setMouseCallback("image", click)

    # Loop until 'q' is pressed
    while True:
        cv2.imshow("image", image_storage[-1])
        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'):
            break
        elif key == ord('b'):
            try:
                print('removed: %(n)s, size %(s)s' % {'n': click_pts[-1], 's': len(click_pts)})
                click_pts.pop()
            except IndexError:
                print('the array is empty')
            image_storage = rshift(image_storage)
            image = np.ndarray.copy(image_storage[-1])
            cv2.imshow("image", image_storage[-1])

    cv2.destroyAllWindows()
    return click_pts

image = cv2.imread('someimage.png')
label_image()

标签: pythonpython-3.xopencvopencv3.0

解决方案


鉴于你想最终调用这个:

def click(image, event, x, y, flags, param):

因此我们image作为第一个参数传入,我们可以创建一个前面已经partial有参数的函数,让回调代码像往常一样应用普通参数。imageevent, x, y, flags, param

这意味着partial为回调做一个:

def label_image():
    # all the usual stuff elided ...

    partial_click = partial(click, image)  # here image is applied first
    cv2.setMouseCallback("image", partial_click)

推荐阅读