Path: blob/master/modules/calib3d/src/chessboard.hpp
16354 views
// This file is part of OpenCV project.1// It is subject to the license terms in the LICENSE file found in the top-level directory2// of this distribution and at http://opencv.org/license.html.34#ifndef CHESSBOARD_HPP_5#define CHESSBOARD_HPP_67#include "opencv2/core.hpp"8#include "opencv2/features2d.hpp"9#include <vector>10#include <set>11#include <map>1213namespace cv {14namespace details{15/**16* \brief Fast point sysmetric cross detector based on a localized radon transformation17*/18class FastX : public cv::Feature2D19{20public:21struct Parameters22{23float strength; //!< minimal strength of a valid junction in dB24float resolution; //!< angle resolution in radians25int branches; //!< the number of branches26int min_scale; //!< scale level [0..8]27int max_scale; //!< scale level [0..8]28bool filter; //!< post filter feature map to improve impulse response29bool super_resolution; //!< up-sample3031Parameters()32{33strength = 40;34resolution = float(CV_PI*0.25);35branches = 2;36min_scale = 2;37max_scale = 5;38super_resolution = 1;39filter = true;40}41};4243public:44FastX(const Parameters &config = Parameters());45virtual ~FastX(){};4647void reconfigure(const Parameters ¶);4849//declaration to be wrapped by rbind50void detect(cv::InputArray image,std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask=cv::Mat())override51{cv::Feature2D::detect(image.getMat(),keypoints,mask.getMat());}5253virtual void detectAndCompute(cv::InputArray image,54cv::InputArray mask,55std::vector<cv::KeyPoint>& keypoints,56cv::OutputArray descriptors,57bool useProvidedKeyPoints = false)override;5859void detectImpl(const cv::Mat& image,60std::vector<cv::KeyPoint>& keypoints,61std::vector<cv::Mat> &feature_maps,62const cv::Mat& mask=cv::Mat())const;6364void detectImpl(const cv::Mat& image,65std::vector<cv::Mat> &rotated_images,66std::vector<cv::Mat> &feature_maps,67const cv::Mat& mask=cv::Mat())const;6869void findKeyPoints(const std::vector<cv::Mat> &feature_map,70std::vector<cv::KeyPoint>& keypoints,71const cv::Mat& mask = cv::Mat())const;7273std::vector<std::vector<float> > calcAngles(const std::vector<cv::Mat> &rotated_images,74std::vector<cv::KeyPoint> &keypoints)const;75// define pure virtual methods76virtual int descriptorSize()const override{return 0;};77virtual int descriptorType()const override{return 0;};78virtual void operator()( cv::InputArray image, cv::InputArray mask, std::vector<cv::KeyPoint>& keypoints, cv::OutputArray descriptors, bool useProvidedKeypoints=false )const79{80descriptors.clear();81detectImpl(image.getMat(),keypoints,mask);82if(!useProvidedKeypoints) // suppress compiler warning83return;84return;85}8687protected:88virtual void computeImpl( const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints, cv::Mat& descriptors)const89{90descriptors = cv::Mat();91detectImpl(image,keypoints);92}9394private:95void detectImpl(const cv::Mat& _src, std::vector<cv::KeyPoint>& keypoints, const cv::Mat& mask)const;96virtual void detectImpl(cv::InputArray image, std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask=cv::noArray())const;9798void rotate(float angle,const cv::Mat &img,cv::Size size,cv::Mat &out)const;99void calcFeatureMap(const cv::Mat &images,cv::Mat& out)const;100101private:102Parameters parameters;103};104105/**106* \brief Ellipse class107*/108class Ellipse109{110public:111Ellipse();112Ellipse(const cv::Point2f ¢er, const cv::Size2f &axes, float angle);113Ellipse(const Ellipse &other);114115116void draw(cv::InputOutputArray img,const cv::Scalar &color = cv::Scalar::all(120))const;117bool contains(const cv::Point2f &pt)const;118cv::Point2f getCenter()const;119const cv::Size2f &getAxes()const;120121private:122cv::Point2f center;123cv::Size2f axes;124float angle,cosf,sinf;125};126127/**128* \brief Chessboard corner detector129*130* The detectors tries to find all chessboard corners of an imaged131* chessboard and returns them as an ordered vector of KeyPoints.132* Thereby, the left top corner has index 0 and the bottom right133* corner n*m-1.134*/135class Chessboard: public cv::Feature2D136{137public:138static const int DUMMY_FIELD_SIZE = 100; // in pixel139140/**141* \brief Configuration of a chessboard corner detector142*143*/144struct Parameters145{146cv::Size chessboard_size; //!< size of the chessboard147int min_scale; //!< scale level [0..8]148int max_scale; //!< scale level [0..8]149int max_points; //!< maximal number of points regarded150int max_tests; //!< maximal number of tested hypothesis151bool super_resolution; //!< use super-repsolution for chessboard detection152bool larger; //!< indicates if larger boards should be returned153154Parameters()155{156chessboard_size = cv::Size(9,6);157min_scale = 2;158max_scale = 4;159super_resolution = true;160max_points = 400;161max_tests = 100;162larger = false;163}164165Parameters(int scale,int _max_points):166min_scale(scale),167max_scale(scale),168max_points(_max_points)169{170chessboard_size = cv::Size(9,6);171}172};173174175/**176* \brief Gets the 3D objects points for the chessboard assuming the177* left top corner is located at the origin.178*179* \param[in] pattern_size Number of rows and cols of the pattern180* \param[in] cell_size Size of one cell181*182* \returns Returns the object points as CV_32FC3183*/184static cv::Mat getObjectPoints(const cv::Size &pattern_size,float cell_size);185186/**187* \brief Class for searching and storing chessboard corners.188*189* The search is based on a feature map having strong pixel190* values at positions where a chessboard corner is located.191*192* The board must be rectangular but supports empty cells193*194*/195class Board196{197public:198/**199* \brief Estimates the position of the next point on a line using cross ratio constrain200*201* cross ratio:202* d12/d34 = d13/d24203*204* point order on the line:205* pt1 --> pt2 --> pt3 --> pt4206*207* \param[in] pt1 First point coordinate208* \param[in] pt2 Second point coordinate209* \param[in] pt3 Third point coordinate210* \param[out] pt4 Forth point coordinate211*212*/213static bool estimatePoint(const cv::Point2f &p0,const cv::Point2f &p1,const cv::Point2f &p2,cv::Point2f &p3);214215// using 1D homography216static bool estimatePoint(const cv::Point2f &p0,const cv::Point2f &p1,const cv::Point2f &p2,const cv::Point2f &p3, cv::Point2f &p4);217218/**219* \brief Checks if all points of a row or column have a valid cross ratio constraint220*221* cross ratio:222* d12/d34 = d13/d24223*224* point order on the row/column:225* pt1 --> pt2 --> pt3 --> pt4226*227* \param[in] points THe points of the row/column228*229*/230static bool checkRowColumn(const std::vector<cv::Point2f> &points);231232/**233* \brief Estimates the search area for the next point on the line using cross ratio234*235* point order on the line:236* (p0) --> p1 --> p2 --> p3 --> search area237*238* \param[in] p1 First point coordinate239* \param[in] p2 Second point coordinate240* \param[in] p3 Third point coordinate241* \param[in] p Percentage of d34 used for the search area width and height [0..1]242* \param[out] ellipse The search area243* \param[in] p0 optional point to improve accuracy244*245* \return Returns false if no search area can be calculated246*247*/248static bool estimateSearchArea(const cv::Point2f &p1,const cv::Point2f &p2,const cv::Point2f &p3,float p,249Ellipse &ellipse,const cv::Point2f *p0 =NULL);250251/**252* \brief Estimates the search area for a specific point based on the given homography253*254* \param[in] H homography descriping the transformation from ideal board to real one255* \param[in] row Row of the point256* \param[in] col Col of the point257* \param[in] p Percentage [0..1]258*259* \return Returns false if no search area can be calculated260*261*/262static Ellipse estimateSearchArea(cv::Mat H,int row, int col,float p,int field_size = DUMMY_FIELD_SIZE);263264/**265* \brief Searches for the maximum in a given search area266*267* \param[in] map feature map268* \param[in] ellipse search area269* \param[in] min_val Minimum value of the maximum to be accepted as maximum270*271* \return Returns a negative value if all points are outside the ellipse272*273*/274static float findMaxPoint(cv::flann::Index &index,const cv::Mat &data,const Ellipse &ellipse,float white_angle,float black_angle,cv::Point2f &pt);275276/**277* \brief Searches for the next point using cross ratio constrain278*279* \param[in] index flann index280* \param[in] data extended flann data281* \param[in] pt1282* \param[in] pt2283* \param[in] pt3284* \param[in] white_angle285* \param[in] black_angle286* \param[in] min_response287* \param[out] point The resulting point288*289* \return Returns false if no point could be found290*291*/292static bool findNextPoint(cv::flann::Index &index,const cv::Mat &data,293const cv::Point2f &pt1,const cv::Point2f &pt2, const cv::Point2f &pt3,294float white_angle,float black_angle,float min_response,cv::Point2f &point);295296/**297* \brief Creates a new Board object298*299*/300Board(float white_angle=0,float black_angle=0);301Board(const cv::Size &size, const std::vector<cv::Point2f> &points,float white_angle=0,float black_angle=0);302Board(const Chessboard::Board &other);303virtual ~Board();304305Board& operator=(const Chessboard::Board &other);306307/**308* \brief Draws the corners into the given image309*310* \param[in] m The image311* \param[out] m The resulting image312* \param[in] H optional homography to calculate search area313*314*/315void draw(cv::InputArray m,cv::OutputArray out,cv::InputArray H=cv::Mat())const;316317/**318* \brief Estimates the pose of the chessboard319*320*/321bool estimatePose(const cv::Size2f &real_size,cv::InputArray _K,cv::OutputArray rvec,cv::OutputArray tvec)const;322323/**324* \brief Clears all internal data of the object325*326*/327void clear();328329/**330* \brief Returns the angle of the black diagnonale331*332*/333float getBlackAngle()const;334335/**336* \brief Returns the angle of the black diagnonale337*338*/339float getWhiteAngle()const;340341/**342* \brief Initializes a 3x3 grid from 9 corner coordinates343*344* All points must be ordered:345* p0 p1 p2346* p3 p4 p5347* p6 p7 p8348*349* \param[in] points vector of points350*351* \return Returns false if the grid could not be initialized352*/353bool init(const std::vector<cv::Point2f> points);354355/**356* \brief Returns true if the board is empty357*358*/359bool isEmpty() const;360361/**362* \brief Returns all board corners as ordered vector363*364* The left top corner has index 0 and the bottom right365* corner rows*cols-1. All corners which only belong to366* empty cells are returned as NaN.367*/368std::vector<cv::Point2f> getCorners(bool ball=true) const;369370/**371* \brief Returns all board corners as ordered vector of KeyPoints372*373* The left top corner has index 0 and the bottom right374* corner rows*cols-1.375*376* \param[in] ball if set to false only non empty points are returned377*378*/379std::vector<cv::KeyPoint> getKeyPoints(bool ball=true) const;380381/**382* \brief Returns the centers of the chessboard cells383*384* The left top corner has index 0 and the bottom right385* corner (rows-1)*(cols-1)-1.386*387*/388std::vector<cv::Point2f> getCellCenters() const;389390/**391* \brief Estimates the homography between an ideal board392* and reality based on the already recovered points393*394* \param[in] rect selecting a subset of the already recovered points395* \param[in] field_size The field size of the ideal board396*397*/398cv::Mat estimateHomography(cv::Rect rect,int field_size = DUMMY_FIELD_SIZE)const;399400/**401* \brief Estimates the homography between an ideal board402* and reality based on the already recovered points403*404* \param[in] field_size The field size of the ideal board405*406*/407cv::Mat estimateHomography(int field_size = DUMMY_FIELD_SIZE)const;408409/**410* \brief Returns the size of the board411*412*/413cv::Size getSize() const;414415/**416* \brief Returns the number of cols417*418*/419size_t colCount() const;420421/**422* \brief Returns the number of rows423*424*/425size_t rowCount() const;426427/**428* \brief Returns the inner contour of the board inlcuding only valid corners429*430* \info the contour might be non squared if not all points of the board are defined431*432*/433std::vector<cv::Point2f> getContour()const;434435436/**437* \brief Grows the board in all direction until no more corners are found in the feature map438*439* \param[in] data CV_32FC1 data of the flann index440* \param[in] flann_index flann index441*442* \returns the number of grows443*/444int grow(const cv::Mat &data,cv::flann::Index &flann_index);445446/**447* \brief Validates all corners using guided search based on the given homography448*449* \param[in] data CV_32FC1 data of the flann index450* \param[in] flann_index flann index451* \param[in] h Homography describing the transformation from ideal board to the real one452* \param[in] min_response Min response453*454* \returns the number of valid corners455*/456int validateCorners(const cv::Mat &data,cv::flann::Index &flann_index,const cv::Mat &h,float min_response=0);457458/**459* \brief check that no corner is used more than once460*461* \returns Returns false if a corner is used more than once462*/463bool checkUnique()const;464465/**466* \brief Returns false if the angles of the contour are smaller than 35°467*468*/469bool validateContour()const;470471/**472* \brief Grows the board to the left by adding one column.473*474* \param[in] map CV_32FC1 feature map475*476* \returns Returns false if the feature map has no maxima at the requested positions477*/478bool growLeft(const cv::Mat &map,cv::flann::Index &flann_index);479void growLeft();480481/**482* \brief Grows the board to the top by adding one row.483*484* \param[in] map CV_32FC1 feature map485*486* \returns Returns false if the feature map has no maxima at the requested positions487*/488bool growTop(const cv::Mat &map,cv::flann::Index &flann_index);489void growTop();490491/**492* \brief Grows the board to the right by adding one column.493*494* \param[in] map CV_32FC1 feature map495*496* \returns Returns false if the feature map has no maxima at the requested positions497*/498bool growRight(const cv::Mat &map,cv::flann::Index &flann_index);499void growRight();500501/**502* \brief Grows the board to the bottom by adding one row.503*504* \param[in] map CV_32FC1 feature map505*506* \returns Returns false if the feature map has no maxima at the requested positions507*/508bool growBottom(const cv::Mat &map,cv::flann::Index &flann_index);509void growBottom();510511/**512* \brief Adds one column on the left side513*514* \param[in] points The corner coordinates515*516*/517void addColumnLeft(const std::vector<cv::Point2f> &points);518519/**520* \brief Adds one column at the top521*522* \param[in] points The corner coordinates523*524*/525void addRowTop(const std::vector<cv::Point2f> &points);526527/**528* \brief Adds one column on the right side529*530* \param[in] points The corner coordinates531*532*/533void addColumnRight(const std::vector<cv::Point2f> &points);534535/**536* \brief Adds one row at the bottom537*538* \param[in] points The corner coordinates539*540*/541void addRowBottom(const std::vector<cv::Point2f> &points);542543/**544* \brief Rotates the board 90° degrees to the left545*/546void rotateLeft();547548/**549* \brief Rotates the board 90° degrees to the right550*/551void rotateRight();552553/**554* \brief Flips the board along its local x(width) coordinate direction555*/556void flipVertical();557558/**559* \brief Flips the board along its local y(height) coordinate direction560*/561void flipHorizontal();562563/**564* \brief Flips and rotates the board so that the anlge of565* either the black or white diagonale is bigger than the x566* and y axis of the board and from a right handed567* coordinate system568*/569void normalizeOrientation(bool bblack=true);570571/**572* \brief Exchanges the stored board with the board stored in other573*/574void swap(Chessboard::Board &other);575576bool operator==(const Chessboard::Board& other) const {return rows*cols == other.rows*other.cols;};577bool operator< (const Chessboard::Board& other) const {return rows*cols < other.rows*other.cols;};578bool operator> (const Chessboard::Board& other) const {return rows*cols > other.rows*other.cols;};579bool operator>= (const cv::Size& size)const { return rows*cols >= size.width*size.height; };580581/**582* \brief Returns a specific corner583*584* \info raises runtime_error if row col does not exists585*/586cv::Point2f& getCorner(int row,int col);587588/**589* \brief Returns true if the cell is empty meaning at least one corner is NaN590*/591bool isCellEmpty(int row,int col);592593/**594* \brief Returns the mapping from all corners idx to only valid corners idx595*/596std::map<int,int> getMapping()const;597598/**599* \brief Estimates rotation of the board around the camera axis600*/601double estimateRotZ()const;602603/**604* \brief Returns true if the cell is black605*606*/607bool isCellBlack(int row,int cola)const;608609private:610// stores one cell611// in general a cell is initialized by the Board so that:612// * all corners are always pointing to a valid cv::Point2f613// * depending on the position left,top,right and bottom might be set to NaN614// * A cell is empty if at least one corner is NaN615struct Cell616{617cv::Point2f *top_left,*top_right,*bottom_right,*bottom_left; // corners618Cell *left,*top,*right,*bottom; // neighbouring cells619bool black; // set to true if cell is black620Cell();621bool empty()const; // indicates if the cell is empty (one of its corners has NaN)622int getRow()const;623int getCol()const;624};625626// corners627enum CornerIndex628{629TOP_LEFT,630TOP_RIGHT,631BOTTOM_RIGHT,632BOTTOM_LEFT633};634635Cell* getCell(int row,int column); // returns a specific cell636const Cell* getCell(int row,int column)const; // returns a specific cell637void drawEllipses(const std::vector<Ellipse> &ellipses);638639// Iterator for iterating over board corners640class PointIter641{642public:643PointIter(Cell *cell,CornerIndex corner_index);644PointIter(const PointIter &other);645void operator=(const PointIter &other);646bool valid() const; // returns if the pointer is pointing to a cell647648bool left(bool check_empty=false); // moves one corner to the left or returns false649bool right(bool check_empty=false); // moves one corner to the right or returns false650bool bottom(bool check_empty=false); // moves one corner to the bottom or returns false651bool top(bool check_empty=false); // moves one corner to the top or returns false652bool checkCorner()const; // returns ture if the current corner belongs to at least one653// none empty cell654bool isNaN()const; // returns true if the currnet corner is NaN655656const cv::Point2f* operator*() const; // current corner coordinate657cv::Point2f* operator*(); // current corner coordinate658const cv::Point2f* operator->() const; // current corner coordinate659cv::Point2f* operator->(); // current corner coordinate660661Cell *getCell(); // current cell662private:663CornerIndex corner_index;664Cell *cell;665};666667std::vector<Cell*> cells; // storage for all board cells668std::vector<cv::Point2f*> corners; // storage for all corners669Cell *top_left; // pointer to the top left corner of the board in its local coordinate system670int rows; // number of row cells671int cols; // number of col cells672float white_angle,black_angle;673};674public:675676/**677* \brief Creates a chessboard corner detectors678*679* \param[in] config Configuration used to detect chessboard corners680*681*/682Chessboard(const Parameters &config = Parameters());683virtual ~Chessboard();684void reconfigure(const Parameters &config = Parameters());685Parameters getPara()const;686687/*688* \brief Detects chessboard corners in the given image.689*690* The detectors tries to find all chessboard corners of an imaged691* chessboard and returns them as an ordered vector of KeyPoints.692* Thereby, the left top corner has index 0 and the bottom right693* corner n*m-1.694*695* \param[in] image The image696* \param[out] keypoints The detected corners as a vector of ordered KeyPoints697* \param[in] mask Currently not supported698*699*/700void detect(cv::InputArray image,std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask=cv::Mat())override701{cv::Feature2D::detect(image.getMat(),keypoints,mask.getMat());}702703virtual void detectAndCompute(cv::InputArray image,cv::InputArray mask, std::vector<cv::KeyPoint>& keypoints,cv::OutputArray descriptors,704bool useProvidedKeyPoints = false)override;705706/*707* \brief Detects chessboard corners in the given image.708*709* The detectors tries to find all chessboard corners of an imaged710* chessboard and returns them as an ordered vector of KeyPoints.711* Thereby, the left top corner has index 0 and the bottom right712* corner n*m-1.713*714* \param[in] image The image715* \param[out] keypoints The detected corners as a vector of ordered KeyPoints716* \param[out] feature_maps The feature map generated by LRJT and used to find the corners717* \param[in] mask Currently not supported718*719*/720void detectImpl(const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints,std::vector<cv::Mat> &feature_maps,const cv::Mat& mask)const;721Chessboard::Board detectImpl(const cv::Mat& image,std::vector<cv::Mat> &feature_maps,const cv::Mat& mask)const;722723// define pure virtual methods724virtual int descriptorSize()const override{return 0;};725virtual int descriptorType()const override{return 0;};726virtual void operator()( cv::InputArray image, cv::InputArray mask, std::vector<cv::KeyPoint>& keypoints, cv::OutputArray descriptors, bool useProvidedKeypoints=false )const727{728descriptors.clear();729detectImpl(image.getMat(),keypoints,mask);730if(!useProvidedKeypoints) // suppress compiler warning731return;732return;733}734735protected:736virtual void computeImpl( const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints, cv::Mat& descriptors)const737{738descriptors = cv::Mat();739detectImpl(image,keypoints);740}741742// indicates why a board could not be initialized for a certain keypoint743enum BState744{745MISSING_POINTS = 0, // at least 5 points are needed746MISSING_PAIRS = 1, // at least two pairs are needed747WRONG_PAIR_ANGLE = 2, // angle between pairs is too small748WRONG_CONFIGURATION = 3, // point configuration is wrong and does not belong to a board749FOUND_BOARD = 4 // board was found750};751752void findKeyPoints(const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints,std::vector<cv::Mat> &feature_maps,753std::vector<std::vector<float> > &angles ,const cv::Mat& mask)const;754cv::Mat buildData(const std::vector<cv::KeyPoint>& keypoints)const;755std::vector<cv::KeyPoint> getInitialPoints(cv::flann::Index &flann_index,const cv::Mat &data,const cv::KeyPoint ¢er,float white_angle,float black_angle, float min_response = 0)const;756BState generateBoards(cv::flann::Index &flann_index,const cv::Mat &data, const cv::KeyPoint ¢er,757float white_angle,float black_angle,float min_response,const cv::Mat &img,758std::vector<Chessboard::Board> &boards)const;759760private:761void detectImpl(const cv::Mat&,std::vector<cv::KeyPoint>&, const cv::Mat& mast =cv::Mat())const;762virtual void detectImpl(cv::InputArray image, std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask=cv::noArray())const;763764private:765Parameters parameters; // storing the configuration of the detector766};767}} // end namespace details and cv768769#endif770771772