SLAM学习——使用ARUCO_marker进行AR投影

2023-05-16

一、简介

1.1 目标

增强现实技术(Augmented Reality,简称 AR),是一种实时地计算摄影机影像的位置及角度并加上相应图像、视频、3D模型的技术,这种技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动。

将三维模型投影到ARUCO marker上,并获取投影效果。

1.2 实现思路

  1. 制作并识别ARUCO marker
  2. 估计旋转矩阵和平移矩阵
  3. 获取模型数据,并根据需要进行缩放和坐标调整
  4. 通过projectPoints重投影将三维坐标转换到图像二维坐标
  5. 显示图像

二、ARUCO marker

2.1 简介

ARUCO marker为汉明(海明)码的格子图,如下所示:
在这里插入图片描述

汉明码(Hamming Code)利用奇偶校验位的概念,通过在数据位后面增加一些比特,可以验证数据的有效性。利用一个以上的校验位,汉明码不仅可以验证数据是否有效,还能在数据出错的情况下指明错误位置。

2.2 原理解析

一个ArUco marker是一个二进制平方标记,它由一个宽的黑边和一个内部的二进制矩阵组成,内部的矩阵决定了它们的id。黑色的边界有利于快速检测到图像,二进制编码可以验证id,并且允许错误检测和矫正技术的应用。marker的大小决定了内部矩阵的大小。例如,一个4x4的marker由16bits组成。
在这里插入图片描述

上图为一个典型的ArUco marker,去除白色边框后为5X5的格子(黑色表示0,白色表示1),5X5的格子的外边缘为黑色。

黑白格子遵循下面的排列规则
p d p d p p d p d p p d p d p p d p d p p d p d p \begin{matrix} p & d & p &d &p\\ p & d & p &d &p\\ p & d & p &d &p\\ p & d & p &d &p\\ p & d & p &d &p\\ \end{matrix} pppppdddddpppppdddddppppp

  • p为校验位:1,3,5列
  • d为数据位:2,4列,共10位能表示0-1023的数字

用数字01可表示为下面的排列,去除验位后可获得右侧排列,
0 1 0 0 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 1 0 1 0 0 1 ⇒ 1 0 0 1 0 0 0 1 1 0 \begin{matrix} 0 & 1 & 0 &0 &1\\ 1 & 0 & 1 &1 &1\\ 1 & 0 & 0 &0 &0\\ 1 & 0 & 1 &1 &1\\ 0 & 1 & 0 &0 &1\\ \end{matrix}\Rightarrow \begin{matrix} 1 & 0 \\ 0 & 1 \\ 0 & 0 \\ 0 & 1 \\ 1 & 0 \\ \end{matrix} 01110100010101001010110111000101010
将数据行行首尾相接后可获得该ArUco marker的id为582
1001000110 ⇒ 582 10 01 00 01 10\Rightarrow582 1001000110582

2.3 ARUCO marker的生成

注意:此处采用opencv的aruco库实现,opencv版本需要3以上,此处使用的是OpenCV3.3.1,下同

  1. 函数解析
void cv::aruco::drawMarker(const Ptr< Dictionary > & dictionary,
						   int 	id,
						   int 	sidePixels,
						   OutputArray 	img,
						   int 	borderBits = 1)	
  • dictionary,包含marker对象的字典:

    cv::Ptr dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);

    DICT_6X6_250为6x6的marker,该字典包含id为0-249的marker。

  • id,返回marker的id,需要在设置的字典的范围内。

  • sidePixels,返回图像的像素值。

  • img,输出marker图像。

  • borderBits,marker图像边缘向像素值。

  1. 完整程序
#include <opencv2/aruco.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/highgui.hpp>

#include <fstream>
#include <iostream>
#include <sstream>

using namespace std;
using namespace cv;

