基于Matlab的激光雷达与单目摄像头联合外参标定

2023-11-06

1、背景介绍 

        目前团队正在与某主机厂合作开发L4级自动驾驶出租车项目,所用的传感器包括80线激光雷达和单目摄像头。为了充分利用Lidar和Cam各自的优势,设计了一种融合算法,需要获得Lidar2Camera的联合外参。

        前期使用Autoware的CalibrationToolKit工具包进行联合外参的标定,但所的结果始终不能令人满意,后经分析主要是在选取确定标定板位姿的点云数据时,红色圆圈范围内的点云并不严格在一个平面上。后偶然发现https://zhuanlan.zhihu.com/p/404762012https://zhuanlan.zhihu.com/p/404762012https://zhuanlan.zhihu.com/p/404762012        博主总结的联合外参标定工具中包含Matlab的相关功能模块,随后基于此重新开始联合外参标定工作。其他参考链接:https://blog.csdn.net/Wolf_Young/article/details/115975157?utm_source=app&app_version=4.16.0&code=app_1562916241&uLinkId=usr1mkqgl919blenhttps://blog.csdn.net/Wolf_Young/article/details/115975157?utm_source=app&app_version=4.16.0&code=app_1562916241&uLinkId=usr1mkqgl919blenhttps://blog.csdn.net/Wolf_Young/article/details/115975157?utm_source=app&app_version=4.16.0&code=app_1562916241&uLinkId=usr1mkqgl919blenMATLAB终于可以完成相机与激光雷达的标定啦!!_高榤497的博客-CSDN博客文章目录一、相机与激光雷达之间的标定一、相机与激光雷达之间的标定1.MATLAB2020b(1)获取方式:百度网盘链接提取码:zadk(2)安装教程:详细说明2.详细步骤官方教程:仔细瞅瞅(1)搭建实验平台,实验操作系统Ubuntu16.04+ROS(kinetic)+velodyne(16线)+basler+棋盘格(10*7 41mm)(2)Ubuntu下打开激光雷达和相机,教程见前文,并录制数据bag(ps:一定要激光雷达和相机的频率的一致!一定一定!)(3)将数据bag中的激光雷https://blog.csdn.net/qq_27339501/article/details/110224436?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-2.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-2.no_search_link

2、Matlab的Lidar and Camera Calibration模块的操作

        Matlab标定工具与CalibrationToolKit的底层原理是一致的,即首先确定标定板在像素坐标系下的位姿,然后确定标定板在点云3D坐标系下的位姿,根据摄像头的内参换算得到Lidar2Cam的联合外参(利用OpenCv的PnP函数)。

        相比较来说,Matlab的标定工具更傻瓜一些,获得pcd点云数据和图片数据后,直接调用Matlab例程代码(需微调)即可自动计算出外参,而CalibrationToolKit则需进行手动调整点云等一系列较为繁琐的操作,且楼主在实际开发过程中获得结果非常不理想。

2.1标定过程及相关代码

        准备工作及注意事项:标定开始需要准备无白边的棋盘格标定板,行和列的格子个数最好分别是奇数和偶数(Matlab推荐);标定时站位距离不应过远,最好在5-10米以内,否则在之后标定过程中会出现相机内参标定不准确及无法自动检测棋盘格边界的问题;标定位置可多选数组,以增加结果的准确性;标定生成的相机内参及联合外参均需转置之后方可进行后续使用(指融合算法)。

        过程1:录制.bag文件,保证Cam和Lidar的时间戳一致;

        过程2:利用代码将.bag信息转换为图片文件及.pcd(点云)文件,代码如下:

#include <ros/ros.h>
#include <iostream>
#include <string.h>
#include <sstream>
#include <termios.h>
#include <typeinfo>


#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <cv_bridge/cv_bridge.h>

#include <pcl/io/pcd_io.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_types.h>

#include <sensor_msgs/PointCloud2.h>
#include <sensor_msgs/Image.h>
#include <sensor_msgs/image_encodings.h>

#include <pcl/io/io.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/crop_box.h>
#include <pcl/visualization/cloud_viewer.h>

using namespace std;

int c;
int count_img=0;
int count_pcd=0;


ros::Subscriber sub_img;
ros::Subscriber sub_velo;
ros::Publisher pub_img;
ros::Publisher pub_velo;


int getch()
{
  static struct termios oldt, newt;
  tcgetattr( STDIN_FILENO, &oldt);           // save old settings
  newt = oldt;
  newt.c_lflag &= ~(ICANON);                 // disable buffering
  tcsetattr( STDIN_FILENO, TCSANOW, &newt);  // apply new settings
  int c = getchar();  // read character (non-blocking)
  tcsetattr( STDIN_FILENO, TCSANOW, &oldt);  // restore old settings
  return c;
}

void img_cb(const sensor_msgs::Image::ConstPtr& image)
{
	cout << "Image call back ..." << endl;
	stringstream ss;
	ss << "/media/enjoy/新加卷/PCD_Image_get/image/" << count_img << ".jpg" << endl;
	
	cv_bridge::CvImagePtr cv_ptr;
	try
	{
		cv_ptr = cv_bridge::toCvCopy(image,"bgr8");
	}
	catch(cv_bridge::Exception& e)
	{
		ROS_ERROR("cv_bridge exception:%s",e.what());
	}
	
	if (c == 'i') // flag to take an input sample
	{
		pub_img.publish(image);
		cout << "I got image  !" << endl;
	}
	
	else if (c == 'o')
	{
		ROS_INFO("Saved this Image sample!");
		cv::imwrite(ss.str(),cv_ptr->image);
		count_img++;	
	}
}

void velo_cb(const sensor_msgs::PointCloud2::ConstPtr& in_cloud)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::fromROSMsg(*in_cloud, *cloud);
	
	cout << "Velodyne call back ..." << endl;
	
	stringstream ss;
	ss << "/media/enjoy/新加卷/PCD_Image_get/pcd/" << count_pcd << ".pcd";
	if (c == 'i') // flag to take an input sample
	{
		pub_velo.publish(in_cloud);
		cout << "I got velodyne  !" << endl;
	}
	else if (c == 'o')
	{
		ROS_INFO("Saved this velodyne sample!");
		pcl::PCDWriter writer;
	std::vector<int> indices;
	pcl::CropBox<pcl::PointXYZ> roof(true);
	roof.setMin(Eigen::Vector4f(0, -3, -6, 1));//看数据像是车身大小
	roof.setMax(Eigen::Vector4f(15, 3,6, 1));
	roof.setInputCloud(cloud);//输入的是上部中的立方体
	roof.filter(indices);
	pcl::PointIndices::Ptr inliers{ new pcl::PointIndices }; //创建一个内点对象,将提取到车身周围点,放到内点对象中
	for (int point : indices) 
	{
		inliers->indices.push_back(point);
	}
 
	//创建点云提取函数
	pcl::ExtractIndices<pcl::PointXYZ> extract;
	extract.setInputCloud(cloud);
	extract.setIndices(inliers);
	extract.setNegative(false);  //false 提取内点也就是提取车身周围的几个点,, true提取出了车身周围的点
	extract.filter(*cloud);

		writer.write<pcl::PointXYZ> (ss.str(),*cloud,false);
		count_pcd++;
	}
}
int main(int argc,char** argv)
{
	ros::init(argc,argv,"capture_node");
	ros::NodeHandle nh("~");
	
	
	sub_img = nh.subscribe("/Image_topic", 1, img_cb);
	sub_velo = nh.subscribe("/middle/rslidar_points", 1, velo_cb);
	pub_img = nh.advertise<sensor_msgs::Image>("/calib/Image", 10);
	pub_velo = nh.advertise<sensor_msgs::PointCloud2>("/calib/pointcloud", 10);
	
	while(ros::ok())
	{
		std::cout << " Now, press an appropriate key ... " << std::endl;
		std::cout << " 'i' to take an input sample" << std::endl;
		std::cout << " 'o' to save an input sample" << std::endl;
		std::cout << " 'e' to end the calibration process" << std::endl;
		//c = getchar();
		c = getch();
		
		if (c == 'e')
		{
			ros::shutdown();
		}
		
		ros::spinOnce();
	}
	return 0;
}

         上述代码利用pcl::CropBox对点云数据进行了精简,仅获得车身前部空间标定板所在的部分点云(增加计算速度),代码参考链接:https://blog.csdn.net/ChuiGeDaQiQiu/article/details/117648182https://blog.csdn.net/ChuiGeDaQiQiu/article/details/117648182icon-default.png?t=L9C2https://blog.csdn.net/ChuiGeDaQiQiu/article/details/117648182

         过程3:利用Matlab的Camera Calibration对相机的intrinsic进行标定,标定输入即为过程2得到的图片。将得到的标定结果保存为.mat文件。

         过程4:调用Matlab代码对上述过程得到的图片、.PCD及.mat(相机内参)进行调用,自动获得联合外参,代码如下:

