OpenCV error img is incompatible with cv::Mat

Question:

Just realized of a surprising thing when using the following code:

import cv2
import numpy as np

a = np.zeros((720, 1280, 2), dtype=np.uint8)
b = np.zeros((720, 1280), dtype=np.uint8)

cv2.circle(b, (100,100),3,1,-1)   # works
cv2.circle(a[..., 0], (100,100),3,1,-1)  # does not work

Calling exactly same function with exactly same arguments is not working. Is this related with how numpy deals with arrays internally?

Asked By: m33n

||

Answers:

when translating between numpy arrays and OpenCV cv::Mat, OpenCV’s bindings require the numpy array to be contiguous.

Numpy slicing commonly produces non-contiguous arrays because it merely adjusts strides and offsets, yet still refers to the entire original data.

The simplest way to "fix" this is to make a copy of the numpy array: a[..., 0].copy()

BUT!!! that’s a copy, so changes to it won’t be reflected in the original array. If you do the copy, you need to take care to copy the data back into your source array.

plane = a[..., 0].copy() # copy makes contiguous
cv2.circle(plane, (100,100), 3, 1, -1)
a[..., 0] = plane
Answered By: Christoph Rackwitz

I opened an issue on Github and it seems the reason is due to OpenCV cv::Mat and cv::Umat support per-row step, but not per-element step. It means that elements in a row should be compact without holes. a[..., 0] creates array with per-element step. This memory layout cannnot be converted to cv::Mat automatically and the only solution is data copy.

See https://github.com/opencv/opencv-python/issues/741

Answered By: m33n
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.