void createArucoMarkers() {
  Mat outputMarker;
  int marker_nums = 10;

  // 6x6,id:0~249
  Ptr<aruco::Dictionary> markerDictionary =
      aruco::getPredefinedDictionary(aruco::DICT_6X6_250);

  for (int i = 0; i < marker_nums; i++) {
    // generate
    cv::aruco::drawMarker(markerDictionary, i, 200, outputMarker, 1);

    // save
    ostringstream convent;
    string imageName = "6X6_Marker_";
    convent << "marker/" << imageName << i << ".jpg";
    imwrite(convent.str(), outputMarker);
  }
}

int main(int argc, char *argv[]) {
  createArucoMarkers();
  return 0;
}

三、姿态估计

姿态估计(Pose estimation)在计算机视觉领域扮演着十分重要的角色:机器人导航、增强现实以及其它。这一过程的基础是找到现实世界和图像投影之间的对应点。

最为常用的方法是基于二进制平方的标记,这种Marker的主要便利之处在于,一个Marker提供了足够多的对应(四个角)来获取相机的信息。同样的,内部的二进制编码使得算法非常健壮,允许应用错误检测和校正技术的可能性。

此处的姿态估计采用PnP(Perspective-n-Point)的方法获得Marker相对相机的旋转矩阵和平移矩阵。

PnP(Perspective-n-Point)是求解3D到2D点对运动的方法。它描述了当我们知道n个3D空间点以及它们的投影位置时,如何估计相机所在的位姿。

3.1 关键函数解析

1. 识别Marker

void cv::aruco::detectMarkers(InputArray 	image,
							  Dictionary 	dictionary,
							  OutputArrayOfArrays 	corners,
							  OutputArray 	ids,
							  DetectorParameters 	parameters = DetectorParameters(),
							  OutputArrayOfArrays 	rejectedImgPoints = noArray()
                              InputArray 	cameraMatrix = noArray(),
							  InputArray 	distCoeff = noArray())	
  • image,待检测marker的图像。
  • dictionary,字典对象,为需要识别的marker类型,与生成marker时设置的字典对象一致即可。
  • corners,检测marker获得的包含所有marker四个角点的数组,数据类型为std::vector<std::vector<cv::Point2f> >,若检测到N个marker,则数组大小为Nx4,角点顺序为顺时针,第一个点为左上角。
  • ids,检测marker获得的id,大小与corners一致,只能检测包含在字典内的id。
  • parameters,marker检测所需参数,输入对象类型为 DetectionParameters
  • rejectedCandidates,返回被检测出来但不是有效编码的marker,每个返回的marker同样通过四个角点定义,数据格式与corners一致,该参数可忽略,参用于debug模式和refineDetectedMarkers()
  • cameraMatrix,相机内参数,可省略。
  • distCoeff,相机畸变参数,可省略。

2. 姿态估计

void cv::aruco::estimatePoseSingleMarkers(InputArrayOfArrays 	corners,
										  float 	markerLength,
										  InputArray 	cameraMatrix,
										  InputArray 	distCoeffs,
										  OutputArrayOfArrays 	rvecs,
										  OutputArrayOfArrays 	tvecs)	
  • corners,识别的包含marker的角点的数组,为detectMarkers() 函数中corners参数的返回值。
  • markerLength,marker的边长,单位为米。
  • cameraMatrix,相机内参数,标定获得。
  • distCoeffs,相机畸变参数,标定获得。
  • rvecs,markers相对相机的旋转矩阵。
  • tvecs,markers相对相机的平移矩阵。

markers的坐标系为:矩形中心为坐标原点,红色为X轴,绿色为Y轴,蓝色为Z轴,轴的指向为该轴的正方向。
在这里插入图片描述

3.2 程序实现

  • 姿态估计
bool poseEstimation(Mat image, Vec3d &markerRvec, Vec3d &markerTvec, int detectID) {
  // detect marker
  vector<int> ids;
  vector<vector<Point2f>> corners;
  aruco::detectMarkers(image, dictionary, corners, ids);

  // if at least one marker detected
  if (ids.size() > 0) {
    // estimate Pose
    vector<Vec3d> rvecs, tvecs;
    aruco::estimatePoseSingleMarkers(corners, 0.05, cameraMatrix, distCoeffs,
                                     rvecs, tvecs);

    // screen out designed marker rvecs and tvecs
    for (int i = 0; i < ids.size(); i++) {
      if (ids[i] == detectID) {
        // save pose
        markerRvec = rvecs[i];
        markerTvec = tvecs[i];
        return true;
      } else
        return false;
    }
  } else
    return false;
}

