前景概要

很多机器视觉定位与识别场景,如无人车、无人机,都会用Aruco码或特定的标志物来实现,Aruco码的优点在于,xxxx(自行搜索)。

对于像在低成本轻量级的无人机这种嵌入式系统上,搭载深度学习的识别算法目前还有困难

所以大家现在采用较多的,就是识别特定的标志物。之前看小鹏汽车的宣传片,他们也是在用黑白同心圆环的目标板。

实现内容

0、打开摄像头或某张图片

1、先检测圆环(因视角变换可能是椭圆环);

2、裁剪保留圆环区域

3、检测圆环中的Aruco码(单个或菱形或棋盘)

4、计算目标的位姿


大致效果

代码预览

完整代码请看github(测试性代码,写的很粗糙,仅供参考)

Github: https://github.com/1061700625/OpenCV_Aruco

Mat testDetect(Mat &markerImage, bool diamond = true, bool aamed=false, bool show=false) {/*************************************检测椭圆*****************************************************/// FeaturePoint(img ,img2);// EDCircle(markerImage);float t1, t2, tdelt;vector<Mat> results;Mat fullSplitImage;if(aamed) {t1 = cv::getTickCount();AAMED_Fled(markerImage, fullSplitImage, results);t2 = cv::getTickCount();tdelt = 1000.0*(t2-t1) / cv::getTickFrequency();std::cout << "AAMED耗时(ms):" << tdelt << std::endl;}else {results.emplace_back(markerImage);fullSplitImage = markerImage.clone();}/************************************************************************************************/// 对每个椭圆区域进行检测for (auto& cropSplitImage: results) {// 检测Arucovector<vector<Point2f>> diamondCorners;vector<cv::Vec4i> diamondIds;vector<vector<Point2f>> markerCorners;vector<int> markerIds;vector<vector<Point2f>> rejectedCandidates;t1 = cv::getTickCount();// cv::copyMakeBorder(cropSplitImage, cropSplitImage, 5, 5, 5, 5, cv::BORDER_CONSTANT, Scalar(255,0,0));detectAruco(cropSplitImage, markerCorners, rejectedCandidates, markerIds);if (markerCorners.empty()) {cout<<"无可用Marker"<<endl;return fullSplitImage;}// 显示检测到的但是由于字典对不上被拒绝的Markerif(show) {if (!rejectedCandidates.empty()){cout<<"一共有 "<<rejectedCandidates.size()<<" 个被拒绝的 Marker "<<endl;for (auto & rejectedCandidate : rejectedCandidates) {for (int i=0;i<4;i++) {cv::circle(fullSplitImage,cv::Point(rejectedCandidate[i].x,rejectedCandidate[i].y),6,cv::Scalar(0,0,255));}}}}if(diamond) {detectDiamon(cropSplitImage, markerCorners, markerIds, diamondCorners, diamondIds);}t2 = cv::getTickCount();tdelt = 1000.0*(t2-t1) / cv::getTickFrequency();std::cout << "检测耗时(ms):" << tdelt << std::endl;std::vector<cv::Vec3d> rvecs, tvecs;cv::Vec3d rvec, tvec;t1 = cv::getTickCount();if(diamond) {if (diamondIds.empty()) {cout<<"无可用diamondIds"<<endl;continue;}// 绘制检测边框if(show) {cv::aruco::drawDetectedDiamonds(fullSplitImage, diamondCorners, diamondIds);}// 估计相机位姿(相对于每一个marker)  markerLength为什么是squareLength?cv::aruco::estimatePoseSingleMarkers(diamondCorners, markerLength, cameraMatrix, distCoeffs, rvecs, tvecs);}else {if (markerIds.empty()){cout<<"无可用markerIds"<<endl;continue;}// 绘制检测边框if(show) {cv::aruco::drawDetectedMarkers(fullSplitImage, markerCorners, markerIds);}// 估计相机位姿(相对于每一个marker)// cv::aruco::estimatePoseSingleMarkers(markerCorners, squareLength, cameraMatrix, distCoeffs, rvecs, tvecs);// 估计相机位姿(相对于 aruco 板)cv::aruco::estimatePoseBoard(markerCorners, markerIds, board, cameraMatrix, distCoeffs, rvec, tvec); rvecs.emplace_back(rvec); tvecs.emplace_back(tvec);}t2 = cv::getTickCount();tdelt = 1000.0*(t2-t1) / cv::getTickFrequency();std::cout << "相机位姿估计耗时(ms):" << tdelt << std::endl;// 为每个标记画轴t1 = cv::getTickCount();for (int i = 0; i < rvecs.size(); ++i) {rvec = rvecs[i];tvec = tvecs[i];// 得到的位姿估计是:从board坐标系到相机坐标系的cv::Mat R;cv::Rodrigues(rvec,R);Eigen::Matrix3d R_eigen;cv::cv2eigen(R,R_eigen);// Eigen中使用右乘的顺序, 因此ZYX对应的是012, 实际上这个编号跟乘法的顺序一致就可以了(从左向右看的顺序)Eigen::Vector3d zyx_Euler_fromR = R_eigen.eulerAngles(0,1,2);if(show) {cout << "R_{camera<---marker} :" << R << endl;cout << "t_{camera<---marker} :" << tvec << endl;cout << "zyx旋转欧拉角[输出顺序为:x,y,z]: " << (180)/(M_PI)*zyx_Euler_fromR.transpose()<<endl;cv::aruco::drawAxis(fullSplitImage, cameraMatrix, distCoeffs, rvec, tvec, 0.1);cout << "--------------------------------------------" << endl;}//cv::aruco::drawAxis(markerImage, cameraMatrix, distCoeffs, rvec, tvec, 0.1);}t2 = cv::getTickCount();tdelt = 1000.0*(t2-t1) / cv::getTickFrequency();std::cout << "欧拉角耗时(ms):" << tdelt << std::endl;}if (aamed && show) {imshow("markerImage", markerImage);//imshow("fullSplitImage", fullSplitImage);//imwrite("../fullSplitImage.png", fullSplitImage);}// waitKey(0);return fullSplitImage;
}int main(int argc, char* argv[])
{Mat fullSplitImage;Mat boardImage;board->draw( cv::Size(200, 200),  // 整个board的大小boardImage,                         // 返回的图像10,                            // 整个board的边距1 );                           // 每个码内的边距imwrite("../boardImage.png", boardImage);cv::aruco::drawCharucoDiamond(dictionary, cv::Vec4i(0,1,2,3), 200, 150, boardImage);imwrite("../diamondImage.png", boardImage);//vector<Mat> markerImages = generateAruco(5);//Mat markerImage = markerImages[0];cout<<">> 预处理完成!"<<endl;/************************************************************************************************/float t1, t2, tdelt;Mat markerImage = imread("../img/4.jpg", 1);t1 = cv::getTickCount();fullSplitImage = testDetect(markerImage, false, false, true);t2 = cv::getTickCount();tdelt = 1000.0*(t2-t1) / cv::getTickFrequency();std::cout << "一帧总耗时(ms):" << tdelt << std::endl;imshow("fullSplitImage", fullSplitImage);waitKey(0);return 0;/************************************************************************************************/Mat frame;VideoCapture capture;capture.open(0);if (!capture.isOpened()) {cerr << "ERROR! Unable to open camera\n";return -1;}cv::namedWindow("fullSplitImage",0);cv::resizeWindow("fullSplitImage", 960, 540);for (;;) {capture.read(frame);cv::resize(frame, frame, cv::Size(752, 480), 0, 0, cv::INTER_AREA);cout << frame.size << endl;if (frame.empty()) {cerr << "ERROR! blank frame grabbed\n";break;}t1 = cv::getTickCount();fullSplitImage = testDetect(frame, false, false);t2 = cv::getTickCount();tdelt = 1000.0*(t2-t1) / cv::getTickFrequency();std::cout << "一帧耗时(ms):" << tdelt << std::endl;imshow("fullSplitImage", fullSplitImage.empty() ? frame : fullSplitImage);if (waitKey(1) >= 0)break;}return 0;
}

其他内容

  • 在线aruco标记生成器:https://chev.me/arucogen/
  • OpenCV识别Aruco markers库:https://docs.opencv.org/4.5.4/d5/dae/tutorial_aruco_detection.html

使用C++ OpenCV实现椭圆区域检测与Aruco码的生成与检测并估计位姿相关推荐

  1. python3 + opencv +pyzbar实时检测二维码 / 定位二维码,并绘制出二维码的框和提取二维码内容

    python3 + opencv +pyzbar实时检测二维码 / 定位二维码,并绘制出二维码的框和提取二维码内容 1 pyzbar二维码检测模块 1.1. pyzbar模块介绍 1.2 pyzbar ...

  2. 基于OpenCV的条形码区域检测(一)

    基于OpenCV的条形码区域检测(一) 1.已有方案  能够很轻松地在网上找到这一篇文章<使用Python和OpenCV检测图片上的条形码_Adrian Rosebrock>,原文:'De ...

  3. Pyhton,OpenCV对象检测之——Haar级联人脸及眼睛检测

    Pyhton,OpenCV对象检测之--Haar级联人脸及眼睛检测 1. 效果图 2. 原理 2.1 Haar人脸检测原理 2.2 Haar级联预训练的模型 3. 源码 3.1 图像面部及眼睛检测 3 ...

  4. opencv学习笔记(二):基于肤色的人手检测

    opencv学习笔记(二):基于肤色的人手检测 原文:http://blog.csdn.net/wzmsltw/article/details/50849810 先写了人手的检测程序,下一步基于检测程 ...

  5. OpenCV之feature2d 模块. 2D特征框架(1)Harris 角点检测子 Shi-Tomasi角点检测子 定制化创建角点检测子 亚像素级的角点检测 特征点检测

    Harris 角点检测子 目标 本教程中我们将涉及: 有哪些特征?它们有什么用? 使用函数 cornerHarris 通过 Harris-Stephens方法检测角点. 理论 有哪些特征? 在计算机视 ...

  6. [转载] OpenCV—Python目标区域图像分割

    参考链接: 使用OpenCV在Python中进行图像处理 使用OpenCV截取目标区域 关于灰度图二值化:https://blog.csdn.net/sinat_21258931/article/de ...

  7. opencv计算指定区域黑白像素占比

    如下在我们拿到二值化的图像之后,想要计算红框内黑白像素在该区域的占比.注意单通道的图像无法出现黑白以外的颜色. 上图为我们拿到的红色区域二值化之后的图像.我们通过遍历该区域所有像素来判断.若值为255 ...

  8. OpenCV 检测二维码并定位

    注意:该程序功能是检测二维码,不是识别,只是在图中定出二维码的位置即可 原图是这样:如果出现这张图片时,程序需要找到二维码 其余图片是这样: 程序步骤: 1.图片缩小 2.灰度化,直方图均衡化,对比度 ...

  9. 利用OpenCV的convexHull和convexityDefects做凸包(凸壳)检测及凸包(凸壳)的缺陷检测

    图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 要理解凸包(凸壳)检测,首无要知道什么是凸包(凸 ...

最新文章

  1. 取余运算怎么算_TensorFlow2.0(2):数学运算
  2. java setdate_java---Set,Date
  3. Go --- 设计模式(工厂模式)
  4. Ubuntu17.10 下配置caffe 仅CPU i386可以直接apt install caffe-cpu,但是怎么运行mnist代码我懵逼了...
  5. 深入理解 PHP7 unset 真的会释放内存吗?
  6. dnf超时空漩涡副本路线流程图_DNF超时空漩涡机制
  7. python爬取json数据_Python爬取数据保存为Json格式的代码示例
  8. 【SAP技术汇】说说SAP那些事儿
  9. 无法定位软件包 docker-ce_自媒体!做自媒体账号需要注意什么?定位很重要
  10. Windows 10 再爆 Bug;罗永浩怼苹果失去灵魂;马化腾回应系 PS | CSDN 极客头条
  11. c语言char aa 1000,char ** 与char * a[ ] 区别
  12. Gps经纬度转化关系
  13. lzg_ad: WES7 技术概览
  14. 计算机usb接口失灵,如何解决电脑USB接口失灵的问题
  15. 菊风携手麦瑞思与Takumi实现中国首个北美运营商Verizon的RCS入库成功案例
  16. 2013网易校园招聘笔试题
  17. 【网络爬虫】实现有道翻译提取
  18. 解决 请求因 HTTP 状态 401 失败: Unauthorized。
  19. Mac小技巧 | 如何在 Touch Bar 上显示歌词
  20. todo---callback

热门文章

  1. C# 使用SMS接口实现手机短信发送功能
  2. opencv中videowriter的使用
  3. HTML 事件参考手册
  4. c语言盐水的故事代码大全,盐水的故事 (Java代码)
  5. 企业中常用的Nginx网站服务相关配置
  6. hdfs回收站的开启
  7. php insert什么意思,PHP insert语法详解
  8. 捐赠10亿美元后,前首富陈天桥的人脑研究出成果了!这一技术成未来AI最大风口…
  9. Ghost恢复后Windows 7无法启动解决
  10. 《系统思考》:先有鸡还是先有蛋?(转)