Speedup ChArUco by avoiding temporary copies

This speeds up processing a 132x128 board by more than 100 times.
This methods return std::vectors<> which means lots of copies and allocations.
This commit is contained in:
Marius Wachtler 2025-09-23 19:00:24 -05:00
parent 6f040337e9
commit 6f9f8f49dd

View File

@ -32,8 +32,10 @@ struct CharucoDetector::CharucoDetectorImpl {
const Mat chIds = charucoIds.getMat();
const vector<int>& boardIds = board.getIds();
const vector<vector<int> > nearestMarkerIdx = board.getNearestMarkerIdx();
vector<Point2f> distance(board.getNearestMarkerIdx().size(), Point2f(0.f, std::numeric_limits<float>::max()));
const vector<vector<int> > nearestMarkerIdx = board.getNearestMarkerIdx(); // only copy the vectors once
const vector<vector<int> > nearestMarkerCorners = board.getNearestMarkerCorners();
vector<Point2f> distance(nearestMarkerIdx.size(), Point2f(0.f, std::numeric_limits<float>::max()));
// distance[i].x: max distance from the i-th charuco corner to charuco corner-forming markers.
// The two charuco corner-forming markers of i-th charuco corner are defined in getNearestMarkerIdx()[i]
// distance[i].y: min distance from the charuco corner to other markers.
@ -52,7 +54,7 @@ struct CharucoDetector::CharucoDetectorImpl {
const int nearestMarkerId1 = boardIds[nearestMarkerIdx[chId][0]];
const int nearestMarkerId2 = boardIds[nearestMarkerIdx[chId][1]];
if (nearestMarkerId1 == idMaker || nearestMarkerId2 == idMaker) {
int nearestCornerId = nearestMarkerId1 == idMaker ? board.getNearestMarkerCorners()[chId][0] : board.getNearestMarkerCorners()[chId][1];
int nearestCornerId = nearestMarkerId1 == idMaker ? nearestMarkerCorners[chId][0] : nearestMarkerCorners[chId][1];
Point2f nearestCorner = mCorners[j].ptr<Point2f>(0)[nearestCornerId];
// distToNearest: distance from the charuco corner to charuco corner-forming markers
float distToNearest = sqrt(normL2Sqr<float>(nearestCorner - charucoCorner));
@ -84,18 +86,21 @@ struct CharucoDetector::CharucoDetectorImpl {
InputArray charucoCorners) {
size_t nCharucoCorners = charucoCorners.getMat().total();
CV_Assert(board.getNearestMarkerIdx().size() == nCharucoCorners);
const vector<vector<int> > nearestMarkerIdx = board.getNearestMarkerIdx(); // only copy the vectors once
const vector<vector<int> > nearestMarkerCorners = board.getNearestMarkerCorners();
CV_Assert(nearestMarkerIdx.size() == nCharucoCorners);
vector<Size> winSizes(nCharucoCorners, Size(-1, -1));
for(size_t i = 0ull; i < nCharucoCorners; i++) {
if(charucoCorners.getMat().at<Point2f>((int)i) == Point2f(-1.f, -1.f)) continue;
if(board.getNearestMarkerIdx()[i].empty()) continue;
if(nearestMarkerIdx[i].empty()) continue;
double minDist = -1;
int counter = 0;
// calculate the distance to each of the closest corner of each closest marker
for(size_t j = 0; j < board.getNearestMarkerIdx()[i].size(); j++) {
for(size_t j = 0; j < nearestMarkerIdx[i].size(); j++) {
// find marker
int markerId = board.getIds()[board.getNearestMarkerIdx()[i][j]];
int markerId = board.getIds()[nearestMarkerIdx[i][j]];
int markerIdx = -1;
for(size_t k = 0; k < markerIds.getMat().total(); k++) {
if(markerIds.getMat().at<int>((int)k) == markerId) {
@ -105,7 +110,7 @@ struct CharucoDetector::CharucoDetectorImpl {
}
if(markerIdx == -1) continue;
Point2f markerCorner =
markerCorners.getMat(markerIdx).at<Point2f>(board.getNearestMarkerCorners()[i][j]);
markerCorners.getMat(markerIdx).at<Point2f>(nearestMarkerCorners[i][j]);
Point2f charucoCorner = charucoCorners.getMat().at<Point2f>((int)i);
double dist = norm(markerCorner - charucoCorner);
if(minDist == -1) minDist = dist; // if first distance, just assign it
@ -212,6 +217,8 @@ struct CharucoDetector::CharucoDetectorImpl {
vector<Mat> transformations(nMarkers);
vector<bool> validTransform(nMarkers, false);
const auto& ids = board.getIds();
const vector<vector<int> > nearestMarkerIdx = board.getNearestMarkerIdx(); // only copy the vectors once
for(size_t i = 0ull; i < nMarkers; i++) {
vector<Point2f> markerObjPoints2D;
int markerId = markerIds.getMat().at<int>((int)i);
@ -227,15 +234,16 @@ struct CharucoDetector::CharucoDetectorImpl {
double det = determinant(transformations[i]);
validTransform[i] = std::abs(det) > 1e-6;
}
size_t nCharucoCorners = (size_t)board.getChessboardCorners().size();
const vector<Point3f> chessboardCorners = board.getChessboardCorners();
size_t nCharucoCorners = (size_t)chessboardCorners.size();
vector<Point2f> allChessboardImgPoints(nCharucoCorners, Point2f(-1, -1));
// for each charuco corner, calculate its interpolation position based on the closest markers
// homographies
for(size_t i = 0ull; i < nCharucoCorners; i++) {
Point2f objPoint2D = Point2f(board.getChessboardCorners()[i].x, board.getChessboardCorners()[i].y);
Point2f objPoint2D = Point2f(chessboardCorners[i].x, chessboardCorners[i].y);
vector<Point2f> interpolatedPositions;
for(size_t j = 0ull; j < board.getNearestMarkerIdx()[i].size(); j++) {
int markerId = board.getIds()[board.getNearestMarkerIdx()[i][j]];
for(size_t j = 0ull; j < nearestMarkerIdx[i].size(); j++) {
int markerId = board.getIds()[nearestMarkerIdx[i][j]];
int markerIdx = -1;
for(size_t k = 0ull; k < markerIds.getMat().total(); k++) {
if(markerIds.getMat().at<int>((int)k) == markerId) {
@ -274,13 +282,14 @@ struct CharucoDetector::CharucoDetectorImpl {
CV_Assert(charucoParameters.minMarkers >= 0 && charucoParameters.minMarkers <= 2);
vector<Point2f> filteredCharucoCorners;
vector<int> filteredCharucoIds;
const vector<vector<int> > nearestMarkerIdx = board.getNearestMarkerIdx(); // only copy the vectors once
// for each charuco corner
for(unsigned int i = 0; i < allCharucoIds.getMat().total(); i++) {
int currentCharucoId = allCharucoIds.getMat().at<int>(i);
int totalMarkers = 0; // nomber of closest marker detected
// look for closest markers
for(unsigned int m = 0; m < board.getNearestMarkerIdx()[currentCharucoId].size(); m++) {
int markerId = board.getIds()[board.getNearestMarkerIdx()[currentCharucoId][m]];
for(unsigned int m = 0; m < nearestMarkerIdx[currentCharucoId].size(); m++) {
int markerId = board.getIds()[nearestMarkerIdx[currentCharucoId][m]];
bool found = false;
for(unsigned int k = 0; k < allArucoIds.getMat().total(); k++) {
if(allArucoIds.getMat().at<int>(k) == markerId) {