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?
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
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.
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?
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
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.