#include "ChessboardDetector.h" #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif ChessboardDetector::ChessboardDetector() : m_adaptiveThresh(true) , m_normalizeImage(true) , m_filterQuads(false) { } ChessboardDetector::~ChessboardDetector() { } int ChessboardDetector::DetectChessboard( const unsigned char* imageData, int width, int height, int channels, int patternWidth, int patternHeight, ChessboardDetectResult& result) { if (!imageData || width <= 0 || height <= 0) { return -1; } result.detected = false; result.corners.clear(); result.patternWidth = patternWidth; result.patternHeight = patternHeight; result.hasPose = false; try { // 创建 OpenCV Mat cv::Mat image; if (channels == 1) { image = cv::Mat(height, width, CV_8UC1, (void*)imageData).clone(); } else if (channels == 3) { image = cv::Mat(height, width, CV_8UC3, (void*)imageData).clone(); cv::cvtColor(image, image, cv::COLOR_BGR2GRAY); } else { return -2; } // 检测标定板角点 cv::Size patternSize(patternWidth, patternHeight); std::vector corners; int flags = 0; if (m_adaptiveThresh) flags |= cv::CALIB_CB_ADAPTIVE_THRESH; if (m_normalizeImage) flags |= cv::CALIB_CB_NORMALIZE_IMAGE; if (m_filterQuads) flags |= cv::CALIB_CB_FILTER_QUADS; bool found = cv::findChessboardCorners(image, patternSize, corners, flags); if (found && corners.size() == patternWidth * patternHeight) { // 亚像素精细化 cv::cornerSubPix(image, corners, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 30, 0.1)); result.detected = true; result.corners.reserve(corners.size()); for (const auto& pt : corners) { result.corners.push_back(Point2D(pt.x, pt.y)); } } return 0; } catch (const cv::Exception& e) { return -3; } } int ChessboardDetector::DetectChessboardWithPose( const unsigned char* imageData, int width, int height, int channels, int patternWidth, int patternHeight, double squareSize, const CameraIntrinsics& intrinsics, ChessboardDetectResult& result) { // 首先检测角点 int ret = DetectChessboard(imageData, width, height, channels, patternWidth, patternHeight, result); if (ret != 0 || !result.detected) { return ret; } try { // 构建3D物体点(标定板坐标系) std::vector objectPoints; for (int i = 0; i < patternHeight; i++) { for (int j = 0; j < patternWidth; j++) { objectPoints.push_back(cv::Point3f(j * squareSize, i * squareSize, 0)); } } // 构建2D图像点 std::vector imagePoints; for (const auto& pt : result.corners) { imagePoints.push_back(cv::Point2f(pt.x, pt.y)); } // 相机内参矩阵 cv::Mat cameraMatrix = (cv::Mat_(3, 3) << intrinsics.fx, 0, intrinsics.cx, 0, intrinsics.fy, intrinsics.cy, 0, 0, 1); // 畸变系数 cv::Mat distCoeffs = (cv::Mat_(5, 1) << intrinsics.k1, intrinsics.k2, intrinsics.p1, intrinsics.p2, intrinsics.k3); // 求解PnP cv::Mat rvec, tvec; bool success = cv::solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvec, tvec, false, cv::SOLVEPNP_ITERATIVE); if (success) { result.hasPose = true; // 保存旋转向量和平移向量 result.rvec[0] = rvec.at(0); result.rvec[1] = rvec.at(1); result.rvec[2] = rvec.at(2); result.tvec[0] = tvec.at(0); result.tvec[1] = tvec.at(1); result.tvec[2] = tvec.at(2); // 标定板中心位置(平移向量就是标定板原点在相机坐标系下的位置) result.center.x = tvec.at(0); result.center.y = tvec.at(1); result.center.z = tvec.at(2); // 将旋转向量转换为旋转矩阵 cv::Mat rotMat; cv::Rodrigues(rvec, rotMat); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { result.rotationMatrix[i * 3 + j] = rotMat.at(i, j); } } // 标定板法向量(标定板坐标系的Z轴在相机坐标系下的方向) // 旋转矩阵的第三列就是标定板Z轴方向 result.normal.x = rotMat.at(0, 2); result.normal.y = rotMat.at(1, 2); result.normal.z = rotMat.at(2, 2); // 计算欧拉角 (ZYX顺序) double sy = sqrt(rotMat.at(0, 0) * rotMat.at(0, 0) + rotMat.at(1, 0) * rotMat.at(1, 0)); bool singular = sy < 1e-6; double roll, pitch, yaw; if (!singular) { roll = atan2(rotMat.at(2, 1), rotMat.at(2, 2)); pitch = atan2(-rotMat.at(2, 0), sy); yaw = atan2(rotMat.at(1, 0), rotMat.at(0, 0)); } else { roll = atan2(-rotMat.at(1, 2), rotMat.at(1, 1)); pitch = atan2(-rotMat.at(2, 0), sy); yaw = 0; } // 转换为度 result.eulerAngles[0] = roll * 180.0 / M_PI; result.eulerAngles[1] = pitch * 180.0 / M_PI; result.eulerAngles[2] = yaw * 180.0 / M_PI; } return 0; } catch (const cv::Exception& e) { return -4; } } int ChessboardDetector::SetDetectionFlags( bool adaptiveThresh, bool normalizeImage, bool filterQuads) { m_adaptiveThresh = adaptiveThresh; m_normalizeImage = normalizeImage; m_filterQuads = filterQuads; return 0; } // 工厂函数实现 IChessboardDetector* CreateChessboardDetectorInstance() { return new ChessboardDetector(); } void DestroyChessboardDetectorInstance(IChessboardDetector* instance) { if (instance) { delete instance; } }