18

I am trying to get OpenCV 2.4.5 to recognize a checkerboard pattern from my webcam. I couldn't get that working, so I decided to try to get it working just using a "perfect" image:

checkerboard with white border

but it still won't work--patternFound returns false every time. Does anyone have any idea what I'm doing wrong?

#include <stdio.h>

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
using namespace std;

int main(){
    Size patternsize(8,8); //number of centers
    Mat frame = imread("perfect.png"); //source image
    vector<Point2f> centers; //this will be filled by the detected centers

    bool patternfound = findChessboardCorners(frame,patternsize,centers);

    cout<<patternfound<<endl;
    drawChessboardCorners(frame, patternsize, Mat(centers), patternfound);

    cvNamedWindow("window");
    while(1){
        imshow("window",frame);
        cvWaitKey(33);
    }
}
laurenelizabeth
  • 786
  • 1
  • 7
  • 19

3 Answers3

32

Through trial and error, I realized that patternsize should be 7x7 since it is counting internal corners. This parameter has to be exact--8x8 won't work, but neither will anything less than 7x7.

laurenelizabeth
  • 786
  • 1
  • 7
  • 19
  • 7
    the chessboard needs to be assymetric. I repeat, the chessboard needs to be assymetric. Tell me how you can possibly calibrate otherwise. – CTZStef Oct 27 '13 at 23:58
  • @laurenelizabeth Your answer got me one step closer, but I seem to have the same problem still. The hint about 7x7 instead of 8x8 was very important to me. However I'm still not able to detect the corners of photographed chessboards, not even on close-to-perfect photos. – Daniel S. Sep 25 '14 at 15:25
  • We are trying with asymmetric 9x7 chessboard, and we ask for 8x6 (interior squares). It just worked really fast. No problems detecting. And we are using a double camera set up where we only consider when both cameras detect the thing at the same time. THANKS!!! – helios May 05 '17 at 23:12
  • @CTZStef If you're saying you can't calibrate with a square shaped plate, I suppose it's possible for OpenCV to have that limitation but it's definitely not true for computer vision in general, it's very possible to calibrate with checkerboards that have (n x n) squares on them. If you're saying that you can't accurately calibrate with a checkerboard that is perfectly up and down (i.e., with checkers that are not the least bit diagonal or tilted), then yes, I agree. – jrh Nov 05 '18 at 16:09
  • 1
    I work with 5x3 pattern and it works. The best way to choose a pattern is to choose a rectangular board and choose at least 1 even number of chessboard corners. The only constraint by openCV is that it should be greater than 2x2 – Shravya Boggarapu Nov 29 '18 at 10:13
  • In my code i am trying combinations from 9x9 down to 3x3 until i find a pattern. I use a size-reduced copy for the first try to speed up the failed attempts but it also seems to be possible to tell openCV so – Wolfgang Fahl Dec 07 '19 at 05:49
  • It doesn't work for me with a 7x7, 8x7 or even a n 8x6 grid. Any help? – skinnybb Sep 26 '22 at 07:27
  • The internal corner part of this answer is what helped me (everywhere a white square meets a black square at the corners), I was counting the squares wrong. Some of the examples on the web are also labeled wrong, so make sure you count them yourself. – Jimmy Johnson Apr 14 '23 at 21:01
13

Instead of using

Size patternsize(8,8); 

use

Size patternsize(7,7);  
Desai
  • 275
  • 3
  • 7
  • why? its an 8x8 grid – john k Nov 29 '19 at 04:47
  • 1
    @johnktejik It looks for the points where two white squares and two black squares meet. So yes, there are 8 squares by 8 squares but the there are only 7x7 points where four squares connect. – user2012741 Mar 27 '20 at 21:18
  • Using the correct patternSize fixed the issue for me, too! However I have to point out that the official OpenCV calibration tutorial then is truly misleading. In their example code they specify a smaller patternSize and it works anyway... see: https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html – robert Feb 20 '23 at 11:04
4

Width and height of the chessboard can't be of the same length, i.e. it needs to be assymetric. This might be the source of your problem. Here is a very good tutorial about camera calibration with OpenCV.

Just below is the code I use for my calibration (tested and fully functional, HOWEVER I call it in some processing thread of my own, you should call it in your processing loop or whatever you are using to catch your frames) :

void MyCalibration::execute(IplImage* in, bool debug)
{
    const int CHESSBOARD_WIDTH = 8;
    const int CHESSBOARD_HEIGHT = 5;
    const int CHESSBOARD_INTERSECTION_COUNT = CHESSBOARD_WIDTH * CHESSBOARD_HEIGHT;

    //const bool DO_CALIBRATION = ((BoolProperty*)getProperty("DoCalibration"))->getValue();
    if(in->nChannels == 1)
        cvCopy(in,gray_image);
    else
        cvCvtColor(in,gray_image,CV_BGR2GRAY);

    int corner_count;
    CvPoint2D32f* corners = new CvPoint2D32f[CHESSBOARD_INTERSECTION_COUNT];
    int wasChessboardFound = cvFindChessboardCorners(gray_image, cvSize(CHESSBOARD_WIDTH, CHESSBOARD_HEIGHT), corners, &corner_count);

    if(wasChessboardFound) {
        // Refine the found corners
        cvFindCornerSubPix(gray_image, corners, corner_count, cvSize(5, 5), cvSize(-1, -1), cvTermCriteria(CV_TERMCRIT_ITER, 100, 0.1));

        // Add the corners to the array of calibration points
        calibrationPoints.push_back(corners);

        cvDrawChessboardCorners(in, cvSize(CHESSBOARD_WIDTH, CHESSBOARD_HEIGHT), corners, corner_count, wasChessboardFound);
    } 
}

Just in case you wondered about the class members, here is my class (IplImage was still around at the time I wrote it) :

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv/cv.h>

class MyCalibration
{
private:
    std::vector<CvPoint2D32f*> calibrationPoints;

    IplImage *gray_image;

public:
    MyCalibration(IplImage* in);
    void execute(IplImage* in, bool debug=false);
    ~MyCalibration(void);
};

And finally the constructor :

MyCalibration::MyCalibration(IplImage* in)
{
    gray_image = cvCreateImage(cvSize(in->width,in->height),8,1);
}
CTZStef
  • 1,675
  • 2
  • 18
  • 47
  • 4
    Well, it worked when I used 7x7, so I'm not sure that it needs to be asymmetric. Thanks for the tutorial link, though! – laurenelizabeth Jul 18 '13 at 15:14
  • 1
    Were you able to calibrate and remap your camera with a symetric pattern ? I don't think so. Therefore, it didn't work. Maybe findChessboardCorners() worked, but that's no calibration. – CTZStef Oct 28 '13 at 00:00
  • I just needed the corners, not the full calibration routines. – laurenelizabeth Oct 28 '13 at 14:25
  • 2
    @CTZStef Thankyou for the answer. I was running into errors trying to calibrate my camera with a symmetric chessboard. – Clive Jan 11 '15 at 18:14