【AprilTag】视觉定位实战 | 使用 ROS 驱动的 USB 摄像头进行相机标定与 AprilTag 识别

news2024/9/19 9:26:20

写在前面:
🌟 欢迎光临 清流君 的博客小天地,这里是我分享技术与心得的温馨角落。📝
个人主页:清流君_CSDN博客,期待与您一同探索 移动机器人 领域的无限可能。

🔍 本文系 清流君 原创之作,荣幸在CSDN首发🐒
若您觉得内容有价值,还请评论告知一声,以便更多人受益。
转载请注明出处,尊重原创,从我做起。

👍 点赞、评论、收藏,三连走一波,让我们一起养成好习惯😜
在这里,您将收获的不只是技术干货,还有思维的火花

📚 系列专栏:【机器视觉】系列,带您深入浅出,探索机器视觉技术。🖊
愿我的分享能为您带来启迪,如有不足,敬请指正,让我们共同学习,交流进步!

🎭 人生如戏,我们并非能选择舞台和剧本,但我们可以选择如何演绎 🌟
感谢您的支持与关注,让我们一起在知识的海洋中砥砺前行~~~


文章目录

  • 引言
  • 一、准备工作
    • 1.1 安装 usb_cam 驱动
    • 1.2 安装相机标定功能包
    • 1.3 准备标定板和 USB 摄像头
  • 二、相机标定
    • 2.1 启动摄像头驱动节点
    • 2.2 确定相机编号
    • 2.3 查看启动的设备是否正确
    • 2.4 运行相机标定节点
    • 2.5 移动标定板或摄像头
    • 2.6 得到标定结果
    • 2.7 保存保定数据
  • 三、对焦问题
    • 3.1 启动摄像头存在的警告
    • 3.2 对焦问题的可能原因
  • 四、运行Apriltag_ros
    • 4.1 安装 Apriltag_ros 功能包
    • 4.2 修改配置文件
    • 4.3 运行Apriltag_ros
      • (1) 启动 USB 相机驱动
      • (2) 运行 AprilTag_ros 算法
      • (3) RViz 可视化界面
      • (4) 输出定位数据
  • 五、总结
  • 参考资料


引言

  上一篇博客介绍了虚拟机 Ubuntu18.04 安装 USB 摄像头 ROS 驱动 usb_cam 的最新方法,本篇博客讲解如何使用 ROS 驱动的 USB 摄像头进行相机标定与 AprilTag 识别。


一、准备工作

1.1 安装 usb_cam 驱动

  系统环境:Ubuntu18.04

  本教程是基于 usb_cam 包读取图像,因此需要提前安装 usb_cam 驱动,参见:

  【Ubuntu】虚拟机安装USB摄像头ROS驱动 usb_cam(最新方法)

1.2 安装相机标定功能包

  安装 camera_calibration 功能包:

sudo apt-get install ros-melodic-camera-calibration

1.3 准备标定板和 USB 摄像头

  准备一个已知尺寸的标定板,本实验使用的是 6 × 9 6\times9 6×9(列X行),边长为 1.8 c m 1.8cm 1.8cm 的棋盘标定板。

  一个通过 ROS 发布图像的单目 USB 摄像头。


二、相机标定

2.1 启动摄像头驱动节点

rosrun usb_cam usb_cam_node

2.2 确定相机编号

  确定使用的video_id,使用如下命令查看:

ls /dev/video*

  一般笔记本电脑自带的摄像头 id 0 0 0,外接的摄像头 id 1 1 1。然后根据需要修改usb_cam/src/usb_cam/launch/usb_cam-test.launch里面的<param name="video_device" value="/dev/video1" />

  尝试启动摄像头。

roslaunch usb_cam usb_cam-test.launch

  但是博主这样写会报错:

… logging to /home/qingliu/.ros/log/0976c44a-7583-11ef-82de-000c293e3ad5/roslaunch-qingliu-4538.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http://localhost:44077/
SUMMARY
========
PARAMETERS

  • /image_view/autosize: True
  • /rosdistro: melodic
  • /rosversion: 1.14.13
  • /usb_cam/camera_frame_id: usb_cam
  • /usb_cam/color_format: yuv422p
  • /usb_cam/image_height: 480
  • /usb_cam/image_width: 640
  • /usb_cam/io_method: mmap
  • /usb_cam/pixel_format: yuyv
  • /usb_cam/video_device: /dev/video1

