findChessboardCorners не удается для калибровочного изображения

Я пытаюсь заставить OpenCV 2.4.5 распознавать шахматную доску по моей веб-камере. Я не мог заставить это работать, поэтому я решил попытаться заставить это работать, просто используя «прекрасное» изображение:

шахматная доска с белой каймой

но это все равно не будет работать — patternFound каждый раз возвращает false. Кто-нибудь знает, что я делаю не так?

#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);
}
}

11

Решение

Методом проб и ошибок я понял, что размер шаблона должен быть 7х7, поскольку он учитывает внутренние углы. Этот параметр должен быть точным — 8×8 не будет работать, но не будет ничего меньше, чем 7×7.

17

Другие решения

Вместо того, чтобы использовать

Size patternsize(8,8);

использование

Size patternsize(7,7);
8

Ширина и высота шахматной доски не могут быть одинаковой длины, то есть она должна быть ассиметричной. Это может быть источником вашей проблемы.
Вот очень хороший урок о калибровке камеры с OpenCV.

Чуть ниже приведен код, который я использую для калибровки (проверенный и полностью функциональный, ОДНАКО я называю его в каком-то собственном потоке обработки, вы должны вызывать его в цикле обработки или во всем, что вы используете для захвата ваших кадров):

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);
}
}

На случай, если вам интересно узнать об участниках класса, вот мой класс (IplImage все еще был на момент написания):

#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);
};

И, наконец, конструктор:

MyCalibration::MyCalibration(IplImage* in)
{
gray_image = cvCreateImage(cvSize(in->width,in->height),8,1);
}
3