(一)相机标定——四大坐标系的介绍、对应转换、畸变原理以及OpenCV完整代码实战(C++版)

news/2025/1/20 0:27:28/

一、四大坐标系介绍

1,世界坐标系

从这个世界(world)的视角来看物体
世界坐标系是3D空间坐标,每个点的位置用 ( X w , Y w , Z w ) (X_w,Y_w,Z_w) (Xw,Yw,Zw)表示

2,相机坐标系

相机本身具有一个坐标系,其也是3D空间坐标
从相机(camera)的视角来看物体,每个点的位置用 ( X c , Y c , Z c ) (X_c,Y_c,Z_c) (Xc,Yc,Zc)表示

3,图像坐标系

相机坐标系是3D空间的,而我们通过相机拍照得到的照片却是2D平面,这之间涉及到了透视投影(perspective projection),大白话就是相似三角形,将3D空间上的点映射到2D平面上
图像坐标系是实际的物理坐标系 ( x , y ) (x,y) (x,y),其原点位置一般在相机光轴成像与成像平面的交点位置,通常为成像平面的中心点,物理单位为mm

4,像素坐标系

我们在处理图像数据的时候,使用的是像素坐标系 ( u , v ) (u,v) (u,v),比如这个图像的大小为1080*720,即长和宽为1080和780个像素;分辨率等相关概念也是这个大概意思,单位是像素pixel
每个像素都有对应的实际物理尺寸,比如1像素=0.5mm
像素有些情况是矩形,分为x和y方向的长度

5,总结

我们需要通过一些手段,将原本在世界坐标系下的点转换到像素坐标系下
世界坐标系是因为物体本身真实存在的位置,而转到像素坐标系下是因为我们在进行图像处理的时候针对的是像素
故,相机标定的最终目的是实现世界坐标系和像素坐标系之间的转换

二、四大坐标系转换

1,世界坐标系——相机坐标系

相机坐标系和世界坐标系都是3D空间坐标系,任何一个空间中的点,都可以通过旋转平移进行相互转换

假设世界坐标系下有个点 P w ( X w , Y w , Z w ) P_w(X_w,Y_w,Z_w) Pw(Xw,Yw,Zw),通过乘以一个变换矩阵(旋转R+平移T)就可以得到相机坐标系下的对应位置 P c ( X c , Y c , Z c ) P_c(X_c,Y_c,Z_c) Pc(Xc,Yc,Zc)

[ X c Y c Z c ] = [ R 11 R 12 R 13 R 21 R 22 R 23 R 31 R 32 R 33 ] [ X w Y w Z w ] + [ T 1 T 2 T 3 ] \begin{bmatrix} X_c\\ Y_c\\ Z_c \end{bmatrix}= \begin{bmatrix} R_{11}&R_{12}&R_{13}\\ R_{21}&R_{22}&R_{23}\\ R_{31}&R_{32}&R_{33} \end{bmatrix} \begin{bmatrix} X_w\\ Y_w\\ Z_w \end{bmatrix}+ \begin{bmatrix} T_1\\ T_2\\ T_3 \end{bmatrix} XcYcZc = R11R21R31R12R22R32R13R23R33 XwYwZw + T1T2T3

为了后续的计算方便,转换为齐次坐标系进行表示
[ X c Y c Z c 1 ] = [ R 11 R 12 R 13 T 1 R 21 R 22 R 23 T 2 R 31 R 32 R 33 T 3 0 0 0 1 ] [ X w Y w Z w 1 ] \begin{bmatrix} X_c\\ Y_c\\ Z_c\\ 1 \end{bmatrix}= \begin{bmatrix} R_{11}&R_{12}&R_{13}&T_1\\ R_{21}&R_{22}&R_{23}&T_2\\ R_{31}&R_{32}&R_{33}&T_3\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} X_w\\ Y_w\\ Z_w\\ 1 \end{bmatrix} XcYcZc1 = R11R21R310R12R22R320R13R23R330T1T2T31 XwYwZw1

