【RoboMaster】我是这样搞定第一次单目相机测距的

2023-05-16

之前在做一个单目测距的小项目,大概需要就是用单目相机,对一个特定的目标进行识别并测算相机与该目标的距离。所以便去网上找了一堆教程,这里给大家总结一下,希望给小白们一个参考。
首先是基本需求了:

  • opencv自然要会的,这咱就不多说了,会一点就行
  • 需要一个摄像头,我用的是一个畸变很大的鱼眼免驱动摄像头,大家用电脑上的那个自带摄像头也可以的,就是不方便。
  • 需要MATLAB进行相机标定
  • 需要一个编程环境,我的是VS2017,至于VS怎么配置opencv,可以参看CSDN博文《VS2017配置Opencv4.10教程》:
    https://blog.csdn.net/qq_43667130/article/details/104127798

其实上面都是废话,下面进入正题吧。
网上的方法大概有两种,这里主要介绍一个我身边的大哥们都称做PnP问题的一个方法,但会另外简单介绍两个比较简单粗暴的,原理可行但其实效果不佳的方法。

相机畸变矫正

在用相机进行单目测距时,需要用到一个叫相机内参的东西,而这需要靠相机标定来得到。这些大概要从相机模型说起了:
相机模型是每个学opencv的同学早晚的要接触到的吧!
我们高中都做过小孔成像的实验,小孔相机模型就是最简单通用的一种相机模型,这个模型我们就用下面一个图带过好了:
在这里插入图片描述
其中f为我们熟知的相机参数——焦距,而光轴与成像平面的交点称为主点,X表示箭头长度,Z是相机到箭头的距离。在上图这个简单且理想的小孔成像"相机"中,我们可以轻松的写出黄色箭头在现实世界坐标系与成像平面坐标系之间的转换关系:
在这里插入图片描述
但是在实际相机中,成像平面就是相机感光芯片,针孔就是透镜,然而主点却并不再在成像平面的中心了(也就是透镜光轴与感光芯片中心并不在一条线上了),因为在实际制作中我们是无法做到将相机里面的成像装置以微米级别的精度进行安装的,因此我们需要引入两个新的参数Cx和Cy,来对我们硬件的偏移进行矫正:
在这里插入图片描述
上式中我们引入了两个不同的焦距fx和fy,这是因为单个像素在低价成像装置上是矩形而不是正方形。其中,fx是透镜的物理焦距长度与成像装置的每个单元尺寸Sx的乘积。
通过上式我们可以知道相机内参的四个参数了,分别是fx,fy,Cx,Cy。但在计算中,我们常通过一些数学技巧来进行一定的变换,从而得到下式:
在这里插入图片描述
其中:
在这里插入图片描述
通过上面的式子,我们可以将空间中的点和图片中的点一一对应起来。式中的矩阵M就是我们常听说的相机内参矩阵了。

相机外参

而有相机内参,就有相机外参了,相机外参来源于相机自身的畸变,畸变可以分为径向畸变(有透镜的形状造成)和切向畸变(由整个相机自身的安装过程造成)。
在这里插入图片描述
镜像畸变是由凸透镜本身形状引起的,好的透镜,经过一些精密处理,畸变并不明显,但在普通网络相机上畸变显得特别突出。我们可以把畸变看作r=0附近的泰勒奇数展开的前几项来便是。一般为前两项 k1 , k2,对于鱼眼透镜 ,会用前三项 k3 。成像装置上某点的径向位置可以根据以下等式进行调整,这时我们便有了3个或2个的未知变量:
这里(x,y)是成像装置上畸变点的原始位置,(Xcorrected,Ycorrected)是矫正后的新位置。
在这里插入图片描述
切向畸变是由于制造上的缺陷使透镜不与成像平面平行而产生的。切向畸变可以用两个参数p1 和 p2 来表示:
在这里插入图片描述
在这里插入图片描述
至此,我们得到了共五个参数:K1 K2 K3 P1 P2 ,这五个参数是我们消除畸变所必须的,称为畸变向量,也叫相机外参。

相机标定

在上文,相机内参加上相机外参一共有至少8个参数,而我们要想消除相机的畸变,就要靠相机标定来求解这8个未知参数。

说完相机模型,又要说一下相机标定了,相机标定是为了求解上面这8个参数的,那求解出这8个参数可以干什么呢?可以进行软件消除畸变,也就是在得知上面8个参数后,利用上面罗列的数学计算式,将每个偏移的像素点归位。

