SLAM ORB-SLAM2(21)基础矩阵的计算和评分

SLAM ORB-SLAM2(21)基础矩阵的计算和评分

  • 1. 前言
  • 2. 基础矩阵
    • 2.1. 对级约束
    • 2.2. 推导
    • 2.3. 计算原理
  • 3. ComputeF21
  • 4. CheckFundamental


1. 前言

在 《SLAM ORB-SLAM2(20)查找基础矩阵》 中了解到 查找基础矩阵主要过程:

  1. 特征点坐标归一化 Normalize

函数 Normalize 参考 《SLAM ORB-SLAM2(14)特征点坐标归一化》

  1. 选择归一化之后的特征点
  2. 八点法计算基础矩阵 ComputeF21
  3. 评分并评优 CheckFundamental

现在来看看基础矩阵如何计算和评分


2. 基础矩阵


2.1. 对级约束

不过先来了解一下什么是对级约束
在这里插入图片描述拿着相机分别在点 O 1 O_1 O1 O 2 O_2 O2 观测空间中一点 P P P
该点在两个视图平面上分别被投影到了点 p 1 p_1 p1 p 2 p_2 p2

由于两次测量都是对同一个点 P P P 的观测
所以 O 1 p 1 O_1p_1 O1p1 O 2 p 2 O_2p_2 O2p2的延长线相交与点 P P P
即点 P , O 1 , O 2 , p 1 , p 2 P,O_1,O_2,p_1,p_2 P,O1,O2,p1,p2 都在一个平面上,这个平面被称为 极面 (epipolar plane)
连线 O 1 O 2 O_1O_2 O1O2 被称为 基线 (baseline)
基线分别与两个像平面相交与点 e 1 , e 2 e_1,e_2 e1,e2 ,这两个点被称为 极点 (epipole)
极点与成像点 p 1 , p 2 p_1,p_2 p1,p2 的连线 p 1 e 1 , p 2 e 2 p_1e_1,p_2e_2 p1e1,p2e2 所在的直线 l 1 , l 2 l_1,l_2 l1,l2 被称为 极线 (epipolar line)

对级约束就是,在两个不同的位置上观测空间中同一个点,其成像一定在极线上


2.2. 推导

假设某个特征点 P P P
相对于参考帧相机坐标系的坐标为 X 1 = [ x 1 y 1 z 1 ] T \boldsymbol{X_1} = \begin{bmatrix} x_1 & y_1 & z_1 \end{bmatrix}^T X1=[x1y1z1]T

成像点的齐次坐标为 x 1 = [ u 1 v 1 1 ] T \boldsymbol{x_1} = \begin{bmatrix} u_1 & v_1 & 1\end{bmatrix}^T x1=[u1v11]T

根据针孔相机模型:
x 1 = 1 z K X 1 ⟺ [ u 1 v 1 1 ] = 1 z [ f x 0 c x 0 f y c y 0 0 1 ] [ x 1 y 1 z 1 ] \boldsymbol{x_1} = \cfrac{1}{z} \boldsymbol{KX_1} \Longleftrightarrow \begin{bmatrix} u_1 \\ v_1 \\ 1 \end{bmatrix} = \cfrac{1}{z} \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x_1 \\ y_1 \\ z_1 \end{bmatrix} x1=z1KX1u1v11=z1fx000fy0cxcy1x1y1z1 矩阵 K K K 为相机的内参矩阵,记录了相机的 x y x\ y x y 轴上的焦距 f x , f y f_x, f_y fx,fy 和 光心坐标 c x , c y c_x,c_y cx,cy

