cv2.rectangle 使用 np 数组中的元组作为颜色时不起作用

cv2.rectangle not working when using a tuple from a np array as color

我试图在脚本中制作具有随机颜色的矩形,但我遇到了这个非常奇怪的错误,当我使用硬编码颜色时一切正常(例如 (255, 0, 0)),但是当我尝试使用 np.random.randint 制作随机颜色时,出现以下错误:

TypeError: function takes exactly 4 arguments (2 given)

这个最少的代码重现了我的问题。

import numpy as np
from cv2 import cv2
    
img = np.ones((900, 1200), dtype='uint8')
color = tuple(np.random.randint(0, 256, 3, dtype='uint8')) # Does not work
color = (127, 127, 127) # Works
cv2.rectangle(img, (100, 100), (300, 300), color, 4)

这确实是一种奇怪的行为,但以下方法适用于您的情况:

编辑:Christoph 的评论是正确的。您只需调用 tolist() 将颜色转换为 python 标量。

示例:

import numpy as np
import cv2

img = np.ones((900, 1200), dtype='uint8')
color = np.random.randint(0, 256, 3, dtype=np.uint8)

cv2.rectangle(img, (100, 100), (300, 300), color.tolist(), 4)

cv2.imshow("Test", img)
cv2.waitKey()

输出:

解决方案:在numpy数组上调用.tolist()方法,然后使用tuple().

将列表转换为元组

发生了什么:

OpenCV 不仅需要一个元组,还需要一个 Python 整数的元组。

只需对任何可迭代对象(列表、numpy 数组...)调用 tuple() 即可将这些元素按原样放入元组中。 tuple() 遍历您传入的任何内容。它甚至可以是您编写的 class 的对象,如果您实现所需的方法使其成为 iterable。猜猜 tuple("foo") 是做什么的?它 ('f', 'o', 'o')

对于 numpy 数组,其元素是 numpy 数字类型的实例。从简单地 printing 这样的元素,你无法分辨出区别。

观察:

>>> numbers = np.random.randint(0, 256, 3, dtype='uint8')
>>> numbers # it's a numpy ndarray
array([243, 188, 231], dtype=uint8)
>>> numbers[0] # looks like a regular Python integer?
243
>>> type(numbers[0]) # it's not a regular Python integer
<class 'numpy.uint8'>
>>> type(tuple(numbers)[0]) # even "converting" to a tuple doesn't fix it
<class 'numpy.uint8'>

这就是 OpenCV 需要发生的事情:

>>> numbers.tolist() # this is not enough for OpenCV
[243, 188, 231]
>>> type(_[0]) # type of elements is correct at least
<class 'int'>
>>> tuple(numbers.tolist()) # OpenCV wants this
(243, 188, 231)

注意:这是 OpenCV 需要整数元组时的常见问题……例如当您尝试传入一个点(用于矩形的角)并且该点恰好由浮点数组成时。在那种情况下,OpenCV 不喜欢浮点数,无论它们是 Python 还是 numpy。它在那里需要整数。我希望这种行为将来可能会改变。