其中这个变换矩阵(旋转R和平移T)称为相机外参
[ R 11 R 12 R 13 T 1 R 21 R 22 R 23 T 2 R 31 R 32 R 33 T 3 0 0 0 1 ] \begin{bmatrix} R_{11}&R_{12}&R_{13}&T_1\\ R_{21}&R_{22}&R_{23}&T_2\\ R_{31}&R_{32}&R_{33}&T_3\\ 0&0&0&1 \end{bmatrix} R11R21R310R12R22R320R13R23R330T1T2T31

相机外参实现了某点所在的世界坐标系相机坐标系之间的转换

2,相机坐标系——图像坐标系

就此我们实现了世界坐标系下点 P w ( X w , Y w , Z w ) P_w(X_w,Y_w,Z_w) Pw(Xw,Yw,Zw)到其所对应的相机的坐标系下位置 P c ( X c , Y c , Z c ) P_c(X_c,Y_c,Z_c) Pc(Xc,Yc,Zc)之间的转换

相机坐标系是3D空间坐标系,而相机拍出来的图片是2D平面,这之间涉及透视投影(perspective projection),大白话为相似三角形
在这里插入图片描述
我们可以看到 X c , Y c , Z c , O c X_c,Y_c,Z_c,O_c Xc,Yc,Zc,Oc这个坐标系为相机坐标系,淡蓝色的平面 x , y , o x,y,o x,y,o为图像坐标系(成像平面)
相机成像的原理是小孔成像,故相机坐标系和图像坐标系的y轴是相反的
相机坐标系的原点 O c O_c Oc与图像坐标系的原点 o o o之间的距离为焦距 f f f这里假设相机坐标系和图像坐标系的轴是相互平行且放置位置为正中心,但也有不平行情况,就需要考虑角度了