clc;clear all;close all;
imagePath = 'D:\PCD_Image_get\image';
ptCloudPath = 'D:\PCD_Image_get\pcd';
cameraParamsPath = fullfile(imagePath, 'matlab1.mat');

intrinsic = load(cameraParamsPath); % Load camera intrinsics
imds = imageDatastore(imagePath); % Load images using imageDatastore
pcds = fileDatastore(ptCloudPath, 'ReadFcn', @pcread); % Load point cloud files

imageFileNames = imds.Files;
ptCloudFileNames = pcds.Files;

squareSize = 108; % Square size of the checkerboard

% Set random seed to generate reproducible results.
rng('default'); 

[imageCorners3d, checkerboardDimension, dataUsed] = ...
    estimateCheckerboardCorners3d(imageFileNames, intrinsic.cameraParams, squareSize);
imageFileNames = imageFileNames(dataUsed); % Remove image files that are not used

% Display Checkerboard corners
% helperShowImageCorners(imageCorners3d, imageFileNames, intrinsic.cameraParams);

% Extract ROI from the detected image corners
roi = helperComputeROI(imageCorners3d, 5);

% Filter point cloud files corresponding to the detected images
ptCloudFileNames = ptCloudFileNames(dataUsed);
[lidarCheckerboardPlanes, framesUsed, indices] = detectRectangularPlanePoints(ptCloudFileNames,checkerboardDimension, ...
    'DimensionTolerance',0.5,'RemoveGround', true);
%[lidarCheckerboardPlanes, framesUsed, indices] = ...detectRectangularPlanePoints(ptCloudFileNames, checkerboardDimension);
%helperShowLidarCorners(ptCloudFileNames, indices);
% Remove ptCloud files that are not used
ptCloudFileNames = ptCloudFileNames(framesUsed);
% Remove image files 
imageFileNames = imageFileNames(framesUsed);
% Remove 3D corners from images
imageCorners3d = imageCorners3d(:, :, framesUsed);

helperShowLidarCorners(ptCloudFileNames, indices);

[tform, errors] = estimateLidarCameraTransform(lidarCheckerboardPlanes, ...
    imageCorners3d, 'CameraIntrinsic', intrinsic.cameraParams);

% visualize the lidar and the image data fused together
helperFuseLidarCamera(imageFileNames, ptCloudFileNames, indices, ...
    intrinsic.cameraParams, tform);

% visualize the Errors
 % The Errors include the follow:
 % 1. Translation Error:Mean of difference between centroid of checkerboard
 % corners in the lidar and the projected corners in 3D from an image.
 % 2. Rotation Error: Mean of difference between the normals of checkerboard in the point cloud and the projected corners in 3-D from an image.
 % 3. Reprojection Error:Mean of difference between the centroid of image
 % corners and projected lidar corners on the image.
helperShowError(errors)

% Results
% After calibration check for data with high calibration errors and re-run the calibration.
outlierIdx = errors.RotationError < mean(errors.RotationError);
[newTform, newErrors] = estimateLidarCameraTransform(lidarCheckerboardPlanes(outlierIdx), ...
        imageCorners3d(:, :, outlierIdx), 'CameraIntrinsic', intrinsic.cameraParams);
    helperShowError(newErrors);
    
% Save the result
% dlmwrite('calib_result.txt',newTform.T)
 

         代码来源及Matlab联合外参标定工具官方说明链接:

