Skip to content
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

cv2.findChessboardCorners() running endlessly on certain images #23558

Open
4 tasks done
JeremyKeusters opened this issue Apr 28, 2023 · 6 comments
Open
4 tasks done

cv2.findChessboardCorners() running endlessly on certain images #23558

JeremyKeusters opened this issue Apr 28, 2023 · 6 comments
Assignees
Labels
category: calib3d confirmed There is stable reproducer / investigation complete optimization
Milestone

Comments

@JeremyKeusters
Copy link

System Information

OpenCV python version: both 3.4.18.65 and 4.7.0.72
Operating System / Platform: Ubuntu 18.04 and macOS 13.2.1
Python version: 3.7

Detailed description

I’m using OpenCV to find chessboard corners on an image using cv2.findChessboardCorners(). It can happen that an image is passed into the function that is of bad quality or almost completely black. When this happens, the function just endlessly runs, trying to find the corners.

I initially opened a topic on the OpenCV forum, but there it was confirmed that it's a bug, hence why I'm also opening a bug report here.

This issue is a problem to me because it completely blocks my application when this happens.

Steps to reproduce

This issue can easily be reproduced.

You can use the code snippet below:

import cv2

test = cv2.imread("/path/to/the/image/27-04-2023_14-13-21_494.png")

found, corners = cv2.findChessboardCorners(image=test,
                                           patternSize=(26, 16),
                                           flags=(cv2.CALIB_CB_FAST_CHECK +
                                                  cv2.CALIB_CB_ADAPTIVE_THRESH +
                                                  cv2.CALIB_CB_NORMALIZE_IMAGE))

print(found)

in combination with the image below:
27-04-2023_14-13-21_494

You will notice that the function just endlessly keeps running and consuming resources (I’ve let it run for +15 minutes already).

Issue submission checklist

  • I report the issue, it's not a question
  • I checked the problem with documentation, FAQ, open issues, forum.opencv.org, Stack Overflow, etc and have not found any solution
  • I updated to the latest OpenCV version and the issue is still there
  • There is reproducer code and related data files (videos, images, onnx, etc)
@asmorkalov asmorkalov added this to the 4.8.0 milestone May 5, 2023
@asmorkalov asmorkalov added category: calib3d confirmed There is stable reproducer / investigation complete labels May 5, 2023
@Daniyal98
Copy link

I ran a test on this and found out that the testChessboardCorners function eventually returns. It is not running endlessly. It takes a lot of time in functions like processQuads and it is running in a loop so it takes around 3 minutes for the function to return.

@JeremyKeusters
Copy link
Author

JeremyKeusters commented May 16, 2023

Even if it returns after some time (it did not return after 20 minutes on my MacBook Pro 2020 i5), I guess it's still not expected behaviour that it takes so long, especially since the cv2.CALIB_CB_FAST_CHECK flag is provided? I can't believe that it is not able to determine faster that this image does not contain a chessboard.

@AleksandrPanov AleksandrPanov self-assigned this Jun 15, 2023
@asmorkalov asmorkalov modified the milestones: 4.8.0, 4.9.0 Jun 20, 2023
@AleksandrPanov
Copy link
Contributor

AleksandrPanov commented Jun 20, 2023

checked, findChessboardCorners() just works for a very long time.

There are two problems:

  1. cv.adaptiveThreshold finds a lot of noise to an almost black picture.
    1
  2. findContours finds many little contours (about 30k), then part of the contours is filtered out (90%), and then processed for a long time. The function needs to filter out more contours, maybe should to increase the threshold for the size of the contours (now int min_size = 25 - empiric bound for minimal allowed perimeter for squares).

@thewoz
Copy link
Contributor

thewoz commented Nov 17, 2023

The problems in my opinion are two:

  • The first that CALIB_CB_FAST_CHECK fails.
    Even though there is no checkChessboardBinary() in the image it returns positive and the rest of the findChessboardCorners code is called.

  • The second that once the adaptive threshold is applied all the noise comes out and generateQuads starts to find several contours in the order of 200K that in turn generate 26159 quads.
    This situation slowing down the execution of the function quite a bit.
    Especially as several rounds of adaptive thresholds and dilations are performed before the function exits.

In my opinion there are two possible things that can be done to mitigate the situation in this and similar cases.

The first, more expensive, is to figure out why checkChessboardBinary() fails.

The second, as already suggested, is to change the threshold that is used to filter quads.
This solution does not completely solve the problem, but it improves it by quite a bit in that it speeds up code execution time.
Ad esempio passare da 25 a 400 change the execution time from 570 sec to 130 sec on my machine.