NODES
/image_view (image_view/image_view)
usb_cam (usb_cam/usb_cam_node)
ROS_MASTER_URI=http://localhost:11311
process[usb_cam-1]: started with pid [4558]
process[image_view-2]: started with pid [4559]
[ INFO] [1726639123.930729617]: Initializing nodelet with 4 worker threads.
[ INFO] [1726639124.024001715]: Using transport “raw”
[ INFO] [1726639124.046743699]: using default calibration URL
[ INFO] [1726639124.047399791]: camera calibration URL: file:///home/qingliu/.ros/camera_info/head_camera.yaml
[ INFO] [1726639124.047502595]: Unable to open camera calibration file [/home/qingliu/.ros/camera_info/head_camera.yaml]
[ WARN] [1726639124.047555944]: Camera calibration file /home/qingliu/.ros/camera_info/head_camera.yaml not found.
[ INFO] [1726639124.047608139]: Starting ‘head_camera’ (/dev/video1) at 640x480 via mmap (yuyv) at 30 FPS
[ERROR] [1726639124.047678525]: VIDIOC_G_FMT error 22, Invalid argument
[usb_cam-1] process has died [pid 4558, exit code 1, cmd /home/qingliu/catkin_ws/devel/lib/usb_cam/usb_cam_node __name:=usb_cam __log:=/home/qingliu/.ros/log/0976c44a-7583-11ef-82de-000c293e3ad5/usb_cam-1.log].
log file: /home/qingliu/.ros/log/0976c44a-7583-11ef-82de-000c293e3ad5/usb_cam-1*.log

解决方法

  修改文件~/catkin_ws/src/usb_cam/launch/usb_cam-test.launch

<param name="video_device" value="/dev/video0" />

  修改为 /dev/video0

2.3 查看启动的设备是否正确

查看启动的设备是否正确,若正确则关掉再打开驱动:

rosrun usb_cam usb_cam_node

查看图像是否发布, 列出 topic 确保相机正在通过ROS发布图像:

rostopic list 

这会显示所有已发布的 topic,检查是否有 image_raw topic。以下是本实验的相机topic:

/image_view/output
/image_view/parameter_descriptions
/image_view/parameter_updates
/usb_cam/camera_info
/usb_cam/image_raw
/usb_cam/image_raw/compressed
/usb_cam/image_raw/compressed/parameter_descriptions
/usb_cam/image_raw/compressed/parameter_updates
/usb_cam/image_raw/compressedDepth
/usb_cam/image_raw/compressedDepth/parameter_descriptions
/usb_cam/image_raw/compressedDepth/parameter_updates
/usb_cam/image_raw/theora
/usb_cam/image_raw/theora/parameter_descriptions
/usb_cam/image_raw/theora/parameter_updates

2.4 运行相机标定节点

运行 camera_calibration 标定节点:

rosrun camera_calibration cameracalibrator.py --size 5x8 --square 0.018 image:=/usb_cam/image_raw camera:=/usb_cam  --no-service-check

此命令运行标定结点的python脚本,其中 :

  • --size 5x8 为棋盘内部角点的个数,方格几列几行(需要减 1 1 1),比如我的标定板方格是 6 × 9 6\times 9 6×9,则 size 5 × 8 5\times 8 5×8
  • --square 0.018 为每个棋盘格的边长,单位默认为米( m m m)

  注意 7 × 9 7\times 9 7×9 中间不能用“ ∗ * ”,是字母“ x x x”。

  • image:=/usb_cam/image_raw 为当前订阅的图像来自名为/usb_cam/image_raw的 topic
  • camera:=/usb_cam 为摄像机名
  • 加上--no-service-check是因为一开始运行后出现下面的错误,参考官网加上此参数后就可正常显示。

(‘Waiting for service’, ‘/camera/set_camera_info’, ‘…’)
Service not found

  此操作将打开标定窗口,如下图所示:

在这里插入图片描述

2.5 移动标定板或摄像头

为了达到良好的标定效果,需要在摄像机周围移动标定板,并完成以下基本需求:

  • 移动标定板到画面的最左、右,最上、下方
  • 移动标定板到视野的最近和最远处
  • 移动标定板使其充满整个画面
  • 保持标定板倾斜状态并使其移动到画面的最左、右,最上、下方