四、显示模型

4.1 模型准备与读入

三维模型采用普林斯顿三维模型库的数据,该数据库的模型为.off格式,程序内部通过fstream读入。读入前需对文件进行修改处理:直接修改.off格式为.txt,同时删除首行的OFF

  • off文件简析

    Object File Format(off)文件通过描述物体表面的多边形来表示一个模型的几何结构

    格式为:

    OFF

    顶点数 面数 边数

    x y z

    x y z

    n个顶点 顶点1的索引 顶点2的索引 … 顶点n的索引

  • 程序实现

  // model data
  vector<Point3f> pointData;
  vector<vector<int>> plantData;
 
  // read model
  fstream modelfile;
  modelfile.open("./marker/m100.txt");
  int pointSize, plantSize, lineSize;
  modelfile >> pointSize;
  modelfile >> plantSize;
  modelfile >> lineSize;

  // point data
  for (int i = 0; i < pointSize; i++) {
    Point3f pointTmp;
    modelfile >> pointTmp.x;
    modelfile >> pointTmp.y;
    modelfile >> pointTmp.z;

    // resize model
    pointTmp.x = pointTmp.x / 0.5 * markerLength - (markerLength / 2.0);
    pointTmp.y = pointTmp.y / 0.5 * markerLength - (markerLength / 2.0);
    pointTmp.z = pointTmp.z / 0.5 * markerLength - (markerLength / 2.0);
    pointData.push_back(pointTmp);
  }

  // plant data
  for (int i = 0; i < plantSize; i++) {
    vector<int> plantTmp;
    for (int j = 0; j < 4; j++) {
      int data;
      modelfile >> data;
      plantTmp.push_back(data);
    }
    plantData.push_back(plantTmp);
  }

4.2 重投影

projectPoints()可根据所给的三维坐标和已知的相机内外参数求解投影到图像坐标系上的二维坐标。

void projectPoints(InputArray objectPoints, 
                   InputArray rvec, 
                   InputArray tvec, 
                   InputArray cameraMatrix, 
                   InputArray distCoeffs, 
                   OutputArray imagePoints, 
                   OutputArray jacobian=noArray(), 
                   double aspectRatio=0 )
  • objectPoints,三维坐标数组。
  • rvec,旋转向量,通过estimatePoseSingleMarkers获得。
  • tvec,平移向量,通过estimatePoseSingleMarkers获得。
  • cameraMatrix,相机内参数。
  • distCoeffs,相机畸变参数。
  • imagePoints,返回图像坐标数组。
  • jacobian,雅克比行列式,
  • aspectRatio,相机传感器的感光单元有关的可选参数,如果设置为非0,则函数默认感光单元的dx/dy是固定的,会依此对雅可比矩阵进行调整。

4.3 绘制模型

4.3.1 绘制函数解析

1. 绘制坐标

void cv::aruco::drawAxis(InputOutputArray 	image,
						 InputArray 	cameraMatrix,
						 InputArray 	distCoeffs,
						 InputArray 	rvec,
						 InputArray 	tvec,
						 float 	length)	
  • image ,是输入/输出图像,坐标将会绘制在该图像上(通常就是检测marker的那张图像)。

  • cameraMatrix,相机内参数,标定获得。

  • distCoeffs ,相机畸变参数,标定获得。

  • rvec ,外参数,旋转向量。

  • tvec ,外参数,平移向量。

  • length,坐标轴的长度,单位为米。

2. 绘制轮廓

void drawContours(InputOutputArray image, 
                  InputArrayOfArrays contours, 
                  int contourIdx, 
                  const Scalar& color, 
                  int thickness=1, 
                  int lineType=LINE_8, 
                  InputArray hierarchy=noArray(), 
                  int maxLevel=INT_MAX, 
                  Point offset=Point() )