The threshold is now defined in this way:

// empirical bound for minimal allowed perimeter for squares
int min_size = 25; //cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 );

To me 25 is a ridiculous number.
By the way it is not as written the minimum perimeter of the quad but the minimum area of the quad as seen just below:

Rect contour_rect = boundingRect(contour);
        if (contour_rect.area() < min_size)
            continue;

25 therefore means a quad of side 5 pixels!

I don't know why this part of the code was commented out and what the various multiplicative factors mean but it made more sense.
int min_size = 25; //cvRound( image->cols * image->rows * .03 * 0.01 * 0.92 );
In my opinion the solution is to pass to generateQuads() the size of the checkerboard and calculate min_size in the following way:
int min_size = ((image->cols * image->rows) * 0.25 / (pattern_size.width * pattern_size.height)) * 0.8;
That is, as if checkerboard occupies at least 25% of the image and that each square occupies roughly 80% of the space it has available

If it makes sense I make a pull request on this

@JeremyKeusters
Copy link
Author

Thanks for your input @thewoz ! In my opinion, the most critical problem is the failing CALIB_CB_FAST_CHECK. For me, the second problem is more a 'performance issue', while the first one is a bug. It's super obvious that no chessboard will ever be found on the image that is visible enough to work, and so in my expectation, the function should immediately skip the image.

Nevertheless, any contributions that work towards solving the issue are of course more than welcome, so would be great if you're willing to spend time in this @thewoz !

@asmorkalov asmorkalov modified the milestones: 4.9.0, 4.10.0 Dec 8, 2023
asmorkalov pushed a commit that referenced this issue Dec 11, 2023
…tor-findQuadNeighbors

Speed up ChessBoardDetector::findQuadNeighbors #24605

### Pull Request Readiness Checklist

Replaced brute-force algorithm with O(N^2) time complexity with kd-tree with something like O(N * log N) time complexity (maybe only in average case).

For example, on image from #23558 without quads filtering (by using `CALIB_CB_FILTER_QUADS` flag) finding chessboards corners took ~770 seconds on my laptop, of which finding quads neighbors took ~620 seconds.

Now finding chessboards corners takes ~155-160 seconds, of which finding quads neighbors takes only ~5-10 seconds.

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

- [x] I agree to contribute to the project under Apache 2 License.
- [x] 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
- [x] The PR is proposed to the proper branch
- [x] 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
@asmorkalov asmorkalov modified the milestones: 4.10.0, 4.11.0 May 16, 2024
thewoz pushed a commit to thewoz/opencv that referenced this issue May 29, 2024
…dDetector-findQuadNeighbors

Speed up ChessBoardDetector::findQuadNeighbors opencv#24605

### Pull Request Readiness Checklist

Replaced brute-force algorithm with O(N^2) time complexity with kd-tree with something like O(N * log N) time complexity (maybe only in average case).

For example, on image from opencv#23558 without quads filtering (by using `CALIB_CB_FILTER_QUADS` flag) finding chessboards corners took ~770 seconds on my laptop, of which finding quads neighbors took ~620 seconds.

Now finding chessboards corners takes ~155-160 seconds, of which finding quads neighbors takes only ~5-10 seconds.

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

- [x] I agree to contribute to the project under Apache 2 License.
- [x] 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
- [x] The PR is proposed to the proper branch
- [x] 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
@spdfghi
Copy link

spdfghi commented Jul 4, 2024

To takle this problem, I think controling threshold for the size of the contours or binarization is less ensential, since we can make a binary background whitch contains small size contours already. Maybe we can do downsampling/blur operations in fast check, which can eliminate small contours in image.
The below code I used run more faster, like 1-2 seconds, for test image of this issue.

if (flags & CALIB_CB_FAST_CHECK)
{
    //perform new method for checking chessboard using a binary image.
    //image is binarised using a threshold dependent on the image histogram
    int max_cols = 1000;
    cv::Mat small_img;
    if (thresh_img_new.cols > max_cols)
    {
        small_img = thresh_img_new.clone();
        cv::resize(small_img, small_img, cv::Size(max_cols, img.rows * max_cols / (float)img.cols));
    }
    if (checkChessboardBinary(small_img, pattern_size) <= 0) //fall back to the old method
    {
        if (!checkChessboard(small_img, pattern_size))
        {
            corners_.release();
            return false;
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category: calib3d confirmed There is stable reproducer / investigation complete optimization
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants