1 | // This file is part of OpenCV project. |
2 | // It is subject to the license terms in the LICENSE file found in the top-level directory |
3 | // of this distribution and at http://opencv.org/license.html. |
4 | |
5 | #ifndef CHESSBOARD_HPP_ |
6 | #define CHESSBOARD_HPP_ |
7 | |
8 | #include "opencv2/core.hpp" |
9 | #include "opencv2/features2d.hpp" |
10 | #include <vector> |
11 | #include <set> |
12 | #include <map> |
13 | |
14 | namespace cv { |
15 | namespace details{ |
16 | /** |
17 | * \brief Fast point sysmetric cross detector based on a localized radon transformation |
18 | */ |
19 | class FastX : public cv::Feature2D |
20 | { |
21 | public: |
22 | struct Parameters |
23 | { |
24 | float strength; //!< minimal strength of a valid junction in dB |
25 | float resolution; //!< angle resolution in radians |
26 | int branches; //!< the number of branches |
27 | int min_scale; //!< scale level [0..8] |
28 | int max_scale; //!< scale level [0..8] |
29 | bool filter; //!< post filter feature map to improve impulse response |
30 | bool super_resolution; //!< up-sample |
31 | |
32 | Parameters() |
33 | { |
34 | strength = 40; |
35 | resolution = float(CV_PI*0.25); |
36 | branches = 2; |
37 | min_scale = 2; |
38 | max_scale = 5; |
39 | super_resolution = true; |
40 | filter = true; |
41 | } |
42 | }; |
43 | |
44 | public: |
45 | FastX(const Parameters &config = Parameters()); |
46 | virtual ~FastX(){} |
47 | |
48 | void reconfigure(const Parameters ¶); |
49 | |
50 | //declaration to be wrapped by rbind |
51 | void detect(cv::InputArray image,std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask=cv::Mat())override |
52 | {cv::Feature2D::detect(image: image.getMat(),keypoints,mask: mask.getMat());} |
53 | |
54 | virtual void detectAndCompute(cv::InputArray image, |
55 | cv::InputArray mask, |
56 | std::vector<cv::KeyPoint>& keypoints, |
57 | cv::OutputArray descriptors, |
58 | bool useProvidedKeyPoints = false)override; |
59 | |
60 | void detectImpl(const cv::Mat& image, |
61 | std::vector<cv::KeyPoint>& keypoints, |
62 | std::vector<cv::Mat> &feature_maps, |
63 | const cv::Mat& mask=cv::Mat())const; |
64 | |
65 | void detectImpl(const cv::Mat& image, |
66 | std::vector<cv::Mat> &rotated_images, |
67 | std::vector<cv::Mat> &feature_maps, |
68 | const cv::Mat& mask=cv::Mat())const; |
69 | |
70 | void findKeyPoints(const std::vector<cv::Mat> &feature_map, |
71 | std::vector<cv::KeyPoint>& keypoints, |
72 | const cv::Mat& mask = cv::Mat())const; |
73 | |
74 | std::vector<std::vector<float> > calcAngles(const std::vector<cv::Mat> &rotated_images, |
75 | std::vector<cv::KeyPoint> &keypoints)const; |
76 | // define pure virtual methods |
77 | virtual int descriptorSize()const override{return 0;} |
78 | virtual int descriptorType()const override{return 0;} |
79 | virtual void operator()( cv::InputArray image, cv::InputArray mask, std::vector<cv::KeyPoint>& keypoints, cv::OutputArray descriptors, bool useProvidedKeypoints=false )const |
80 | { |
81 | descriptors.clear(); |
82 | detectImpl(image: image.getMat(),keypoints,mask); |
83 | if(!useProvidedKeypoints) // suppress compiler warning |
84 | return; |
85 | return; |
86 | } |
87 | |
88 | protected: |
89 | virtual void computeImpl( const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints, cv::Mat& descriptors)const |
90 | { |
91 | descriptors = cv::Mat(); |
92 | detectImpl(image,keypoints); |
93 | } |
94 | |
95 | private: |
96 | void detectImpl(const cv::Mat& _src, std::vector<cv::KeyPoint>& keypoints, const cv::Mat& mask)const; |
97 | virtual void detectImpl(cv::InputArray image, std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask=cv::noArray())const; |
98 | |
99 | void rotate(float angle,cv::InputArray img,cv::Size size,cv::OutputArray out)const; |
100 | void calcFeatureMap(const cv::Mat &images,cv::Mat& out)const; |
101 | |
102 | private: |
103 | Parameters parameters; |
104 | }; |
105 | |
106 | /** |
107 | * \brief Ellipse class |
108 | */ |
109 | class Ellipse |
110 | { |
111 | public: |
112 | Ellipse(); |
113 | Ellipse(const cv::Point2f ¢er, const cv::Size2f &axes, float angle); |
114 | |
115 | void draw(cv::InputOutputArray img,const cv::Scalar &color = cv::Scalar::all(v0: v0: 120))const; |
116 | bool contains(const cv::Point2f &pt)const; |
117 | cv::Point2f getCenter()const; |
118 | const cv::Size2f &getAxes()const; |
119 | |
120 | private: |
121 | cv::Point2f center; |
122 | cv::Size2f axes; |
123 | float angle,cosf,sinf; |
124 | }; |
125 | |
126 | /** |
127 | * \brief Chessboard corner detector |
128 | * |
129 | * The detectors tries to find all chessboard corners of an imaged |
130 | * chessboard and returns them as an ordered vector of KeyPoints. |
131 | * Thereby, the left top corner has index 0 and the bottom right |
132 | * corner n*m-1. |
133 | */ |
134 | class Chessboard: public cv::Feature2D |
135 | { |
136 | public: |
137 | static const int DUMMY_FIELD_SIZE = 100; // in pixel |
138 | |
139 | /** |
140 | * \brief Configuration of a chessboard corner detector |
141 | * |
142 | */ |
143 | struct Parameters |
144 | { |
145 | cv::Size chessboard_size; //!< size of the chessboard |
146 | int min_scale; //!< scale level [0..8] |
147 | int max_scale; //!< scale level [0..8] |
148 | int max_points; //!< maximal number of points regarded |
149 | int max_tests; //!< maximal number of tested hypothesis |
150 | bool super_resolution; //!< use super-repsolution for chessboard detection |
151 | bool larger; //!< indicates if larger boards should be returned |
152 | bool marker; //!< indicates that valid boards must have a white and black cirlce marker used for orientation |
153 | |
154 | Parameters() |
155 | { |
156 | chessboard_size = cv::Size(9,6); |
157 | min_scale = 3; |
158 | max_scale = 4; |
159 | super_resolution = true; |
160 | max_points = 200; |
161 | max_tests = 50; |
162 | larger = false; |
163 | marker = false; |
164 | } |
165 | |
166 | Parameters(int scale,int _max_points): |
167 | min_scale(scale), |
168 | max_scale(scale), |
169 | max_points(_max_points) |
170 | { |
171 | chessboard_size = cv::Size(9,6); |
172 | } |
173 | }; |
174 | |
175 | |
176 | /** |
177 | * \brief Gets the 3D objects points for the chessboard assuming the |
178 | * left top corner is located at the origin. |
179 | * |
180 | * \param[in] pattern_size Number of rows and cols of the pattern |
181 | * \param[in] cell_size Size of one cell |
182 | * |
183 | * \returns Returns the object points as CV_32FC3 |
184 | */ |
185 | static cv::Mat getObjectPoints(const cv::Size &pattern_size,float cell_size); |
186 | |
187 | /** |
188 | * \brief Class for searching and storing chessboard corners. |
189 | * |
190 | * The search is based on a feature map having strong pixel |
191 | * values at positions where a chessboard corner is located. |
192 | * |
193 | * The board must be rectangular but supports empty cells |
194 | * |
195 | */ |
196 | class Board |
197 | { |
198 | public: |
199 | /** |
200 | * \brief Estimates the position of the next point on a line using cross ratio constrain |
201 | * |
202 | * cross ratio: |
203 | * d12/d34 = d13/d24 |
204 | * |
205 | * point order on the line: |
206 | * p0 --> p1 --> p2 --> p3 |
207 | * |
208 | * \param[in] p0 First point coordinate |
209 | * \param[in] p1 Second point coordinate |
210 | * \param[in] p2 Third point coordinate |
211 | * \param[out] p3 Forth point coordinate |
212 | * |
213 | */ |
214 | static bool estimatePoint(const cv::Point2f &p0,const cv::Point2f &p1,const cv::Point2f &p2,cv::Point2f &p3); |
215 | |
216 | // using 1D homography |
217 | static bool estimatePoint(const cv::Point2f &p0,const cv::Point2f &p1,const cv::Point2f &p2,const cv::Point2f &p3, cv::Point2f &p4); |
218 | |
219 | /** |
220 | * \brief Checks if all points of a row or column have a valid cross ratio constraint |
221 | * |
222 | * cross ratio: |
223 | * d12/d34 = d13/d24 |
224 | * |
225 | * point order on the row/column: |
226 | * pt1 --> pt2 --> pt3 --> pt4 |
227 | * |
228 | * \param[in] points THe points of the row/column |
229 | * |
230 | */ |
231 | static bool checkRowColumn(const std::vector<cv::Point2f> &points); |
232 | |
233 | /** |
234 | * \brief Estimates the search area for the next point on the line using cross ratio |
235 | * |
236 | * point order on the line: |
237 | * (p0) --> p1 --> p2 --> p3 --> search area |
238 | * |
239 | * \param[in] p1 First point coordinate |
240 | * \param[in] p2 Second point coordinate |
241 | * \param[in] p3 Third point coordinate |
242 | * \param[in] p Percentage of d34 used for the search area width and height [0..1] |
243 | * \param[out] ellipse The search area |
244 | * \param[in] p0 optional point to improve accuracy |
245 | * |
246 | * \return Returns false if no search area can be calculated |
247 | * |
248 | */ |
249 | static bool estimateSearchArea(const cv::Point2f &p1,const cv::Point2f &p2,const cv::Point2f &p3,float p, |
250 | Ellipse &ellipse,const cv::Point2f *p0 =NULL); |
251 | |
252 | /** |
253 | * \brief Estimates the search area for a specific point based on the given homography |
254 | * |
255 | * \param[in] H homography describing the transformation from ideal board to real one |
256 | * \param[in] row Row of the point |
257 | * \param[in] col Col of the point |
258 | * \param[in] p Percentage [0..1] |
259 | * |
260 | * \return Returns false if no search area can be calculated |
261 | * |
262 | */ |
263 | static Ellipse estimateSearchArea(cv::Mat H,int row, int col,float p,int field_size = DUMMY_FIELD_SIZE); |
264 | |
265 | /** |
266 | * \brief Searches for the maximum in a given search area |
267 | * |
268 | * \param[in] map feature map |
269 | * \param[in] ellipse search area |
270 | * \param[in] min_val Minimum value of the maximum to be accepted as maximum |
271 | * |
272 | * \return Returns a negative value if all points are outside the ellipse |
273 | * |
274 | */ |
275 | static float findMaxPoint(cv::flann::Index &index,const cv::Mat &data,const Ellipse &ellipse,float white_angle,float black_angle,cv::Point2f &pt); |
276 | |
277 | /** |
278 | * \brief Searches for the next point using cross ratio constrain |
279 | * |
280 | * \param[in] index flann index |
281 | * \param[in] data extended flann data |
282 | * \param[in] pt1 |
283 | * \param[in] pt2 |
284 | * \param[in] pt3 |
285 | * \param[in] white_angle |
286 | * \param[in] black_angle |
287 | * \param[in] min_response |
288 | * \param[out] point The resulting point |
289 | * |
290 | * \return Returns false if no point could be found |
291 | * |
292 | */ |
293 | static bool findNextPoint(cv::flann::Index &index,const cv::Mat &data, |
294 | const cv::Point2f &pt1,const cv::Point2f &pt2, const cv::Point2f &pt3, |
295 | float white_angle,float black_angle,float min_response,cv::Point2f &point); |
296 | |
297 | /** |
298 | * \brief Creates a new Board object |
299 | * |
300 | */ |
301 | Board(float white_angle=0,float black_angle=0); |
302 | Board(const cv::Size &size, const std::vector<cv::Point2f> &points,float white_angle=0,float black_angle=0); |
303 | Board(const Chessboard::Board &other); |
304 | virtual ~Board(); |
305 | |
306 | Board& operator=(const Chessboard::Board &other); |
307 | |
308 | /** |
309 | * \brief Draws the corners into the given image |
310 | * |
311 | * \param[in] m The image |
312 | * \param[out] out The resulting image |
313 | * \param[in] H optional homography to calculate search area |
314 | * |
315 | */ |
316 | void draw(cv::InputArray m,cv::OutputArray out,cv::InputArray H=cv::Mat())const; |
317 | |
318 | /** |
319 | * \brief Estimates the pose of the chessboard |
320 | * |
321 | */ |
322 | bool estimatePose(const cv::Size2f &real_size,cv::InputArray _K,cv::OutputArray rvec,cv::OutputArray tvec)const; |
323 | |
324 | /** |
325 | * \brief Clears all internal data of the object |
326 | * |
327 | */ |
328 | void clear(); |
329 | |
330 | /** |
331 | * \brief Returns the angle of the black diagnonale |
332 | * |
333 | */ |
334 | float getBlackAngle()const; |
335 | |
336 | /** |
337 | * \brief Returns the angle of the black diagnonale |
338 | * |
339 | */ |
340 | float getWhiteAngle()const; |
341 | |
342 | /** |
343 | * \brief Initializes a 3x3 grid from 9 corner coordinates |
344 | * |
345 | * All points must be ordered: |
346 | * p0 p1 p2 |
347 | * p3 p4 p5 |
348 | * p6 p7 p8 |
349 | * |
350 | * \param[in] points vector of points |
351 | * |
352 | * \return Returns false if the grid could not be initialized |
353 | */ |
354 | bool init(const std::vector<cv::Point2f> points); |
355 | |
356 | /** |
357 | * \brief Returns true if the board is empty |
358 | * |
359 | */ |
360 | bool isEmpty() const; |
361 | |
362 | /** |
363 | * \brief Returns all board corners as ordered vector |
364 | * |
365 | * The left top corner has index 0 and the bottom right |
366 | * corner rows*cols-1. All corners which only belong to |
367 | * empty cells are returned as NaN. |
368 | */ |
369 | std::vector<cv::Point2f> getCorners(bool ball=true) const; |
370 | |
371 | /** |
372 | * \brief Returns all board corners as ordered vector of KeyPoints |
373 | * |
374 | * The left top corner has index 0 and the bottom right |
375 | * corner rows*cols-1. |
376 | * |
377 | * \param[in] ball if set to false only non empty points are returned |
378 | * |
379 | */ |
380 | std::vector<cv::KeyPoint> getKeyPoints(bool ball=true) const; |
381 | |
382 | /** |
383 | * \brief Returns the centers of the chessboard cells |
384 | * |
385 | * The left top corner has index 0 and the bottom right |
386 | * corner (rows-1)*(cols-1)-1. |
387 | * |
388 | */ |
389 | std::vector<cv::Point2f> getCellCenters() const; |
390 | |
391 | /** |
392 | * \brief Returns all cells as mats of four points each describing their corners. |
393 | * |
394 | * The left top cell has index 0 |
395 | * |
396 | */ |
397 | std::vector<cv::Mat> getCells(float shrink_factor = 1.0,bool bwhite=true,bool bblack = true) const; |
398 | |
399 | /** |
400 | * \brief Estimates the homography between an ideal board |
401 | * and reality based on the already recovered points |
402 | * |
403 | * \param[in] rect selecting a subset of the already recovered points |
404 | * \param[in] field_size The field size of the ideal board |
405 | * |
406 | */ |
407 | cv::Mat estimateHomography(cv::Rect rect,int field_size = DUMMY_FIELD_SIZE)const; |
408 | |
409 | /** |
410 | * \brief Estimates the homography between an ideal board |
411 | * and reality based on the already recovered points |
412 | * |
413 | * \param[in] field_size The field size of the ideal board |
414 | * |
415 | */ |
416 | cv::Mat estimateHomography(int field_size = DUMMY_FIELD_SIZE)const; |
417 | |
418 | /** |
419 | * \brief Warp image to match ideal checkerboard |
420 | * |
421 | */ |
422 | cv::Mat warpImage(cv::InputArray image)const; |
423 | |
424 | /** |
425 | * \brief Returns the size of the board |
426 | * |
427 | */ |
428 | cv::Size getSize() const; |
429 | |
430 | /** |
431 | * \brief Returns the number of cols |
432 | * |
433 | */ |
434 | size_t colCount() const; |
435 | |
436 | /** |
437 | * \brief Returns the number of rows |
438 | * |
439 | */ |
440 | size_t rowCount() const; |
441 | |
442 | /** |
443 | * \brief Returns the inner contour of the board including only valid corners |
444 | * |
445 | * \info the contour might be non squared if not all points of the board are defined |
446 | * |
447 | */ |
448 | std::vector<cv::Point2f> getContour()const; |
449 | |
450 | /** |
451 | * \brief Masks the found board in the given image |
452 | * |
453 | */ |
454 | void maskImage(cv::InputOutputArray img,const cv::Scalar &color=cv::Scalar::all(v0: v0: 0))const; |
455 | |
456 | /** |
457 | * \brief Grows the board in all direction until no more corners are found in the feature map |
458 | * |
459 | * \param[in] data CV_32FC1 data of the flann index |
460 | * \param[in] flann_index flann index |
461 | * |
462 | * \returns the number of grows |
463 | */ |
464 | int grow(const cv::Mat &data,cv::flann::Index &flann_index); |
465 | |
466 | /** |
467 | * \brief Validates all corners using guided search based on the given homography |
468 | * |
469 | * \param[in] data CV_32FC1 data of the flann index |
470 | * \param[in] flann_index flann index |
471 | * \param[in] h Homography describing the transformation from ideal board to the real one |
472 | * \param[in] min_response Min response |
473 | * |
474 | * \returns the number of valid corners |
475 | */ |
476 | int validateCorners(const cv::Mat &data,cv::flann::Index &flann_index,const cv::Mat &h,float min_response=0); |
477 | |
478 | /** |
479 | * \brief check that no corner is used more than once |
480 | * |
481 | * \returns Returns false if a corner is used more than once |
482 | */ |
483 | bool checkUnique()const; |
484 | |
485 | /** |
486 | * \brief Returns false if the angles of the contour are smaller than 35° |
487 | * |
488 | */ |
489 | bool validateContour()const; |
490 | |
491 | |
492 | /** |
493 | \brief delete left column of the board |
494 | */ |
495 | bool shrinkLeft(); |
496 | |
497 | /** |
498 | \brief delete right column of the board |
499 | */ |
500 | bool shrinkRight(); |
501 | |
502 | /** |
503 | \brief shrink first row of the board |
504 | */ |
505 | bool shrinkTop(); |
506 | |
507 | /** |
508 | \brief delete last row of the board |
509 | */ |
510 | bool shrinkBottom(); |
511 | |
512 | /** |
513 | * \brief Grows the board to the left by adding one column. |
514 | * |
515 | * \param[in] map CV_32FC1 feature map |
516 | * |
517 | * \returns Returns false if the feature map has no maxima at the requested positions |
518 | */ |
519 | bool growLeft(const cv::Mat &map,cv::flann::Index &flann_index); |
520 | void growLeft(); |
521 | |
522 | /** |
523 | * \brief Grows the board to the top by adding one row. |
524 | * |
525 | * \param[in] map CV_32FC1 feature map |
526 | * |
527 | * \returns Returns false if the feature map has no maxima at the requested positions |
528 | */ |
529 | bool growTop(const cv::Mat &map,cv::flann::Index &flann_index); |
530 | void growTop(); |
531 | |
532 | /** |
533 | * \brief Grows the board to the right by adding one column. |
534 | * |
535 | * \param[in] map CV_32FC1 feature map |
536 | * |
537 | * \returns Returns false if the feature map has no maxima at the requested positions |
538 | */ |
539 | bool growRight(const cv::Mat &map,cv::flann::Index &flann_index); |
540 | void growRight(); |
541 | |
542 | /** |
543 | * \brief Grows the board to the bottom by adding one row. |
544 | * |
545 | * \param[in] map CV_32FC1 feature map |
546 | * |
547 | * \returns Returns false if the feature map has no maxima at the requested positions |
548 | */ |
549 | bool growBottom(const cv::Mat &map,cv::flann::Index &flann_index); |
550 | void growBottom(); |
551 | |
552 | /** |
553 | * \brief Adds one column on the left side |
554 | * |
555 | * \param[in] points The corner coordinates |
556 | * |
557 | */ |
558 | void addColumnLeft(const std::vector<cv::Point2f> &points); |
559 | |
560 | /** |
561 | * \brief Adds one column at the top |
562 | * |
563 | * \param[in] points The corner coordinates |
564 | * |
565 | */ |
566 | void addRowTop(const std::vector<cv::Point2f> &points); |
567 | |
568 | /** |
569 | * \brief Adds one column on the right side |
570 | * |
571 | * \param[in] points The corner coordinates |
572 | * |
573 | */ |
574 | void addColumnRight(const std::vector<cv::Point2f> &points); |
575 | |
576 | /** |
577 | * \brief Adds one row at the bottom |
578 | * |
579 | * \param[in] points The corner coordinates |
580 | * |
581 | */ |
582 | void addRowBottom(const std::vector<cv::Point2f> &points); |
583 | |
584 | /** |
585 | * \brief Rotates the board 90° degrees to the left |
586 | */ |
587 | void rotateLeft(); |
588 | |
589 | /** |
590 | * \brief Rotates the board 90° degrees to the right |
591 | */ |
592 | void rotateRight(); |
593 | |
594 | /** |
595 | * \brief Flips the board along its local x(width) coordinate direction |
596 | */ |
597 | void flipVertical(); |
598 | |
599 | /** |
600 | * \brief Flips the board along its local y(height) coordinate direction |
601 | */ |
602 | void flipHorizontal(); |
603 | |
604 | /** |
605 | * \brief Flips and rotates the board so that the angle of |
606 | * either the black or white diagonal is bigger than the x |
607 | * and y axis of the board and from a right handed |
608 | * coordinate system |
609 | */ |
610 | void normalizeOrientation(bool bblack=true); |
611 | |
612 | /** |
613 | * \brief Flips and rotates the board so that the marker |
614 | * is normalized |
615 | */ |
616 | bool normalizeMarkerOrientation(); |
617 | |
618 | /** |
619 | * \brief Exchanges the stored board with the board stored in other |
620 | */ |
621 | void swap(Chessboard::Board &other); |
622 | |
623 | bool operator==(const Chessboard::Board& other) const {return rows*cols == other.rows*other.cols;} |
624 | bool operator< (const Chessboard::Board& other) const {return rows*cols < other.rows*other.cols;} |
625 | bool operator> (const Chessboard::Board& other) const {return rows*cols > other.rows*other.cols;} |
626 | bool operator>= (const cv::Size& size)const { return rows*cols >= size.width*size.height; } |
627 | |
628 | /** |
629 | * \brief Returns a specific corner |
630 | * |
631 | * \info raises runtime_error if row col does not exists |
632 | */ |
633 | cv::Point2f& getCorner(int row,int col); |
634 | |
635 | /** |
636 | * \brief Returns true if the cell is empty meaning at least one corner is NaN |
637 | */ |
638 | bool isCellEmpty(int row,int col); |
639 | |
640 | /** |
641 | * \brief Returns the mapping from all corners idx to only valid corners idx |
642 | */ |
643 | std::map<int,int> getMapping()const; |
644 | |
645 | /** |
646 | * \brief Returns true if the cell is black |
647 | * |
648 | */ |
649 | bool isCellBlack(int row,int col)const; |
650 | |
651 | /** |
652 | * \brief Returns true if the cell has a round marker at its |
653 | * center |
654 | * |
655 | */ |
656 | bool hasCellMarker(int row,int col); |
657 | |
658 | /** |
659 | * \brief Detects round markers in the chessboard fields based |
660 | * on the given image and the already recoverd board corners |
661 | * |
662 | * \returns Returns the number of found markes |
663 | * |
664 | */ |
665 | int detectMarkers(cv::InputArray image); |
666 | |
667 | /** |
668 | * \brief Calculates the average edge sharpness for the chessboard |
669 | * |
670 | * \param[in] image The image where the chessboard was detected |
671 | * \param[in] rise_distance Rise distance 0.8 means 10% ... 90% |
672 | * \param[in] vertical by default only edge response for horiontal lines are calculated |
673 | * |
674 | * \returns Scalar(sharpness, average min_val, average max_val) |
675 | * |
676 | * \author aduda@krakenrobotik.de |
677 | */ |
678 | cv::Scalar calcEdgeSharpness(cv::InputArray image,float rise_distance=0.8,bool vertical=false,cv::OutputArray sharpness=cv::noArray()); |
679 | |
680 | |
681 | /** |
682 | * \brief Gets the 3D objects points for the chessboard |
683 | * assuming the left top corner is located at the origin. In |
684 | * case the board as a marker, the white marker cell is at position zero |
685 | * |
686 | * \param[in] cell_size Size of one cell |
687 | * |
688 | * \returns Returns the object points as CV_32FC3 |
689 | */ |
690 | cv::Mat getObjectPoints(float cell_size)const; |
691 | |
692 | |
693 | /** |
694 | * \brief Returns the angle the board is rotated agains the x-axis of the image plane |
695 | * \returns Returns the object points as CV_32FC3 |
696 | */ |
697 | float getAngle()const; |
698 | |
699 | /** |
700 | * \brief Returns true if the main direction of the board is close to the image x-axis than y-axis |
701 | */ |
702 | bool isHorizontal()const; |
703 | |
704 | /** |
705 | * \brief Updates the search angles |
706 | */ |
707 | void setAngles(float white,float black); |
708 | |
709 | private: |
710 | // stores one cell |
711 | // in general a cell is initialized by the Board so that: |
712 | // * all corners are always pointing to a valid cv::Point2f |
713 | // * depending on the position left,top,right and bottom might be set to NaN |
714 | // * A cell is empty if at least one corner is NaN |
715 | struct Cell |
716 | { |
717 | cv::Point2f *top_left,*top_right,*bottom_right,*bottom_left; // corners |
718 | Cell *left,*top,*right,*bottom; // neighbouring cells |
719 | bool black; // set to true if cell is black |
720 | bool marker; // set to true if cell has a round marker in its center |
721 | Cell(); |
722 | bool empty()const; // indicates if the cell is empty (one of its corners has NaN) |
723 | int getRow()const; |
724 | int getCol()const; |
725 | cv::Point2f getCenter()const; |
726 | bool isInside(const cv::Point2f &pt)const; // check if point is inside the cell |
727 | }; |
728 | |
729 | // corners |
730 | enum CornerIndex |
731 | { |
732 | TOP_LEFT, |
733 | TOP_RIGHT, |
734 | BOTTOM_RIGHT, |
735 | BOTTOM_LEFT |
736 | }; |
737 | |
738 | Cell* getCell(int row,int column); // returns a specific cell |
739 | const Cell* getCell(int row,int column)const; // returns a specific cell |
740 | void drawEllipses(const std::vector<Ellipse> &ellipses); |
741 | |
742 | // Iterator for iterating over board corners |
743 | class PointIter |
744 | { |
745 | public: |
746 | PointIter(Cell *cell,CornerIndex corner_index); |
747 | PointIter(const PointIter &other); |
748 | void operator=(const PointIter &other); |
749 | bool valid() const; // returns if the pointer is pointing to a cell |
750 | |
751 | bool left(bool check_empty=false); // moves one corner to the left or returns false |
752 | bool right(bool check_empty=false); // moves one corner to the right or returns false |
753 | bool bottom(bool check_empty=false); // moves one corner to the bottom or returns false |
754 | bool top(bool check_empty=false); // moves one corner to the top or returns false |
755 | bool checkCorner()const; // returns true if the current corner belongs to at least one |
756 | // none empty cell |
757 | bool isNaN()const; // returns true if the current corner is NaN |
758 | |
759 | const cv::Point2f* operator*() const; // current corner coordinate |
760 | cv::Point2f* operator*(); // current corner coordinate |
761 | const cv::Point2f* operator->() const; // current corner coordinate |
762 | cv::Point2f* operator->(); // current corner coordinate |
763 | |
764 | Cell *getCell(); // current cell |
765 | private: |
766 | CornerIndex corner_index; |
767 | Cell *cell; |
768 | }; |
769 | |
770 | std::vector<Cell*> cells; // storage for all board cells |
771 | std::vector<cv::Point2f*> corners; // storage for all corners |
772 | Cell *top_left; // pointer to the top left corner of the board in its local coordinate system |
773 | int rows; // number of inner pattern rows |
774 | int cols; // number of inner pattern cols |
775 | float white_angle,black_angle; |
776 | }; |
777 | public: |
778 | |
779 | /** |
780 | * \brief Creates a chessboard corner detectors |
781 | * |
782 | * \param[in] config Configuration used to detect chessboard corners |
783 | * |
784 | */ |
785 | Chessboard(const Parameters &config = Parameters()); |
786 | virtual ~Chessboard(); |
787 | void reconfigure(const Parameters &config = Parameters()); |
788 | Parameters getPara()const; |
789 | |
790 | /* |
791 | * \brief Detects chessboard corners in the given image. |
792 | * |
793 | * The detectors tries to find all chessboard corners of an imaged |
794 | * chessboard and returns them as an ordered vector of KeyPoints. |
795 | * Thereby, the left top corner has index 0 and the bottom right |
796 | * corner n*m-1. |
797 | * |
798 | * \param[in] image The image |
799 | * \param[out] keypoints The detected corners as a vector of ordered KeyPoints |
800 | * \param[in] mask Currently not supported |
801 | * |
802 | */ |
803 | void detect(cv::InputArray image,std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask=cv::Mat())override |
804 | {cv::Feature2D::detect(image: image.getMat(),keypoints,mask: mask.getMat());} |
805 | |
806 | virtual void detectAndCompute(cv::InputArray image,cv::InputArray mask, std::vector<cv::KeyPoint>& keypoints,cv::OutputArray descriptors, |
807 | bool useProvidedKeyPoints = false)override; |
808 | |
809 | /* |
810 | * \brief Detects chessboard corners in the given image. |
811 | * |
812 | * The detectors tries to find all chessboard corners of an imaged |
813 | * chessboard and returns them as an ordered vector of KeyPoints. |
814 | * Thereby, the left top corner has index 0 and the bottom right |
815 | * corner n*m-1. |
816 | * |
817 | * \param[in] image The image |
818 | * \param[out] keypoints The detected corners as a vector of ordered KeyPoints |
819 | * \param[out] feature_maps The feature map generated by LRJT and used to find the corners |
820 | * \param[in] mask Currently not supported |
821 | * |
822 | */ |
823 | void detectImpl(const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints,std::vector<cv::Mat> &feature_maps,const cv::Mat& mask)const; |
824 | Chessboard::Board detectImpl(const cv::Mat& image,std::vector<cv::Mat> &feature_maps,const cv::Mat& mask)const; |
825 | |
826 | // define pure virtual methods |
827 | virtual int descriptorSize()const override{return 0;} |
828 | virtual int descriptorType()const override{return 0;} |
829 | virtual void operator()( cv::InputArray image, cv::InputArray mask, std::vector<cv::KeyPoint>& keypoints, cv::OutputArray descriptors, bool useProvidedKeypoints=false )const |
830 | { |
831 | descriptors.clear(); |
832 | detectImpl(image: image.getMat(),keypoints,mask); |
833 | if(!useProvidedKeypoints) // suppress compiler warning |
834 | return; |
835 | return; |
836 | } |
837 | |
838 | protected: |
839 | virtual void computeImpl( const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints, cv::Mat& descriptors)const |
840 | { |
841 | descriptors = cv::Mat(); |
842 | detectImpl(image,keypoints); |
843 | } |
844 | |
845 | // indicates why a board could not be initialized for a certain keypoint |
846 | enum BState |
847 | { |
848 | MISSING_POINTS = 0, // at least 5 points are needed |
849 | MISSING_PAIRS = 1, // at least two pairs are needed |
850 | WRONG_PAIR_ANGLE = 2, // angle between pairs is too small |
851 | WRONG_CONFIGURATION = 3, // point configuration is wrong and does not belong to a board |
852 | FOUND_BOARD = 4 // board was found |
853 | }; |
854 | |
855 | void findKeyPoints(const cv::Mat& image, std::vector<cv::KeyPoint>& keypoints,std::vector<cv::Mat> &feature_maps, |
856 | std::vector<std::vector<float> > &angles ,const cv::Mat& mask)const; |
857 | cv::Mat buildData(const std::vector<cv::KeyPoint>& keypoints)const; |
858 | std::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; |
859 | BState generateBoards(cv::flann::Index &flann_index,const cv::Mat &data, const cv::KeyPoint ¢er, |
860 | float white_angle,float black_angle,float min_response,const cv::Mat &img, |
861 | std::vector<Chessboard::Board> &boards)const; |
862 | |
863 | private: |
864 | void detectImpl(const cv::Mat&,std::vector<cv::KeyPoint>&, const cv::Mat& mast =cv::Mat())const; |
865 | virtual void detectImpl(cv::InputArray image, std::vector<cv::KeyPoint>& keypoints, cv::InputArray mask=cv::noArray())const; |
866 | |
867 | private: |
868 | Parameters parameters; // storing the configuration of the detector |
869 | }; |
870 | }} // end namespace details and cv |
871 | |
872 | #endif |
873 | |