3. 绘制线

void line(InputOutputArray img, 
          Point pt1, 
          Point pt2, 
          const Scalar& color, 
          int thickness=1, 
          int lineType=LINE_8, 
          int shift=0 )

4. 绘制点

void circle(InputOutputArray img, 
            Point center, 
            int radius, 
            const Scalar& color, 
            int thickness=1, 
            int lineType=LINE_8, 
            int shift=0 )

4.3.2 程序实现

#include <opencv2/aruco.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>

#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>

#include <cv_bridge/cv_bridge.h>
#include <ros/ros.h>
#include <sensor_msgs/Image.h>

using namespace std;
using namespace cv;

#define markerLength 0.05 // ar码实际边长,单位m
#define modelSize 1       //模型大小0-1

ros::Publisher image_pub;

// init data
Mat cameraMatrix, distCoeffs;
Ptr<cv::aruco::Dictionary> dictionary =
    cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250);

// model data
vector<Point3f> pointData;
vector<vector<int>> plantData;

// 绘制模型
Mat drawModel(Mat image, Vec3d rvec, Vec3d tvec, vector<Point3f> modelPoints,
              vector<vector<int>> modelPlants, bool judge) {
  Mat showImage;
  cvtColor(image, showImage, CV_GRAY2BGR);

  if (judge) {
    // draw axis
    aruco::drawAxis(showImage, cameraMatrix, distCoeffs, rvec, tvec, 0.05);

    // draw model
    // projectPoints
    std::vector<cv::Point2f> imagePoints;
    projectPoints(modelPoints, rvec, tvec, cameraMatrix, distCoeffs,
                  imagePoints);

    // draw plant
    vector<vector<Point>> plantPoints(modelPlants.size());
    vector<Point> tmpPoints(3);
    for (int i = 0; i < modelPlants.size(); i++) {
      tmpPoints[0] = imagePoints[modelPlants[i][1]];
      tmpPoints[1] = imagePoints[modelPlants[i][2]];
      tmpPoints[2] = imagePoints[modelPlants[i][3]];
      plantPoints[i] = tmpPoints;
    }
    for (int i = 0; i < plantPoints.size(); i++) {
      drawContours(showImage, plantPoints, i, Scalar(203, 192, 255), FILLED);
    }

    // draw line
    for (int i = 0; i < modelPlants.size(); i++) {
      line(showImage, imagePoints[modelPlants[i][1]],
           imagePoints[modelPlants[i][2]], Scalar(0, 0, 0), 1);
      line(showImage, imagePoints[modelPlants[i][2]],
           imagePoints[modelPlants[i][3]], Scalar(0, 0, 0), 1);
      line(showImage, imagePoints[modelPlants[i][3]],
           imagePoints[modelPlants[i][1]], Scalar(0, 0, 0), 1);
    }

    // draw point
    for (int i = 0; i < imagePoints.size(); i++) {
      circle(showImage, imagePoints[i], 1, Scalar(0, 0, 0), 1);
    }
  }
  return showImage;
}

// 状态估计
bool poseEstimation(Mat image, Vec3d &markerRvec, Vec3d &markerTvec) {
  Mat imageCopy = image.clone();

  // detect marker
  vector<int> ids;
  vector<vector<Point2f>> corners;
  aruco::detectMarkers(imageCopy, dictionary, corners, ids);

  // if at least one marker detected
  if (ids.size() > 0) {
    // aruco::drawDetectedMarkers(showImage, corners, ids);
    vector<Vec3d> rvecs, tvecs;
    aruco::estimatePoseSingleMarkers(corners, 0.05, cameraMatrix, distCoeffs,
                                     rvecs, tvecs);

    // screen out designed marker rvecs and tvecs
    for (int i = 0; i < ids.size(); i++) {
      if (ids[i] == 2) {
        markerRvec = rvecs[i];
        markerTvec = tvecs[i];
        return true;
      } else
        return false;
    }
  } else
    return false;
}