此时,考虑相机的内参,将 X 1 , X 2 X_1,X_2 X1,X2投影到成像平面上有:
{ x 1 = 1 z 1 K X 1 x 2 = 1 z 2 K X 2 ⇒ { X 1 = z 1 K − 1 x 1 X 2 = z 2 K − 1 x 2 \begin{cases} \boldsymbol{x_1} = \cfrac{1}{z_1} \boldsymbol{K} \boldsymbol{X_1} \\ \boldsymbol{x_2} = \cfrac{1}{z_2} \boldsymbol{K} \boldsymbol{X_2} \end{cases} \Rightarrow \begin{cases} \boldsymbol{X_1} = z_1\boldsymbol{K}^{-1} \boldsymbol{x_1} \\ \boldsymbol{X_2} = z_2\boldsymbol{K}^{-1} \boldsymbol{x_2} \end{cases} x1=z11KX1x2=z21KX2{X1=z1K1x1X2=z2K1x2
相机经过位姿变换 ⟨ R , t ⟩ ⟨R,t⟩ R,t后,观测到 P P P 点坐标为,上式导入运动关系:
X 2 = R X 1 + t ⇒ z 2 K − 1 x 2 = z 1 R K − 1 x 1 + t \boldsymbol{X_2} = \boldsymbol{RX_1} + \boldsymbol{t} \ \ \ \ \ \Rightarrow \ \ \ z_2 \boldsymbol{K}^{-1} \boldsymbol{x_2} = z_1 \boldsymbol{R}\boldsymbol{K}^{-1}\boldsymbol{x_1} + \boldsymbol{t}\\ X2=RX1+t        z2K1x2=z1RK1x1+t
两边叉乘 t t t
z 2 t × K − 1 x 2 = z 1 t × R K − 1 x 1 z_2 \boldsymbol{t}_{\times}\boldsymbol{K}^{-1}\boldsymbol{x_2} = z_1 \boldsymbol{t}{\times}\boldsymbol{R}\boldsymbol{K}^{-1}\boldsymbol{x_1} z2t×K1x2=z1t×RK1x1

叉乘(外积): A X B = |A| |B| s i n θ sin\theta sinθ, 向量形成的平行四边形的面积,也是法向量

t = [ a 1 a 2 a 3 ] ⇒ t ∧ = [ 0 − a 3 a 2 a 3 0 − a 1 − a 2 a 1 0 ] t=\left[\begin{array}{l}a_{1} \\ a_{2} \\ a_{3}\end{array}\right] \Rightarrow \ t^{\wedge}=\left[\begin{array}{ccc}0 & -a_{3} & a_{2} \\ a_{3} & 0 & -a_{1} \\ -a_{2} & a_{1} & 0\end{array}\right] t=a1a2a3 t=0a3a2a30a1a2a10

反对称矩阵,它的主对角线上的元素全为0,而位于主对角线两侧对称的元素反号

A X B = [ 0 − z a y a z a 0 − x a − y a x a 0 ] \begin{bmatrix}0 & -z_a & y_a \\z_a &0 & -x_a \\-y_a & x_a & 0 \end{bmatrix} 0zayaza0xayaxa0 [ x b y b z b ] \begin{bmatrix}x_b \\y_b \\z_b \end{bmatrix} xbybzb= [ y a z b − y b z a x b z a − x a z b x a y b − x b y a ] \begin{bmatrix}y_az_b-y_bz_a \\x_bz_a-x_az_b \\x_ay_b-x_by_a \end{bmatrix} yazbybzaxbzaxazbxaybxbya

那么两个平行的向量叉乘为0

两边点乘 ( K − 1 x 2 ) T \left(\boldsymbol{K}^{-1}\boldsymbol{x_2}\right)^T (K1x2)T
z 2 ( K − 1 x 2 ) T t × K − 1 x 2 = z 1 ( K − 1 x 2 ) T t × R K − 1 x 1 z_2 \left(\boldsymbol{K}^{-1}\boldsymbol{x_2}\right)^T\boldsymbol{t}{\times}\boldsymbol{K}^{-1}\boldsymbol{x_2} = z_1 \left(\boldsymbol{K}^{-1}\boldsymbol{x_2}\right)^T\boldsymbol{t}{\times}\boldsymbol{R}\boldsymbol{K}^{-1}\boldsymbol{x_1} z2(K1x2)Tt×K1x2=z1(K1x2)Tt×RK1x1
关注式子的左侧的左边, t × K − 1 x 2 \boldsymbol{t}_{\times}\boldsymbol{K}^{-1}\boldsymbol{x_2} t×K1x2的含义就是向量 t t t K − 1 x 2 \boldsymbol{K}^{-1}\boldsymbol{x_2} K1x2 的叉乘
将得到一个同时与这两个向量垂直的向量,该向量与 K − 1 x 2 \boldsymbol{K}^{-1}\boldsymbol{x_2} K1x2 的点积为零
所以上式可以写成如下的形式:
z 1 ( K − 1 x 2 ) T t × R K − 1 x 1 = 0 z_1 \left(\boldsymbol{K}^{-1}\boldsymbol{x_2}\right)^T\boldsymbol{t}{\times}\boldsymbol{R}\boldsymbol{K}^{-1}\boldsymbol{x_1}=0 z1(K1x2)Tt×RK1x1=0

上式就是一个等式为零的约束,所以其中 z z z的取值实际上没有什么作用,只要非零就行,那么
x 2 T K − T t × R K − 1 x 1 = 0 \boldsymbol{x_2}^T\boldsymbol{K}^{-T}\boldsymbol{t}{\times}\boldsymbol{R}\boldsymbol{K}^{-1}\boldsymbol{x_1}=0 x2TKTt×RK1x1=0

把矩阵 K − T t × R K − 1 \boldsymbol{K}^{-T}\boldsymbol{t}_{\times}\boldsymbol{R}\boldsymbol{K}^{-1} KTt×RK1 称为 基础矩阵,用符号 F \boldsymbol{F} F 表示,那么得到映射关系:
x 2 T F x = 0 \boldsymbol{x_2}^T \boldsymbol{Fx} = 0 x2TFx=0


2.3. 计算原理

根据两帧图像之间的映射关系: x 2 T F x = 0 \boldsymbol{x_2}^T \boldsymbol{Fx} = 0 x2TFx=0
代入求解:
[ u 2 v 2 1 ] [ f 11 f 12 f 13 f 21 f 22 f 23 f 31 f 32 f 33 ] [ u 1 v 1 1 ] = 0 ⇒ u 2 u 1 f 11 + u 2 v 1 f 12 + u 2 f 13 + v 2 u 1 f 21 + v 2 v 1 f 22 + v 2 f 23 + u 1 f 31 + v 1 f 32 + f 33 = 0 \begin{bmatrix} u_2 & v_2 & 1 \end{bmatrix} \begin{bmatrix} f_{11} & f_{12} & f_{13} \\ f_{21} & f_{22} & f_{23} \\ f_{31} & f_{32} & f_{33} \end{bmatrix} \begin{bmatrix} u_1 \\ v_1 \\ 1 \end{bmatrix} = 0 \ \ \ \ \ \Rightarrow \\ \ \\ u_2u_1f_{11} + u_2v_1f_{12} + u_2f_{13} + v_2u_1f_{21} + v_2v_1f_{22} + v_2f_{23} + u_1f_{31} + v_1f_{32} + f_{33} = 0 [u2v21]f11f21f31f12f22f32f13f23f33u1v11=0      u2u1f11+u2v1f12+u2f13+v2u1f21+v2v1f22+v2f23+u1f31+v1f32+f33=0

f = [ f 11 f 12 f 13 f 21 f 22 f 23 f 31 f 32 f 33 ] T \boldsymbol{f} = \begin{bmatrix} f_{11} & f_{12} & f_{13} & f_{21} & f_{22} & f_{23} & f_{31} & f_{32} & f_{33} \end{bmatrix}^T f=[f11f12f13f21f22f23f31f32f33]T ,上式可以写成向量点乘的形式:
[ u 2 u 1 u 2 v 1 u 2 v 2 u 1 v 2 v 1 v 2 u 1 v 1 1 ] f = 0 \begin{bmatrix} u_2u_1 & u_2v_1 & u_2 & v_2u_1 & v_2v_1 & v_2 & u_1 & v_1 & 1 \end{bmatrix} \boldsymbol{f} = 0 [u2u1u2v1u2v2u1v2v1v2u1v11]f=0

假有 m m m 对匹配点,根据上式可以写出 m m m 个约束,可以写成 A f = 0 \boldsymbol{Af}=\boldsymbol{0} Af=0 的矩阵形式,如下:
A f = [ u 1 , 2 u 1 , 1 u 1 , 2 v 1 , 1 u 1 , 2 v 1 , 2 u 1 , 1 v 1 , 2 v 1 , 1 v 1 , 2 u 1 , 1 v 1 , 1 1 ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ u m , 2 u m , 1 u m , 2 v m , 1 u m , 2 v m , 2 u m , 1 v m , 2 v m , 1 v m , 2 u m , 1 v m , 1 1 ] f = 0 \boldsymbol{Af} = \begin{bmatrix} u_{1,2}u_{1,1} & u_{1,2}v_{1,1} & u_{1,2} & v_{1,2}u_{1,1} & v_{1,2}v_{1,1} & v_{1,2} & u_{1,1} & v_{1,1} & 1 \\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \\ u_{m,2}u_{m,1} & u_{m,2}v_{m,1} & u_{m,2} & v_{m,2}u_{m,1} & v_{m,2}v_{m,1} & v_{m,2} & u_{m,1} & v_{m,1} & 1 \\ \end{bmatrix} \boldsymbol{f} = \boldsymbol{0} Af=u1,2u1,1um,2um,1u1,2v1,1um,2vm,1u1,2um,2v1,2u1,1vm,2um,1v1,2v1,1vm,2vm,1v1,2vm,2u1,1um,1v1,1vm,111f=0
对矩阵 A A A 进行奇异值分解,得到的 右奇异矩阵的最后一列 就是 f \boldsymbol{f} f最优解
能够最小化 ∥ A f ∥ / ∥ f ∥ \boldsymbol{∥Af∥/∥f∥} Af/f的解,使 A f \boldsymbol{Af} Af 尽可能的接近 0

为何右奇异矩阵的最后一列为单应矩阵的最优解 参考 《SLAM ORB-SLAM2(16)奇异值分解》 的 求解超定方程

至少需要8个点才能求得基础矩阵,这也就是所谓的八点法


3. ComputeF21

直接线性法 DLT 方法求解 基础矩阵 F F F

按上述公式填充数据于系数矩阵 A A A

/*** @brief 基础矩阵计算求解函数* @param vP1  参考帧归一化坐标* @param vP2  当前帧归一化坐标* @return cv::Mat 计算的基础矩阵F*/
cv::Mat Initializer::ComputeF21(const vector<cv::Point2f> &vP1, const vector<cv::Point2f> &vP2)
{/* 获取坐标数量 */const int N = vP1.size();/* 定义系数矩阵A */cv::Mat A(N, 9, CV_32F);/* 配置系数 */for (int i = 0; i < N; i++){/* 获取特征点对的像素坐标 */const float u1 = vP1[i].x;const float v1 = vP1[i].y;const float u2 = vP2[i].x;const float v2 = vP2[i].y;/* 配置当前特征点对应的约束 */A.at<float>(i, 0) = u2 * u1;A.at<float>(i, 1) = u2 * v1;A.at<float>(i, 2) = u2;A.at<float>(i, 3) = v2 * u1;A.at<float>(i, 4) = v2 * v1;A.at<float>(i, 5) = v2;A.at<float>(i, 6) = u1;A.at<float>(i, 7) = v1;A.at<float>(i, 8) = 1;}/* 定义输出变量,u是左边的正交矩阵U, w为奇异矩阵,vt为右正交矩阵V的转置T */cv::Mat u, w, vt;/* 奇异值分解 */cv::SVDecomp(A, w, u, vt, cv::SVD::MODIFY_A | cv::SVD::FULL_UV);/* 右奇异矩阵的最后一列,重整为基础矩阵 */cv::Mat Fpre = vt.row(8).reshape(0, 3);/* 对初步得来的基础矩阵进行第2次奇异值分解 */cv::SVDecomp(Fpre, w, u, vt, cv::SVD::MODIFY_A | cv::SVD::FULL_UV);/* 基础矩阵的秩为2,强制将第3个奇异值设置为0 */w.at<float>(2) = 0;/* 返回重组满足秩约束的基础矩阵 */return u * cv::Mat::diag(w) * vt;
}

通过OpenCV的接口对矩阵 A A A 进行 SVD分解,取最小的奇异值在 V T V^T VT空间中对应的行向量构建基础矩阵
但是基础矩阵的秩只有2,也就是它应当有一个为0的奇异值
对矩阵 A A A 进行 SVD分解 时并不能保证这一点
所以构建矩阵 Fpre 再次进行 SVD分解,令最小的奇异值为 0,再重组基础矩阵

:矩阵 A A A非零特征值个数
奇异值分解 参考 《SLAM ORB-SLAM2(16)奇异值分解》


4. CheckFundamental

经过计算,得到基础矩阵,那么根据基础矩阵计算重投影误差

这里返回的单应矩阵是归一化之后的,还不能直接使用, 需要恢复归一化之前的矩阵才行
在 《SLAM ORB-SLAM2(20)查找基础矩阵》 的 5. 八点法计算基础矩阵 中已经恢复了:

cv::Mat Fn = ComputeF21(vPn1i, vPn2i); /* 八点法计算基础矩阵 */
F21i = T2t * Fn * T1;                  /* 根据归一化的矩阵恢复 基础矩阵 F21 */

在第一步已经进行特征点归一化:vPn1 = T1 * mvKeys1, vPn2 = T2 * mvKeys2

又因为 x x x2T F F F21 x x x1=0
根据基础矩阵约束得到:(T2 * mvKeys2)T * Fn * T1 * mvKeys1 = 0
进一步得到 : mvKeys2T * T2t * Fn * T1 * mvKeys1 = 0

/*** @brief 基础矩阵评分函数* @param F21  参考帧到当前帧的基础矩阵* @param vbMatchesInliers  特征点对的Inlier标记* @param sigma  标准差* @return score 得分*/
float Initializer::CheckFundamental(const cv::Mat &F21, vector<bool> &vbMatchesInliers, float sigma)
{/* 获取匹配点对数量 */const int N = mvMatches12.size();/* 获取从参考帧到当前帧的基础矩阵的各个元素 */const float f11 = F21.at<float>(0, 0);const float f12 = F21.at<float>(0, 1);const float f13 = F21.at<float>(0, 2);const float f21 = F21.at<float>(1, 0);const float f22 = F21.at<float>(1, 1);const float f23 = F21.at<float>(1, 2);const float f31 = F21.at<float>(2, 0);const float f32 = F21.at<float>(2, 1);const float f33 = F21.at<float>(2, 2);

获取从参考帧到当前帧的基础矩阵中的各个元素

    /* 预分配特征点对Inliers标记的空间 */vbMatchesInliers.resize(N);/* 初始化单应矩阵得分 */float score = 0;/* 基于卡方检验计算出的阈值(假设测量有一个像素的偏差)自由度为1的卡方分布在显著性水平为0.05时对应的临界阈值为3.841自由度为2的卡方分布在显著性水平为0.05时对应的临界阈值为5.991 */const float th = 3.841;const float thScore = 5.991;/* 方差平方的倒数,作为信息矩阵 协方差的逆 */const float invSigmaSquare = 1.0 / (sigma * sigma);

根据传入的sigma值计算协方差矩阵

    /* 通过F矩阵,进行参考帧和当前帧之间的双向投影,并计算出加权重投影误差 */for (int i = 0; i < N; i++){/* 开始都默认为Inlier */bool bIn = true;/* 提取参考帧和当前帧之间的特征匹配点对 */const cv::KeyPoint &kp1 = mvKeys1[mvMatches12[i].first];const cv::KeyPoint &kp2 = mvKeys2[mvMatches12[i].second];/* 提取出特征点的坐标 */const float u1 = kp1.pt.x;const float v1 = kp1.pt.y;const float u2 = kp2.pt.x;const float v2 = kp2.pt.y;// Reprojection error in second image// l2=F21x1=(a2,b2,c2)/* 计算 参考帧 上的点在 当前帧 上投影得到的极线 l2 = F21 * p1 = (a2, b2, c2) */const float a2 = f11 * u1 + f12 * v1 + f13;const float b2 = f21 * u1 + f22 * v1 + f23;const float c2 = f31 * u1 + f32 * v1 + f33;/* 计算 当前帧的特征点 到 投影得到的极线 l2 的距离平方 d^2 = ((ax+by+c) / sqrt(a^2 + b^2))^2 */const float num2 = a2 * u2 + b2 * v2 + c2;const float squareDist1 = num2 * num2 / (a2 * a2 + b2 * b2);/* 转换参考帧投影至当前帧的误差 */const float chiSquare1 = squareDist1 * invSigmaSquare;/* 阀值用th,而累加得分用thScore,确保与单应基础评分标准一致 *//* 用阈值标记离群点,内点的话累加得分 */if (chiSquare1 > th)bIn = false;else/* 累计得分。误差越大,得分越低 */score += thScore - chiSquare1;// Reprojection error in second image// l1 =x2tF21=(a1,b1,c1)/* 计算 当前帧 上的点在 参考帧 上投影得到的极线 l1 = p2 * F21 = (a1, b1, c1) */const float a1 = f11 * u2 + f21 * v2 + f31;const float b1 = f12 * u2 + f22 * v2 + f32;const float c1 = f13 * u2 + f23 * v2 + f33;/* 计算 参考帧的特征点 到 投影得到的极线 l1 的距离平方 d^2 = ((ax+by+c) / sqrt(a^2 + b^2))^2 */const float num1 = a1 * u1 + b1 * v1 + c1;const float squareDist2 = num1 * num1 / (a1 * a1 + b1 * b1);/* 转换当前帧投影至参考帧的误差 */const float chiSquare2 = squareDist2 * invSigmaSquare;/* 用阈值标记离群点,内点的话累加得分 */if (chiSquare2 > th)bIn = false;else/* 累计得分。误差越大,得分越低 */score += thScore - chiSquare2;/* 双向重投影误差均满足要求,则说明当前点为内点 */if (bIn)vbMatchesInliers[i] = true;elsevbMatchesInliers[i] = false;}/* 返回得分 */return score;
}

根据对极约束的几何意义,它能够将一幅图像中的某个点投影到另一幅图像的极线上

在这里插入图片描述
对每个匹配的特征点,计算双向投影误差(特征点 到 投影得到的极线 的距离 d = d = d= a x + b y + c a 2 + b 2 ax+by+c \over \sqrt{a^2 + b^2} a2+b2 ax+by+c 的 平方),并获取对应得分和更新内点标记,具体如下:

  1. 获取匹配点的像素坐标
  2. 计算参考帧上的点 x 1 x_1 x1 在当前帧上投影得到的极线 l 2 l_2 l2,再计算参考帧到当前帧的带权重的重投影误差,同时累积当前得分并进行内点判断
  3. 计算当前帧上的点 x 2 x_2 x2 在参考帧上投影得到的极线 l 1 l_1 l1,再计算当前帧到参考帧的带权重的重投影误差,同时累积当前得分并进行内点判断
  4. 记录当前匹配点的内点标记

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

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

相关文章

web基础03-JavaScript

目录 一、JavaScript基础 1.变量 2.输出 3.变量提升 4.区块 5.JavaScript数据类型 6.查看数值类型 7.undefined和null 8.布尔值 9.和的区别 10.算数/三元/比较/逻辑/赋值运算符 11.特殊字符 12.字符串 &#xff08;1&#xff09;获取字符串长度 &#xff08;2&am…

备战蓝桥杯Day21 - 堆排序的内置模块+topk问题

一、内置模块 在python中&#xff0c;堆排序已经设置好了内置模块&#xff0c;不想自己写的话可以使用内置模块&#xff0c;真的很方便&#xff0c;但是堆排序算法的底层逻辑最好还是要了解并掌握一下的。 使用heapq模块的heapify()函数将列表转换为堆&#xff0c;然后使用he…

41、网络编程/TCP.UDP通信模型练习20240301

一、编写基于TCP的客户端实现以下功能&#xff1a; 通过键盘按键控制机械臂&#xff1a;w(红色臂角度增大)s&#xff08;红色臂角度减小&#xff09;d&#xff08;蓝色臂角度增大&#xff09;a&#xff08;蓝色臂角度减小&#xff09;按键控制机械臂 1.基于TCP服务器的机械臂…

Python3零基础教程之数学运算专题进阶

大家好,我是千与编程,今天已经进入我们Python3的零基础教程的第十节之数学运算专题进阶。上一次的数学运算中我们介绍了简单的基础四则运算,加减乘除运算。当涉及到数学运算的 Python 3 刷题使用时,进阶课程包含了许多重要的概念和技巧。下面是一个简单的教程,涵盖了一些常…

勒索软件类型

勒索软件类型 加密勒索软件 它使个人文件和文件夹&#xff08;文档、电子表格、图片和视频&#xff09;被加密。受感染的文件被加密后会被删除&#xff0c;用户通常会在当下无法使用的文件的文件夹中看到一个包含付款说明的文本文件。当您尝试打开其中一个加密文件时,您才可能…

Tomcat负载均衡、动静分离

目录 引言 实验图解 1.实验环境搭建 2.部署Nginx服务器及配置静态页面Web服务 3.部署Tomcat服务及配置动态页面Web服务 4.实验验收 动态页面 静态页面 引言 tomcat服务既可以处理动态页面&#xff0c;也可以处理静态页面&#xff1b;但其处理静态页面的速度远远不如…

js优雅的统计字符串字符出现次数

题目如下 统计一串字符串中每个字符出现的频率 示例字符串 let str asdfasqwerqwrdfafafasdfopasdfopckpasdfassfd小白写法 let str asdfasqwerqwrdfafafasdfopasdfopckpasdfassfdlet result {}; for (let i 0; i < str.length; i) {if (result[str[i]]) {result[str[…

链表基础知识详解(非常详细简单易懂)

概述&#xff1a; 链表作为 C 语言中一种基础的数据结构&#xff0c;在平时写程序的时候用的并不多&#xff0c;但在操作系统里面使用的非常多。不管是RTOS还是Linux等使用非常广泛&#xff0c;所以必须要搞懂链表&#xff0c;链表分为单向链表和双向链表&#xff0c;单向链表很…

【Vue3】解锁Vue3黑科技:探索接口、泛型和自定义类型的前端奇迹

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

Android Compose - PlainTooltipBox(已废弃)的替代方案

Android Compose - PlainTooltipBox 的替代方案 TooltipBox(positionProvider TooltipDefaults.rememberPlainTooltipPositionProvider(),tooltip {PlainTooltip {Text(/* tooltip content */)}},state rememberTooltipState(), ) {// tooltip anchorIconButton(onClick {…

跨站脚本攻击xss-labs(1-20)靶机练手

目录 一、跨站脚本攻击&#xff08;XSS&#xff09; 1.1 漏洞简介 1.2:类型 1.3 XSS危害 1.4XSS防御规则 二、环境搭建 三、xsst通关记录 Level 1&#xff1a;文本解析为 HTML Level 2&#xff1a;htmlspecialchars;input 标签 value 注入 定义和用法 字符过滤绕过 …

从零自制docker-1-【环境配置 docker go介绍与安装】

文章目录 docker简介举例docker安装go语言go安装go 配置 docker简介 Docker可以看作是一种极其轻巧的“虚拟机”&#xff0c;它允许你将一个或多个程序及其运行环境打包在一起&#xff0c;形成一个标准化的单元&#xff0c;这个单元可以在任何支持Docker的系统上运行&#xff…

实用!IntelliJ IDEA离线开发使用要点(一)

如果IntelliJ IDEA在本地网络之外没有HTTP访问&#xff0c;它将无法检查更新和应用补丁。在这种情况下&#xff0c;您必须下载新版本的IDE并按照离线安装中的描述手动安装它们。 IDEA v2023.3正式版下载 注意&#xff1a;没有互联网接入&#xff0c;您不能安装IntelliJ IDEA使…

SaaS 电商设计 (九) 动态化且易扩展的实现购物车底部弹层(附:一套普适的线上功能切量的发布方案)

目录 一.背景1.1 业务背景1.2 技术负债 二.技术目标三.方案设计3.1 解决移动端频繁发版3.1.1 场景分析3.1.2 技术方案 3.2 减少后端坏味道代码&无法灵活扩展问题3.2.1 通过抽象接口完成各自单独楼层渲染逻辑3.2.2 通过配置能力做到部分字段可配 四.升级上线(普适于高并发大…

学习:吴恩达:什么是神经元?神经网络如何工作?

学习-吴恩达《AI for everyone》2019 深度学习非技术解释 第2部分 可选.zh_哔哩哔哩_bilibili 深度学习Deep learning 人工神经网络Artificial Neural network 什么是神经网络&#xff1f; 只有一个神经元 4个神经元的神经网络 神经网路的绝妙之处 神经网路的绝妙之处就在…

Java快读

java的快读 (1)BufferedReader BufferedReader br new BufferedReader(new InputStreamReader(System.in));//定义对象String[] strings br.readLine().split(" ");//读取一行字符串&#xff0c;以空格为分隔转化为字符串数组int n Integer.parseInt(strings[0])…

k8s分布式图床(k8s,metricsapi,vue3+ts)

image-manage 图像管理应用 图像管理应用提供了一个方便管理图片的平台&#xff0c;支持单机和Kubernetes集群部署。请确保您至少拥有一个MySQL数据库和一个Redis数据库&#xff0c;以及一个至少为Kubernetes 1.29版本的集群&#xff08;如果选择集群部署&#xff09;。 文档…

PCL1.14.0安装、使用教程

写在前面 本文内容 本文是PCL1.14.0在Windows下的安装、使用教程&#xff1b; PCL、Open3D其他版本的编译和使用相关教程见 各个版本的Open3D、PCL的编译、使用教程平台/环境 windows11(windows10): visual studio 2022&#xff1b;cmake 3.22; VsCode转载请注明出处&#xff…

http和https的区别是什么?

–前言 传输信息安全性不同、连接方式不同、端口不同、证书申请方式不同 一、传输信息安全性不同 1、http协议&#xff1a;是超文本传输协议&#xff0c;信息是明文传输。如果攻击者截取了Web浏览器和网站服务器之间的传输报文&#xff0c;就可以直接读懂其中的信息。 2、h…

排序(3)——直接选择排序

目录 直接选择排序 基本思想 整体思路&#xff08;升序&#xff09; 单趟 多趟 代码实现 特性总结 直接选择排序 基本思想 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的…