d435i 相机和imu标定

一、IMU 标定

使用 imu_utils 功能包标定 IMU,由于imu_utils功能包的编译依赖于code_utils,需要先编译code_utils,主要参考

相机与IMU联合标定_熊猫飞天的博客-CSDN博客

Ubuntu20.04编译并运行imu_utils,并且标定IMU_学无止境的小龟的博客-CSDN博客

1.1 编译 code_utils

创建工作空间

mkdir -p ~/catkin_ws/src/imu_calib/src/
cd ~/catkin_ws/src/imu_calib/src
git clone https://github.com/gaowenliang/code_utils.git

1.1.1 修改 CMakeLists.txt 文件

修改 set(CMAKE_CXX_FLAGS "-std=c++11") 为 set(CMAKE_CXX_FLAGS "-std=c++14")

修改 #include "backward.hpp" 为 include “code_utils/backward.hpp”

 如果安装的是 OpenCV 4.x.x 则需要修改一些全局变量的名称,终端输入

cd ~/catkin_ws/src/imu_calib/src/code_utils/
sed -i 's/CV_LOAD_IMAGE_UNCHANGED/cv::IMREAD_UNCHANGED/g' `grep CV_LOAD_IMAGE_UNCHANGED -rl ./`
sed -i 's/CV_LOAD_IMAGE_GRAYSCALE/cv::IMREAD_GRAYSCALE/g' `grep CV_LOAD_IMAGE_GRAYSCALE -rl ./`
sed -i 's/CV_MINMAX/cv::NORM_MINMAX/g' `grep CV_MINMAX -rl ./`

安装依赖

sudo apt-get install libdw-dev

编译 code_utils

mkdir -p ~/catkin_ws/src/imu_calib/
catkin_make

1.2 编译 imu_utils

mkdir -p ~/catkin_ws/src/imu_calib/src/
cd ~/catkin_ws/src/imu_calib/src
git clone https://github.com/gaowenliang/imu_utils.git

修改 CMakeLists.txt 文件

修改 set(CMAKE_CXX_FLAGS "-std=c++11") 为 set(CMAKE_CXX_FLAGS "-std=c++14")

修改 imu_an.cpp 文件

添加头文件:#include <fstream>

编译 imu_utils

mkdir -p ~/catkin_ws/src/imu_calib/
catkin_make

1.3 录制 imu 数据集

创建录制的数据保存路径

mkdir ~/catkin_ws/src/imu_calib/bag/
cd imu_calib/bag/

启动相应的设备开始发布 imu 数据,d435i 相机可以启用 realsense-ros 发布相机 imu 数据

roslaunch realsense2_camera rs_camera.launch

静止情况下采集IMU的数据,并录制为ROS包,采集的时间 2小时 左右

rosbag record /camera/imu -O ~/catkin_ws/src/imu_calib/bag/imu.bag

在 ~/imu_calib/src/imu_utils/launch 路径下创建如下 d435i.launch 文件

<launch><node pkg="imu_utils" type="imu_an" name="imu_an" output="screen"><!--订阅的imu话题--><param name="imu_topic" type="string" value= "/camera/imu"/><!--标定结果的名称--><param name="imu_name" type="string" value= "d435i"/><!--标定结果存放路径--><param name="data_save_path" type="string" value= "$(find imu_utils)/../../bag/d435i/"/><!--数据录制时间-min 120分钟 可以自行修改 一般要大于60--><param name="max_time_min" type="int" value= "120"/><!--imu采样频率,设置为400--><param name="max_cluster" type="int" value= "400"/></node>
</launch>

在 imu 数据采集完毕后(录制时间两小时左右),启动上述 launch 文件标定 imu 内参

roslaunch imu_utils d435i.launch
rosbag play -r 200 ~/catkin_ws/src/imu_calib/bag/imu.bag

数据包播放结束之后,在 ~/catkin_ws/src/imu_calib/bag/ 这个文件夹下会出现一系列的参数文件,

打开 d435i_imu_param.yaml 这个文件,会看到计算出来的噪声和随机游走的系数值

至此,IMU的内参标定和记录结束。

二、相机标定

2.1 编译 kalibr

使用 kalibr 功能包标定相机,编译 kalibr,主要参考

https://github.com/ethz-asl/kalibr/wiki/installation

创建工作空间并下载源码

