【发布时间】:2019-12-26 10:14:58
【问题描述】:
我目前正在对一些图像进行可视化,并发现了 opencv 的 cv2.rectangle 的这种奇怪行为:
当输入图像是 np.ndarray 时,比如 arr,cv2.rectangle() 返回 np.ndarray,arr 用矩形绘制。
当输入图像是 arr 的某种变体时,例如 arr[:, :, [2, 0, 1]],cv2.rectangle() 返回一个 cv2.UMat,并且不绘制矩形。
我现在的环境是:
- Python 3.7
- Opencv 4.1
代码如下:
- 首先生成一张随机图片。
import numpy as np
import cv2
import copy
img = np.random.randint(0, 255, (100, 120, 3)).astype("uint8")
- 现在添加一个矩形
a = copy.deepcopy(img)
ret = cv2.rectangle(a, (0, 0), (10, 10), color=(255, 255, 255), thickness=2)
-
你会发现:
- ret 是一个 np.ndarray
- ret 的可视化和显示一个矩形被绘制
尝试其他方式:
b = copy.deepcopy(img)
c = b[:, :, [2, 1, 0]]
ret = cv2.rectangle(c, (0, 0), (10, 10), color=(255, 255, 255), thickness=2)
-
你会发现:
- ret 是一个 cv2.UMat
- ret 或 c 的可视化显示 没有绘制矩形
我真的很好奇我的代码有什么问题吗?还是背后隐藏着什么?
【问题讨论】:
-
有趣的行为,对我来说这听起来像是一个错误......也许你应该把它放在 OpenCV github 问题中......另外,如果你用 numpy copy 复制数据,它看起来像正常...像
c = img[:, :, [2, 1, 0]].copy() -
@api55 我以前见过这个。主要问题是 numpy 数组在数据在内存中的布局方式方面更加灵活。
img[:, :, [2, 1, 0]只是为同一个缓冲区创建一个视图,并设置元数据,以便以相反的顺序解释第三个轴。不幸的是,无法为该缓冲区创建等效的cv::Mat标头。因此,尝试使用Mat等效调用函数失败。然而,在 Python 包装器中完成了重载解析,因此它尝试从缓冲区创建一个 UMat... -
这(因为我们得到了一个 UMat 并且没有错误消息)似乎成功了。当我尝试
result = ret.get();并可视化结果时,我看到那里有一个白色矩形。然而,原始输入(OPs 代码中的c)不包含矩形,这表明在创建 UMat 对象时涉及到一个副本(某种预期)。 |像您一样使用ndarray.copy()制作数组的深层副本似乎会重新排列过程中的缓冲区,以便元数据再次“正常”(与cv::Mat兼容)。 -
@DanMašek 你应该把它写成答案,这听起来很完整并且很好地解释了问题:) 我知道 ndarray 的“视图”,但我猜 OpenCV 可以转换它或至少发出警告。不过很高兴知道
-
@api55 是的,虽然我还不能真正解释为什么它能够把它变成
UMat...我得预留一些时间来理解这一点。
标签: python python-3.x numpy opencv