Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

ibaiGorordo
Copy link
Contributor

@ibaiGorordo ibaiGorordo commented Feb 1, 2023

This is a replacement for #23052, where I made some mistakes with the branches at the end.

  • It fixes the nfa function which is missing the first log_gamma call compared with the function in the binomial_nfa repository.
  • It also fixes the logic issue on rect_nfa function, which had a logic issue on the way the pixels inside the rectangle were being checked.

With the changes to the rect_nfa function, now it checks the same pixels inside the rectangle as the original paper. In the image below I fill a rotated rectangle using the original paper method (blue channel), the old OpenCV method (green channel), and the fixed code (red channel). As you can see, the old calculation had some logic issues.
rect_fill_comparison

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 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

Comparing the nfa function with the function in the binomial_nfa repository (https://github.com/rafael-grompone-von-gioi/binomial_nfa/blob/main/C99/log_binomial_nfa.c#L152), the first log_gamma call is missing.

// function to get the slope of the rectangle for a specific row
inline double get_slope(cv::Point2d p1, cv::Point2d p2) {
return (p2.y != p1.y) ? (p2.x - p1.x) / (p2.y - p1.y) : 0;
Copy link
Member

Choose a reason for hiding this comment

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

p2.y != p1.y

This check is not enough to avoid NaN / Inf results of this expression.

: 0;

Why is 0 here?
Both horizontal and vertical lines has the same value from this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @alalek, thank you for reviewing the PR.

The main reason for that function is that I moved the old code logic (lines below) to a function. There was a mistake because I forgot that I switched to Point2d, so I changed the check to use integer values instead.

double flstep = (min_y->p.y != leftmost->p.y) ?
(min_y->p.x - leftmost->p.x) / (min_y->p.y - leftmost->p.y) : 0; //first left step
double slstep = (leftmost->p.y != tailp->p.x) ?
(leftmost->p.x - tailp->p.x) / (leftmost->p.y - tailp->p.x) : 0; //second left step
double frstep = (min_y->p.y != rightmost->p.y) ?
(min_y->p.x - rightmost->p.x) / (min_y->p.y - rightmost->p.y) : 0; //first right step
double srstep = (rightmost->p.y != tailp->p.x) ?
(rightmost->p.x - tailp->p.x) / (rightmost->p.y - tailp->p.x) : 0; //second right step

But the reality is that due to the way the vertices are ordered (the image below shows the possible cases), and the way the 2 regions are defined for the slope calculation, the y value of both points should only be the same when the rectangle is horizontal. In that case, in the calculation for the second left region (vertices 1 and 2), and the first right region (vertices 0 and 3) the y value of the points used for the slope calculation will be the same.

And because of the checks inside the for loop (code below), the slope in those cases will not be used. So, in theory, it does not matter what the slope is when the y value is the same. But actually, returning 0 is a safe option, in case there is a mistake (like the one I just fixed with the left limit check).

if(y <= int(ceil(ordered_y[1].y)))
left_limit = get_limit(ordered_y[0], y, flstep);
else
left_limit = get_limit(ordered_y[1], y, slstep);
if(y < int(ceil(ordered_y[3].y)))
right_limit = get_limit(ordered_y[0], y, frstep);
else
right_limit = get_limit(ordered_y[3], y, srstep);

However, despite all that (sorry for the long response btw), I can make other changes to the function if necessary.

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.

LGTM 👍 Thank you for contribution!

@alalek alalek merged commit c280cd7 into opencv:3.4 Feb 8, 2023
@alalek alalek mentioned this pull request Feb 11, 2023
@asmorkalov asmorkalov mentioned this pull request Apr 20, 2023
@asmorkalov asmorkalov mentioned this pull request May 31, 2023
geversonsto pushed a commit to stodev-com-br/opencv that referenced this pull request Jun 3, 2023
Fix rect_nfa (lsd)

* Fix missing log_gamma in nfa()

Comparing the nfa function with the function in the binomial_nfa repository (https://github.com/rafael-grompone-von-gioi/binomial_nfa/blob/main/C99/log_binomial_nfa.c#L152), the first log_gamma call is missing.

* Fix rect_nfa pixel index

* Replace std::rotate

* Rename tmp to v_tmp

* Replace auto and std::min_element

* Change slope equality check to int

* Fix left limit check
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.

3 participants