Skip to content

Implement cv::cuda::inRange (Fixes OpenCV #6295) #2803

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
Jan 21, 2021

Conversation

amiller27
Copy link
Contributor

@amiller27 amiller27 commented Jan 2, 2021

Merge with extra: opencv/opencv_extra#834

resolves opencv/opencv#6295

Implementation of cv::cuda::inRange, as requested in this issue. It's not a complete implementation of cv::inRange; my implementation supports cv::Scalar for the upper and lower bounds, which seems like the most common use case by far, but the CPU version does also support Mats for the bounds as well, which mine does not. It seemed like more of a challenge to support that as well, but if you don't want to merge this without full feature parity I might be able to spend more time on it to figure that out.

Some questions -

  1. Wasn't sure about whether the base branch should be master or 3.4, happy to rebase to 3.4 if desired. I do use std::array, but I think that's the only C++11 feature I'm using and it'd be easily removed.
  2. Wasn't sure if I need to do anything special for performance test data - I followed the instructions here to update the values for my new test only (PR in opencv_extra), but I didn't know how your performance test system deals with the fact that this should perform very differently depending on the GPU (I tested on a GeForce 750M).
  3. I added Doxygen comments in the code; if there's more documentation or sample code needed I can do that as well
  4. I had to use some recursive templates in functional.hpp to copy and compare CUDA vectors; if CUDA or OpenCV already has utilities somewhere to do this I can switch to make that simpler

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or other license that is incompatible with OpenCV
  • The PR is proposed to proper branch - see comment below
  • There is reference to original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake - see comment below
force_builders=Custom
buildworker:Custom=linux-5
build_image:Custom=ubuntu-cuda:18.04

Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

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

Thank you for contribution!

Please take a look on comments below.

inRangeImpl<double, 4>}};

const func_t func = funcs.at(channels - 1).at(depth);
func(src, lb, ub, dst, stream);
Copy link
Member

Choose a reason for hiding this comment

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

Please use CV_Check*() macro to validate channels / depth values.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Copy link
Member

Choose a reason for hiding this comment

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

src.depth()

where is validated?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Previously wasn't; I was trying to cover all depths. I've now realized that it doesn't work for float16, because CUDA doesn't have a float16 vector type. So I added a CV_Check that the depth is CV_64F or lower

@param dst output array of the same size as src and CV_8U type.
@param stream Stream for the asynchronous version.

@sa inRange
Copy link
Member

Choose a reason for hiding this comment

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

There is self-reference loop.

Try this one instead:
@sa cv::inRange

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed


@sa inRange
*/
CV_EXPORTS_W void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst, Stream& stream = Stream::Null());
Copy link
Member

Choose a reason for hiding this comment

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

CV_EXPORTS_W

Did you try to call this from Python binding? Are lowerb / upperb handled properly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can make calls like

src = (np.random.random((1920, 1080, 4)) * 256).astype(np.uint8)
lowerb = (0, 0, 0, 0)
upperb = (255, 255, 255, 255)
dst = cv2.cuda.inRange(src, lowerb, upperb)

with different types and numbers of channels for src (up to 4 channels). The CV_Check fires correctly if I pass the wrong shape for lowerb or upperb, or too many channels for src. It doesn't work if I pass a cv2.cuda_GpuMat (I get a TypeError: Expected Ptr<cv::UMat> for argument 'src') - I'm really not familiar with using OpenCV CUDA from Python so I don't know if that's the intended behavior.

Copy link
Member

Choose a reason for hiding this comment

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

I get a TypeError

Current messages from Python bindings are quite useless. You can set OPENCV_PYTHON_DEBUG=1 env variable to investigate conversion errors.
The "GPU" overload assumes that all inputs must be a GpuMat including lowerb/upperb parameters (because they a InputArray). But wrapping 4 scalars into GpuMat has significant overhead.

InputArray lowerb, InputArray upperb

Try to replace type to const Scalar& to eliminate unnecessary complexity.

Copy link
Member

Choose a reason for hiding this comment

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

Please add simple Python test into this file.

(please note, that public OpenCV CI doesn't run CUDA code/tests)

Copy link
Contributor Author

@amiller27 amiller27 Jan 18, 2021

Choose a reason for hiding this comment

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

Done. I switched to const Scalar& for lowerb and upperb, and added a Python test to that file which passes on my machine, it now works if you pass a numpy array or a cuda_GpuMat

@amiller27
Copy link
Contributor Author

I think everything has been addressed, but the docs build is failing on CI with

From git://code.ocv/opencv/opencv-ci
 * branch            master     -> FETCH_HEAD
HEAD is now at 5258c2f CMAKE_CXX_FLAGS: removed duplicate -Winit-self
FATAL: Build image for 'docs--18.04' is missing on the current build worker
program finished with exit code 1

It passes on my machine and this seems unrelated to anything I've done, not sure if there's anything I can do to fix it

@alalek
Copy link
Member

alalek commented Jan 19, 2021

@amiller27 It is CI issue, I will fix that soon.

Custom (CUDA) builder is failed due to changes from #2807 (should be fixed soon in separate PR)

Copy link
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

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

Well done! Thank you for contribution 👍

@opencv-pushbot opencv-pushbot merged commit 59a9c88 into opencv:master Jan 21, 2021
@alalek alalek mentioned this pull request Apr 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CUDA implementation of cv::inRange()
3 participants