https://ww2.mathworks.cn/help/lidar/ug/lidar-and-camera-calibration.html;jsessionid=065c4d973f55f8ff49fb7cf7a225https://ww2.mathworks.cn/help/lidar/ug/lidar-and-camera-calibration.html;jsessionid=065c4d973f55f8ff49fb7cf7a225icon-default.png?t=L9C2https://ww2.mathworks.cn/help/lidar/ug/lidar-and-camera-calibration.html;jsessionid=065c4d973f55f8ff49fb7cf7a225重要说明:在直接调用标定板点云边框识别函数detectRectangularPlanePoints时常常会出现无法检测到标定板而出现的各种报错。楼主经过查看Matlab对该函数的定义发现,如果不指定函数中'DimensionTolerance'的值(即点云检测边框精度),则它默认为0.01。过高的精度要求常常导致无法检测到标定板的点云位姿,为了提高标定板检测成功率,可根据自己需要将该参数调高(即允许更高的边框检测误差)。

        标定结果如上图所示,精度令人比较满意,保存生成的tform数据,即为联合外参的旋转矩阵(偏置后使用)及平移矩阵 。

        过程5:利用Opencv对标定结果进一步验证,代码如下:

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

#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/filter.h>
#include <iostream>
#include "cv_bridge/cv_bridge.h"
#include "sensor_msgs/image_encodings.h"
int main(int argc, char** argv)
{
  // read a image and a pcd
  cv::Mat image_origin = cv::imread("/home/enjoy/points2image/0.jpg");
  pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_origin(new pcl::PointCloud<pcl::PointXYZI>);
  pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_withoutNAN(new pcl::PointCloud<pcl::PointXYZI>);
  pcl::io::loadPCDFile<pcl::PointXYZI> ("/home/enjoy/points2image/0.pcd", *cloud_origin);
  std::vector<int> indices;
  pcl::removeNaNFromPointCloud(*cloud_origin, *cloud_withoutNAN, indices);

  std::vector<cv::Point3f> pts_3d;
  // for (size_t i = 0; i < cloud_withoutNAN->size(); ++i)
  // {
  //   pcl::PointXYZI point_3d = cloud_withoutNAN->points[i];
  //     if (point_3d.x > 0 )
  //    {
  //     pts_3d.emplace_back(cv::Point3f(point_3d.x, point_3d.y, point_3d.z));
  //   }
  // }
 for (size_t i = 0; i < cloud_origin->size(); ++i)
  {
    pcl::PointXYZI point_3d = cloud_origin->points[i];
      if (point_3d.x > 0 )
     {
      pts_3d.emplace_back(cv::Point3f(point_3d.x, point_3d.y, point_3d.z));
    }
  }
  // using iterator
 //Rodrigues transform
   double r_vec1[3];
   double R_matrix[9] ={-0.0248081563169757,-0.999577342547861,0.0151555813187337,
                                                -0.0102513534023755,-0.0149050838374972,-0.999836360725702,
                                                0.999639667647084,-0.0249594619483961,-0.00987725294170718
   };
    CvMat pr_vec;
    CvMat pR_matrix;
    cvInitMatHeader(&pr_vec,1,3,CV_64FC1,r_vec1,CV_AUTOSTEP);
    cvInitMatHeader(&pR_matrix,3,3,CV_64FC1,R_matrix,CV_AUTOSTEP);
    cvRodrigues2(&pR_matrix, &pr_vec,0);
  // read calibration parameter
  double fx = 2399.33875598524, fy =2408.73780160170;
  double cx = 1007.26495794494, cy = 560.636410205530;
  double k1 =-0.528079600928251, k2 =0.243825655125111, k3 =0;
  double p1 = 0, p2 = 0;
  cv::Mat camera_matrix = (cv::Mat_<double>(3, 3) << fx, 0.0, cx, 0.0, fy, cy, 0.0, 0.0, 1.0);
  cv::Mat distortion_coeff = (cv::Mat_<double>(1, 5) <<k1,k2,p1,p2,k3); 
  cv::Mat r_vec = (cv::Mat_<double>(3, 1) << r_vec1[0], r_vec1[1], r_vec1[2]);
  cv::Mat t_vec = (cv::Mat_<double>(3, 1) <<-0.0159063387558948,	-0.472938103973732,	0.505238210760195);
  // project 3d-points into image view
  std::vector<cv::Point2f> pts_2d;
  cv::projectPoints(pts_3d, r_vec, t_vec, camera_matrix, distortion_coeff, pts_2d);
  cv::Mat image_project = image_origin.clone();
  int image_rows = image_origin.rows;
  int image_cols = image_origin.cols;

  for (size_t i = 0; i < pts_2d.size(); ++i)
  {
    cv::Point2f point_2d = pts_2d[i];
    // if (point_2d.x < 0 || point_2d.x > image_cols || point_2d.y < 0 || point_2d.y > image_rows)
    // {
    //   continue;
    // }
    // else
    // {
    //   image_project.at<cv::Vec3b>(point_2d.y, point_2d.x)[0] = 0;
    //   image_project.at<cv::Vec3b>(point_2d.y, point_2d.x)[1] = 0;
    //   image_project.at<cv::Vec3b>(point_2d.y, point_2d.x)[2] = 255;
    // }
    
    if (point_2d.x > 0 && point_2d.x < image_cols && point_2d.y > 0 && point_2d.y < image_rows)
    {
      image_project.at<cv::Vec3b>(point_2d.y, point_2d.x)[0] = 0;
      image_project.at<cv::Vec3b>(point_2d.y, point_2d.x)[1] = 0;
      image_project.at<cv::Vec3b>(point_2d.y, point_2d.x)[2] = 255;
    } 
    else
    {
      continue;
    }  
  }

  cv::imshow("origin image", image_origin);
  cv::imshow("project image", image_project);
  cv::imwrite("/home/enjoy/points2image/image_origin.jpg", image_origin);
  cv::imwrite("/home/enjoy/points2image/image_project.jpg", image_project);
  cv::waitKey(1000000);

  return 0;
}

 参考链接:https://my.oschina.net/u/4414208/blog/3720172https://my.oschina.net/u/4414208/blog/3720172icon-default.png?t=L9C2https://my.oschina.net/u/4414208/blog/3720172

 

 最后,感谢上述链接的博主,对本人在开发工作中的启发与帮助。 

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