mkdir -p ~/catkin_ws/src/kalibr/src/ && cd ~/catkin_ws/src/kalibr/src/
git clone https://github.com/ethz-asl/kalibr.git

编译 kalibr

cd ~/catkin_ws/src/kalibr/ && catkin build -DCMAKE_BUILD_TYPE=Release -j4

2.2 制作标定板

终端输入

source ~/catkin_ws/src/kalibr/devel/setup.bash
cd ~/catkin_ws/src/kalibr/bag/stereo/
rosrun kalibr kalibr_create_target_pdf --type apriltag --nx 6 --ny 6 --tsize 0.022 --tspace 0.3

不论是打印PDF标定还是直接在电脑里面打开PDF标定,都要实际测量一下二维码方格和小方格的的长度,再填到yaml文件里面,

--type apriltag                标定板类型
--nx [NUM_COLS]                列个数
--ny [NUM_ROWS]                行个数
--tsize [TAG_WIDTH_M]          二维码方格长度,单位m
--tspace [TAG_SPACING_PERCENT] 小方格与二维码方格长度比例

新建 april_6x6_A4.yaml 文件,格式参考上面的yaml,内容展示如下:

target_type: 'aprilgrid' #gridtype
tagCols: 6               #number of apriltags
tagRows: 6               #number of apriltags
tagSize: 0.0318           #size of apriltag, edge to edge [m]  要亲自拿尺子量一下
tagSpacing: 0.305          #ratio of space between tags to tagSize

千万要自己量一下 tagSize!!!

2.3 录制数据集

启动相应的设备开始发布 相机 数据,d435i 相机可以启用 realsense-ros 发布相机 imu 数据

roslaunch realsense2_camera rs_camera.launch

kalibr 在处理标定数据的时候要求频率不能太高,官方推荐是4Hz(尽管实际频率不完全准确,但是不影响结果),我们可以使用如下命令来更改topic的频率,实际上是将原来的topic以新的频率转成新的topic, infra1 对应左目相机。

rosrun topic_tools throttle messages /camera/infra1/image_rect_raw 4.0 /infra_left
rosrun topic_tools throttle messages /camera/infra2/image_rect_raw 4.0 /infra_right

创建数据保存路径,并录制双目图像数据

mkdir -p ~/kalibr/bag/stereo/
rosbag record /infra_left /infra_right -O ~/kalibr/bag/stereo/stereo.bag

录制操作参考

Kalibr相机及IMU校准教程(Tutorial: IMU-camera calibration)_哔哩哔哩_bilibili

总结下来就是偏航角左右摆动2次,俯仰角摆动2次,滚转角摆动2次,上下移动2次,左右移动2次,前后移动2次,然后自由移动一段时间,摆动幅度要大一点,让视角变化大一点,但是移动要缓慢一点,同时要保证标定板在2个相机视野内部,整个标定时间要在90s以上更好,但是优化时间会比较长。

2.4 标定

录制完成后使用 kalibr 标定

rosrun kalibr kalibr_calibrate_cameras \
--target /home/lilabws001/catkin_ws/src/kalibr/bag/stereo/april_6x6_A4.yaml \
--bag  /home/lilabws001/catkin_ws/src/kalibr/bag/stereo/stereo.bag \
--models pinhole-radtan pinhole-radtan \
--topics /infra_left /infra_right \
--bag-from-to 10 130 --show-extraction

参数解释

  • --targt 标定板的配置文件路径
  • --bag 采集的数据包的路径
  • --models 每个相机的模型
  • --topics 每个相机发布的话题,需要与前面的相机模型对应
  • --bag-from-to 处理bag中指定时间段的数据
  • --show-extraction 表示显示检测特征点的过程

报错:
Initialization of focal length failed. You can enable manual input by setting ‘KALIBR_MANUAL_FOCAL_LENGTH_INIT’.
[ERROR] [1668944382.174500]: initialization of focal length for cam with topic /color failed

解决:
如果提示不能得到初始焦距的时候,可以设置:export KALIBR_MANUAL_FOCAL_LENGTH_INIT=1(终端输入)。然后运行程序,当程序运行失败的时候,它会提示要你手动输入一个焦距,Initialization of focal length failed. Provide manual initialization: 这时手动输入比如 400,给比较大的值,也能收敛。
参考:Realsence D455标定并运行Vins-Fusion_realsense 自动标定_呼叫江江的博客-CSDN博客