右侧四个参数的含义:

  • 当标定板移动到画面的最左、右方时,此时,窗口的X会达到最小或满值
  • 同理,Y指示标定板的在画面的上下位置
  • Size表示标定板在视野中的距离,也可以理解为标定板离摄像头的远近
  • Skew为标定板在视野中的倾斜位置

  每次移动之后,保持标定板不动直到窗口出现高亮提示。

  直到条形变为绿色。当 CRLIBRATE 按钮亮起时,代表已经有足够的数据进行摄像头的标定,此时按下 CRLIBRATE 并等待一分钟左右,标定界面变成灰色,无法进行操作,属于正常情况。
在这里插入图片描述

2.6 得到标定结果

*** Added sample 1, p_x = 0.612, p_y = 0.460, p_size = 0.340, skew = 0.152
*** Added sample 2, p_x = 0.556, p_y = 0.498, p_size = 0.319, skew = 0.277
*** Added sample 3, p_x = 0.373, p_y = 0.579, p_size = 0.321, skew = 0.245
*** Added sample 4, p_x = 0.363, p_y = 0.353, p_size = 0.319, skew = 0.201
*** Added sample 5, p_x = 0.471, p_y = 0.309, p_size = 0.294, skew = 0.162
*** Added sample 6, p_x = 0.603, p_y = 0.319, p_size = 0.282, skew = 0.110
*** Added sample 7, p_x = 0.663, p_y = 0.296, p_size = 0.358, skew = 0.164
*** Added sample 8, p_x = 0.671, p_y = 0.199, p_size = 0.434, skew = 0.139
*** Added sample 9, p_x = 0.674, p_y = 0.144, p_size = 0.524, skew = 0.194
*** Added sample 10, p_x = 0.683, p_y = 0.026, p_size = 0.572, skew = 0.131
*** Added sample 11, p_x = 0.623, p_y = 0.086, p_size = 0.652, skew = 0.143
*** Added sample 12, p_x = 0.586, p_y = 0.262, p_size = 0.635, skew = 0.183
*** Added sample 13, p_x = 0.531, p_y = 0.403, p_size = 0.635, skew = 0.250
*** Added sample 14, p_x = 0.485, p_y = 0.223, p_size = 0.663, skew = 0.244
*** Added sample 15, p_x = 0.560, p_y = 0.329, p_size = 0.516, skew = 0.194
*** Added sample 16, p_x = 0.570, p_y = 0.489, p_size = 0.470, skew = 0.177
*** Added sample 17, p_x = 0.515, p_y = 0.515, p_size = 0.399, skew = 0.122
*** Added sample 18, p_x = 0.494, p_y = 0.618, p_size = 0.334, skew = 0.089
*** Added sample 19, p_x = 0.491, p_y = 0.516, p_size = 0.265, skew = 0.061
*** Added sample 20, p_x = 0.459, p_y = 0.414, p_size = 0.207, skew = 0.069
**** Calibrating ****
mono pinhole calibration…
*** Added sample 63, p_x = 0.568, p_y = 0.398, p_size = 0.252, skew = 0.181
*** Added sample 64, p_x = 0.449, p_y = 0.598, p_size = 0.242, skew = 0.006
*** Added sample 65, p_x = 0.382, p_y = 0.635, p_size = 0.218, skew = 0.080
D = [0.03868745150785007, -0.029877004108823855, -0.0007851867081518497, -0.0008866834766470662, 0.0]
K = [433.18386473568006, 0.0, 341.5023734989315, 0.0, 433.4953796121861, 244.3823670617905, 0.0, 0.0, 1.0]
R = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
P = [438.92010498046875, 0.0, 340.88175832247, 0.0, 0.0, 439.3984375, 243.95816827518865, 0.0, 0.0, 0.0, 1.0, 0.0]
None
# oST version 5.0 parameters

[image]

width 640

height 480

[narrow_stereo]

camera matrix
433.183865 0.000000 341.502373
0.000000 433.495380 244.382367
0.000000 0.000000 1.000000

distortion
0.038687 -0.029877 -0.000785 -0.000887 0.000000

rectification
1.000000 0.000000 0.000000
0.000000 1.000000 0.000000
0.000000 0.000000 1.000000

projection
438.920105 0.000000 340.881758 0.000000
0.000000 439.398438 243.958168 0.000000
0.000000 0.000000 1.000000 0.000000

