Skip to content

Fix issues in Convex Hull algorithm #27020

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

Open
wants to merge 14 commits into
base: 4.x
Choose a base branch
from

Conversation

kallaballa
Copy link
Contributor

@kallaballa kallaballa commented Mar 6, 2025

Pull Request Readiness Checklist

See: #26952 and #26975

  • 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 another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the 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

@kallaballa
Copy link
Contributor Author

I created a simpler patch (than for #26975) that is considerably slower but seems to be correct.

@kallaballa
Copy link
Contributor Author

kallaballa commented Mar 6, 2025

To fix this issue entirely i would propose something like the following:

Preferred signature: easy to be implemented fast and correct. allows for input validation.

template<typename TpointContainer, typename Thull>
void convexHull(TpointContainer& points, std::vector<Thull>& hull, bool clockwise>

Deprecated signature 1: does the same as the preferred signature, only deprecated because the last parameter should be removed.

template<typename TpointContainer, typename Tpoints, typename Thull>
void convexHull(TpointContainer& points, std::vector<Thull>& hull, bool clockwise, bool ignored>

Deprecated signature 2: the original function fixed to the point where it retains behavior as closely as possible while preventing memory errors. probably considerably slower.

void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool returnPoints )

@opencv-alalek opencv-alalek added pr: needs test New functionality requires minimal tests set category: imgproc labels Mar 6, 2025
@kallaballa
Copy link
Contributor Author

Afaics tests fail now when they are using numerical arrays as input. I wouldn't know how to fix that except by explicitly converting (i use _InputArray::copyTo now)... but actually arrays are not documented as possible input for convexHull. How should i proceed?

@kallaballa
Copy link
Contributor Author

kallaballa commented Mar 8, 2025

There is no array kind. I am puzzled by how to make this work with all the variants.

In short: how can i convert numerical arrays, std::vector<Point_> and cv::Matx_<Point_> via InputArray to a continuous memory region of points? how to distinguish them and perform input validation?
The current approach if seen is to rely on the illegal assumption that:

int arr[2] = {2,3};
Point* pt = (Point*) arr;

Just going through getMat() doesn't work for numerical arrays.

and: how should i handle the discrepancies with the documentation?

@kallaballa kallaballa marked this pull request as ready for review March 8, 2025 08:35
@asmorkalov asmorkalov requested a review from mshabunin March 11, 2025 09:27
@asmorkalov asmorkalov added this to the 4.12.0 milestone Mar 11, 2025
@asmorkalov
Copy link
Contributor

@mshabunin could you take a look?

@asmorkalov
Copy link
Contributor

@mshabunin Could you take a look on it?

@mshabunin
Copy link
Contributor

I couldn't reproduce original issue, waiting for more details (see #26952).

@kallaballa
Copy link
Contributor Author

Sorry for the delay. I'll try to continue now but I don't know if i have enough time to finish.
btw. no matter if you can easily reproduce it, those are quite obviously severe issues, don't you think?

@kallaballa
Copy link
Contributor Author

i am just asking because i wonder... you wouldn't ask for a reproducer if it was something like std::vector({0,1,2})[99] (and i think it is even worse). anyway i am on it.

@asmorkalov
Copy link
Contributor

Friendly reminder.

for( i = 0; i < nout; i++ )
*(Point*)(hull.ptr() + i*step) = data0[hullbuf[i]];
} else {
_hull.create(nout, 1, _hull.type());
Copy link
Contributor

Choose a reason for hiding this comment

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

_hull.type() may be undefined, e.g. in Python case of it output is just cv::Mat. The original approach works better here.

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 am not sure how this should work without violating C++. we are not allowed to guess the size and layout of any object (after all a Point object is more than just 2 ints).

Comment on lines 254 to 257
for(int i = 0; i < bl_count-1; i++ )
hullbuf[nout++] = int(&pointer[bl_stack[i]] - pointer);
for(int i = br_count-1; i > 0; i-- )
hullbuf[nout++] = int(&pointer[br_stack[i]] - pointer);
Copy link
Contributor

Choose a reason for hiding this comment

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

&pointer[bl_stack[i]] - pointer is just bl_stack[i], right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nice catch! thx

Comment on lines 217 to 220
for(int i = 0; i < tl_count-1; i++ )
hullbuf[nout++] = int(&pointer[tl_stack[i]] - pointer);
for(int i = tr_count - 1; i > 0; i-- )
hullbuf[nout++] = int(&pointer[tr_stack[i]] - pointer);
Copy link
Contributor

Choose a reason for hiding this comment

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

pointer[tl_stack[i]] - pointer is just tl_stack[i], right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nice catch! thx

@asmorkalov
Copy link
Contributor

@kallaballa Friendly reminder.

@asmorkalov asmorkalov modified the milestones: 4.12.0, 4.13.0 Jun 19, 2025
@kallaballa
Copy link
Contributor Author

before i can continue: is the documentation authoritative or not? if not could you update it so i have a fixed reference to how this should actually work?

@kallaballa
Copy link
Contributor Author

I somehow cause problems with the java bindings. would someone have a hint on how to fix this?

https://pullrequest.opencv.org/buildbot/builders/precommit_linux64/builds/112467/steps/compile%20release/logs/stdio

    [javac] /build/precommit_linux64/build/modules/java/jar/opencv/java/org/opencv/imgproc/Imgproc.java:8295: error: method convexHull(MatOfPoint,MatOfInt,boolean) is already defined in class Imgproc
    [javac]     public static void convexHull(MatOfPoint points, MatOfInt hull, boolean clockwise) {
    [javac]                        ^
    [javac] /build/precommit_linux64/build/modules/java/jar/opencv/java/org/opencv/imgproc/Imgproc.java:8301: error: method convexHull(MatOfPoint,MatOfInt) is already defined in class Imgproc
    [javac]     public static void convexHull(MatOfPoint points, MatOfInt hull) {
    [javac]                        ^
    [javac] /build/precommit_linux64/build/modules/java/jar/opencv/java/org/opencv/imgproc/Imgproc.java:8312: error: method convexHull(MatOfPoint,MatOfInt,boolean) is already defined in class Imgproc
    [javac]     public static void convexHull(MatOfPoint points, MatOfInt hull, boolean clockwise) {
    [javac]                        ^
    [javac] /build/precommit_linux64/build/modules/java/jar/opencv/java/org/opencv/imgproc/Imgproc.java:8318: error: method convexHull(MatOfPoint,MatOfInt) is already defined in class Imgproc
    [javac]     public static void convexHull(MatOfPoint points, MatOfInt hull) {
    [javac]                        ^
    [javac] /build/precommit_linux64/build/modules/java/jar/opencv/java/org/opencv/imgproc/Imgproc.java:8329: error: method convexHull(MatOfPoint,MatOfInt,boolean) is already defined in class Imgproc
    [javac]     public static void convexHull(MatOfPoint points, MatOfInt hull, boolean clockwise) {
    [javac]                        ^
    [javac] /build/precommit_linux64/build/modules/java/jar/opencv/java/org/opencv/imgproc/Imgproc.java:8335: error: method convexHull(MatOfPoint,MatOfInt) is already defined in class Imgproc
    [javac]     public static void convexHull(MatOfPoint points, MatOfInt hull) {
    [javac]  

Comment on lines +4267 to +4269
CV_EXPORTS_W void convexHull( InputArray points, std::vector<int>& hull, bool clockwise = false, bool returnPoints = true );
CV_EXPORTS_W void convexHull( InputArray points, std::vector<Point>& hull, bool clockwise = false, bool returnPoints = true );
CV_EXPORTS_W void convexHull( InputArray points, std::vector<Point2f>& hull, bool clockwise = false, bool returnPoints = true );
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need the overloads?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That is my workaround (that allows me to use meta-programming behind the scenes and avoid OutputArray while having static input validation) for the problems i have:

#27020 (comment)
#27020 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category: imgproc pr: needs test New functionality requires minimal tests set
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants