t/calibration: Add support for findChessboardCornersSB

This commit is contained in:
Jakob Bornecrantz 2021-06-23 17:27:08 +01:00 committed by Moses Turner
parent d86adce39d
commit de283a8b0c
3 changed files with 107 additions and 1 deletions

View file

@ -14,6 +14,7 @@
#include "util/u_debug.h" #include "util/u_debug.h"
#include "util/u_frame.h" #include "util/u_frame.h"
#include "util/u_format.h" #include "util/u_format.h"
#include "util/u_logging.h"
#include "tracking/t_tracking.h" #include "tracking/t_tracking.h"
#include "tracking/t_calibration_opencv.hpp" #include "tracking/t_calibration_opencv.hpp"
@ -22,6 +23,13 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <utility> #include <utility>
#if CV_MAJOR_VERSION >= 4
#define SB_CHEESBOARD_CORNERS_SUPPORTED
#if CV_MINOR_VERSION >= 3 || CV_MAJOR_VERSION > 4
#define SB_CHEESBOARD_CORNERS_MARKER_SUPPORTED
#endif
#endif
DEBUG_GET_ONCE_BOOL_OPTION(hsv_filter, "T_DEBUG_HSV_FILTER", false) DEBUG_GET_ONCE_BOOL_OPTION(hsv_filter, "T_DEBUG_HSV_FILTER", false)
DEBUG_GET_ONCE_BOOL_OPTION(hsv_picker, "T_DEBUG_HSV_PICKER", false) DEBUG_GET_ONCE_BOOL_OPTION(hsv_picker, "T_DEBUG_HSV_PICKER", false)
@ -99,6 +107,8 @@ public:
cv::Size dims = {8, 6}; cv::Size dims = {8, 6};
enum t_board_pattern pattern = T_BOARD_CHECKERS; enum t_board_pattern pattern = T_BOARD_CHECKERS;
float spacing_meters = 0.05; float spacing_meters = 0.05;
bool marker; //!< Center board marker for sb_checkers.
bool normalize_image; //!< For SB checkers.
} board; } board;
struct struct
@ -325,6 +335,45 @@ do_view_chess(class Calibration &c, struct ViewState &view, cv::Mat &gray, cv::M
return found; return found;
} }
#ifdef SB_CHEESBOARD_CORNERS_SUPPORTED
static bool
do_view_sb_checkers(class Calibration &c, struct ViewState &view, cv::Mat &gray, cv::Mat &rgb)
{
/*
* Fisheye requires measurement and model to be double, other functions
* requires them to be floats (like cornerSubPix). So we give in
* current_f32 here and convert below.
*/
int flags = 0;
if (c.board.normalize_image) {
flags += cv::CALIB_CB_NORMALIZE_IMAGE;
}
#ifdef SB_CHEESBOARD_CORNERS_MARKER_SUPPORTED
if (c.board.marker) {
// Only available in OpenCV 4.3 and above.
flags += cv::CALIB_CB_MARKER;
}
#endif
bool found = cv::findChessboardCornersSB(gray, // Image
c.board.dims, // patternSize
view.current_f32, // corners
flags); // flags
// Do the conversion here.
view.current_f64.clear(); // Doesn't effect capacity.
for (const cv::Point2f &p : view.current_f32) {
view.current_f64.emplace_back(double(p.x), double(p.y));
}
do_view_coverage(c, view, gray, rgb, found);
return found;
}
#endif
static bool static bool
do_view_circles(class Calibration &c, struct ViewState &view, cv::Mat &gray, cv::Mat &rgb) do_view_circles(class Calibration &c, struct ViewState &view, cv::Mat &gray, cv::Mat &rgb)
{ {
@ -364,6 +413,11 @@ do_view(class Calibration &c, struct ViewState &view, cv::Mat &gray, cv::Mat &rg
case T_BOARD_CHECKERS: // case T_BOARD_CHECKERS: //
found = do_view_chess(c, view, gray, rgb); found = do_view_chess(c, view, gray, rgb);
break; break;
#ifdef SB_CHEESBOARD_CORNERS_SUPPORTED
case T_BOARD_SB_CHECKERS: //
found = do_view_sb_checkers(c, view, gray, rgb);
break;
#endif
case T_BOARD_CIRCLES: // case T_BOARD_CIRCLES: //
found = do_view_circles(c, view, gray, rgb); found = do_view_circles(c, view, gray, rgb);
break; break;
@ -405,6 +459,7 @@ build_board_position(class Calibration &c)
switch (c.board.pattern) { switch (c.board.pattern) {
case T_BOARD_CHECKERS: case T_BOARD_CHECKERS:
case T_BOARD_SB_CHECKERS:
case T_BOARD_CIRCLES: case T_BOARD_CIRCLES:
// Nothing to do. // Nothing to do.
break; break;
@ -416,6 +471,7 @@ build_board_position(class Calibration &c)
switch (c.board.pattern) { switch (c.board.pattern) {
case T_BOARD_CHECKERS: case T_BOARD_CHECKERS:
case T_BOARD_SB_CHECKERS:
case T_BOARD_CIRCLES: case T_BOARD_CIRCLES:
c.board.model_f32.reserve(rows_num * cols_num); c.board.model_f32.reserve(rows_num * cols_num);
c.board.model_f64.reserve(rows_num * cols_num); c.board.model_f64.reserve(rows_num * cols_num);
@ -1217,6 +1273,19 @@ t_calibration_stereo_create(struct xrt_frame_context *xfctx,
struct xrt_frame_sink *gui, struct xrt_frame_sink *gui,
struct xrt_frame_sink **out_sink) struct xrt_frame_sink **out_sink)
{ {
#ifndef SB_CHEESBOARD_CORNERS_SUPPORTED
if (params->pattern == T_BOARD_SB_CHECKERS) {
U_LOG_E("OpenCV %u.%u doesn't support SB chessboard!", CV_MAJOR_VERSION, CV_MINOR_VERSION);
return -1;
}
#endif
#ifndef SB_CHEESBOARD_CORNERS_MARKER_SUPPORTED
if (params->pattern == T_BOARD_SB_CHECKERS && params->sb_checkers.marker) {
U_LOG_W("OpenCV %u.%u doesn't support SB chessboard marker option!", CV_MAJOR_VERSION,
CV_MINOR_VERSION);
}
#endif
auto &c = *(new Calibration()); auto &c = *(new Calibration());
// Basic setup. // Basic setup.
@ -1238,6 +1307,15 @@ t_calibration_stereo_create(struct xrt_frame_context *xfctx,
c.subpixel_enable = params->checkers.subpixel_enable; c.subpixel_enable = params->checkers.subpixel_enable;
c.subpixel_size = params->checkers.subpixel_size; c.subpixel_size = params->checkers.subpixel_size;
break; break;
case T_BOARD_SB_CHECKERS:
c.board.dims = {
params->sb_checkers.cols,
params->sb_checkers.rows,
};
c.board.spacing_meters = params->sb_checkers.size_meters;
c.board.marker = params->sb_checkers.marker;
c.board.normalize_image = params->sb_checkers.normalize_image;
break;
case T_BOARD_CIRCLES: case T_BOARD_CIRCLES:
c.board.dims = { c.board.dims = {
params->circles.cols, params->circles.cols,
@ -1307,6 +1385,8 @@ t_calibration_stereo_create(struct xrt_frame_context *xfctx,
push_model(c); push_model(c);
} }
#endif #endif
return ret; return ret;
} }

View file

@ -351,6 +351,8 @@ t_slam_start(struct xrt_tracked_slam *xts);
enum t_board_pattern enum t_board_pattern
{ {
T_BOARD_CHECKERS, T_BOARD_CHECKERS,
//! Sector based checker board, using `cv::findChessboardCornersSB`.
T_BOARD_SB_CHECKERS,
T_BOARD_CIRCLES, T_BOARD_CIRCLES,
T_BOARD_ASYMMETRIC_CIRCLES, T_BOARD_ASYMMETRIC_CIRCLES,
}; };
@ -390,6 +392,16 @@ struct t_calibration_params
int subpixel_size; int subpixel_size;
} checkers; } checkers;
struct
{
int cols;
int rows;
float size_meters;
bool marker;
bool normalize_image;
} sb_checkers;
struct struct
{ {
int cols; int cols;
@ -446,6 +458,13 @@ t_calibration_params_default(struct t_calibration_params *p)
p->checkers.subpixel_enable = true; p->checkers.subpixel_enable = true;
p->checkers.subpixel_size = 5; p->checkers.subpixel_size = 5;
// Sector based checker board.
p->sb_checkers.cols = 14;
p->sb_checkers.rows = 9;
p->sb_checkers.size_meters = 0.01206f;
p->sb_checkers.marker = false;
p->sb_checkers.normalize_image = false;
// Symmetrical circles. // Symmetrical circles.
p->circles.cols = 9; p->circles.cols = 9;
p->circles.rows = 7; p->circles.rows = 7;

View file

@ -273,7 +273,7 @@ scene_render_select(struct gui_scene *scene, struct gui_program *p)
igInputInt("Collect in groups of #", &cs->params.num_collect_restart, 1, 5, 0); igInputInt("Collect in groups of #", &cs->params.num_collect_restart, 1, 5, 0);
igSeparator(); igSeparator();
igComboStr("Board type", (int *)&cs->params.pattern, "Checkers\0Circles\0Asymetric Circles\0\0", 3); igComboStr("Board type", (int *)&cs->params.pattern, "Checkers\0Corners SB\0Circles\0Asymetric Circles\0\0", 3);
switch (cs->params.pattern) { switch (cs->params.pattern) {
case T_BOARD_CHECKERS: case T_BOARD_CHECKERS:
igInputInt("Checkerboard Rows", &cs->params.checkers.rows, 1, 5, 0); igInputInt("Checkerboard Rows", &cs->params.checkers.rows, 1, 5, 0);
@ -282,6 +282,13 @@ scene_render_select(struct gui_scene *scene, struct gui_program *p)
igCheckbox("Subpixel", &cs->params.checkers.subpixel_enable); igCheckbox("Subpixel", &cs->params.checkers.subpixel_enable);
igInputInt("Subpixel Search Size", &cs->params.checkers.subpixel_size, 1, 5, 0); igInputInt("Subpixel Search Size", &cs->params.checkers.subpixel_size, 1, 5, 0);
break; break;
case T_BOARD_SB_CHECKERS:
igInputInt("Internal Corner Rows", &cs->params.sb_checkers.rows, 1, 5, 0);
igInputInt("Internal Corner Columns", &cs->params.sb_checkers.cols, 1, 5, 0);
igInputFloat("Corner Spacing (m)", &cs->params.sb_checkers.size_meters, 0.0005, 0.001, NULL, 0);
igCheckbox("Marker", &cs->params.sb_checkers.marker);
igCheckbox("Normalize image", &cs->params.sb_checkers.normalize_image);
break;
case T_BOARD_CIRCLES: case T_BOARD_CIRCLES:
igInputInt("Circle Rows", &cs->params.circles.rows, 1, 5, 0); igInputInt("Circle Rows", &cs->params.circles.rows, 1, 5, 0);
igInputInt("Circle Columns", &cs->params.circles.cols, 1, 5, 0); igInputInt("Circle Columns", &cs->params.circles.cols, 1, 5, 0);