标定完成后会输出标定结果。

三、相机 和 IMU 联合标定

新建文件夹

mkdir -p ~/catkin_ws/src/kalibr/bag/stereo_imu/

3.1 建立标定所需的配置文件

首先将前面用于标定的标定板的配置文件 april_6x6_A4.yaml 复制到当前目录下,文件内容

target_type: 'aprilgrid' #gridtype
tagCols: 6               #number of apriltags
tagRows: 6               #number of apriltags
tagSize: 0.0318           #size of apriltag, edge to edge [m]  要亲自拿尺子量一下
tagSpacing: 0.305          #ratio of space between tags to tagSize

然后利用前面两节标定出来的相机和 imu 数据分别创建用于联合标定的两个 yaml 文件

第一个是 imu 标定文件,命名为 imu.yaml,放在 ~/kalibr/bag/stereo_imu/ 目录下

#Accelerometers
accelerometer_noise_density: 2.3726567696372197e-02  #Noise density (continuous-time)
accelerometer_random_walk:   3.4998014052324268e-04  #Bias random walk#Gyroscopes
gyroscope_noise_density:     2.9170092608699020e-03   #Noise density (continuous-time)
gyroscope_random_walk:       2.0293647966050773e-05  #Bias random walkrostopic:                    /imu      #the IMU ROS topic
update_rate:                 200.0      #Hz (for discretization of the values above)

第二个是 相机 标定文件,命名为 stereo.yaml,放在 ~/kalibr/bag/stereo_imu/ 目录下

cam0:camera_model: pinholedistortion_coeffs: [0.008164119133114047, -0.004262736896205682, 0.00018631722833154752, 0.000787900754729365]distortion_model: radtanintrinsics: [382.6730910374852, 382.92071041253627, 322.75543963112193, 236.70194625219574]resolution: [640, 480]rostopic: /infra_left
cam1:T_cn_cnm1:- [0.999998451671115, 2.8757914694169446e-05, 0.0017594966182482613, -0.050366075624740984]- [-2.9002408639730846e-05, 0.9999999899284603, 0.00013893140083111915, 6.282865148510808e-05]- [-0.0017594926051500526, -0.00013898221535954127, 0.9999984424336424, -4.991600269348002e-05]- [0.0, 0.0, 0.0, 1.0]camera_model: pinholedistortion_coeffs: [0.008643399298017006, -0.0051253525048807844, -0.00019751500921053345, 0.00044002401613992687]distortion_model: radtanintrinsics: [382.64357095584296, 382.86804296348265, 322.37239440429965, 236.64851650860956]resolution: [640, 480]rostopic: /infra_right

这两个文件的具体数据需要于前两节的标定结果相对应。

3.2 录制 相机 和 imu 的联合数据

调整 相机 和 imu 的 topic 的发布频率以及以新的topic名发布它们,其中双目图像的发布频率改为20Hz,imu发布频率改为200Hz

rosrun topic_tools throttle messages /camera/infra1/image_rect_raw 4.0 /infra_left
rosrun topic_tools throttle messages /camera/infra2/image_rect_raw 4.0 /infra_right
rosrun topic_tools throttle messages /camera/imu 200.0 /imu

然后录制数据

rosbag record /infra_left /infra_right /imu -O ~/kalibr/bag/stereo_imu/stereo_imu.bag

录制操作与第二节相同,参考

Kalibr相机及IMU校准教程(Tutorial: IMU-camera calibration)_哔哩哔哩_bilibili

总结下来就是偏航角左右摆动2次,俯仰角摆动2次,滚转角摆动2次,上下移动2次,左右移动2次,前后移动2次,然后自由移动一段时间,摆动幅度要大一点,让视角变化大一点,但是移动要缓慢一点,同时要保证标定板在2个相机视野内部,整个标定时间要在90s以上更好,但是优化时间会比较长。

3.3 联合标定 相机 和 imu

录制完成后,终端输入

rosrun kalibr kalibr_calibrate_imu_camera \
--target /home/lilabws001/catkin_ws/src/kalibr/bag/stereo_imu/april_6x6_A4.yaml \
--bag  /home/lilabws001/catkin_ws/src/kalibr/bag/stereo_imu/stereo_imu.bag \
--cam /home/lilabws001/catkin_ws/src/kalibr/bag/stereo_imu/stereo.yaml \
--imu /home/lilabws001/catkin_ws/src/kalibr/bag/stereo_imu/imu.yaml \
--bag-from-to 10 50 --show-extraction

