Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python GpuMat not subscriptable #22175

Open
4 tasks done
gentlegiantJGC opened this issue Jun 30, 2022 · 5 comments
Open
4 tasks done

Python GpuMat not subscriptable #22175

gentlegiantJGC opened this issue Jun 30, 2022 · 5 comments

Comments

@gentlegiantJGC
Copy link

gentlegiantJGC commented Jun 30, 2022

System information (version)
  • OpenCV => 4.6.0
  • Operating System / Platform => Windows 10, 64 Bit
  • Compiler => Visual Studio 2017
Detailed description

GpuMat in the Python bindings is missing support for __getitem__

From my understanding the GpuMat class is supposed to behave mostly the same as the Mat class.
__getitem__ works on the Mat class but not on the GpuMat class.

I am using OpenCV with Python. I think this is the correct place to report this.
I would try and debug this issue myself but I don't know where to find the python bindings or how they are generated.

Steps to reproduce

I would expect getitem to work on the GpuMat class.

import cv2
im = cv2.cuda.GpuMat(10, 10, cv2.CV_8UC1)
im_slice = im[:2, :2]

TypeError: 'cv2.cuda.GpuMat' object is not subscriptable

The behaviour works correctly on the Mat class

import numpy
a = numpy.arange(16).reshape(4,4)
im = cv2.Mat(a)
im_slice = im[:2, :2]

It could just be that I am misunderstanding the documentation. There is very little Python documentation in this part of the code.

Issue submission checklist
  • I report the issue, it's not a question
  • I checked the problem with documentation, FAQ, open issues,
    forum.opencv.org, Stack Overflow, etc and have not found any solution
  • I updated to the latest OpenCV version and the issue is still there
  • There is reproducer code and related data files: videos, images, onnx, etc
@gentlegiantJGC
Copy link
Author

It looks like the same behaviour can be achieved by passing it to the constructor.

import cv2
im = cv2.cuda.GpuMat(10, 10, cv2.CV_8UC1)
im_slice = cv2.cuda.GpuMat(im, (0, 2), (0, 2))

The original issue still exists though. Either the GpuMat should be modified to behave the same as the Mat class or the docs should be updated to indicate that the functionality is not available in python and the constructor can be used instead.

@gentlegiantJGC
Copy link
Author

Extended to this it looks like none of the public attributes are exposed to python.

I would be interested in solving this but I don't know where to begin.

@asmorkalov
Copy link
Contributor

OpenCV GpuMat stores data on GPU side. It's not available for CPU code directly. To do modifications on CPU side you need to call download(), get regular Mat, modify it and call upload() to transfer data back. So it's not missing python binding, it's C++ API design and object liefecycle.

@gentlegiantJGC
Copy link
Author

gentlegiantJGC commented Jul 4, 2022

OpenCV GpuMat stores data on GPU side. It's not available for CPU code directly. To do modifications on CPU side you need to call download(), get regular Mat, modify it and call upload() to transfer data back. So it's not missing python binding, it's C++ API design and object liefecycle.

I understand what you are saying but I think you misunderstood me. I should have linked to the documentation.

This is the method that is not available in Python
https://docs.opencv.org/3.4/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a2b3c25e36b0f82ca8f9f74b6ae68c41d

It is a 2D slice that returns a new GpuMat viewing the original data (still on the GPU)

The 1D alternatives and the constructor version do work. (rowRange and colRange)
https://docs.opencv.org/3.4/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a0bf9a88fc518cc9986808aaf916f2182
https://docs.opencv.org/3.4/d0/d60/classcv_1_1cuda_1_1GpuMat.html#a7256892911593daf1bdefb183d6fd29e
https://docs.opencv.org/3.4/d0/d60/classcv_1_1cuda_1_1GpuMat.html#acb11621e15a3e06d243b73ae04a0f398

Edit: also as I said above none of the public attributes are exposed in python either. cols and rows being the primary ones of use.

@Eddy202208
Copy link

Eddy202208 commented Oct 13, 2022

Hi, how can I pass a set of images to GpuMat? it's possible? or do you have to create a GpuMat for each image? example:

from distutils.command.upload import upload
import cv2
import numpy as np

GOOD_MATCH_PERCENT = 0.15
max_features = 9000
orb = cv2.cuda_ORB.create(max_features)
matcherGPU = cv2.cuda.DescriptorMatcher_createBFMatcher(cv2.NORM_HAMMING)

Read the images as normal

npMat1 = cv2.imread("C:\Users\Geddy\Desktop\0.png")
npMat2 = cv2.imread("C:\Users\Geddy\Desktop\1.png")#cv2.imread("path_to_reference_image")

Load the images onto the GPU

cuMat1 = cv2.cuda_GpuMat()
cuMat2 = cv2.cuda_GpuMat()
cuMat1.upload(npMat1)
cuMat2.upload(npMat2)

Convert the color on the GPU

cuMat1 = cv2.cuda.cvtColor(cuMat1, cv2.COLOR_BGR2GRAY)
cuMat2 = cv2.cuda.cvtColor(cuMat2, cv2.COLOR_BGR2GRAY)

Create the CUDA ORB detector and detect keypoints/descriptors

kps1, descs1 = orb.detectAndComputeAsync(cuMat1, None) # Both are returned as GPU Mats
kps2, descs2 = orb.detectAndComputeAsync(cuMat2, None)
matches = matcherGPU.match(descs1, descs2)
matches2=sorted(matches,key=lambda x: x.distance, reverse=False)
numGoodMatches = int(len(matches2) * GOOD_MATCH_PERCENT)
matches2 = matches2[:numGoodMatches]
kps1c = orb.convert(kps1)
kps2c = orb.convert(kps2)
imMatches = cv2.drawMatches(npMat1, kps1c, npMat2, kps2c, matches2, None)
cv2.imwrite("gpu_matches.jpg", imMatches)

the previous code works great !!! But it is with 2 images I want to do it with 50 images, how can I do it ?

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

No branches or pull requests

4 participants