【问题标题】:How can I avoid global variable with callback function如何使用回调函数避免全局变量
【发布时间】:2020-10-02 08:28:24
【问题描述】:

我想将label_image() 代码放入一个用图像初始化的函数中,label_image(image)。现在,如果我不将图像声明为全局变量,它不会正确更新,因为回调函数将image 作为全局变量,而label_image(image) 具有image 的本地副本。此外,尽管回调函数click()label_image() 内部初始化,但它无法看到变量image,除非它被全局声明。我想如果我可以将image 传递给click(),那么我的问题将很容易解决,这样就可以更新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()

【问题讨论】:

  • 在 setMouseCallback 中使用可选的“param”变量
  • 试试这个 cv2.setMouseCallback("image", click, image) 然后我认为图像会传递给参数。看看这个answers.opencv.org/question/32888/…
  • 在 C++ 中,您可以将图像的地址传递给 setMouseCallback(可能转换为 void*),然后在您的实际回调函数中,您可以再次将其转换为图像的类。在您运行的代码中,您将更改图像的内容,但不会更改其地址。
  • 在这里查看 cmets 和答案:stackoverflow.com/questions/23596511/…
  • @Micka,非常感谢!啊,我有这种直觉,但我很困惑将回调嵌套在类中......非常简单!

标签: python python-3.x opencv opencv3.0


【解决方案1】:

鉴于你想最终调用这个:

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

所以我们传入image作为第一个参数,我们可以创建一个partial函数,它前面已经有image参数,让回调代码应用正常的event, 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-07
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    • 2011-04-10
    • 2012-05-04
    • 2016-03-19
    • 2012-02-02
    相关资源
    最近更新 更多