参数解释

  • --targt 标定板的配置文件路径
  • --bag 采集的数据包的路径
  • --cam 标定好的相机的参数文件
  • --imu 标定好的 imu 的参数文件
  • --bag-from-to 处理bag中指定时间段的数据(时间太长要等很久而且结果可能退化)
  • --show-extraction 表示显示检测特征点的过程

如果选的时间太长要等很久,因为结果可能退化

多等一会即可,输出标定结果。

其中 stereo_imu-results-imucam.txt 内容为标定结果

Calibration results
===================
Normalized Residuals
----------------------------
Reprojection error (cam0):     mean 0.1104504565760671, median 0.10931046996879386, std: 0.04566466456955288
Reprojection error (cam1):     mean 0.10568403044796316, median 0.10371974631938084, std: 0.04481417386193855
Gyroscope error (imu0):        mean 0.0013850311184222608, median 2.5661565262693863e-06, std: 0.009802423645836557
Accelerometer error (imu0):    mean 0.001268643166366196, median 4.695420807691451e-07, std: 0.00974036762203694Residuals
----------------------------
Reprojection error (cam0) [px]:     mean 0.1104504565760671, median 0.10931046996879386, std: 0.04566466456955288
Reprojection error (cam1) [px]:     mean 0.10568403044796316, median 0.10371974631938084, std: 0.04481417386193855
Gyroscope error (imu0) [rad/s]:     mean 5.713632942751922e-05, median 1.058609894733102e-07, std: 0.00040437683974539325
Accelerometer error (imu0) [m/s^2]: mean 0.0004256860317308491, median 1.5755218677114464e-07, std: 0.0032683252080259934Transformation (cam0):
-----------------------
T_ci:  (imu0 to cam0): 
[[ 0.99991885 -0.00448156 -0.01192529 -0.00263335][ 0.00454447  0.99997587  0.00525384 -0.00174852][ 0.01190145 -0.00530761  0.99991509 -0.00021396][ 0.          0.          0.          1.        ]]T_ic:  (cam0 to imu0): 
[[ 0.99991885  0.00454447  0.01190145  0.00264362][-0.00448156  0.99997587 -0.00530761  0.00173554][-0.01192529  0.00525384  0.99991509  0.00019172][ 0.          0.          0.          1.        ]]timeshift cam0 to imu0: [s] (t_imu = t_cam + shift)
0.002278866295546706Transformation (cam1):
-----------------------
T_ci:  (imu0 to cam1): 
[[ 0.99992565 -0.0044584  -0.01134993 -0.05300071][ 0.00452389  0.99997323  0.00575127 -0.00163601][ 0.01132399 -0.00580219  0.99991905 -0.00023653][ 0.          0.          0.          1.        ]]T_ic:  (cam1 to imu0): 
[[ 0.99992565  0.00452389  0.01132399  0.05300685][-0.0044584   0.99997323 -0.00580219  0.0013983 ][-0.01134993  0.00575127  0.99991905 -0.00035563][ 0.          0.          0.          1.        ]]timeshift cam1 to imu0: [s] (t_imu = t_cam + shift)
0.00246986588204672Baselines:
----------
Baseline (cam0 to cam1): 
[[ 0.99999983  0.00002622  0.00057526 -0.05036719][-0.0000265   0.99999988  0.00049716  0.00011254][-0.00057525 -0.00049718  0.99999971 -0.00002496][ 0.          0.          0.          1.        ]]
baseline norm:  0.05036732476881377 [m]Gravity vector in target coords: [m/s^2]
[-0.0908983  -9.80442883  0.18258076]Calibration configuration
=========================cam0
-----Camera model: pinholeFocal length: [382.17500647201865, 382.4214301817554]Principal point: [322.86349593743256, 236.54094094752824]Distortion model: radtanDistortion coefficients: [0.005773123668491621, -0.0040545501820581885, 0.00028207298182264084, 0.0008053010502294262]Type: aprilgridTags: Rows: 6Cols: 6Size: 0.0318 [m]Spacing 0.009699000000000001 [m]cam1
-----Camera model: pinholeFocal length: [382.2362024108845, 382.43170351451005]Principal point: [322.9638181263497, 236.36811655369087]Distortion model: radtanDistortion coefficients: [0.006243739765081835, -0.004482994321431694, -0.0003470496074590888, 0.0006688633081104086]Type: aprilgridTags: Rows: 6Cols: 6Size: 0.0318 [m]Spacing 0.009699000000000001 [m]IMU configuration
=================IMU0:----------------------------Model: calibratedUpdate rate: 200.0Accelerometer:Noise density: 0.023726567696372197 Noise density (discrete): 0.3355443382477292 Random walk: 0.0003499801405232427Gyroscope:Noise density: 0.002917009260869902Noise density (discrete): 0.04125274058290133 Random walk: 2.0293647966050773e-05T_ib (imu0 to imu0)[[1. 0. 0. 0.][0. 1. 0. 0.][0. 0. 1. 0.][0. 0. 0. 1.]]time offset with respect to IMU0: 0.0 [s]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/128105.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

