Skip to content

python: cv.Mat wrapper over numpy.ndarray#20558

Merged
opencv-pushbot merged 1 commit intoopencv:masterfrom
alalek:python_cv_mat
Sep 26, 2021
Merged

python: cv.Mat wrapper over numpy.ndarray#20558
opencv-pushbot merged 1 commit intoopencv:masterfrom
alalek:python_cv_mat

Conversation

@alalek
Copy link
Copy Markdown
Member

@alalek alalek commented Aug 16, 2021

resolves #19091

On hold, merge after: #20611

Usage:

# data3D = np.zeros((3,3,2))
cv.call(cv.Mat(data3D))
cv.call(data3D)  # passes as 2D array with the last dimension wrapped into channels (current behavior for images)

C++-written cv.Mat is not reliable with Python limited API and numpy 1.20+ (not stable ABI guarantee).
Package loader is required (OPENCV_SKIP_PYTHON_LOADER must be OFF).
No plans to backport to "3.4" maintenance branch.
No plans to support Python 2.7.

TODO:

obj = arr.view(Mat)
return obj

def __init__(self, arr, **kwargs):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why __init__ is required?
I think Mat is RealisticInfoArray from the user guide except that Mat should wrap only numeric types. For Python objects and strings it should raise AssertionError

And it is better to explicitly add wrap_channels argument to __new__ with the documentation string.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It make sense to keep instance custom initialization in __init__ instead of __new__.


I thought about pre-checks too, but they can be added later. At least to keep this patch minimal. Currently such cases are catched in cv2.cpp anyway.

raise unittest.SkipTest('Python 2.x is not supported')


class MatTest(NewOpenCVTests):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 practical use cases to test:

  1. Create a Mat wrapper for ndarray and try to use one of the NumPy ufuncs e.g.:
data = np.arange(10)
mat_data = cv.Mat(data)
np.testing.assert_equal(2 * data, 2 * mat_data)
  1. Should 2 Mat objects constructed with different value of wrap_channels property be treated as equals?
data = np.ones((10, 10, 3))
mat_wrapped = cv.Mat(data, wrap_channels=True)
mat_simple = cv.Mat(data)
self.assertEqual(mat_wrapped, mat_simple) # ???

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VadimLevin Thank you for the review!

I added ufunc test case.
Comparison is tricky for now (numpy == returns an array which can't be casted to boolean result without .any/.all calls), so I would like to postpone introducing of custom comparison overloads.

@alalek
Copy link
Copy Markdown
Member Author

alalek commented Sep 26, 2021

👍

@opencv-pushbot opencv-pushbot merged commit 98ad72b into opencv:master Sep 26, 2021
@alalek alalek mentioned this pull request Oct 15, 2021
@dan-masek
Copy link
Copy Markdown
Contributor

I just learned of the existence of this wrapper thanks to a question on Stack Overflow, which lead me to dig through the repo. The only hint at its existence seems to be a single sentence in the note you added to https://docs.opencv.org/4.x/da/d49/tutorial_py_bindings_basics.html

OpenCV 4.5.4+ has cv.Mat wrapper derived from numpy.ndarray to explicitly handle the channels behavior.

.... and just like in the quote, the link in the documenation goes to https://docs.opencv.org/4.x/d3/d63/classcv_1_1Mat.html which contains no mention at all of anything relevant.

This really needs better documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment