Skip to content

Fix cudacodec and cudastereo python bindings #3267

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

Merged
merged 1 commit into from
Jun 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 49 additions & 13 deletions modules/cudacodec/include/opencv2/cudacodec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,12 @@ class CV_EXPORTS_W VideoReader

/** @brief Grabs, decodes and returns the next video frame.

If no frames has been grabbed (there are no more frames in video file), the methods return false .
The method throws Exception if error occurs.
@param [out] frame The video frame.
@param stream Stream for the asynchronous version.
@return `false` if no frames have been grabbed.

If no frames have been grabbed (there are no more frames in video file), the methods return false.
The method throws an Exception if error occurs.
*/
CV_WRAP virtual bool nextFrame(CV_OUT GpuMat& frame, Stream &stream = Stream::Null()) = 0;

Expand All @@ -364,6 +368,7 @@ class CV_EXPORTS_W VideoReader

/** @brief Grabs the next frame from the video source.

@param stream Stream for the asynchronous version.
@return `true` (non-zero) in the case of success.

The method/function grabs the next frame from video file or camera and returns true (non-zero) in
Expand All @@ -376,17 +381,44 @@ class CV_EXPORTS_W VideoReader

/** @brief Returns previously grabbed video data.

@param [out] frame The returned data which depends on the provided idx. If there is no new data since the last call to grab() the image will be empty.
@param idx Determins the returned data inside image. The returned data can be the:
Decoded frame, idx = get(PROP_DECODED_FRAME_IDX).
Extra data if available, idx = get(PROP_EXTRA_DATA_INDEX).
Raw encoded data package. To retrieve package i, idx = get(PROP_RAW_PACKAGES_BASE_INDEX) + i with i < get(PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB)
@return `false` if no frames has been grabbed
@param [out] frame The returned data which depends on the provided idx.
@param idx Determines the returned data inside image. The returned data can be the:
- Decoded frame, idx = get(PROP_DECODED_FRAME_IDX).
- Extra data if available, idx = get(PROP_EXTRA_DATA_INDEX).
- Raw encoded data package. To retrieve package i, idx = get(PROP_RAW_PACKAGES_BASE_INDEX) + i with i < get(PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB)
@return `false` if no frames have been grabbed

The method returns data associated with the current video source since the last call to grab() or the creation of the VideoReader. If no data is present
the method returns false and the function returns an empty image.
*/
virtual bool retrieve(OutputArray frame, const size_t idx = static_cast<size_t>(VideoReaderProps::PROP_DECODED_FRAME_IDX)) const = 0;

/** @brief Returns previously grabbed encoded video data.

@param [out] frame The encoded video data.
@param idx Determines the returned data inside image. The returned data can be the:
- Extra data if available, idx = get(PROP_EXTRA_DATA_INDEX).
- Raw encoded data package. To retrieve package i, idx = get(PROP_RAW_PACKAGES_BASE_INDEX) + i with i < get(PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB)
@return `false` if no frames have been grabbed

The method returns data associated with the current video source since the last call to grab() or the creation of the VideoReader. If no data is present
the method returns false and the function returns an empty image.
*/
CV_WRAP virtual bool retrieve(CV_OUT OutputArray frame, const size_t idx = static_cast<size_t>(VideoReaderProps::PROP_DECODED_FRAME_IDX)) const = 0;
CV_WRAP inline bool retrieve(CV_OUT Mat& frame, const size_t idx) const {
return retrieve(OutputArray(frame), idx);
}

/** @brief Returns the next video frame.

@param [out] frame The video frame. If grab() has not been called then this will be empty().
@return `false` if no frames have been grabbed

The method returns data associated with the current video source since the last call to grab(). If no data is present
the method returns false and the function returns an empty image.
*/
CV_WRAP inline bool retrieve(CV_OUT GpuMat& frame) const {
return retrieve(OutputArray(frame));
}

/** @brief Sets a property in the VideoReader.

Expand All @@ -395,7 +427,10 @@ class CV_EXPORTS_W VideoReader
@param propertyVal Value of the property.
@return `true` if the property has been set.
*/
CV_WRAP virtual bool set(const VideoReaderProps propertyId, const double propertyVal) = 0;
virtual bool set(const VideoReaderProps propertyId, const double propertyVal) = 0;
CV_WRAP inline bool setVideoReaderProps(const VideoReaderProps propertyId, double propertyVal) {
return set(propertyId, propertyVal);
}

/** @brief Set the desired ColorFormat for the frame returned by nextFrame()/retrieve().

Expand All @@ -408,11 +443,12 @@ class CV_EXPORTS_W VideoReader
@param propertyId Property identifier from cv::cudacodec::VideoReaderProps (eg. cv::cudacodec::VideoReaderProps::PROP_DECODED_FRAME_IDX,
cv::cudacodec::VideoReaderProps::PROP_EXTRA_DATA_INDEX, ...).
@param propertyVal
In - Optional value required for querying specific propertyId's, e.g. the index of the raw package to be checked for a key frame (cv::cudacodec::VideoReaderProps::PROP_LRF_HAS_KEY_FRAME).
Out - Value of the property.
- In: Optional value required for querying specific propertyId's, e.g. the index of the raw package to be checked for a key frame (cv::cudacodec::VideoReaderProps::PROP_LRF_HAS_KEY_FRAME).
- Out: Value of the property.
@return `true` unless the property is not supported.
*/
CV_WRAP virtual bool get(const VideoReaderProps propertyId, CV_IN_OUT double& propertyVal) const = 0;
virtual bool get(const VideoReaderProps propertyId, double& propertyVal) const = 0;
CV_WRAP virtual bool getVideoReaderProps(const VideoReaderProps propertyId, CV_OUT double& propertyValOut, double propertyValIn = 0) const = 0;

/** @brief Retrieves the specified property used by the VideoSource.

Expand Down
29 changes: 29 additions & 0 deletions modules/cudacodec/misc/python/test/test_cudacodec.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,35 @@ def test_reader(self):
ret, _gpu_mat2 = reader.nextFrame(gpu_mat)
#TODO: self.assertTrue(gpu_mat == gpu_mat2)
self.assertTrue(ret)

params = cv.cudacodec.VideoReaderInitParams()
params.rawMode = True
ms_gs = 1234
reader = cv.cudacodec.createVideoReader(vid_path,[cv.CAP_PROP_OPEN_TIMEOUT_MSEC, ms_gs], params)
ret, ms = reader.get(cv.CAP_PROP_OPEN_TIMEOUT_MSEC)
self.assertTrue(ret and ms == ms_gs)
ret, raw_mode = reader.getVideoReaderProps(cv.cudacodec.VideoReaderProps_PROP_RAW_MODE)
self.assertTrue(ret and raw_mode)

ret, colour_code = reader.getVideoReaderProps(cv.cudacodec.VideoReaderProps_PROP_COLOR_FORMAT)
self.assertTrue(ret and colour_code == cv.cudacodec.ColorFormat_BGRA)
colour_code_gs = cv.cudacodec.ColorFormat_GRAY
reader.set(colour_code_gs)
ret, colour_code = reader.getVideoReaderProps(cv.cudacodec.VideoReaderProps_PROP_COLOR_FORMAT)
self.assertTrue(ret and colour_code == colour_code_gs)

ret, i_base = reader.getVideoReaderProps(cv.cudacodec.VideoReaderProps_PROP_RAW_PACKAGES_BASE_INDEX)
self.assertTrue(ret and i_base == 2.0)
self.assertTrue(reader.grab())
ret, gpu_mat3 = reader.retrieve()
self.assertTrue(ret and isinstance(gpu_mat3,cv.cuda.GpuMat) and not gpu_mat3.empty())
ret = reader.retrieve(gpu_mat3)
self.assertTrue(ret and isinstance(gpu_mat3,cv.cuda.GpuMat) and not gpu_mat3.empty())
ret, n_raw_packages_since_last_grab = reader.getVideoReaderProps(cv.cudacodec.VideoReaderProps_PROP_NUMBER_OF_RAW_PACKAGES_SINCE_LAST_GRAB)
self.assertTrue(ret and n_raw_packages_since_last_grab > 0)
ret, raw_data = reader.retrieve(int(i_base))
self.assertTrue(ret and isinstance(raw_data,np.ndarray) and np.any(raw_data))

except cv.error as e:
notSupported = (e.code == cv.Error.StsNotImplemented or e.code == cv.Error.StsUnsupportedFormat or e.code == cv.Error.GPU_API_CALL_ERROR)
self.assertTrue(notSupported)
Expand Down
24 changes: 17 additions & 7 deletions modules/cudacodec/src/video_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace
void set(const ColorFormat _colorFormat) CV_OVERRIDE;

bool get(const VideoReaderProps propertyId, double& propertyVal) const CV_OVERRIDE;
bool getVideoReaderProps(const VideoReaderProps propertyId, double& propertyValOut, double propertyValIn) const CV_OVERRIDE;

bool get(const int propertyId, double& propertyVal) const CV_OVERRIDE;

Expand Down Expand Up @@ -246,13 +247,13 @@ namespace
}
else if (idx == extraDataIdx) {
if (!frame.isMat())
CV_Error(Error::StsUnsupportedFormat, "Extra data is stored on the host and must be retrueved using a cv::Mat");
CV_Error(Error::StsUnsupportedFormat, "Extra data is stored on the host and must be retrieved using a cv::Mat");
videoSource_->getExtraData(frame.getMatRef());
}
else{
if (idx >= rawPacketsBaseIdx && idx < rawPacketsBaseIdx + rawPackets.size()) {
if (!frame.isMat())
CV_Error(Error::StsUnsupportedFormat, "Raw data is stored on the host and must retrievd using a cv::Mat");
CV_Error(Error::StsUnsupportedFormat, "Raw data is stored on the host and must be retrieved using a cv::Mat");
Mat tmp(1, rawPackets.at(idx - rawPacketsBaseIdx).size, CV_8UC1, rawPackets.at(idx - rawPacketsBaseIdx).Data(), rawPackets.at(idx - rawPacketsBaseIdx).size);
frame.getMatRef() = tmp;
}
Expand All @@ -264,8 +265,9 @@ namespace
switch (propertyId) {
case VideoReaderProps::PROP_RAW_MODE :
videoSource_->SetRawMode(static_cast<bool>(propertyVal));
return true;
}
return true;
return false;
}

void VideoReaderImpl::set(const ColorFormat _colorFormat) {
Expand Down Expand Up @@ -303,20 +305,28 @@ namespace
else
break;
}
case VideoReaderProps::PROP_ALLOW_FRAME_DROP: {
case VideoReaderProps::PROP_ALLOW_FRAME_DROP:
propertyVal = videoParser_->allowFrameDrops();
return true;
}
case VideoReaderProps::PROP_UDP_SOURCE: {
case VideoReaderProps::PROP_UDP_SOURCE:
propertyVal = videoParser_->udpSource();
return true;
}
case VideoReaderProps::PROP_COLOR_FORMAT:
propertyVal = static_cast<double>(colorFormat);
return true;
default:
break;
}
return false;
}

bool VideoReaderImpl::getVideoReaderProps(const VideoReaderProps propertyId, double& propertyValOut, double propertyValIn) const {
double propertyValInOut = propertyValIn;
const bool ret = get(propertyId, propertyValInOut);
propertyValOut = propertyValInOut;
return ret;
}

bool VideoReaderImpl::get(const int propertyId, double& propertyVal) const {
return videoSource_->get(propertyId, propertyVal);
}
Expand Down
2 changes: 2 additions & 0 deletions modules/cudacodec/test/test_video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ CUDA_TEST_P(Video, Reader)
// request a different colour format for each frame
const std::pair< cudacodec::ColorFormat, int>& formatToChannels = formatsToChannels[i % formatsToChannels.size()];
reader->set(formatToChannels.first);
double colorFormat;
ASSERT_TRUE(reader->get(cudacodec::VideoReaderProps::PROP_COLOR_FORMAT, colorFormat) && static_cast<cudacodec::ColorFormat>(colorFormat) == formatToChannels.first);
ASSERT_TRUE(reader->nextFrame(frame));
if(!fmt.valid)
fmt = reader->format();
Expand Down
5 changes: 4 additions & 1 deletion modules/cudastereo/include/opencv2/cudastereo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,10 @@ disparity map.

@sa reprojectImageTo3D
*/
CV_EXPORTS_W void reprojectImageTo3D(InputArray disp, OutputArray xyzw, InputArray Q, int dst_cn = 4, Stream& stream = Stream::Null());
CV_EXPORTS void reprojectImageTo3D(InputArray disp, OutputArray xyzw, InputArray Q, int dst_cn = 4, Stream& stream = Stream::Null());
CV_EXPORTS_W inline void reprojectImageTo3D(GpuMat disp, CV_OUT GpuMat& xyzw, Mat Q, int dst_cn = 4, Stream& stream = Stream::Null()) {
reprojectImageTo3D((InputArray)disp, (OutputArray)xyzw, (InputArray)Q, dst_cn, stream);
}

/** @brief Colors a disparity image.

Expand Down
28 changes: 28 additions & 0 deletions modules/cudastereo/misc/python/test/test_cudastereo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python
import os
import cv2 as cv
import numpy as np

from tests_common import NewOpenCVTests, unittest

class cudastereo_test(NewOpenCVTests):
def setUp(self):
super(cudastereo_test, self).setUp()
if not cv.cuda.getCudaEnabledDeviceCount():
self.skipTest("No CUDA-capable device is detected")

def test_reprojectImageTo3D(self):
# Test's the functionality but not the results from reprojectImageTo3D
sz = (128,128)
np_disparity = np.random.randint(0, 64, sz, dtype=np.int16)
cu_disparity = cv.cuda_GpuMat(np_disparity)
np_q = np.random.randint(0, 100, (4, 4)).astype(np.float32)
stream = cv.cuda.Stream()
cu_xyz = cv.cuda.reprojectImageTo3D(cu_disparity, np_q, stream = stream)
self.assertTrue(cu_xyz.type() == cv.CV_32FC4 and cu_xyz.size() == sz)
cu_xyz1 = cv.cuda.GpuMat(sz, cv.CV_32FC3)
cv.cuda.reprojectImageTo3D(cu_disparity, np_q, cu_xyz1, 3, stream)
self.assertTrue(cu_xyz1.type() == cv.CV_32FC3 and cu_xyz1.size() == sz)

if __name__ == '__main__':
NewOpenCVTests.bootstrap()