相机坐标系下的点 P c ( X c , Y c , Z c ) P_c(X_c,Y_c,Z_c) Pc(Xc,Yc,Zc)与相机坐标系原点 O c O_c Oc的连线过图像坐标系平面上的点 p ( x , y ) p(x,y) p(x,y)
也就是相机坐标系下的点 P c ( X c , Y c , Z c ) P_c(X_c,Y_c,Z_c) Pc(Xc,Yc,Zc)对应的图像坐标系下的位置为 p ( x , y ) p(x,y) p(x,y)
根据相似三角形可知:
{ x f = X c Z c y f = Y c Z c ⇒ { Z c ⋅ x = f ⋅ X c Z c ⋅ y = f ⋅ Y c \begin{cases} \frac{x}{f} = \frac{X_c}{Z_c}\\ \frac{y}{f} = \frac{Y_c}{Z_c} \end{cases} \Rightarrow \begin{cases} Z_c·x = f·X_c\\ Z_c·y = f·Y_c \end{cases} {fx=ZcXcfy=ZcYc{Zcx=fXcZcy=fYc

转化为矩阵形式
Z c [ x y 1 ] = [ f 0 0 0 0 f 0 0 0 0 1 0 ] [ X c Y c Z c 1 ] Z_c \begin{bmatrix} x\\y\\1\end{bmatrix} =\begin{bmatrix} f&0&0&0\\ 0&f&0&0\\ 0&0&1&0 \end{bmatrix} \begin{bmatrix} X_c\\ Y_c\\ Z_c\\ 1 \end{bmatrix} Zc xy1 = f000f0001000 XcYcZc1
其中 Z c Z_c Zc为点所在相机坐标系下的Z轴方向位置,是个常量,又称为比例因子
f f f为相机的焦距

通过该矩阵就可以实现相机坐标系图像坐标系之间的转换

3,图像坐标系——像素坐标系

图像坐标系是物理坐标系,因为它涉及到具体的尺寸大小,每个像素都有其对应的物理尺寸
一般情况下像素是矩形,通常情况下假设 1 p i x e l = d x m m , 1 p i x e l = d y m m 1 pixel = dx mm,1 pixel = dy mm 1pixel=dxmm1pixel=dymm,其中 d x dx dx d y dy dy表示一个像素的长宽分别为多少mm

在这里插入图片描述

已知有个小蓝点在图像坐标系下的位置为 ( x , y ) (x,y) (x,y),图像坐标系原点所在像素坐标系下的位置为 ( u 0 , v 0 ) (u_0,v_0) (u0,v0)
求解:小蓝点所对应的像素坐标系为多少?

假设:1个像素的长和宽分别为 d x dx dx d y dy dy mm,图像坐标系下1mm对应像素坐标系下为 1 d x \frac{1}{dx} dx1个像素
小蓝点在图像坐标系下 ( x , y ) (x,y) (x,y)应像素坐标为 ( x ∗ 1 d x , y ∗ 1 d y ) (x * \frac{1}{dx} , y * \frac{1}{dy}) (xdx1,ydy1),即 ( x d x , y d y ) (\frac{x}{dx},\frac{y}{dy}) (dxx,dyy)

u = x d x + u 0 v = y d y + v 0 u = \frac{x}{dx} + u_0\\ v = \frac{y}{dy} + v_0 u=dxx+u0v=dyy+v0

整理成矩阵形式:
[ u v 1 ] = [ 1 d x 0 u 0 0 1 d y v 0 0 0 1 ] [ x y 1 ] \begin{bmatrix} u\\ v\\ 1 \end{bmatrix} = \begin{bmatrix} \frac{1}{dx}&0&u_0\\ 0&\frac{1}{dy}&v_0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} uv1 = dx1000dy10u0v01 xy1

也可以写成另一种形式

[ x y 1 ] = [ d x 0 − u 0 d x 0 d y − v 0 d y 0 0 1 ] [ u v 1 ] \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} = \begin{bmatrix} dx&0&-u_0dx\\ 0&dy&-v_0dy\\ 0&0&1 \end{bmatrix} \begin{bmatrix} u\\ v\\ 1 \end{bmatrix} xy1 = dx000dy0u0dxv0dy1 uv1

由此可以得到一个矩阵,实现该点在图像坐标系 ( x , y ) (x,y) (x,y)和像素坐标系 ( u , v ) (u,v) (u,v)下的直接转换

4,各个坐标系转换相互推导结合

我们的最终目的是:世界坐标系转换到像素坐标系

若已知世界坐标系下点的坐标为 P w ( X w , Y w , Z w ) P_w(X_w,Y_w,Z_w) Pw(Xw,Yw,Zw)

将世界坐标系 P w ( X w , Y w , Z w ) P_w(X_w,Y_w,Z_w) Pw(Xw,Yw,Zw)转换为相机坐标系 P c ( X c , Y c , Z c ) P_c(X_c,Y_c,Z_c) Pc(Xc,Yc,Zc)
[ X c Y c Z c 1 ] = [ R 11 R 12 R 13 T 1 R 21 R 22 R 23 T 2 R 31 R 32 R 33 T 3 0 0 0 1 ] [ X w Y w Z w 1 ] \begin{bmatrix} X_c\\ Y_c\\ Z_c\\ 1 \end{bmatrix}= \begin{bmatrix} R_{11}&R_{12}&R_{13}&T_1\\ R_{21}&R_{22}&R_{23}&T_2\\ R_{31}&R_{32}&R_{33}&T_3\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} X_w\\ Y_w\\ Z_w\\ 1 \end{bmatrix} XcYcZc1 = R11R21R310R12R22R320R13R23R330T1T2T31 XwYwZw1

将相机坐标系 P c ( X c , Y c , Z c ) P_c(X_c,Y_c,Z_c) Pc(Xc,Yc,Zc)转化为图像坐标系 p ( x , y ) p(x,y) p(x,y)

Z c [ x y 1 ] = [ f 0 0 0 0 f 0 0 0 0 1 0 ] [ X c Y c Z c 1 ] Z_c \begin{bmatrix} x\\y\\1\end{bmatrix} =\begin{bmatrix} f&0&0&0\\ 0&f&0&0\\ 0&0&1&0 \end{bmatrix} \begin{bmatrix} X_c\\ Y_c\\ Z_c\\ 1 \end{bmatrix} Zc xy1 = f000f0001000 XcYcZc1

将图像坐标系 ( x , y ) (x,y) (x,y)转化为像素坐标系 ( u , v ) (u,v) (u,v),这里的 ( u 0 , v 0 ) (u_0,v_0) (u0,v0)图像坐标系的原点所对应的像素坐标系下的位置
[ u v 1 ] = [ 1 d x 0 u 0 0 1 d y v 0 0 0 1 ] [ x y 1 ] \begin{bmatrix} u\\ v\\ 1 \end{bmatrix} = \begin{bmatrix} \frac{1}{dx}&0&u_0\\ 0&\frac{1}{dy}&v_0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} uv1 = dx1000dy10u0v01 xy1