标定需要用到一个叫标定板的东西,有很多种类,但常用的大概就是棋盘图了,棋盘要求精度需要很高,格子是正方形,买一张标定板很贵的,在csdn上下棋盘图也要画好多c币,所以大家可以用word画一张,很简单的,只要做一个5列7行的表格,拉大到全页,再设置每个格子的宽高来将它设为正方形再涂色就可以了。这张图里有符号,但打印出来就没有了,建议大家自己画一张就OK了。
在这里插入图片描述
标定过程是用MATLAB进行的,过程就不在这里说了,CSDN上的教程一抓一大把,在完成标定后MATLAB会返回相机的内参和外参。关于原理,《学习oepncv3》这本书已经说的很好了,除了照着书抄我说不出什么新意,但今天,原理不懂也没有关系。

有了相机内参外参后,我们就可以进行相机消畸变了:

#include <opencv2/opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <iostream>
#include <stdio.h>using namespace std;
using namespace cv;const int imageWidth = 640; //定义图片大小,即摄像头的分辨率  
const int imageHeight = 480;
Size imageSize = Size(imageWidth, imageHeight);
Mat mapx, mapy;
// 相机内参
Mat cameraMatrix = (Mat_<double>(3, 3) << 273.4985, 0, 321.2298,
0, 273.3338, 239.7912,
0, 0, 1);
// 相机外参
Mat distCoeff = (Mat_<double>(1, 4) << -0.3551, 0.1386,0, 0);
Mat R = Mat::eye(3, 3, CV_32F);
​
VideoCapture cap1; //打开摄像头void img_init(void)  //初始化摄像头
{
  cap1.set(CAP_PROP_FOURCC, 'GPJM');
  cap1.set(CAP_PROP_FRAME_WIDTH, imageWidth);
  cap1.set(CAP_PROP_FRAME_HEIGHT, imageHeight);
}int main()
{
  initUndistortRectifyMap(cameraMatrix, distCoeff, R, cameraMatrix, imageSize, CV_32FC1, mapx, mapy);
  Mat frame;
  img_init();
while (1)
  {
    cap1>>frame;
    imshow("原鱼眼摄像头图像",frame);
    remap(frame,frame,mapx,mapy, INTER_LINEAR);
    imshow("消畸变后",frame);
    waitKey(30);
  }
return 0;
}

上面源码中我们在32行和39行有两个函数,就是opencv提供给我们进行消畸变的函数。
使用cv::initUndistortRecitifyMap()函数计算矫正映射,函数原型如下:

initUndistortRectifyMap(
InputArray  cameraMaxtrix,    3*3内参矩阵 
InputArray  distCoeffs,       畸变系数1*4向量
InputArray  R,           可以使用或者设置为noArray()。是一个旋转矩阵,将在矫正前
预先使用,来补偿相机相对于相机所处的全局坐标系的旋转。
InputArray  newCameraMatrix,  单目成像时一般不会使用它
Size    size,           输出映射的尺寸,对应于用来矫正的图像的尺寸
int      m1type,        最终的映射类型,可能只为CV_32FC1  32_16SC2,对应于map1的表示类型
OutputArray  map1,        
OutputArray  map2
);

我们只需在程序开头使用该函数计算一次矫正映射,就可以使用cv::remap()函数将该矫正应用到视频每一帧图像。
在这里插入图片描述

PnP方法测距

好了到此我们对相机的那点事儿有了一点点的了解了,那什么是PnP问题呢?在有些情况下我们已经知道了相机的内在参数,因此只需要计算正在观察的对象的位置,这种情况下与一般的相机标定明显不同,但有相通之处。这种操作就叫N点透视(Perspective N-Point)或PnP问题。

bool cv::solvePnP(
  cv::InputArray  objectPoints,     //三维点坐标矩阵,至少四个(世界坐标系)
  cv::InputArray  imagePoints,      //该四个点在图像中的像素坐标
  cv::InputArray  cameraMatrix,     //相机内参矩阵(9*9)
  cv::InputArray  distCoeffs,       //相机外参矩阵(1*4)或(1*5)
  cv::OutputArray rvec,             //输出旋转矩阵
  cv::OutputArray tvec,             //输出平移矩阵
  bool        useExtrinsicGuess = false,  
  int        flags = cv::SOLVEPNP_ITERATIVE
);

首先来解释一下该函数的输出是什么吧,

旋转矩阵就是一个3*1的向量,该矩阵可以表示相机相对于世界坐标系XYZ轴的3个旋转角度。

平移矩阵也是一个3维向量,可以表示相机相对于物体的XYZ轴的偏移,而这个矩阵就是我们需要求的:我们知道了相机相对于物体的位置,也就得到了距离,从而实现了测距的目的。

那输入的参数都是什么呢?相机内参和相机外参就不用说了吧。

第一个参数,是物体任意四个点在世界坐标系的三位点坐标,为什么是四个其实很好理解,我们需要求解的是一个旋转矩阵和XYZ轴偏移量,一共四个未知量,需要至少列四个式子才可以求解。

更详细的解释大家可以看一下这篇CSDN:

https://blog.csdn.net/cocoaqin/article/details/77841261

第二个参数,我们在第一个参数中任意找的物体上的四个点在图像中的像素坐标。

现在就很清楚明白了吧?通过旋转向量和平移向量就可以得到相机坐标系相对于世界坐标系的旋转参数与平移情况。

不过我们还要解决一个问题,如何确保这四个点的位置呢?就是,例如物体是一个正方形板子,板子长为2L,我可以选板子中心作为世界坐标系的中心,那么我可以得到板子四个角上的坐标分别为(L,L),(L,-L),(-L,L),(-L,-L)。但如何确定图像上哪四个点是板子的四个角呢?你就需要把板子识别出来。但如果不是个板子是个人呢?你怎么把人分出来?这就需要更复杂的东西了,什么语义分割啊分类器啊啥的,这里就不多说了。

那我不取板子的四个角,利用角点检测任意取四个点也可以,这就解决了世界坐标系与像素坐标系之间的对应问题,但又有一个新问题,如何确保这四个角点是物体身上的而不是背景上的呢?还是要把正方形识别出来。。。

所以说这么多,我们便引入了二维码,我们可以直接识别二维码来测距,这儿就要用到一个叫ZBar库的东西了,它是一个可以识别二维码或条形码的函数库,具体的自行百度吧。那我们还需要学一个新库?opencv库都还没学明白呢,又要学一个识别二维码的?其实不需要,这个库的两个例程已经可以满足我们的需要了:

例程一:

#include <zbar.h>
#include <opencv2\opencv.hpp>
#include <iostream>int main(int argc, char*argv[])
{
  zbar::ImageScanner scanner;
  scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);
  cv::VideoCapture capture;
  capture.open(0);  //打开摄像头
  cv::Mat image;
  cv::Mat imageGray;
std::vector<cv::Point2f> obj_location;
bool flag = true;if (!capture.isOpened())
  {
std::cout << "cannot open cam!" << std::endl;
  }
else
  {
while (flag)
    {
      capture >> image;
      cv::cvtColor(image, imageGray, CV_RGB2GRAY);
int width = imageGray.cols;
int height = imageGray.rows;
      uchar *raw = (uchar *)imageGray.data;
      zbar::Image imageZbar(width, height, "Y800", raw, width * height);
      scanner.scan(imageZbar);  //扫描条码
      zbar::Image::SymbolIterator symbol = imageZbar.symbol_begin();
if (imageZbar.symbol_begin() != imageZbar.symbol_end())  //如果扫描到二维码
      {
        flag = false;
//解析二维码
for (int i = 0; i < symbol->get_location_size(); i++)
        {
          obj_location.push_back(cv::Point(symbol->get_location_x(i), symbol->get_location_y(i)));
        }
for (int i = 0; i < obj_location.size(); i++)
        {
          cv::line(image, obj_location[i], obj_location[(i + 1) % obj_location.size()], cv::Scalar(255, 0, 0), 3);//定位条码
        }
for (; symbol != imageZbar.symbol_end(); ++symbol)
        {
std::cout << "Code Type: " << std::endl << symbol->get_type_name() << std::endl; //获取条码类型
std::cout << "Decode Result: " << std::endl << symbol->get_data() << std::endl;  //解码
        }
        imageZbar.set_data(NULL, 0);
      }
      cv::imshow("Result", image);
      cv::waitKey(50);
    }
    cv::waitKey();
  }
return 0;
}

这个函数可以实现打开摄像头,并识别看到的二维码,进而打印二维码的类型和内容:
在这里插入图片描述
所以这个ZBar库需要怎么配置到我们的VS2017上并和opencv库一起使用呢?大家可以参看我的CSDN博文:
《Win10+VS2017+opencv410+ZBar库完美配置》
例程二:

#include <opencv2/opencv.hpp>
#include <zbar.h>using namespace cv;
using namespace std;
using namespace zbar;typedef struct
{
string type;
string data;
vector <Point> location;
} decodedObject;// Find and decode barcodes and QR codes
void decode(Mat &im, vector<decodedObject>&decodedObjects)
{// Create zbar scanner
  ImageScanner scanner;// Configure scanner
  scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);// Convert image to grayscale
  Mat imGray;
  cvtColor(im, imGray,COLOR_BGR2GRAY);// Wrap image data in a zbar image