// 回调函数
void imageCb(const sensor_msgs::ImageConstPtr &msg) {
  // get image
  cv_bridge::CvImagePtr cv_ptr =
      cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::MONO8);
  Mat cameraImage = cv_ptr->image;

  // estimate pose
   Vec3d markerRvec, markerTvec;
   bool judge = poseEstimation(cameraImage, markerRvec, markerTvec);

  // draw model
   Mat showImage = drawModel(cameraImage, markerRvec, markerTvec, pointData,
                            plantData, judge);

  // pub result
  cv_bridge::CvImage out_msg;
  out_msg.encoding = sensor_msgs::image_encodings::BGR8;
  out_msg.image = showImage;
  image_pub.publish(out_msg.toImageMsg());
}

int main(int argc, char *argv[]) {
  // init ros
  ros::init(argc, argv, "aruco");
  ros::NodeHandle nh;
  ros::Subscriber image_sub =
      nh.subscribe<sensor_msgs::Image>("/camera/image", 1, imageCb);
  image_pub = nh.advertise<sensor_msgs::Image>("/camera/aruco", 1);

  // init parms
  vector<double> cameraMatrixData, distCoeffsData;
  ros::param::get("/camera_matrix/data", cameraMatrixData);
  ros::param::get("/distortion_coefficients/data", distCoeffsData);

  Mat cameraMatrixTmp =
      (Mat_<double>(3, 3) << cameraMatrixData[0], cameraMatrixData[1],
       cameraMatrixData[2], cameraMatrixData[3], cameraMatrixData[4],
       cameraMatrixData[5], cameraMatrixData[6], cameraMatrixData[7],
       cameraMatrixData[8]);
  cameraMatrix = cameraMatrixTmp;

  Mat distCoeffsTmp =
      (Mat_<double>(1, 5) << distCoeffsData[0], distCoeffsData[1],
       distCoeffsData[2], distCoeffsData[3], distCoeffsData[4]);
  distCoeffs = distCoeffsTmp;

  // read model
  fstream modelfile;
  modelfile.open("./marker/m100.txt");
  int pointSize, plantSize, lineSize;
  modelfile >> pointSize;
  modelfile >> plantSize;
  modelfile >> lineSize;

  for (int i = 0; i < pointSize; i++) {
    Point3f pointTmp;
    modelfile >> pointTmp.x;
    modelfile >> pointTmp.y;
    modelfile >> pointTmp.z;

    // resize model
    pointTmp.x = pointTmp.x / 0.5 * markerLength - (markerLength / 2.0);
    pointTmp.y = pointTmp.y / 0.5 * markerLength - (markerLength / 2.0);
    pointTmp.z = pointTmp.z / 0.5 * markerLength - (markerLength / 2.0);
    pointData.push_back(pointTmp);
  }

  for (int i = 0; i < plantSize; i++) {
    vector<int> plantTmp;
    for (int j = 0; j < 4; j++) {
      int data;
      modelfile >> data;
      plantTmp.push_back(data);
    }
    plantData.push_back(plantTmp);
  }

  ros::spin();
  return 0;
}

4.4 实现效果

在这里插入图片描述

在这里插入图片描述