最终进行前后整理可得:
Z c [ u v 1 ] = [ 1 d x 0 u 0 0 1 d y v 0 0 0 1 ] [ f 0 0 0 0 f 0 0 0 0 1 0 ] [ R 11 R 12 R 13 T 1 R 21 R 22 R 23 T 2 R 31 R 32 R 33 T 3 0 0 0 1 ] [ X w Y w Z w 1 ] Z_c \begin{bmatrix} u\\ v\\ 1 \end{bmatrix} = \begin{bmatrix} \frac{1}{dx}&0&u_0\\ 0&\frac{1}{dy}&v_0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} f&0&0&0\\ 0&f&0&0\\ 0&0&1&0 \end{bmatrix} \begin{bmatrix} R_{11}&R_{12}&R_{13}&T_1\\ R_{21}&R_{22}&R_{23}&T_2\\ R_{31}&R_{32}&R_{33}&T_3\\ 0&0&0&1 \end{bmatrix} \begin{bmatrix} X_w\\ Y_w\\ Z_w\\ 1 \end{bmatrix} Zc uv1 = dx1000dy10u0v01 f000f0001000 R11R21R310R12R22R320R13R23R330T1T2T31 XwYwZw1

其中 Z c Z_c Zc表示该点在相机坐标系下的Z轴方向的位置,又称为比例因子,本质是常量

相机内参为:
[ 1 d x 0 u 0 0 1 d y v 0 0 0 1 ] [ f 0 0 0 0 f 0 0 0 0 1 0 ] \begin{bmatrix} \frac{1}{dx}&0&u_0\\ 0&\frac{1}{dy}&v_0\\ 0&0&1 \end{bmatrix} \begin{bmatrix} f&0&0&0\\ 0&f&0&0\\ 0&0&1&0 \end{bmatrix} dx1000dy10u0v01 f000f0001000

相机外参为:
[ R 11 R 12 R 13 T 1 R 21 R 22 R 23 T 2 R 31 R 32 R 33 T 3 0 0 0 1 ] \begin{bmatrix} R_{11}&R_{12}&R_{13}&T_1\\ R_{21}&R_{22}&R_{23}&T_2\\ R_{31}&R_{32}&R_{33}&T_3\\ 0&0&0&1 \end{bmatrix} R11R21R310R12R22R320R13R23R330T1T2T31

就此我们实现了世界坐标系和像素坐标系的转换,这就是相机标定的意义所在

5,总结

理想状态下的相机标定,其本质是求解相机的内外参数矩阵

相机外参矩阵需要求解旋转和平移共6个参数
相机内参菊展需要求解焦距 f f f、图像坐标系原点所在的像素坐标系的坐标 ( u 0 , v 0 ) (u_0,v_0) (u0,v0)也称为像主点坐标、单个像素点的长和宽 d x dx dx d y dy dy mm,共5个参数

相机内外参数矩阵需要求解11个参数,这是不考虑畸变的理想状况,但实际相机都不可避免存在畸变,故还需要求解畸变系数

三、畸变

相机标定的最终目的是拿到相机的内外参数矩阵,这些内外参数针对同一个相机是固定的,只需要标定一次即可
相机硬件本身多多少少不可避免存在一定的误差,故需要求解畸变系数用于相机的校准,然后再进行求解内外参矩阵

畸变主要包括(影响最大):切向畸变径向畸变,是相机本身无法避免的误差

1,切向畸变

切向畸变产生于相机组装过程中,透镜本身与相机传感器成像平面不平行
在这里插入图片描述

2,径向畸变

径向畸变产生于透镜本身的形状,光线在远离透镜中心的地方比靠近中心的地方更加弯曲

径向畸变主要包括:桶形畸变枕形畸变
在这里插入图片描述

切向畸变和径向畸变有对应的模型公式,网上一大堆教程,需要的小伙伴自行学习推导哈

