CARVIEW |
Navigation Menu
-
-
Notifications
You must be signed in to change notification settings - Fork 56.2k
Issue 26972: Proper treatment of float values in intersectConvexConvex #26974
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
Conversation
8bc4da4
to
e2a9f70
Compare
modules/imgproc/src/geometry.cpp
Outdated
return s < - eps || s > 1.+ eps || t < - eps || t > 1. + eps ? LS_NO_INTERSECTION : | ||
s < eps || s > 1. - eps || t < eps || t > 1. - eps ? LS_ENDPOINT_INTERSECTION : | ||
LS_SINGLE_INTERSECTION; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it's not correct to compare floats/doubles on equality, but why do you change the first line of conditions? I would say that the correct check is:
return s < 0. || s > 1. || t < 0. || t > 1. ? LS_NO_INTERSECTION :
fabs(num) < eps || fabs(s-1.) < eps || fabs(t) < eps || fabs(t-1.) < eps ? LS_ENDPOINT_INTERSECTION :
LS_SINGLE_INTERSECTION;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The numerical error can happen on both sides, and in particular the one "outside" the line actually caused the problem that the polygon intersection was not detected (see unit test). The one on the inside is probably harmless and could be treated either way, as endpoint and single intersection are "intersections". For symmetry reasons I also updated the second check.
The tests probably timed out due to unrelated reasons, can they be retriggered? |
@asmorkalov Anything missing from my side before merging? [edit] I tested the fix on a much larger number of examples, and the proper treatment makes other algorithm assumptions fail. So merging as is, is not a good option. Either another fix is needed or the algorithm needs to be written in a way that is not relying on exact corner treatment in other parts. I will continue looking into it. |
a067524
to
acf4b8c
Compare
So the original idea with putting the "numerical circle" around endpoints failed. I had examples, where a intersection was detected, even though polygons did not touch. For some reason the algorithm went crazy from that point on. Now the new approach would be to only check "on the polygon". So if one edge goes through the vertex it will have its (let's say) s in [0,1]. Then the issue observed was that for the edge before the vertex we had t > 1 and after the vertex t < 0, but in fact we passed the vertex, so it should have been either t <= 1 or s>= 0. For now I put the MR to draft status: The original solution would not work, the new approach should circumvent those issues. I will remove the draft status once I arrive at a solution that reliably works for me. In the meantime I invite to iterate on the idea proposed with my second commit. If you want to reproduce the issue with the original fix yourself, use: |
acf4b8c
to
5bb7121
Compare
Ok, so unit tests pass now as before and also on my side I ran some initial automated tests with random rectangles - so far it looks good, so I would say the MR is again ready for review. Compared to the first solution where I enlarged the vertex, I am now checking whether the intersecting lines start point was outside and its end point inside the polygon. Unless the edge is super tiny in the magnitude of the numeric errors, this is a robust alternative to checking whether a float point ==0. I am not super happy yet with the names of variables and organization of the updates per "advance". I am open for suggestions making the code more readable. In fact if there is interest I could also propose some cleanup towards more readable code. It took me quite some time to wrap my head around the several a's b's p's and q's. |
5bb7121
to
679f580
Compare
@klosteraner, thank you for the contribution and sorry for a long delay with the review. I found that if
|
…but with more double-precision calculations. Hopefully, that also solves the original problem.
As outlined in #26972 the function
intersectConvexConvex()
may not work as expected in the corner case, where two polygons intersect at a corner. A concrete example is given that I added as unit test. The unit test would fail without the proposed bug fix. I recommend porting the fix to all versions.Now concerning the fix: When digging into the implementation I found, that when the line intersections are computed, openCV currently does not apply floating point comparison syntax, but pretends that line end points are exact. Instead I replaced the formulation using the eps that is already used in another component of the function in line.277:
epx=1e-5
. IMO that is solid enough, definitely better than assuming an exact floating point comparison is possible.As a follow up I would suggest to use a scalable eps, s.t. also cases with high floating point numbers would be less error prone. However that would need to be done in all relevant sub steps, not just the line intersection code. So for me outside the scope of this fix.
Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
Patch to opencv_extra has the same branch name.