Image image(im.cols, im.rows, "Y800", (uchar *)imGray.data, im.cols * im.rows);// Scan the image for barcodes and QRCodes
int n = scanner.scan(image);// Print results
for(Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end(); ++symbol)
  {
    decodedObject obj;
​
    obj.type = symbol->get_type_name();
    obj.data = symbol->get_data();// Print type and data
cout << "Type : " << obj.type << endl;
cout << "Data : " << obj.data << endl << endl;// Obtain location
for(int i = 0; i< symbol->get_location_size(); i++)
    {
      obj.location.push_back(Point(symbol->get_location_x(i),symbol->get_location_y(i)));
    }
​
    decodedObjects.push_back(obj);
  }
}// Display barcode and QR code location  
void display(Mat &im, vector<decodedObject>&decodedObjects)
{
// Loop over all decoded objects
for(int i = 0; i < decodedObjects.size(); i++)
  {
vector<Point> points = decodedObjects[i].location;
vector<Point> hull;// If the points do not form a quad, find convex hull
if(points.size() > 4)
      convexHull(points, hull);
else
      hull = points;// Number of points in the convex hull
int n = hull.size();for(int j = 0; j < n; j++)
    {
      line(im, hull[j], hull[ (j+1) % n], Scalar(255,0,0), 3);
    }}// Display results 
  imshow("Results", im);
  waitKey(0);}int main(int argc, char* argv[])
{// Read image
  Mat im = imread("zbar-test.jpg");// Variable for decoded objects 
vector<decodedObject> decodedObjects;// Find and decode barcodes and QR codes
  decode(im, decodedObjects);// Display location 
  display(im, decodedObjects);return EXIT_SUCCESS;
}

该例程可以在实现例程一的功能的基础上,还可以识别出二维码的位置。

代码实现

下面,如何实现测距代码编写呢?我们需要在上面例程二这个代码的基础上,加上相机畸变矫正的代码,还要加上一段PnP函数求解的代码:

vector<Point3f> obj = vector<Point3f>{
        cv::Point3f(-HALF_LENGTH, -HALF_LENGTH, 0),  //tl
        cv::Point3f(HALF_LENGTH, -HALF_LENGTH, 0),  //tr
        cv::Point3f(HALF_LENGTH, HALF_LENGTH, 0),  //br
        cv::Point3f(-HALF_LENGTH, HALF_LENGTH, 0)  //bl
    };   //自定义二维码四个点坐标
    cv::Mat rVec = cv::Mat::zeros(3, 1, CV_64FC1);//init rvec 
    cv::Mat tVec = cv::Mat::zeros(3, 1, CV_64FC1);//init tvec
    solvePnP(obj, pnts, cameraMatrix, distCoeff, rVec, tVec, false, SOLVEPNP_ITERATIVE);