基于Matlab的激光雷达与单目摄像头联合外参标定 的相关文章

随机推荐

  • java 获取 sessionid_通过sessionid获取session方法

    使用HttpSessionListener来监听session的创建和销毁 首先创建HttpSessionListener的实现类 SessionListeners java packagecom test importjava util
  • 【详细学习Docker部署搭建高可用的MySQL集群环境】

    一 MySQL高可用集群搭建 MySQL集群搭建在实际项目中是非常必须的 接下来我们来学习通过PXC Percona XtraDB Cluster 来实现强一致性数据库集群搭建 1 1 MySQL集群搭建 1 1 1 中央仓库查找相关镜像
  • 三年级计算机考试题目及答案,三年级信息技术试题及答案.doc

    三年级信息技术试题及答案 三年级信息技术期末试题 学校 班级 姓名 分数 一 单项选择题 共10题 每小题4 共计40分 1 计算机的心脏是 显示屏 鼠标 2 输入汉字时我们需要选择输入法 是我们使用的输入法之一 它的名字叫 五笔输入法 智
  • 【刷题笔记7】LeetCode 54. 螺旋矩阵(数组模拟)

    用分享的方式成长 用有趣的眼光看世界 欢迎来到12 26 25的博客 热爱编码 算法 知识总结 不定期更新有趣 有料 有营养内容 让我们共同学习 共同进步 系列索引 刷题笔记0 系列目录索引 持续更新 推荐收藏 本题题目 LeetCode
  • NVIDIA FasterTransformer

    NVIDIA FasterTransformer NVIDIA GPU计算专家团队针对transformer推理提出了性能优化方案 FasterTransformer 截止到2022年7月 这套方案支持的模型涵盖了BERT GPT Long
  • Mybatis整合Spring -- typeAliasesPackage

    Mybatis 整合 Spring integration MapperScannerConfigurer Mybatis整合Spring 根据官方的说法 在ibatis3 也就是Mybatis3问世之前 Spring3的开发工作就已经完成
  • python时间计算 周开始第一天和结束天 通过年周计算

    python def year mon for check year week 通过年周获取当前月 按每周最后一天的月份比对 最后一天为周日 end year week str year str week 0 end week result
  • xss入门闯关详解6-10关

    继续进行6 10关 第6关 简单的尝试之后发现闭合掉了 尝试空格或者大小写 tab绕过 大小写成功绕过 Onclick alert 1 第七关 老样子 value gt click alert 1 gt value gt lt gt ale
  • 取消idm下载器和google浏览器的关联(让谷歌浏览器禁止使用idm插件)

    https jingyan baidu com article 597035529ae46b8fc107405d html IDM下载安装成功之后 会自动默认关联你电脑上的所有浏览器 在使用浏览器下载的时候自动会变成IDM下载 如果不想让I
  • 2018-2019-2 网络对抗技术 20165335 Exp2 后门原理与实践

    一 基础问题回答 1 例举你能想到的一个后门进入到你系统中的可能方式 钓鱼网站 搞一个假网站 假淘宝 盗版电影 文库下载文档什么的 下载东西的时候把带隐藏的后门程序附带下载进去 自启动 反弹连接 搞一个小网站 用iframe标签跳转到危险网
  • 自动化测试工具Parasoft c++ test v2021.1全新发布,简化嵌入式测试

    随着Parasoft C C test 2021 1的发布 嵌入式测试和开发团队获得了现代高度自动化CI CD管道的速度和效率 最新版本为团队提供了完全集成的静态和单元测试 以实现持续合规性和质量的交付 新版本继续全面支持最新的合规标准 包
  • 几种查找的时间复杂度

    1 顺序查找 1 最好情况 要查找的第一个就是 时间复杂度为 O 1 2 最坏情况 最后一个是要查找的元素 时间复杂度未 O n 3 平均情况下就是 n 1 2 所以总的来说时间复杂度为 O n 2 二分查找 O log2n gt log以
  • 在Ubuntu上编译安装LLVM

    章节索引 Motivation 环境 Git 下载LLVM源码 CMake 编译 安装 文件链接 验证 后记 Motivation 两周前实验室要求我配置一个叫Speedy js的编译器 配置这个编译器需要先配置好LLVM 根据这个编译器作
  • Unity 流程控制

    异步函数 Invoke 被调用的方法不是立刻执行 而是过一段时间后才执行 注 Invoke是不能接受有参数的方法的 Invoke是受Time timeScale的影响 所以当Time timeScale 0 的时候 Invoke是无效的 因
  • python测试url是否可访问,网站是否连通的方法

    目录 前言 1 requests库 1 1 传参 1 2 响应内容 2 python web 前言 一般这种方法用在校验 比如 前端界面传回后端的url 如果返回值不是200 不保存其值 调用的接口不通 直接返回非200 爬虫网站 验证ur
  • C# Dictionary用法总结

    1 常规用法 增加键值对之前需要判断是否存在该键 如果已经存在该键而且不判断 将抛出异常 所以这样每次都要进行判断 很麻烦 在备注里使用了一个扩展方法 public static void DicSample1 Dictionary
  • 【今日CV 计算机视觉论文速览 第111期】Fri, 3 May 2019

    今日CS CV 计算机视觉论文速览 Fri 3 May 2019 Totally 29 papers 上期速览 更多精彩请移步主页 Interesting Single Image Portrait Relighting单图肖像光照重建 本
  • 【Java基础】使用HashMap和For循环查找数据并且统计耗费时长

    准备一个ArrayList其中存放3000000 三百万个 Hero对象 其名称是随机的 格式是hero 4位随机数 hero 3229 hero 6232 hero 9365 因为总数很大 所以几乎每种都有重复 把名字叫做 hero 55
  • ICS大作业--hello程序人生

    摘 要 Hello是每个程序员第一个接触的程序 在本文中利用计算机系统所学的知识 基于Linux平台 通过gcc objdump gdb edb等工具 从c源程序的预处理开始 跟踪分析程序编译 汇编 链接 进程管理 存储管理 I O管理整个
  • 基于Matlab的激光雷达与单目摄像头联合外参标定

    1 背景介绍 目前团队正在与某主机厂合作开发L4级自动驾驶出租车项目 所用的传感器包括80线激光雷达和单目摄像头 为了充分利用Lidar和Cam各自的优势 设计了一种融合算法 需要获得Lidar2Camera的联合外参 前期使用Autowa