其中,K为相机内参矩阵

  • distortion:畸变系数矩阵
  • camera matrix:摄像头的内部参数矩阵
  • distortion:畸变系数矩阵
  • rectification:矫正矩阵,一般为单位阵
  • projection:外部世界坐标到像平面的投影矩阵

2.7 保存保定数据

  点击 SAVE 按钮。

在这里插入图片描述
  点击 COMMIT 按钮将结果保存到默认文件夹,终端输出如下信息,说明标定结果已经保存在相应文件夹下。下次启动 usb_cam 节点时,会自动调用。

(‘Wrote calibration data to’, ‘/tmp/calibrationdata.tar.gz’)

在这里插入图片描述
  其中,ost.yaml 文件即为相机内参的标定文件。

  至此,相机标定完成!


三、对焦问题

3.1 启动摄像头存在的警告

  启动摄像头存在如下警告:

[ WARN] [1726642015.933315970]: unknown control ‘focus_auto’

3.2 对焦问题的可能原因

出现这个警告可能是有以下两种原因:

  • 因为参数设置不匹配,默认像素的宽和高跟摄像头不匹配。

  • 还有可能只是所使用的相机根本没有自动对焦功能。

因此不用管这个问题。


四、运行Apriltag_ros

4.1 安装 Apriltag_ros 功能包

  Apriltag_ros 的安装非常简单,将源码放到工作空间路径下,如catkin_ws/src,然后编译即可。

cd catkin_ws/src
git clone https://github.com/AprilRobotics/apriltag_ros.git
cd ..
catkin_make

4.2 修改配置文件

  首先修改 ~/catkin_ws/src/apriltag_ros/apriltag_ros/launch/continuous_detection.launch 文件。

  apriltag_ros 需要订阅相机图像数据与相机信息,比如对于USB摄像头,在开启相机时会发布两个相关的 topic:

  • /usb_cam/camera_info
  • /usb_cam/image_raw

  因此需将 camera_namecamera_frame 的内容修改为订阅的 topic。

launch 文件内容修改如下:

<!-- 修改 -->
  <arg name="camera_name" default="/usb_cam" />
  <arg name="image_topic" default="image_raw" />
<!-- 添加 -->
  <arg name="camera_frame" default="/camera" />

完整launch文件内容如下:

<launch>
  <!-- set to value="gdbserver localhost:10000" for remote debugging -->
  <arg name="launch_prefix" default="" />

  <!-- configure camera input -->
  <arg name="camera_name" default="/usb_cam" />
  <arg name="image_topic" default="image_raw" />
  <arg name="camera_frame" default="/camera" />

  <arg name="queue_size" default="1" /> 

  <!-- apriltag_ros continuous detection node -->
  <node pkg="apriltag_ros" type="apriltag_ros_continuous_node" name="apriltag_ros_continuous_node" clear_params="true" output="screen" launch-prefix="$(arg launch_prefix)">
    <!-- Remap topics from those used in code to those on the ROS network -->
    <remap from="image_rect" to="$(arg camera_name)/$(arg image_topic)" />
    <remap from="camera_info" to="$(arg camera_name)/camera_info" />

    <param name="publish_tag_detections_image" type="bool" value="true" /><!-- default: false -->
    <param name="queue_size" type="int" value="$(arg queue_size)" />

    <!-- load parameters (incl. tag family, tags, etc.) -->
    <rosparam command="load" file="$(find apriltag_ros)/config/settings.yaml"/>
    <rosparam command="load" file="$(find apriltag_ros)/config/tags.yaml"/>
  </node>
</launch>

  修改 ~/catkin_ws/src/apriltag_rosapriltag_ros/config/tags.yaml 文件,添加需要检测的二维码id与自己测量得到的二维码尺寸大小size(单位:米)。

standalone_tags:
  [
      {id: 1, size: 0.0515},
      {id: 2, size: 0.0515},
      {id: 3, size: 0.0515},
      {id: 4, size: 0.0515},
      {id: 5, size: 0.0515},
      {id: 6, size: 0.0515}    
  ]

注意
1、同一 ID 的 Apriltag 码不能在该配置文件中以不同的大小出现两次,也不能出现在一张图片的两个地方。这些都将在检测中产生歧义。

2、确保打印的 AprilTag 码至少包含 1 1 1 位宽的白色边框,AprilTag 算法会对周围的白色边框进行采样。

4.3 运行Apriltag_ros

  分别打开四个终端,运行如下命令行:

(1) 启动 USB 相机驱动