把上面三个部分融合在一起,就可以写出我们的单目测距代码啦:

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <zbar.h>using namespace cv;
using namespace std;#define HALF_LENGTH 15   //二维码宽度的二分之一const int imageWidth = 640; //设置图片大小,即摄像头的分辨率  
const int imageHeight = 480;
Size imageSize = Size(imageWidth, imageHeight);
Mat mapx, mapy;
// 相机内参
Mat cameraMatrix = (Mat_<double>(3, 3) << 273.4985, 0, 321.2298,
0, 273.3338, 239.7912,
0, 0, 1);
// 相机外参
Mat distCoeff = (Mat_<double>(1, 4) << -0.3551, 0.1386, 0, 0);
Mat R = Mat::eye(3, 3, CV_32F);
​
VideoCapture cap1;typedef struct   //定义一个二维码对象的结构体
{
  string type;
  string data;
  vector <Point> location;
} decodedObject;void img_init(void);   
void decode(Mat &im, vector<decodedObject>&decodedObjects);
void display(Mat &im, vector<decodedObject>&decodedObjects);
​
​
int main(int argc, char* argv[])
{
  initUndistortRectifyMap(cameraMatrix, distCoeff, R, cameraMatrix, imageSize, CV_32FC1, mapx, mapy);
  img_init();
  namedWindow("yuantu", WINDOW_AUTOSIZE);
  Mat im;while (waitKey(1) != 'q') {
    cap1 >> im;
if (im.empty())  break;
    remap(im, im, mapx, mapy, INTER_LINEAR);//畸变矫正
    imshow("yuantu", im);// 已解码对象的变量
    vector<decodedObject> decodedObjects;// 找到并解码条形码和二维码
    decode(im, decodedObjects);// 显示位置
    display(im, decodedObjects);
//vector<Point> points_xy = decodedObjects[0].location;  //假设图中就一个二维码对象,将二维码四角位置取出
    imshow("二维码", im);waitKey(30);
  }return EXIT_SUCCESS;
}void img_init(void)
{
//初始化摄像头
  cap1.open(0);
  cap1.set(CAP_PROP_FOURCC, 'GPJM');
  cap1.set(CAP_PROP_FRAME_WIDTH, imageWidth);
  cap1.set(CAP_PROP_FRAME_HEIGHT, imageHeight);
}
// 找到并解码条形码和二维码
//输入为图像
//返回为找到的条形码对象
void decode(Mat &im, vector<decodedObject>&decodedObjects)
{// 创建zbar扫描仪
  zbar::ImageScanner scanner;// 配置扫描仪
  scanner.set_config(zbar::ZBAR_NONE, zbar::ZBAR_CFG_ENABLE, 1);// 转换图像为灰度图灰度
  Mat imGray;
  cvtColor(im, imGray, COLOR_BGR2GRAY);// 将图像数据包 装在zbar图像中
//可以参考:https://blog.csdn.net/bbdxf/article/details/79356259
  zbar::Image image(im.cols, im.rows, "Y800", (uchar *)imGray.data, im.cols * im.rows);// Scan the image for barcodes and QRCodes
//扫描图像中的条形码和qr码
  int n = scanner.scan(image);// Print results
for (zbar::Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end(); ++symbol)
  {
    decodedObject obj;
​
    obj.type = symbol->get_type_name();
    obj.data = symbol->get_data();// Print type and data
//打印
//cout << "Type : " << obj.type << endl;
//cout << "Data : " << obj.data << endl << endl;// Obtain location
//获取位置
for (int i = 0; i < symbol->get_location_size(); i++)
    {
      obj.location.push_back(Point(symbol->get_location_x(i), symbol->get_location_y(i)));
    }
​
    decodedObjects.push_back(obj);
  }
}
// 显示位置  
void display(Mat &im, vector<decodedObject>&decodedObjects)
{
// Loop over all decoded objects
//循环所有解码对象
for (int i = 0; i < decodedObjects.size(); i++)
  {
    vector<Point> points = decodedObjects[i].location;
    vector<Point> hull;// If the points do not form a quad, find convex hull
//如果这些点没有形成一个四边形,找到凸包
if (points.size() > 4)
      convexHull(points, hull);
else
      hull = points;
    vector<Point2f> pnts;
// Number of points in the convex hull
//凸包中的点数
    int n = hull.size();for (int j = 0; j < n; j++)
    {
      line(im, hull[j], hull[(j + 1) % n], Scalar(255, 0, 0), 3);
      pnts.push_back(Point2f(hull[j].x, hull[j].y));
    }
    vector<Point3f> obj = vector<Point3f>{
        cv::Point3f(-HALF_LENGTH, -HALF_LENGTH, 0),  //tl
        cv::Point3f(HALF_LENGTH, -HALF_LENGTH, 0),  //tr
        cv::Point3f(HALF_LENGTH, HALF_LENGTH, 0),  //br
        cv::Point3f(-HALF_LENGTH, HALF_LENGTH, 0)  //bl
    };   //自定义二维码四个点坐标
    cv::Mat rVec = cv::Mat::zeros(3, 1, CV_64FC1);//init rvec 
    cv::Mat tVec = cv::Mat::zeros(3, 1, CV_64FC1);//init tvec
    solvePnP(obj, pnts, cameraMatrix, distCoeff, rVec, tVec, false, SOLVEPNP_ITERATIVE);
    cout << "tvec:\n " << tVec << endl;
  }
}

下图是运行结果:
在这里插入图片描述
三个数分别是X,Y,Z的距离了,单位cm,精度可以达到0.1cm。

三角测距法

还记得文章开头的那个小孔相机模型吗?
在这里插入图片描述
三角测距法就是基于这个理想的,简单的模型,进行的,在知道物体大小,透镜焦距F,并测出图像中的物体长度后,就可以基于下面公式进行计算长度Z了。
在这里插入图片描述

像素块测距法

这个方法是玩openmv时知道的,openmv封装的单目测距算法,就是将目标对象先在固定的距离(10cm)拍一张照片,测出照片中该物体的像素面积。得到一个比例系数K,然后将物体挪到任意位置,就可以根据像素面积估算距离了。
不过这两种方法肯定鲁棒性都不咋样。

今天就到这里啦。

在这里插入图片描述

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