参考

  • aruco

    ARUCO marker的解释

    [OpenCV] aruco Markers识别

    tutorial_aruco_detection

  • 程序参考

    https://github.com/fdcl-gwu/aruco-markers

    https://github.com/jeradesign/ar-challenge

  • 原理参考

    《视觉SLAM十四讲》——第7讲 视觉里程计1

  • 模型数据

    off文件格式(Object File Format)

    常见的三维点云数据下载链接

    普林斯顿三维模型库

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SLAM学习——使用ARUCO_marker进行AR投影 的相关文章

  • LeGO-LOAM论文翻译(内容精简)

    LeGO LOAM是一种在LOAM之上进行改进的激光雷达建图方法 建图效果比LOAM要好 但是建图较为稀疏 计算量也更小了 本文原地址 wykxwyc的博客 github注释后LeGO LOAM源码 LeGO LOAM NOTED 关于代码
  • 深度相机Kinect2.0三维点云拼接实验(一)

    文章目录 摘要 Kinect2 0简介 工作原理 RGB相机成像原理 深度相机成像原理 总结 参考文献 摘要 Kinect2 0是微软推出的一款RGB D相机 它即支持普通相机的拍摄 也支持脉冲测量深度信息 本系列文章基于该传感器给出基本的
  • vscode配置eigen3

    目录 1 头文件包含 2 c cpp properties json 3 CMakeList txt 4 完整代码 1 头文件包含 Eigen 核心部分 include
  • 图像匹配算法

    图像匹配算法分为3类 基于灰度的匹配算法 基于特征的匹配算法 基于关系的匹配算法 1 基于灰度的模板匹配算法 模板匹配 Blocking Matching 是根据已知模板图像到另一幅图像中寻找与模板图像相似的子图像 基于灰度的匹配算法也称作
  • PnP 问题

    欢迎访问我的博客首页 PnP 问题 1 DLT 2 P3P 3 G2O 求解 PnP 3 1 单目 3 2 双目 4 自定义顶点与边优化内参 4 1 二元边 4 2 三元边 4 3 总结 5 参考 PnP Perspective n Poi
  • SLAM--三角测量SVD分解法、最小二乘法及R t矩阵的判断

    目录 一 三角测量 方法一 SVD分解法的推导 方法二 最小二乘法求解 二 ORB SLAM2 三角测量源码 三 利用Eigen源码实现三角测量 方法一 SVD分解法 方法二 最小二乘法求解 速度最快 方法三 利用OpenCV自带函数 四
  • 快看!那个学vSLAM的上吊了! —— (一)综述

    不同于之前发布的文章 我将使用一种全新的方式 iPad Notability Blog的方式打开这个板块的大门 原因有两个 1 Notability更方便手写长公式 也方便手绘坐标系变换等等 2 之前Apple Pencil找不到了新破费买
  • Ubuntu18.04安装pcl(过程/坑记录式教程)

    Ubuntu18 04安装pcl 1 下载pcl 2 安装依赖项 3 编译 4 安装 5 网上教程说要安装QT5和VTK 但按照本文的 本文记录了安装时出现的问题 出错的安装命令也记录了 建议浏览一遍再参考 不要错用了错误的指令 1 下载p
  • Object SLAM: An Object SLAM Framework for Association, Mapping, and High-Level Tasks 论文解读

    是一篇来自机器人顶刊T RO的文章 发表于2023 5 An Object SLAM Framework for Association Mapping and High Level Tasks 论文 An Object SLAM Fram
  • BLAM跑自己的数据包无法显示全局点云地图解决(速腾聚创RS-LiDAR-16 雷达 )-SLAM不学无术小问题

    BLAM算法跑自己的数据包无法显示全局点云地图解决 适配速腾聚创RS LiDAR 16 雷达 提示 本文笔者使用环境Ubuntu18 04 ROS melodic版本 首先放一个效果链接 由b站up VladimirDuan上传 非官方 官
  • 视觉SLAM漫谈

    视觉SLAM漫谈 1 前言 开始做SLAM 机器人同时定位与建图 研究已经近一年了 从一年级开始对这个方向产生兴趣 到现在为止 也算是对这个领域有了大致的了解 然而越了解 越觉得这个方向难度很大 总体来讲有以下几个原因 入门资料很少 虽然国
  • ORB_SLAM2运行官方数据集/自己数据集

    官方数据集运行结果 WeChat 20230210194425 可以正常运行 自己数据集运行结果 自己的数据集 主要是用手机摄像头采集的实验室进行了一下简单的运行 可以成功运行 但是由于查看的相关程序的是死循环不能像运行官方数据集那样完整保
  • 如何使传单中的标记闪烁

    有没有一种简单的方法可以使传单地图中的标记闪烁 我的意思是动画闪烁 类似于 1 秒内从不透明度 1 0 过渡到不透明度 0 5 的循环 然后反转 循环结束 当您添加一个Marker你可以指定一个Icon 选项包括className 你可以用
  • Android - 地图标记绕 X 轴和 Y 轴的动画旋转

    我想知道是否可以为 Google 地图标记沿 x 轴和 y 轴旋转设置动画 就像我们如何使用 ObjectAnimator 围绕 x 轴和 或 y 轴旋转 ImageView 一样 显然 人们可以顺时针旋转 改变 标记的方向 即沿着 z 轴
  • 当我们旋转手机时如何旋转 googlemap v2 中的箭头

    有人可以帮助我如何旋转谷歌地图 v2 中的箭头吗 您已经看到 在导航中 箭头旋转到我们面对的方向 我想将其实现到我的应用程序中 我红了关于markerOption rotation rotation 这似乎是静态的 我想在旋转手机时动态旋转
  • 高翔博士Faster-LIO论文和算法解析

    说明 题目 Faster LIO 快速激光IMU里程计 参考链接 Faster LIO 快速激光IMU里程计 iVox Faster Lio 智行者高博团队开源的增量式稀疏体素结构 Faster Lio是高翔博士在Fast系列的新作 对标基
  • 发布了未知的位图参考 - 在 android 中设置标记

    CODE Update marker position and icon private void setMarker synchronized OBJ LOCK if mLatitude 0 0 mLongitude 0 0 mRotat
  • 如何使用 OpenCV Viz 和 ARUCO 转换增强现实应用的 3D 模型

    我正在开发一个简单的基于标记的增强现实应用程序OpenCV 可视化 and ARUCO 我只想在标记上可视化 3D 对象 PLY 格式 我可以使用 ARUCO 毫无问题地运行标记检测和姿态估计 返回旋转和平移向量 我可以在 Viz 窗口中可
  • JS Maps v3:带有用户个人资料图片的自定义标记

    两天以来 我一直在努力解决一些我认为很简单的事情 在地图上 我必须为每个用户显示一个标记 其中包含用户 FB 个人资料图片 我想知道如何才能得到与此类似的结果 我所尝试的确实很hackish 我把FB图片作为标记图标 我在标记的标签上放置了
  • Aruco 标记与 openCv,获取 3d 角坐标?

    我正在使用 opencv 3 2 检测打印的 Aruco 标记 aruco estimatePoseSingleMarkers corners markerLength camMatrix distCoeffs rvecs tvecs 这将