roslaunch usb_cam usb_cam-test.launch

(2) 运行 AprilTag_ros 算法

roslaunch apriltag_ros continuous_detection.launch

(3) RViz 可视化界面

rosrun rviz rviz

(4) 输出定位数据

rostopic echo /tag_detections

  正确运行识别到 AprilTag 的界面如下图所示:

在这里插入图片描述

  输出的定位数据如下:

在这里插入图片描述


五、总结

  本教程介绍了如何使用 ROS 进行相机标定和 Apriltag 识别。

  首先,安装了 usb_cam 驱动和 camera_calibration 功能包,并准备了一个 6 × 9 6\times9 6×9 的棋盘格标定板和一个单目 USB 摄像头。

  然后,启动了摄像头驱动节点,并调整了摄像头视频设备 id,以正确地接收摄像头图像。

  接下来,运行了相机标定节点,通过在摄像机周围移动标定板,完成了标定过程,并得到了相机的内参矩阵和畸变系数矩阵。

  最后,安装了 Apriltag_ros 功能包,并修改了配置文件以匹配摄像头和 Apriltag 尺寸。运行了 Apriltag 识别节点,并在 RViz 中可视化了检测结果。

  通过本教程,读者可掌握如何使用 ROS 进行相机标定和 Apriltag 识别,这对于机器人视觉系统至关重要。


参考资料

  1、【Ubuntu】虚拟机安装USB摄像头ROS驱动 usb_cam(最新方法)

  2、使用Apriltags实现定位、评估定位精度的全流程记录

  3、ROS下采用camera_calibration进行单目相机标定


后记:

🌟 感谢您耐心阅读这篇关于 使用 ROS 驱动的 USB 摄像头进行相机标定与 AprilTag 识别 的技术博客。 📚

🎯 如果您觉得这篇博客对您有所帮助,请不要吝啬您的点赞和评论 📢

🌟您的支持是我继续创作的动力。同时,别忘了收藏本篇博客,以便日后随时查阅。🚀

🚗 让我们一起期待更多的技术分享,共同探索移动机器人的无限可能!💡

🎭感谢您的支持与关注,让我们一起在知识的海洋中砥砺前行 🚀

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Matlab进行频率切片小波变换

Matlab进行频率切片小波变换(FSWT)源代码&#xff0c;将一维信号生成时频图。 输入信号可以是任何一维信号&#xff0c;心电信号、脑电信号、地震波形、电流电压数据等。 相比连续小波变换(CWT)&#xff0c;频率切片小波变换(Frequency Slice Wavelet Transform,FSWT)是一种更具…

C# 使用代码清理 以及禁用某个代码清理

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

鸿蒙Harmony应用开发,数据驾驶舱 项目结构搭建

对于一个项目而言&#xff0c;在拿到我们的开发任务后&#xff0c;我们最重要的就是技术的选型。选型定下来了之后我们便开始脚手架的搭建&#xff0c;然后开始撸代码&#xff0c;开搞. 首先我们需要对一些常见依赖库的引入 我们需要再oh-package.json5的dependencies节点下面…

strlen和sizeof

在 C 语言中&#xff0c;strlen 和 sizeof 是两个非常常用的操作符&#xff0c;但它们的作用和用途有很大的不同。下面详细解释这两个操作符&#xff1a; strlen strlen 是一个函数&#xff0c;定义在 <string.h> 头文件中&#xff0c;用于计算一个以空字符&#xff08…