百度抓取香港服务器抓取超时是什么情况?

​ 网络延迟导致抓取超时 网络延迟是指从发送请求到接收响应之间的时间延迟。如果网络延迟过高&#xff0c;服务器可能无法及时响应请求&#xff0c;导致超时。在香港服务器上抓取数据时&#xff0c;如果网络延迟过高&#xff0c;可能会出现抓取超时的情况。 服务器负载过高可能…

业务安全及实战案例

业务安全 关于漏洞&#xff1a; 注入业务逻辑信息泄露 A04:2021 – Insecure Design 在线靶场PortSwigger 1. 概述 1.1 业务安全现状 1.1.1 业务逻辑漏洞 ​ 近年来&#xff0c;随着信息化技术的迅速发展和全球一体化进程的不断加快&#xff0c;计算机和网络已经成为与…

【补】代码随想录算法训练营day38|动态规划 |509. 斐波那契数|70. 爬楼梯|746. 使用最小花费爬楼梯

动态规划&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;简称DP&#xff0c;如果某一问题有很多重叠子问题&#xff0c;使用动态规划是最有效的。所以动态规划中每一个状态一定是由上一个状态推导出来的&#xff0c;这一点就区分于贪心&#xff0c;贪心没有状态推…

[SICTF 2023 #Round2] Crypto,PWN,Reverse

似乎很久没写了。 周五到周日&#xff0c;两天的这个比赛&#xff0c;有些东西还真是头回用&#xff0c;值得纪录一下。 Crypto 密码这块这届还是比较简单的&#xff0c;没有复杂的题&#xff0c;但量大分多。 【签到】古典大杂烩 给了一堆emoji的图 &#x1f429;&#x…

STM32低功耗分析

1.ARM发布最新内核 2023 年5 月 29 日&#xff0c;Arm 公司今天发布了处理器核心&#xff1a;Cortex-X4、Cortex-A720 和Cortex-A520。这些核心都是基于 Arm v9.2 架构&#xff0c;只支持 64 位指令集&#xff0c;不再兼容 32 位应用。Arm 公司表示&#xff0c;这些核心在性能…

j解决Ubuntu无法安装pycairo和PyGObject

环境&#xff1a;虚拟机Ubuntu20.04&#xff0c;vscode无法安装pycairo和PyGObject 虚拟机Ubuntu20.04&#xff0c;vscode中运行Anaconda搭建的vens 的Python3.8.10 首先在vscode中点击ctrlshiftp&#xff0c;选择Python3.8.10的环境&#xff0c;自动激活Python 最近在搞无人…

使用 multiprocessing 多进程处理批量数据

示例代码 import multiprocessingdef process_data(data):# 这里是处理单个数据的过程return data * 2# 待处理的数据 data [1, 2, 3, 4, 5]def normal_func():# 普通处理方式result []for obj in data:result.append(process_data(obj)return resultdef parallel_func():# …

操作系统:四大特征(并发,共享,虚拟,异步)

1.并发 1.并发的定义 并发:指两个或多个事件在同一时间间隔内发生。 这些事件宏观上是同时发生的&#xff0c;但微观上是交替发生的。 值得注意的是&#xff0c;与并行&#xff08;指两个或多个事件在同一时刻同时发生&#xff09;区分开来。 2.操作系统的并发性 指计算机…

使用Vue + axios实现图片上传,轻松又简单

目录 一、Vue框架介绍 二、Axios 介绍 三、实现图片上传 四、Java接收前端图片 一、Vue框架介绍 Vue是一款流行的用于构建用户界面的开源JavaScript框架。它被设计用于简化Web应用程序的开发&#xff0c;特别是单页面应用程序。 Vue具有轻量级、灵活和易学的特点&#xf…

自适应迭代扩展卡尔曼滤波算法AIEKF估计SOC VS 扩展卡尔曼估计SOC

自适应迭代扩展卡尔曼滤波算法&#xff08;AIEK&#xff09; 自适应迭代扩展卡尔曼滤波算法&#xff08;AIEK&#xff09;是一种滤波算法&#xff0c;其目的是通过迭代过程来逐渐适应不同的状态和环境&#xff0c;从而优化滤波效果。 该算法的基本思路是在每一步迭代过程中&a…

AndroidStudio最下方显示不出来Terminal等插件

File->Settings->Plugins 然后在上面的输入框中输入Terminal&#xff0c;并将最右侧的对勾打上即可。 安装即可

Bootloader概述和Uboot

Bootloader 基本概念 什么是Bootloader? Bootloader是硬件启动的引导程序&#xff0c;是运行操作系统的前提&#xff1b;在操作系统内核或用户应用程序运行之前运行的一小段代码。对软硬件进行相应的初始化和设定&#xff0c;为最终运行操作系统准备好环境&#xff1b;在嵌入…

Linux中的软件管家——yum

目录 ​编辑 一&#xff0c;软件安装的方式 二&#xff0c;对yum的介绍 1.yum的作用 2&#xff0c;yum的库 三&#xff0c;yum下载软件的操作 1.yumlist 2.yuminstall 3.yumremove 四&#xff0c;yum源的转换 一&#xff0c;软件安装的方式 软件安装的方式大概分为三种…

解除百度安全验证

使用chrome浏览器用百度浏览时&#xff0c;一直弹百度安全验证&#xff1a; 在设置里进行重置&#xff1a; 然后重启浏览器就可以了。

vue+elementUI el-select 自定义搜索逻辑(filter-method)

下拉列表的默认搜索是搜索label显示label,我司要求输入id显示label名称 <el-form-item label"部门&#xff1a;"><el-select v-model"form.region1" placeholder"请选择部门" filterable clearable:filter-method"dataFilter&qu…

C# Emgu.CV+Tesseract实现识别图像验证码

效果图&#xff0c;简单的还行&#xff0c;复杂的。。。拉跨 懒得写讲解了&#xff0c;全部源码直接上吧 /// <summary>/// 验证码识别/// </summary>public partial class FrmCodeIdentify : FrmBase{private string _filePath;// 原图像Image<Bgr, byte> …

软路由的负载均衡设置:优化网络性能和带宽利用率

在现代网络环境中&#xff0c;提升网络性能和最大化带宽利用率至关重要。通过合理配置软路由IP的负载均衡设置&#xff0c;可以有效地实现这一目标&#xff0c;并提高整体稳定性与效果。本文将详细介绍如何进行软路由IP的负载均衡设置&#xff0c;从而优化网络表现、增加带宽利…

基于RabbitMQ的模拟消息队列之六——网络通信设计

自定义基于TCP的应用层通信协议。实现客户端对服务器的远程调用 编写服务器及客户端代码 文章目录 基于TCP的自定义应用层协议一、请求1.请求格式2.创建Request类 二、响应1.响应格式2.创建Response类 三、客户端-服务器交互四、type五、请求payload1.BasicAruguments(方法公共…

英国私校的艺术奖学金有哪些?申请要求和申请流程详解!

众所周知&#xff0c;英国私校不仅学术拔尖&#xff0c;在对学生艺术方面的培养也是毫不逊色的。几乎打开每一所英国私校的官网&#xff0c;都可以看到学校罗列的提供的各类课外艺术活动的精彩照片。      每个英国私校除了课后开设的五花八门的兴趣课外&#xff0c;还有各…

【c++】stringstream基础:实现数据类型转换和字符串分割

传统实现整型转换为字符串需要使用itoa或者sprintf&#xff0c;对于itoa和atoi的使用可以看文章&#xff1a; atoi和itoa极简无废话概述 但是用这两个函数进行转换时&#xff0c;所需要的空间事先不确定&#xff0c;所以可能造成程序崩溃&#xff0c;今天介绍的stringstream可…