畸变涉及到五个参数:径向畸变参数 k 1 、 k 2 、 k 3 k_1、k_2、k_3 k1k2k3;切向畸变参数 p 1 、 p 2 p_1、p_2 p1p2

四、OpenCV代码实战

求解方法很多,这里以张正友标定法(也成为棋盘格标定法)为例进行演示

1,准备棋盘格数据

①OpenCV自带几张棋盘格图片,大致路径为:opencv\sources\samples\data,当然也可以自己去拍几张棋盘格
把这几张图片放到VS项目中
在这里插入图片描述
在这里插入图片描述
②新建一个项目,需要用到OpenCV
③跑一下代码即可

2,完整代码

修改地方:
①棋盘格角点行列数:int CHECKERBOARD[2]{ 6,9 };
在这里插入图片描述

②图片所在文件夹路径:std::string path = "./image/*.jpg";

#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <iostream>using namespace std;
using namespace cv;// Defining the dimensions of checkerboard
// 定义棋盘格的尺寸
int CHECKERBOARD[2]{ 6,9 }; // 一行有6个,一共有9行     数点的行列---6行9列int main()
{// Creating vector to store vectors of 3D points for each checkerboard image// 创建矢量以存储每个棋盘图像的三维点矢量std::vector<std::vector<cv::Point3f> > objpoints;// Creating vector to store vectors of 2D points for each checkerboard image// 创建矢量以存储每个棋盘图像的二维点矢量std::vector<std::vector<cv::Point2f> > imgpoints;// Defining the world coordinates for 3D points// 为三维点定义世界坐标系std::vector<cv::Point3f> objp;for (int i{ 0 }; i < CHECKERBOARD[1]; i++){for (int j{ 0 }; j < CHECKERBOARD[0]; j++){objp.push_back(cv::Point3f(j, i, 0));}}// Extracting path of individual image stored in a given directory// 提取存储在给定目录中的单个图像的路径std::vector<cv::String> images;// Path of the folder containing checkerboard images// 包含棋盘图像的文件夹的路径std::string path = "./image/*.jpg";// 使用glob函数读取所有图像的路径cv::glob(path, images);cv::Mat frame, gray;// vector to store the pixel coordinates of detected checker board corners// 存储检测到的棋盘转角像素坐标的矢量std::vector<cv::Point2f> corner_pts;bool success;// Looping over all the images in the directory// 循环读取图像for (int i{ 0 }; i < images.size(); i++){frame = cv::imread(images[i]);if (frame.empty()){continue;}if (i == 40){int b = 1;}cout << "the current image is " << i << "th" << endl;cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);// Finding checker board corners// 寻找角点// If desired number of corners are found in the image then success = true// 如果在图像中找到所需数量的角,则success = true// opencv4以下版本,flag参数为CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGEsuccess = cv::findChessboardCorners(gray, cv::Size(CHECKERBOARD[0], CHECKERBOARD[1]), corner_pts, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE);/** If desired number of corner are detected,* we refine the pixel coordinates and display* them on the images of checker board*/// 如果检测到所需数量的角点,我们将细化像素坐标并将其显示在棋盘图像上if (success){// 如果是OpenCV4以下版本,第一个参数为CV_TERMCRIT_EPS | CV_TERMCRIT_ITERcv::TermCriteria criteria(TermCriteria::EPS | TermCriteria::Type::MAX_ITER, 30, 0.001);// refining pixel coordinates for given 2d points.// 为给定的二维点细化像素坐标cv::cornerSubPix(gray, corner_pts, cv::Size(11, 11), cv::Size(-1, -1), criteria);// Displaying the detected corner points on the checker board// 在棋盘上显示检测到的角点cv::drawChessboardCorners(frame, cv::Size(CHECKERBOARD[0], CHECKERBOARD[1]), corner_pts, success);objpoints.push_back(objp);imgpoints.push_back(corner_pts);}cv::imshow("Image", frame);cv::waitKey(0);}cv::destroyAllWindows();cv::Mat cameraMatrix, distCoeffs, R, T;/** Performing camera calibration by* passing the value of known 3D points (objpoints)* and corresponding pixel coordinates of the* detected corners (imgpoints)*/// 通过传递已知3D点(objpoints)的值和检测到的角点(imgpoints)的相应像素坐标来执行相机校准cv::calibrateCamera(objpoints, imgpoints, cv::Size(gray.rows, gray.cols), cameraMatrix, distCoeffs, R, T);// 内参矩阵std::cout << "cameraMatrix : " << std::endl;std::cout << cameraMatrix << std::endl;// 透镜畸变系数std::cout << "distCoeffs : " << std::endl;std::cout << distCoeffs << std::endl;// rvecsstd::cout << "Rotation vector : " << std::endl;std::cout << R << std::endl;// tvecsstd::cout << "Translation vector : " << std::endl;std::cout << T << std::endl;return 0;
}