华为OD机试 - 字符串划分(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

注意,传统的提示工程对新模型o1可能失效:来自OpenAI官方的4条提示词建议!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

Flink系列知识之:Checkpoint原理

Flink系列知识之&#xff1a;Checkpoint原理 在介绍checkpoint的执行流程之前&#xff0c;需要先明白Flink中状态的存储机制&#xff0c;因为状态对于检查点的持续备份至关重要。 State Backends分类 下图显示了Flink中三个内置的状态存储种类。MemoryStateBackend和FsState…

linux设置常见开机自启动命令

本文介绍了三种开机自启的方式&#xff0c;重点介绍使用systemctl的方式自启动的 方式一、修改 /etc/rc.d/rc.local 文件 /etc/rc.d/rc.local 文件会在 Linux 系统各项服务都启动完毕之后再被运行。所以你想要自己的脚本在开机后被运行的话&#xff0c;可以将自己脚本路径加到…

Kubernetes从零到精通(12-Ingress、Gateway API)

Ingress和Gateway API都是Kubernetes中用于管理外部访问集群服务的机制&#xff0c;但它们有不同的设计理念和适用场景。它们的基本原理是通过配置规则&#xff0c;将来自外部的网络流量路由到Kubernetes集群内部的服务上。 Ingress/Gateway API和Service Ingress/Gateway API…

边缘计算智能网关的功能应用与优势-天拓四方

在物联网的世界中&#xff0c;数以亿计的设备不断产生、传输和处理数据。然而&#xff0c;传统的云计算架构在面对这些实时性要求高、数据量庞大的物联网数据时&#xff0c;常常面临着网络延迟、带宽限制和安全风险等问题。这时&#xff0c;边缘计算智能网关作为一种新兴的技术…

图书馆座位预约系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;图书馆管理&#xff0c;座位信息管理&#xff0c;预约选座管理&#xff0c;签到信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;论坛&#xf…

【Harmony】轮播图特效,持续更新中。。。。

效果预览 swiper官网例子 Swiper 高度可变化 两边等长露出&#xff0c;跟随手指滑动 Swiper 指示器导航点位于 Swiper 下方 一、官网 例子 参考代码&#xff1a; // xxx.ets class MyDataSource implements IDataSource {private list: number[] []constructor(list: nu…

python:Django与Celery配合实现定时任务

Celery是一个基于python开发的分布式任务队列&#xff0c;而做python WEB开发最为流行的框架莫属Django&#xff0c;但是Django的请求处理过程都是同步的无法实现异步任务&#xff0c;若要实现异步任务处理需要通过其他方式&#xff08;前端的一般解决方案是ajax操作&#xff0…

监控网线和电话线水晶头

监控网线 1、网络摄像机网线接口的线序与B类网线的对应关系&#xff08;表格从左到右代表线序1-8&#xff09; 表格解读&#xff1a; &#xff08;1&#xff09;请先查看摄像机网线对应的颜色&#xff0c;确定是第一种还是第二种摄像机类型 &#xff08;2&#xff09;确定好…

计算机网络基础 - 应用层(3)

计算机网络基础 应用层P2P 应用P2P 体系结构的扩展性BitTorrent 协议torrenl 洪流BitTorrent 运行的过程 P2P文件共享应用非结构化 P2PDHT 结构化 P2P&#xff08;了解&#xff09; 视频流和内容分发网视频流化服务HTTP 流和 DASH内容分发网 CDN面临挑战CDN 概述CDN 操作过程集…

MFC获取网页的html文本

使用 CInternetSession 类和 CHttpFile 类&#xff1b; 在stdafx.h中加入 #include <afxinet.h> &#xff1b; 基本的代码如下&#xff0c; void CMFCApplication3Dlg::OnBnClickedButton1() {// TODO: 在此添加控件通知处理程序代码try{CInternetSession session;CH…

4.事件组

事件组的本质:一个整数 里面的每一个bit,表示一类事件 任务A:可以等待这个整数的"bitx,bity,bitz....."都被设置为1. 这就是"AND"的关系 也可以等待这个整数的"bitx bity bitz..."任意一个被设置为1. 事件组有一个特别的地方在于: 1.假设任…

【QML 基础】QML ——描述性脚本语言,用于用户界面的编写

文章目录 1. QML 定义 1. QML 定义 &#x1f427; QML全称为Qt Meta-Object Language&#xff0c;QML是一种描述性的脚本语言&#xff0c;文件格式以.qml结尾。支持javascript形式的编程控制。QML是Qt推出的Qt Quick技术当中的一部分&#xff0c;Qt Quick是 Qt5中用户界面的涵…

React框架搭建,看这一篇就够了,看完你会感谢我

传统搭建框架的方式 在2024年以前&#xff0c;我们构建框架基本上采用官方脚手架&#xff0c;但是官方脚手架其实大概率都不符合我们的项目要求&#xff0c;搭建完了以后往往需要再继续集成一些第三方的包。这时候又会碰到一些版本冲突&#xff0c;配置教程等&#xff0c;往往…

C++入门基础知识九

1.string类对象的容量操作 函数名称功能说明size返回字符串有效长度length返回字符串有效长度capacity返回总空间大小empty检测字符串是否为空&#xff0c;为空返回true&#xff0c;否则falseclear清空有效字符reserve为字符预留空间number大小空间resize将有效字符改为n个&am…