Charuco生成和检测


#include <iostream>
#include <opencv2/highgui.hpp>
#include <opencv2/aruco.hpp>
#include <opencv2/aruco/charuco.hpp>
#include <opencv2/opencv.hpp>

// opencv Aruco官方示例
// https://github.com/opencv/opencv_contrib/tree/4.x/modules/aruco/samples

using namespace std;
using namespace cv;

auto aruco_t = cv::aruco::DICT_7X7_50;     // maker为6*6,数量有250个

static const int squaresX = 5;      // x方向棋盘格数量
static const int squaresY = 5;          // y方向棋盘格数量
static const float squareLength = 0.18;     // 棋盘格正方块边长(m为单位)
static const float markerLength = 0.12;     // 棋盘格中maker的长度(m为单位)

void generateMarker(const std::string &charuco_path,  cv::Mat& boardImage) {
	// 声明字典,字典名称表示了该字典的aruco标记数量和尺寸
	Ptr<aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(aruco_t);
	// https://docs.opencv.org/4.5.2/d0/d3c/classcv_1_1aruco_1_1CharucoBoard.html#aa83b0a885d4dd137a41686991f85594c
	cv::Ptr<cv::aruco::CharucoBoard> board = cv::aruco::CharucoBoard::create(squaresX, squaresY, squareLength, markerLength, dictionary);
	
	// https://docs.opencv.org/4.5.2/d0/d3c/classcv_1_1aruco_1_1CharucoBoard.html#a5f1b7c91bd8bf8271931d6f06292f1bc
	board->draw(cv::Size(600, 600), boardImage, 10, 1);
	//API:drawMarker()来绘制出aruco标记,其参数含义如下:
	//	(1)参数dictionary : 之前创建的 Dictionary 对象指针
	//	(2)参数id:标记 id,表示绘制字典中的哪一个aruco标记。每个字典由不同数量的标记组成,id 有效范围是[0,字典包含的标记数 ),任何超出有效范围的特定 id 都会产生异常。
	//	(3)参数 sidepixel: 输出标记图像的尺寸,输出标记图像的尺寸为Size(sidepixel,sidepixel);此参数应足够大以存储特定字典的位数,至少需要满足(sidepixel - 标记的边长) >= 2;
	//	并且为了避免输出标记图像变形,sidepixel应与位数 + 边界大小成比例,或者至少比标记尺寸大得多,以使变形不明显。
	//	(4)参数img:输出的标记图像;
	//	(5)参数borderBist:用于指定标记黑色边框的宽度,例如borderBist = 2 表示边框的宽度等于两个内部像素的大小,默认值 borderBist = 1。
	imwrite(charuco_path, boardImage);

	imshow("board", boardImage);
	waitKey(0);
	destroyAllWindows();
}


void detectMarker(const std::string &image_path, const std::string& detectedcharuco_path) {

	cv::Mat cur_img, copyImage, imageCopy;
	cur_img = cv::imread(image_path, 1);
	//cvtColor(cur_img, cur_img, CV_GRAY2BGR);
	std::cout << "cur_img:" << cur_img.channels() << std::endl;

	// 声明字典,字典名称表示了该字典的aruco标记数量和尺寸
	Ptr<aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(aruco_t);
	cv::Ptr<cv::aruco::CharucoBoard> board = cv::aruco::CharucoBoard::create(squaresX, squaresY, squareLength, markerLength, dictionary);
	cv::Ptr<cv::aruco::DetectorParameters> params = cv::aruco::DetectorParameters::create();
	cur_img.copyTo(copyImage);

	// ids: 检测到的 ArUco 序号。这是按检测先后存放,所以可能是乱序的
	// corners: 第一层 vector 是检测到的 Marker,第二层是 1 个 ArUco 对应 4 个 Point2f 点坐标;
	vector<int> markerIds;
	vector<vector<Point2f>> markerCorners, rejectedMarkers;
	// https://docs.opencv.org/4.5.2/d9/d6a/group__aruco.html#gab9159aa69250d8d3642593e508cb6baa
	aruco::detectMarkers(copyImage, board->dictionary, markerCorners, markerIds, params, rejectedMarkers);

	std::vector<cv::Point2f> charucoCorners;
	std::vector<int> charucoIds;
	// 根据检测的aruco角点优化插值棋盘格角点
	int interpolatedCorners = 0;
	if (markerIds.size() > 0) {
		std::cout << "markeriDs:" << markerIds.size() << std::endl;
		//cv::aruco::interpolateCornersCharuco(markerCorners, markerIds, copyImage, board, charucoCorners, charucoIds);
		interpolatedCorners =
		aruco::interpolateCornersCharuco(markerCorners, markerIds, copyImage, board,
			charucoCorners, charucoIds);

	}
	cur_img.copyTo(imageCopy);
	// 画出maker角点和id
	if (markerIds.size() > 0) {
		aruco::drawDetectedMarkers(imageCopy, markerCorners, markerIds, Scalar(0, 255, 0)); // bgr,画出边框并显示出id,且标出来左上角第一个角点
		// 下面与drawDetectedMarkers效果等同
		int cnt = 0;
		for (auto m : markerIds)
		{
			for (int i = 0; i < markerCorners[m].size(); ++i) {
				if (markerCorners[m][i].x < 0) {
					continue;
				}
				cout << "point2f:" << markerCorners[m][i].x << ", " << markerCorners[m][i].y << endl;
				Point2i point = Point2i(int(markerCorners[m][i].x), int(markerCorners[m][i].y));
				circle(imageCopy, point, 5,Scalar(255,0,0), 1);
				/*putText(imageCopy, to_string(m)+" " + to_string(i), point, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(12, 23, 200), 1, 8);*/
				putText(imageCopy,  to_string(i), point, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(12, 23, 200), 1, 8);

			}
			
			++cnt;
		}

	}
	// 画出charuco角点和id
	if (interpolatedCorners > 0) {
		aruco::drawDetectedCornersCharuco(imageCopy, charucoCorners, charucoIds, Scalar(0, 0, 255));
		// 下面与drawDetectedCornersCharuco效果等同
		int cnt(0);
		for (auto m : charucoIds)
		{
			cout << "point2f:" << charucoCorners[m].x << ", " << charucoCorners[m].y << endl;
			Point2i point = Point2i(int(charucoCorners[m].x), int(charucoCorners[m].y));
			circle(imageCopy, point, 5, Scalar(255, 255, 0), 1);
			putText(imageCopy, to_string(cnt), point, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(13, 230, 13), 1, 8);
			++cnt;
		}
	}
	imwrite(detectedcharuco_path, imageCopy);
	namedWindow("out", WINDOW_NORMAL);
	imshow("out", imageCopy);
	
	waitKey(0);
	destroyAllWindows();
}
// g++ ../charuco.cpp -o charuco `pkg-config --cflags --libs opencv4`

int main() {

	Mat boardImage;
	std::string charuco_path = "./charuco.png";
	std::string detectedcharuco_path = "./detectedcharuco.png";

	generateMarker(charuco_path, boardImage);

	detectMarker(charuco_path, detectedcharuco_path);
	

}


生成的charuco
生成的charuco

检测结果
检测结果

posted @ 2022-05-26 11:34  小小灰迪  阅读(1164)  评论(0编辑  收藏  举报