【RoboMaster】我是这样搞定第一次单目相机测距的 的相关文章

  • 【RoboMaster】我是这样搞定第一次单目相机测距的

    之前在做一个单目测距的小项目 xff0c 大概需要就是用单目相机 xff0c 对一个特定的目标进行识别并测算相机与该目标的距离 所以便去网上找了一堆教程 xff0c 这里给大家总结一下 xff0c 希望给小白们一个参考 首先是基本需求了 x
  • robomaster视觉规则细谈

    目录 攻击与检测 弹丸参数 增益点增益 升级效果 击打检测 涂装要求 裁判系统 机器人端各模块 赛事引擎各部分 客户端 服务器 能量机关 小能量机关 大能量机关 算法归纳 攻击与检测 弹丸参数 如图所示 xff0c 赛场中我们使用的弹丸有两
  • ROBOMASTER机甲大师赛视觉组学习方案

    ROBOMASTER机甲大师赛视觉学习方案 视觉技能学习踩坑硬件平台环境配置个人修为坑 机甲大师 xff08 RoboMaster xff09 是由大疆创新 xff08 DJI xff09 的创始人汪滔发起并承办 由共青团中央 全国学联 深
  • RoboMaster机甲大师——视觉组——计算平台的选型与感想(主流几款)

    RoboMaster机甲大师 视觉组 计算平台 xff08 工控机 xff09 的选型与感想 xff08 主流几款 xff09 FOR THE SIGMA FOR THE GTINDER FOR THE ROBOMASTER 简介 xff1
  • 大疆RoboMaster技术总监:我是如何成为一名机器人工程师的

    作者 大疆创新RoboMaster技术总监YY硕 前言 很多朋友私信问我对机器人和人工智能感兴趣 xff0c 该怎么展开学习 最近稍微有点空 xff0c 我写写我的看法 两年前 xff0c 我在知乎回答如何定义 机器人 xff1f YY硕的
  • RoboMaster视觉教程(1)摄像头

    观文有感 之 RoboMaster视觉教程 xff08 1 xff09 摄像头 闲来垂钓碧溪上 今天钓到一篇RM视觉摄像头的好文 xff0c 记录一下笔记 xff1a 文章目录 观文有感 之 RoboMaster视觉教程 xff08 1 x
  • 了解CV和RoboMaster视觉组(一)摘要

    NeoZng neozng1 64 hnu edu cn 1 摘要 在阅读本文之前 xff0c 你需要有计算机科学的基本知识并至少掌握一门编程语言 xff0c 同时对robomaster比赛规则和过程有大致的了解 若只是希望知道视觉组的基本
  • 了解CV和RoboMaster视觉组(二)视觉在各兵种中的作用

    NeoZng neozng1 64 hnu edu cn 2 视觉在各兵种中的作用 2 1 装甲板识别 xff08 步兵 英雄 无人机 xff09 由于机器人上安装的图传模块到操作手看到的第一视角的延迟加上操作手反应速度的延迟 xff0c
  • 了解CV和RoboMaster视觉组(三)视觉组使用的软件

    NeoZng neozng1 64 hnu edu cn 3 视觉组接触的软件 进行视觉开发会用到各种各样的软件 开发环境 辅助工具等 xff0c 所以很有必要了解一些相关的快捷键 命令 使用技巧 选择一款适合自己的IDE能够提高开发效率
  • 了解CV和RoboMaster视觉组(四)视觉组使用的硬件

    NeoZng neozng1 64 hnu edu cn 4 视觉组接触的硬件 虽然别人总觉得视觉组就是整天对着屏幕臭敲代码的程序员 xff0c 实际上我们也会接触很多的底层硬件与传感器 xff0c 在使用硬件的同时很可能还需要综合运用其他
  • 了解CV和RoboMaster视觉组(五)滤波器、观测器和预测方法

    neozng1 64 hnu edu cn 5 3 滤波器 观测器 估计器和预测方法 这些装置之间的区别在于面对不同场景时候的不同解释 xff08 是否考虑信号的统计学特性 随机特点 参数是否变化等 xff09 滤波器在信号与系统中的定义为
  • RoboMaster步兵机器人简介

    RoboMaster步兵机器人简介 湖北工业大学 蔡饶 如下图所示 xff0c 设计的是一个基于麦克纳姆轮的四轮全向越障平台 xff0c 纵臂式独立悬挂 xff0c 搭载两轴云台和弹丸发射机构 xff0c 是大疆承办的RoboMaster机
  • Robomaster云台,底盘,陀螺仪校准

    文章目录 前言一 云台校准二 底盘校准三 陀螺仪校准 前言 本文主要介绍了Robomaster云台 xff0c 底盘 xff0c 陀螺仪怎么校准 一 云台校准 1 将开关 S2 和开关 S1 都拨到最下面 2 将两侧拨杆打成内八字 xff0
  • RoboMaster怎么设计新步兵悬挂

    流程 xff1a 明确需求 gt 提出可量化目标 gt 方案提出与评估 gt 细化方案 gt 任务分配 gt 画图设计 gt 图纸提交与验收 gt 加工 gt 装配 gt 机械调试 需求 xff1a 性能优越的悬挂 目标 xff1a 1 任
  • 【RoboMaster】舵机驱动&蓝牙模块教程

    本文是为参加2021赛季北京理工大学机器人队校内赛所写的简单教程 xff0c 意在帮助参赛选手快速了解校内赛所需模块的使用方法 xff0c 以及其与薪火培训知识的联系 舵机驱动 硬件接线 舵机是由直流电机 减速齿轮组 传感器和控制电路组成的
  • RoboMaster视觉 深度相机(1):Ubuntu20.04上安装Intel D435深度相机SDK与ROS

    RoboMaster视觉 深度相机 xff08 1 xff09 xff1a Ubuntu20 04上安装Intel D435深度相机SDK与ROS 1 安装RealSense SDK 先去下载 librealsense 可以在GitHub下
  • 了解CV和RoboMaster视觉组(四)视觉组使用的硬件

    NeoZng neozng1 64 hnu edu cn 4 视觉组接触的硬件 虽然别人总觉得视觉组就是整天对着屏幕臭敲代码的程序员 xff0c 实际上我们也会接触很多的底层硬件与传感器 xff0c 在使用硬件的同时很可能还需要综合运用其他
  • RoboMaster机器人运行教程(一)

    1 环境配置 系统 xff1a ubuntu16 04 xff0c 安装ROS 2 基础学习 需要C 43 43 和python基础 xff0c 和ROS的基础知识 xff0c 网上有很多教程 xff0c 推荐知乎大佬教程 xff1a 我的
  • RoboMaster机甲大师比赛入门?我们从STM32开始!

    同步博客地址 xff1a 从STM32开始的RoboMaster生活 xff1a 入门篇 项目 amp 教程仓库 xff1a STM32 RoboMaster 1 0 STM32是什么 1 1 定义 ST 43 M 43 32 61 STM
  • RoboMaster机甲大师:裁判系统服务器搭建助手(RMServer Aid)

    RoboMaster机甲大师 裁判系统服务器搭建助手 RMServer Aid 更新 2022 03 28 写在前面 使用教程 软件简介 软件下载 软件安装 软件使用 打开软件 首次使用 1 组建局域网 2 配置RM环境 3 启动RM服务