3,运行效果

在这里插入图片描述
在这里插入图片描述
求解得到内参矩阵透镜畸变系数旋转和平移向量


http://www.ppmy.cn/news/1564529.html

相关文章

技术洞察:C++在后端开发中的前沿趋势与社会影响

文章目录 引言C在后端开发中的前沿趋势1. 高性能计算的需求2. 微服务架构的兴起3. 跨平台开发的便利性 跨领域技术融合与创新实践1. C与人工智能的结合2. C与区块链技术的融合 C对社会与人文的影响1. 提升生产力与创新能力2. 促进技术教育与人才培养3. 技术与人文的深度融合 结…

如何实现工作流自动化?实用案例分享

一、CI/CD 与自动化运维概述 &#xff08;一&#xff09;CI/CD 概念解析 在软件开发领域&#xff0c;CI/CD 是两个极为重要的实践&#xff0c;分别代表持续集成&#xff08;Continuous Integration&#xff09;和持续交付 / 持续部署&#xff08;Continuous Delivery/Continuou…

网络安全防护指南:筑牢网络安全防线(510)

一、网络安全的基本概念 &#xff08;一&#xff09;网络的定义 网络是指由计算机或者其他信息终端及相关设备组成的按照一定的规则和程序对信息收集、存储、传输、交换、处理的系统。在当今数字化时代&#xff0c;网络已经成为人们生活和工作中不可或缺的一部分。它连接了世…

ESP8266-01S、手机、STM32连接

1、ESP8266-01S的工作原理 1.1、AP和STA ESP8266-01S为WIFI的透传模块&#xff0c;主要模式如下图&#xff1a; 上节说到&#xff0c;我们需要用到AT固件进行局域网应用&#xff08;ESP8266连接的STM32和手机进行连接&#xff09;。 ESP8266为一个WiFi透传模块&#xff0c;和…

电梯系统的UML文档05

Dispatcher 不控制实际的电梯组件&#xff0c;但它在软件系统中是重要的。每一个电梯有一个ispatcher&#xff0c;主要功能是计算电梯的移动方向、移动目的地以及保持门的打开时间。它和系统中除灯控制器以外的几乎所有控制对象交互。 安全装置也是一个环境对象&#xff0c;它…

【make】makefile变量全解

目录 makefile简介变量全解变量基础变量高级使用1. 将变量里的值进行替换后输出2. 使用变量的嵌套使用3. $ 可以组合使用 override 指示符目标指定变量模式变量 总结参考链接 makefile简介 makefile 是一种类似shell的脚本文件&#xff0c;需要make工具进行解释 makefile 内的语…

Java 数据结构 队列之双端队列 常用方法 示例代码 及其实现

目录 常用方法 示例代码 常见实现 Java中的双端队列&#xff08;Deque&#xff0c;Double Ended Queue&#xff09;是一种队列&#xff0c;它允许在队列的两端插入和删除元素。与普通队列&#xff08;FIFO&#xff09;不同&#xff0c;双端队列的元素可以从队列的两端进行添…

wireshark 网络分析工具

✍作者&#xff1a;柒烨带你飞 &#x1f4aa;格言&#xff1a;生活的情况越艰难&#xff0c;我越感到自己更坚强&#xff1b;我这个人走得很慢&#xff0c;但我从不后退。 &#x1f4dc;系列专栏&#xff1a;网络安全从菜鸟到飞鸟的逆袭 目录 一、网络截获数据包的基础1、以太网…