随机推荐

  • 深入了解C语言和C++哪个更难?

    众所周知C语言与C 43 43 都是主流的开发语言 xff0c 并且在大多数人看来C语言的学习难度要更难 xff0c 那事实是怎么样的呢 xff1f 接下来小编带你深入了解下C语言和C 43 43 哪个更难 xff1a 深入了解C语言和C
  • ffmpeg分析 之 如何解析mpegts流

    转 xff1a http blog chinaunix net uid 20364597 id 3530284 html ffmpeg分析 之 如何解析mpegts流 2013 03 19 11 02 40 分类 xff1a LINUX 数
  • 使用input上传图片并本地预览

    话不多说上代码 span class token operator lt span div id span class token operator 61 span span class token string 34 app 34 spa
  • 1、【STM32】学习初探(方法及准备)

    前言 由于个人原因已经有好长时间没搞了 xff0c 最近工作需要 xff0c 但是拿起32基本上都忘记差不多了 xff0c 接下来一段时间将急中学习一下STM32的基础知识 以前是学习的库函数版本 xff0c 有一定的基础 xff0c 因此
  • Pixhawk入门指南-目录

    文章转载自 xff1a http www ncnynl com archives 201701 1271 html APM PX4 Pixhawk入门指南 目录 介绍 xff1a APM xff08 ArduPilotMega xff09
  • 初学PX4之环境搭建

    文章转自 xff1a http www jianshu com p 36dac548106b 前言 前段时间linux崩溃了 xff0c 桌面进去后只有背景 xff0c 折腾好久没搞定 xff0c 为了节省时间索性重装了系统 xff0c 同
  • C++构造函数后面的冒号

    构造函数后加冒号是初始化表达式 xff1a 有四种情况下应该使用初始化表达式来初始化成员 xff1a 1 xff1a 初始化const成员 2 xff1a 初始化引用成员 3 xff1a 当调用基类的构造函数 xff0c 而它拥有一组参数时
  • 01python画的玫瑰

    刚开始学习python xff0c 还处于菜鸟阶段 xff0c 这段时间学习了turtle库 xff0c 纯手工画了一朵玫瑰 xff0c 拿出来与大家分享 xff01 源码地址 xff1a https github com YinZhong
  • 02turtle模块常用函数

    turtle模块函数
  • 04主存储器、BIOS和CMOS存储器

    主存储器 BIOS和CMOS存储器 一 PC AT机内存使用图 二 ROM BIOS 存放在ROM中的系统BIOS程序主要用于计算机开机时执行系统各部分的自检 xff0c 建立系统需要使用的各种配置表 xff0c 例如中断向量表 硬盘参数表
  • 06异常处理

    python的异常处理 python使用try except xff0c 可使程序不因为运行错误而崩溃 结构如下 xff1a try span class hljs tag lt span class hljs title body spa
  • 07turtle库的进阶使用

    turtle库的进阶使用 turtle库以屏幕中心为绘制原点利用代码绘制一棵树 span class hljs keyword import span turtle span class hljs string 34 34 34 plist
  • 结束,也是开始

    结束 xff0c 也是开始 序言 看到CSDN征文要求 xff0c 感觉非常适合自己 四年前的自己正在参加高考 xff0c 转眼四年过去了 xff0c 自己也即将步入社会 xff0c 四年的大学生活感慨颇多 xff0c 谨以此文作为自己的阶
  • 01策略模式

    策略模式 最近在看 Head First设计模式 这本书 xff0c 最大的感触就是 xff0c 原来写代码也是有 套路 的 xff0c 刚学了策略模式 xff0c 用C 43 43 实现了一下 xff0c 做个笔记 xff0c 备忘 xf
  • 1、STM32CubeMX和STM32Cube库(HAL)详细介绍

    目录 前言 STM32Cube生态 STM32Cube 是什么 xff1f STM32Cube 软件工具套件 STM32Cube Embedded 软件 STM32CubeMX 编辑 前言 也许大家在学习正点原子或者其他32视频和代码的时候
  • 安卓SATA自动挂载实例

    平台 xff1a IMX6 OS 安卓4 2和安卓4 4 查看挂载log信息 xff1a logcat s Vold MountService 手动挂载 xff1a mount t ntfs dev block mnt mount t v
  • linux驱动开发 - 12_platform 平台驱动模型

    文章目录 platform 平台驱动模型1 platform 总线platform匹配过程 2 platform 驱动platform 驱动框架如下所示 xff1a 3 platform 设备platform 设备信息框架如下所示 xff1
  • 多旋翼飞行器设计与控制(二):基本组成

    一 前言核心问题 二 总体介绍多旋翼系统内部布局 三 机架机身起落架涵道 四 动力系统概述螺旋桨电机电调电池 五 指挥控制系统遥控器和接收器自动驾驶仪地面站数传 一 前言 核心问题 xff08 1 xff09 多旋翼组成结构 机架动力系统控
  • 多旋翼飞行器设计与控制(三):机架设计

    一 布局设计机身基本布局旋翼的安装旋翼和机体半径 xff1a 尺寸和机动性关系 xff1a 重心位置 xff1a 自驾仪安装位置 xff1a 气动布局 xff1a 二 结构设计机体基本设计原则减振设计减噪设计 一 布局设计 机身基本布局 交
  • SLAM学习——使用ARUCO_marker进行AR投影

    一 简介 1 1 目标 增强现实技术 xff08 Augmented Reality xff0c 简称 AR xff09 xff0c 是一种实时地计算摄影机影像的位置及角度并加上相应图像 视频 3D模型的技术 xff0c 这种技术的目标是在