随机推荐

  • PVE7.1安装Jellyfin几个问题

    按网络资料显示 xff0c 最好是在LXC安装 一 模板问题 直接创建CT xff0c 模板里是空的 xff0c 所以需要在pve local xff08 pve xff09 模板里 xff0c 找到相关模板 xff08 如ubuntu20
  • Mybatis-Plus代码生成器(generator)

    在写代码的时候 xff0c 使用mybatis plus的代码生成器可以帮助我们减少很多工作量 xff0c 详细说明可以看官方文档https baomidou com pages 779a6e 在使用之前需要把包给导一下 xff0c gen
  • TT 的神秘礼物

    题目 TT 的神秘礼物 题意 xff1a TT 是一位重度爱猫人士 xff0c 每日沉溺于 B 站上的猫咪频道 有一天 xff0c TT 的好友 ZJM 决定交给 TT 一个难题 xff0c 如果 TT 能够解决这个难题 xff0c ZJM
  • computed和watch

    computed 1 什么是computed xff1f computed是计算属性 类似于方法 xff0c 但和methods不同 xff0c methods每次调用时会重新执行函数 xff0c 而computed在其内部变量不变或其返回
  • Anaconda3 2021.05(64bit)安装图文教程

    目录 little背景安装包下载安装 little背景 有朋友说下学期要学Python xff0c anaconda的jupyter notebook这么方便不得不安利一下 xff0c 顺手写个博客记下来 本文如有问题请多指教 xff01
  • 数据结构第三章 栈和队列题目答案

    一 选择题 1 xff0e 栈结构通常采用的两种存储结构是 xff08 A xff09 A xff0e 顺序存储结构和链表存储结构 B xff0e 散列方式和索引方式 C xff0e 链表存储结构和数组 D xff0e 线性链表结构和非线性
  • 博客模板

    题目链接 xff1a 题目描述 xff1a Input xff1a Output xff1a Sample Input xff1a Sample Output xff1a Hint xff1a 思路 xff1a 总结 xff1a 代码 xf
  • 程序设计思维与实践 Week9 作业 C-长凳问题(签到题)

    题目链接 xff1a C 长凳问题 题目描述 xff1a SDUQD 旁边的滨海公园有 x 条长凳 第 i 个长凳上坐着 a i 个人 这时候又有 y 个人将来到公园 xff0c 他们将选择坐在某些公园中的长凳上 xff0c 那么当这 y
  • 程序设计思维与实践 Week11 作业 必做题 A-蒜头君买房子

    题目链接 xff1a A 蒜头君买房子 题目描述 xff1a 蒜头君从现在开始工作 xff0c 年薪N万 他希望在蒜厂附近买一套60平米的房子 xff0c 现在价格是 200万 假设房子价格以每年百分之K增长 xff0c 并且蒜头君未来年薪
  • 程序设计思维与实践 Week11 作业 必做题 B-蒜头君列队

    题目链接 xff1a B 蒜头君列队 题目描述 xff1a 蒜头君的班级里有n 2个同学 xff0c 现在全班同学已经排列成一个n n的方阵 xff0c 但是老师却临时给出了一组新的列队方案 为了方便列队 xff0c 所以老师只关注这个方阵
  • 程序设计思维与实践 Week11 作业 必做题 C-简单密码

    题目链接 xff1a C 简单密码 题目描述 xff1a Julius Caesar 曾经使用过一种很简单的密码 对于明文中的每个字符 xff0c 将它用它字母表中后 55 位对应的字符来代替 xff0c 这样就得到了密文 比如字符 A 用
  • 【蓝桥杯单片机3】共阳数码管的静态显示

    本节要完成的实验现象 xff1a 8个数码管分别单独依次显示0 xff5e 9的值 xff0c 然后所有数码管一起同时显示0 F的值 xff0c 如此往复 训练重点 xff1a 1 弄清楚数码管的段码与显示数值之间关系 2 共阳数码管的基本
  • 程序设计思维与实践 CSP-M3 B-消消乐大师——Q老师

    题目描述 xff1a Q老师是个很老实的老师 xff0c 最近在积极准备考研 Q老师平时只喜欢用Linux系统 xff0c 所以Q老师的电 脑上没什么娱乐的游戏 xff0c 所以Q老师平时除了玩Linux上的赛车游戏SuperTuxKart
  • 程序设计思维与实践 Week12 作业 必做题 C-东东扫寝室

    题目链接 xff1a C 东东扫寝室 题目描述 xff1a 东东每个学期都会去寝室接受扫楼的任务 xff0c 并清点每个寝室的人数 每个寝室里面有ai个人 1 lt 61 i lt 61 n 从第i到第j个宿舍一共有sum i j 61 a
  • 程序设计思维与实践 Week13 作业 必做题 A-TT 的神秘任务1

    题目链接 xff1a A TT的神秘任务1 题目描述 xff1a 这一天 xff0c TT 遇到了一个神秘人 神秘人给了两个数字 xff0c 分别表示 n 和 k xff0c 并要求 TT 给出 k 个奇偶性相同的正整数 xff0c 使得其
  • 程序设计思维与实践 Week13 作业 必做题 C-TT 的奖励

    题目链接 xff1a C TT的奖励 题目描述 xff1a 在大家不辞辛劳的帮助下 xff0c TT 顺利地完成了所有的神秘任务 神秘人很高兴 xff0c 决定给 TT 一个奖励 xff0c 即白日做梦之捡猫咪游戏 捡猫咪游戏是这样的 xf
  • 程序设计思维与实践 Week15 实验 B-ZJM的本领

    题目链接 xff1a B ZJM的本领 题目描述 xff1a 众所周知 xff0c ZJM 住在 B 站 这一天 Q 老师来找 ZJM 玩 xff0c ZJM 决定向 Q 老师展现一下自己快速看番的本领 ZJM 让 Q 老师任意挑选了一部番
  • CCF 2018-9-3 元素选择器

    题目链接 xff1a 元素选择器 题目描述 xff1a 思路 xff1a 模拟题 xff0c 简化版的元素选择器 xff0c 首先创建储存每一层的节点 xff0c 节点中包括标签 xff0c id属性和缩进 由于对于标签的大小写不敏感 xf
  • 期末验收汇总

    WEEK9作业 xff1a A 咕咕东的目录管理器 B 东东学打牌 C 长凳问题 签到题 WEEK10作业 xff1a A Game23 签到题 B LIS amp LCS C 拿数问题 II WEEK10限时大模拟 xff1a A STr
  • 【RoboMaster】我是这样搞定第一次单目相机测距的

    之前在做一个单目测距的小项目 xff0c 大概需要就是用单目相机 xff0c 对一个特定的目标进行识别并测算相机与该目标的距离 所以便去网上找了一堆教程 xff0c 这里给大家总结一下 xff0c 希望给小白们一个参考 首先是基本需求了 x