Why cv2.rectangle sometimes return np.ndarray, while sometimes cv2.UMat

DKD*_*DDK 7 python opencv numpy python-3.x

I'm currently working on visualizing some images and found this weired behaviour of opencv's cv2.rectangle:

  • when input image is an np.ndarray, say arr, cv2.rectangle() returns an np.ndarray, and arr is drawn with a rectangle.

  • when input image is some variant of arr, like arr[:, :, [2, 0, 1]], cv2.rectangle() returns a cv2.UMat, and no rectangle is drawn.

My current environment is :

  • Python 3.7
  • Opencv 4.1

Here are the codes:

  1. Firstly generates a random image.
import numpy as np
import cv2
import copy

img = np.random.randint(0, 255, (100, 120, 3)).astype("uint8")
Run Code Online (Sandbox Code Playgroud)
  1. Now add a rectangle
a = copy.deepcopy(img)
ret = cv2.rectangle(a, (0, 0), (10, 10), color=(255, 255, 255), thickness=2)
Run Code Online (Sandbox Code Playgroud)
  1. You'll find:

    • ret is an np.ndarray
    • visualization of ret and a show that one rectangle is drawn
  2. Try another way:

b = copy.deepcopy(img)
c = b[:, :, [2, 1, 0]]
ret = cv2.rectangle(c, (0, 0), (10, 10), color=(255, 255, 255), thickness=2)
Run Code Online (Sandbox Code Playgroud)
  1. You'll find:

    • ret is a cv2.UMat
    • visualization of ret or c show that no rectangle is drawn

I'm really curious that is there anything wrong with my code? Or there is something hidden behind it?

Dor*_*ian 2

我会尽力回答这个问题,因为我经常偶然发现这个问题,并且在评论中我看到了很多正确的东西!

OpenCV 只能处理连续数组,这意味着它们必须在内存中以某种方式布局。切片时np.arraynumpy只需更改读取顺序即可提高速度(而不是耗时的复制)并使其不连续(在此处找到)。

@Das Masek 和 @Eric 的说法都是正确的。使用索引数组对 an 进行切片总是np.array会创建一个副本,如此处所述。然而,不幸的是复制数组但不会将其更改回连续数组(对我来说这似乎是不好的行为)。numpy

解决方案是以下之一:

  1. copy()np.array; 通过显式复制,numpy将布局更改回连续的,这与索引数组切片不同。您可以使用等等检查flags您的阵列。a.flags如果您想要自动化某些操作,这显然是最昂贵的,因为您实际上每次都在复制。
  2. 对我来说更优雅的版本是使用np.ascontiguousarray(). 仅当数组已经不连续时,此函数才会更改数组的布局,但事实并非如此copy

另一方面:根据文档,所有 OpenCV 绘图函数实际上都有一个None返回值,因为它们是就地函数。因此我建议这样使用它们。