algoLib/sourceCode/binocularMarkCam.cpp

238 lines
8.7 KiB
C++
Raw Normal View History

2025-12-05 23:08:46 +08:00
#include <vector>
#include "SG_baseDataType.h"
#include "SG_baseAlgo_Export.h"
#include "binocularMarkCam_Export.h"
#include <opencv2/opencv.hpp>
#include "aruco.hpp"
#include "aruco/charuco.hpp"
#include <limits>
#define _OUTPUT_DEBUG_DATA 0
//version 1.0.0 : <20><>ʼ<EFBFBD>
std::string m_strVersion = "1.0.0";
//<2F><><EFBFBD><EFBFBD><E6B1BE>
const char* wd_charuco3DMarkVersion(void)
{
return m_strVersion.c_str();
}
/*Breif<69><66><EFBFBD><EFBFBD>ά<EFBFBD><CEAC><EFBFBD><EFBFBD><EAB6A8><EFBFBD>ǵ㺯<C7B5><E3BAAF>*/
void detectCharucoCorners(const cv::Mat& img,
const SWD_BQ_CharucoMarkInfo markInfo,
const SWD_BQ_MarkBoardInfo boardInfo,
std::vector<int>& markerIdsAll,
std::vector<std::vector<cv::Point2f> >& markerCornersAll,
std::vector<int>& charucoIds,
std::vector<std::vector<cv::Point2f>>& charucoCorners)
{
cv::Mat gray;
if (img.channels() == 3)
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
else
gray = img.clone();
enum cv::aruco::PredefinedDictionaryType dictType;
if (1 == markInfo.dictType)
dictType = cv::aruco::DICT_6X6_1000;
else
dictType = cv::aruco::DICT_6X6_1000; //Ŀǰֻ֧<D6BB><D6A7>DICT_6X6_1000
cv::aruco::Dictionary aruco_dict = cv::aruco::getPredefinedDictionary(dictType);
cv::aruco::DetectorParameters params = cv::aruco::DetectorParameters();
params.cornerRefinementMethod = cv::aruco::CORNER_REFINE_NONE;
cv::Ptr<cv::aruco::Dictionary> ptrDictionary = cv::makePtr<cv::aruco::Dictionary>(aruco_dict);
cv::Ptr<cv::aruco::DetectorParameters> ptrParams = cv::makePtr<cv::aruco::DetectorParameters>(params);
#if 0
// <20>Ż<EFBFBD><C5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȶ<EFBFBD><C8B6>ԣ<EFBFBD>
ptrParams->adaptiveThreshWinSizeMin = 3;
ptrParams->adaptiveThreshWinSizeMax = 23;
ptrParams->adaptiveThreshWinSizeStep = 10;
ptrParams->minMarkerPerimeterRate = 0.01; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD>ı<EFBFBD><C4B1><EFBFBD>
#endif
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>нǵ<D0BD>
cv::aruco::detectMarkers(gray, ptrDictionary, markerCornersAll, markerIdsAll, ptrParams);
//<2F><><EFBFBD><EFBFBD>Mark(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD>ı<C4B1>
for (int board = 0; board < boardInfo.totalBoardNum; board++)
{
int startId = board * boardInfo.boardIdInterval;
int endId = startId + boardInfo.boardChaucoIDNum - 1;
std::vector<int> ids;
for (int i = 0; i < boardInfo.boardChaucoIDNum; i++)
ids.push_back(startId + i);
//<2F><><EFBFBD><EFBFBD>
std::vector<int> markerIds;
std::vector<std::vector<cv::Point2f> > markerCorners;
for (int i = 0; i < markerIdsAll.size(); i++)
{
if ((markerIdsAll[i] >= startId) && (markerIdsAll[i] <= endId))
{
markerIds.push_back(markerIdsAll[i]);
markerCorners.push_back(markerCornersAll[i]);
}
}
if (markerIds.size() > 0)
{
std::vector<int> board_charucoIds;
std::vector<cv::Point2f> board_charucoCorners;
cv::aruco::CharucoBoard board = cv::aruco::CharucoBoard(markInfo.patternSize, markInfo.checkerSize, markInfo.markerSize, aruco_dict, ids);
cv::Ptr<cv::aruco::CharucoBoard> ptrBoard = cv::makePtr<cv::aruco::CharucoBoard>(board);
cv::aruco::interpolateCornersCharuco(
markerCorners,
markerIds,
gray,
ptrBoard,
board_charucoCorners,
board_charucoIds);
if (board_charucoIds.size() > 0)
{
// <20><><EFBFBD><EFBFBD><EFBFBD>ؾ<EFBFBD>ȷ<EFBFBD><C8B7>
cv::cornerSubPix(gray, board_charucoCorners, cv::Size(11, 11), cv::Size(-1, -1),
cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER, 50, 0.1));
charucoIds.push_back(startId);
charucoCorners.push_back(board_charucoCorners);
}
}
}
return;
}
SVzNL3DPoint _getStereoPoints3d(cv::Point2f left, cv::Point2f right, const cv::Mat& Q, double offset = 0)
{
const double cx = Q.at<double>(0, 3);
const double cy = Q.at<double>(1, 3);
const double f = Q.at<double>(2, 3);
const double t = 1.0 / Q.at<double>(3, 2);
//std::cout << "Cx: " << cx << ", Cy: " << cy << ", f: " << f << ", t: " << t << std::endl;
SVzNL3DPoint result;
double dis = left.x - right.x + offset;
result.x = (left.x + cx) * t / dis;
result.y = (left.y + cy) * t / dis;
result.z = f * t / dis;
//std::cout << "L: " << left[_i] << ", R: " << right[_i] << ", dis: " << dis << std::endl;
return result;
}
typedef struct
{
int markID;
std::vector<cv::Point2f> left;
std::vector<cv::Point2f> right;
}_MarkerPairing;
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Mark3D<33><44>Ϣ
void wd_BQ_getCharuco3DMark(
cv::Mat& leftImage,
cv::Mat& rightImage,
cv::Mat& cameraMatrixL,
cv::Mat& distCoeffsL,
cv::Mat& cameraMatrixR,
cv::Mat& distCoeffsR,
cv::Mat& R1,
cv::Mat& R2,
cv::Mat& P1,
cv::Mat& P2,
cv::Mat& Q,
SWD_BQ_CharucoMarkInfo markInfo,
SWD_BQ_MarkBoardInfo boardInfo,
double disparityOffset,
std::vector<SWD_charuco3DMark>& marks)
{
std::vector<int> markerIdsLeft;
std::vector<std::vector<cv::Point2f> > markerCornersLeft;
std::vector<int> charucoIdsLeft;
std::vector<std::vector<cv::Point2f>> charucoCornersLeft;//ÿ<><C3BF>Mark<72><6B>4<EFBFBD><34><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD>Ӧ4<D3A6><34><EFBFBD><EFBFBD>ά<EFBFBD><CEAC>
detectCharucoCorners(leftImage,
markInfo,
boardInfo,
markerIdsLeft,
markerCornersLeft,
charucoIdsLeft,
charucoCornersLeft);
std::vector<int> markerIdsRight;
std::vector<std::vector<cv::Point2f> > markerCornersRight;
std::vector<int> charucoIdsRight;
std::vector<std::vector<cv::Point2f>> charucoCornersRight;
detectCharucoCorners(rightImage,
markInfo,
boardInfo,
markerIdsRight,
markerCornersRight,
charucoIdsRight,
charucoCornersRight);
#if _OUTPUT_DEBUG_DATA
cv::Mat imageCopyLeft = leftImage.clone();
if (markerIdsLeft.size() > 0)
cv::aruco::drawDetectedMarkers(imageCopyLeft, markerCornersLeft, markerIdsLeft);
if (charucoIdsLeft.size() > 0)
cv::aruco::drawDetectedCornersCharuco(imageCopyLeft, charucoCornersLeft, charucoIdsLeft, cv::Scalar(0, 255, 255));
char markFilenameL[256];
sprintf_s(markFilenameL, "markersLeft.bmp");
cv::imwrite(markFilenameL, imageCopyLeft);
cv::Mat imageCopyRight = leftImage.clone();
if (markerIdsRight.size() > 0)
cv::aruco::drawDetectedMarkers(imageCopyRight, markerCornersRight, markerIdsRight);
if (charucoIdsRight.size() > 0)
cv::aruco::drawDetectedCornersCharuco(imageCopyRight, charucoCornersRight, charucoIdsRight, cv::Scalar(0, 255, 255));
char markFilenameR[256];
sprintf_s(markFilenameR, "markersRight.bmp");
cv::imwrite(markFilenameR, imageCopyRight);
#endif
//Marker<65><72><EFBFBD><EFBFBD>
std::vector<_MarkerPairing> stereoMarks;
for (int i = 0, i_max = (int)charucoIdsLeft.size(); i < i_max; i++)
{
for (int j = 0, j_max = (int)charucoIdsRight.size(); j < j_max; j++)
{
if ( (charucoIdsLeft[i] == charucoIdsRight[j]) && (charucoCornersLeft[i].size() == charucoCornersRight[j].size()))
{
_MarkerPairing a_pair;
a_pair.markID = charucoIdsLeft[i];
a_pair.left.insert(a_pair.left.end(), charucoCornersLeft[i].begin(), charucoCornersLeft[i].end());
a_pair.right.insert(a_pair.right.end(), charucoCornersRight[j].begin(), charucoCornersRight[j].end());
stereoMarks.push_back(a_pair);
break;
}
}
}
for (int i = 0, i_max = (int)stereoMarks.size(); i < i_max; i++)
{
//˫ĿУ<C4BF><D0A3>
std::vector<cv::Point2f> rectCornersLeft;
cv::undistortPoints(stereoMarks[i].left, rectCornersLeft, cameraMatrixL, distCoeffsL, R1, P1);
std::vector<cv::Point2f> rectCornersRight;
cv::undistortPoints(stereoMarks[i].right, rectCornersRight, cameraMatrixR, distCoeffsR, R2, P2);
std::vector<SVzNL3DPoint> corners;
for (int m = 0; m < rectCornersLeft.size(); m++)
{
double abs_diff = abs(rectCornersLeft[m].y - rectCornersRight[m].y);
if (abs_diff < 1.0) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1>1<EFBFBD><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
{
SVzNL3DPoint a_pt3d = _getStereoPoints3d(rectCornersLeft[m], rectCornersRight[m], Q, disparityOffset);
corners.push_back(a_pt3d);
}
}
if (corners.size() == 4)
{
SWD_charuco3DMark a_3dMark;
a_3dMark.markID = stereoMarks[i].markID;
a_3dMark.mark3D.x = (corners[0].x + corners[1].x + corners[2].x + corners[3].x) / 4;
a_3dMark.mark3D.y = (corners[0].y + corners[1].y + corners[2].y + corners[3].y) / 4;
a_3dMark.mark3D.z = (corners[0].z + corners[1].z + corners[2].z + corners[3].z) / 4;
marks.push_back(a_3dMark);
}
}
return;
}