5.1ORB-SLAM3之回环检测线程检测是否存在共视区域

news2024/11/27 15:38:28

1.简介

本质上是计算当前关键帧和关键帧数据库中的关键帧是否存在公共单词,相似性分数是否满足要求。

bool LoopClosing::NewDetectCommonRegions();

主要包括以下几个模块:

  • 寻找回环候选关键帧和融合候选关键帧
  • 对候选关键帧进行共视几何验证
  • 如果共视几何验证失败了,再进行时序几何验证

2.进行共视区域检测(回环检测)的条件

  1. 回环开启标志mbActiveLC=True,该变量在系统初始化函数中创建LoopClosing线程时设置。
  2. 系统还未创建地图,或者当前子地图IMU模式下还未进行第三次初始化
    mpLastMap->IsInertial() && !mpLastMap->GetIniertialBA2()
    
  3. 双目模式下关键帧数量少于5帧不进行初始化
    mpTracker->mSensor == System::STEREO && mpLastMap->GetAllKeyFrames().size() < 5
    
  4. 其他模式下当前活跃子地图中也要保持一定数量的关键帧(12帧)

3.寻找回环候选关键帧和融合候选关键帧DetectNBestCandidates

void DetectNBestCandidates(KeyFrame *pKF, vector<KeyFrame*> &vpLoopCand, 
				vector<KeyFrame*> &vpMergeCand, int nNumCandidates)

回环候选和融合候选的区别在于候选关键帧和当前关键帧是否属于同一个活跃子地图,如果是则是回环候选关键帧,反之是融合候选关键帧,关键步骤如下:

  • 找出和当前关键帧存在公共单词数的历史关键帧,并进行筛选
  • 基于L1范数计算和候选关键帧之间的相似性得分
  • 根据共视关系将所有上述候选关键帧进行分组,找出每组相似性得分总分数,以总分数最高的一组里相似性得分最高的关键帧
  • 根据候选关键帧与当前关键帧是否存在于同一个子地图,将关键帧放入不同的容器

3.1找出和当前关键帧存在公共单词数的历史关键帧,并进行筛选

  1. 寻找具备公共单词数的关键帧这里主要依据词袋向量的逆序索引,关键帧数据库维护一个std::vector<list<KeyFrame*> >类型的成员变量,vector的索引表示单词的索引,索引对应的元素mvInvertedFile[i]表示包含该单词的所有关键帧,因此对于某个单词可以直接获取包含该单词的所有关键帧
list<KeyFrame*> &lKFs = mvInvertedFile[vit->first];
  1. 排除和当前关键帧存在连接关系的共视关键帧:共视关键帧必然和当前关键帧处于同一区域,虽然存在公共单词但不是回环关键帧。
  2. 排除和当前关键帧公共单词数较少的候选关键帧

3.2基于L1范数计算和候选关键帧之间的相似性得分

float si = mpVoc->score(pKF->mBowVec,pKFi->mBowVec);

基于L1范数计算两个词袋向量的距离,实质上就是两个向量对应元素之和减去对应元素之差。

计算相似性得分时并不是根据单词的有无进行0,1的比较,而是根据单词出现的频率计算一个TF-IDF权重,所以词袋向量中每个元素都表征了每个单词在图像中出现的频率.

单词权重和相似性得分的计算方式如下:
在这里插入图片描述

在这里插入图片描述

3.3通过分组寻找和当前关键帧相似性程度最高的候选关键帧

根据共视关系将所有上述候选关键帧进行分组,找出每组相似性得分最高的关键帧及其对应的分数。

分组方式如下:
在这里插入图片描述

最佳相似性关键帧: 假设以下几个节点中与当前KF相似性得分最好的分别为:1,2,2,3,10,则将这五个得分最高的关键帧拿出来作为最佳候选,其中可能有重复的,但无所谓后面会处理。

3.4.根据候选关键帧与当前关键帧是否存在于同一个子地图,将关键帧放入不同的容器

  • 如果候选帧与当前关键帧在同一个地图里,且候选者数量还不足够,将其放入回环候选关键帧容器vpLoopCand
  • 如果候选者与当前关键帧不再同一个地图里, 且候选者数量还不足够, 且候选者所在地图不是bad,将其添加到融合候选关键帧容器vpMergeCand
while(i < lAccScoreAndMatch.size() && (vpLoopCand.size() < nNumCandidates || vpMergeCand.size() < nNumCandidates)){
    KeyFrame* pKFi = it->second;
    if(pKFi->isBad())
        continue;
    // 如果没有被重复添加
    if(!spAlreadyAddedKF.count(pKFi)){
        // 如果候选帧与当前关键帧在同一个地图里,且候选者数量还不足够,将其放入回环候选关键帧容器
        if(pKF->GetMap() == pKFi->GetMap() && vpLoopCand.size() < nNumCandidates){
            vpLoopCand.push_back(pKFi);
        }
        // 如果候选者与当前关键帧不再同一个地图里, 且候选者数量还不足够, 且候选者所在地图不是bad,将其添加到融合候选关键帧容器
        else if(pKF->GetMap() != pKFi->GetMap() && vpMergeCand.size() < nNumCandidates && !pKFi->GetMap()->IsBad()){
            vpMergeCand.push_back(pKFi);
        }
        spAlreadyAddedKF.insert(pKFi);
    }
    i++;
    it++;
}

4.几何相似性验证DetectCommonRegionsFromBoW

  1. 对于每个候选关键帧找出其共视程度最高的10个共视关键帧
  2. 通过Bow寻找候选帧窗口内的关键帧地图点与当前关键帧的匹配点
  3. 利用RANSAC寻找候选关键帧窗口与当前关键帧的相对位姿T_cm的初始值
  4. 利用搜索到的更多的匹配点用Sim3优化投影误差得到的更好的相似变换信息
  5. 利用地图中的共视关键帧验证(共视几何校验)

函数声明:

/**
 * @brief 实现论文第8页的2-5步中的一部分功能(对后面新进来的关键帧的验证没有放在这个函数里进行)
 * 
 * @param[in] vpBowCand bow 给出的一些候选关键帧
 * @param[out] pMatchedKF2 最后成功匹配的候选关键帧
 * @param[out] pLastCurrentKF 用于记录当前关键帧为上一个关键帧(后续若仍需要时序几何校验需要记录此信息)
 * @param[out] g2oScw 候选关键帧世界坐标系到当前关键帧的Sim3变换
 * @param[out] nNumCoincidences 成功几何验证的帧数,超过3就认为几何验证成功,不超过继续进行时序验证
 * @param[out] vpMPs  所有地图点
 * @param[out] vpMatchedMPs 成功匹配的地图点 
 * @return true 检测到一个合格的共同区域
 * @return false 没检测到一个合格的共同区域
 */
bool DetectCommonRegionsFromBoW(std::vector<KeyFrame*> &vpBowCand, KeyFrame* &pMatchedKF, KeyFrame* &pLastCurrentKF, g2o::Sim3 &g2oScw,
                                     int &nNumCoincidences, std::vector<MapPoint*> &vpMPs, std::vector<MapPoint*> &vpMatchedMPs);

4.1对于每个候选关键帧找出其共视程度最高的10个共视关键帧

std::vector<KeyFrame*> vpCovKFi = pKFi->GetBestCovisibilityKeyFrames(nNumCovisibles);

对于某个候选关键帧的10个共视关键帧,如果其中存在当前帧的共视关键帧,则放弃该候选关键帧。

4.2通过Bow寻找候选帧窗口内的关键帧地图点与当前关键帧的匹配点

int num = matcherBoW.SearchByBoW(mpCurrentKF, vpCovKFi[j], vvpMatchedMPs[j]);

vvpMatchedMPs是一个std::vector<std::vector<MapPoint*> >类型的变量,其中每个元素储存了每个候选关键帧的共视帧与当前帧的匹配的地图点。

通过词袋,对关键帧的特征点进行跟踪,该函数用于闭环检测时两个关键帧间的特征点匹配。通过bow对pKF和F中的特征点进行快速匹配(不属于同一node的特征点直接跳过匹配)。对属于同一node的特征点通过描述子距离进行匹配,通过距离阈值、比例阈值和角度投票进行剔除误匹配。

4.3利用RANSAC寻找候选关键帧窗口与当前关键帧的相对位姿T_cm的初始值

随机选择3对匹配点,计算相似变换,直到算法收敛(基于sim3相似变换矩阵得到的内点数量大于一定阈值)或者达到最大迭代次数。

之所以求解sim3而不是直接求解变换矩阵的原因是,跑那么长时间了可能会出现尺度漂移的情况。

mTcm = solver.iterate(20,bNoMore, vbInliers, nInliers, bConverge);

求解步骤如下:
1. 分别基于三对匹配3D点建立两个坐标系
在这里插入图片描述

X轴: x l ^ = x l / ∥ x l ∥ \hat{x_l} = x_l/\left \| x_l \right \| xl^=xl/xl , 其中 x l = r l , 2 − r l , 1 x_l = r_{l,2} - r_{l,1} xl=rl,2rl,1
Y轴: y l ^ = y l / ∥ y l ∥ \hat{y_l} = y_l/\left \| y_l \right \| yl^=yl/yl,其中 y l = ( r l , 3 − r l , 1 ) − [ ( r l , 3 − r l , 1 ) ⋅ x l ^ ] x l ^ y_l = \left ( r_{l,3} - r_{l,1} \right ) - \left [ \left ( r_{l,3} - r_{l,1} \right ) \cdot \hat{x_l} \right ]\hat{x_l} yl=(rl,3rl,1)[(rl,3rl,1)xl^]xl^
Z轴: z l ^ = x l ^ × y l ^ \hat{z_l} = \hat{x_l}\times\hat{y_l} zl^=xl^×yl^

右坐标系同理,且令: M l = ∣ x l ^ , y l ^ , z l ^ ∣ , M r = ∣ x r ^ , y r ^ , z r ^ ∣ M_l = \left | \hat{x_l}, \hat {y_l}, \hat{z_l} \right | ,M_r = \left | \hat{x_r}, \hat{y_r}, \hat{z_r} \right | Ml=xl^,yl^,zl^,Mr=xr^,yr^,zr^

其中, ( r l , 3 − r l , 1 ) \left ( r_{l,3} - r_{l,1} \right ) (rl,3rl,1)表示斜边向量 r 13 r_{13} r13 x l ^ \hat{x_l} xl^表示x轴方向的单位向量, ( r l , 3 − r l , 1 ) ⋅ x l ^ \left( r_{l,3} - r_{l,1} \right ) \cdot \hat{x_l} (rl,3rl,1)xl^表示斜边向量在x轴上分量的长度, [ ( r l , 3 − r l , 1 ) ⋅ x l ^ ] x l ^ \left [ \left ( r_{l,3} - r_{l,1} \right ) \cdot \hat{x_l} \right ]\hat{x_l} [(rl,3rl,1)xl^]xl^表示斜边向量在x轴上的分量大小,最终 y l y_l yl表示斜边向量减去在x轴方向的分量得到在y轴上的分量,归一化处理后得到y轴方向

2.旋转量R计算
旋转矩阵的变换涉及到了同一向量在不同基底(坐标系)下的表示和变换关系.

如果左边坐标系有一个向量 r l r_l rl,那么 M l T r l M_{l}^{T}r_l MlTrl 可以得到 r l r_l rl向量沿着坐标轴的值

M r M_r Mr左乘 M l T r l M_{l}^{T}r_l MlTrl后可以得到该向量在右侧坐标系的表示 r r = M r M l T r l r_r=M_rM_{l}^{T}r_l rr=MrMlTrl,因此可以推导出左右坐标系的旋转:
R = M r M l T R = M_rM_{l}^{T} R=MrMlT

3.扩展-代码中旋转矩阵的计算
在这里插入图片描述

在这里插入图片描述

3.平移向量计算
假设左右坐标系中各有n个点,他们在两个坐标系下的坐标分别为: { r l , i } \left \{r_{l,i} \right \} {rl,i} { r r , i } \left \{r_{r,i} \right \} {rr,i}, i i i的取值为1到n

假设某个向量由左侧坐标系到右侧坐标系的变换可以表示为: r r = s R ( r l ) + r 0 r_r = sR\left ( r_l \right ) + r_0 rr=sR(rl)+r0,其中s为尺度变换, r 0 r_0 r0为平移偏移量。 ( r l ) \left ( r_l \right ) (rl)表示向量从左侧坐标系到右侧坐标系的旋转。

而实际求解时,两个坐标系之间的变换总是会存在误差,因此可以将问题的求解转换为一个最小二乘问题,可以看出这里的误差为:
e i = r r , i − s R ( r l , i ) − r 0 e_i = r_{r,i} - sR\left ( r_{l,i} \right ) - r_0 ei=rr,isR(rl,i)r0
最终最小二乘问题变为求解以下问题,待求解量为平移向量 r 0 r_0 r0
1 2 min ⁡ ∑ i = 1 n ∥ e i ∥ 2 \frac{1}{2}\min \sum_{i=1}^{n} \left \| e_i \right \| ^2 21mini=1nei2

看到这里可以联想到《十四讲》中关于视觉ICP的求解过程,使用去质心法构造误差函数形式,求解使得误差最小时对应的平移向量 r 0 r_0 r0

step1 分别计算左侧和右侧坐标系所有点的质心
r l ˉ = 1 n ∑ i = 1 n r l , i r r ˉ = 1 n ∑ i = 1 n r r , i \begin{equation}\begin{split} \bar{r_l} = \frac{1}{n}\sum_{i=1}^{n}r_{l,i}\\ \bar{r_r} = \frac{1}{n}\sum_{i=1}^{n}r_{r,i}\end{split}\end{equation} rlˉ=n1i=1nrl,irrˉ=n1i=1nrr,i

step2 对每对点的误差作以下处理
e i = r r , i − s R r l , i − r 0 = r r , i − s R r l , i − r 0 − r r ˉ + R r l ˉ + r r ˉ − R r l ˉ = r r , i − r r ˉ − s R ( r l , i − r l ˉ ) + ( r r ˉ − R r l ˉ − r 0 ) \begin{equation} \begin{split} e_i & = r_{r,i} - sRr_{l,i} - r0\\ & = r_{r,i} - sRr_{l,i} - r0 -\bar{r_r} + R\bar{r_l} + \bar{r_r} - R\bar{r_l}\\ & = r_{r,i} - \bar{r_r} - sR(r_{l,i} -\bar{r_l}) + (\bar{r_r} - R\bar{r_l} -r0)\\ \end{split} \end{equation} ei=rr,isRrl,ir0=rr,isRrl,ir0rrˉ+Rrlˉ+rrˉRrlˉ=rr,irrˉsR(rl,irlˉ)+(rrˉRrlˉr0)

step3 关于误差的最小二乘函数为
1 2 ∑ i = 1 n ∥ e i ∥ 2 = 1 2 ∑ i = 1 n ∥ r r , i − r r ˉ − s R ( r l , i − r l ˉ ) + ( r r ˉ − R r l ˉ − r 0 ) ∥ 2 = 1 2 ∑ i = 1 n ( ∥ r r , i − r r ˉ − s R ( r l , i − r l ˉ ) ∥ 2 + ∥ r r ˉ − R r l ˉ − r 0 ∥ 2 + 2 ( r r , i − r r ˉ − s R ( r l , i − r l ˉ ) ) T ( r r ˉ − R r l ˉ − r 0 ) ) \begin{equation} \begin{split} \frac{1}{2} \sum_{i=1}^{n} \left \| e_i \right \| ^2 & =\frac{1}{2} \sum_{i=1}^{n} \left \| r_{r,i} - \bar{r_r} - sR(r_{l,i} -\bar{r_l}) + (\bar{r_r} - R\bar{r_l} -r0) \right \| ^2\\ & =\frac{1}{2} \sum_{i=1}^{n} (\left \| r_{r,i} - \bar{r_r} - sR(r_{l,i} -\bar{r_l}) \right \| ^2 +\left \| \bar{r_r} - R\bar{r_l} -r0 \right \|^2 +\\ &\quad 2(r_{r,i} - \bar{r_r} - sR(r_{l,i} -\bar{r_l}))^T(\bar{r_r} - R\bar{r_l} -r0))\end{split}\end{equation} 21i=1nei2=21i=1nrr,irrˉsR(rl,irlˉ)+(rrˉRrlˉr0)2=21i=1n(rr,irrˉsR(rl,irlˉ)2+rrˉRrlˉr02+2(rr,irrˉsR(rl,irlˉ))T(rrˉRrlˉr0))

可以看到整个式子可以分为3项,对于第三项交叉项部分 ( r r , i − r r ˉ − s R ( r l , i − r l ˉ ) ) (r_{r,i} - \bar{r_r} - sR(r_{l,i} -\bar{r_l})) (rr,irrˉsR(rl,irlˉ))在求和后为0,第一项 ∥ r r , i − r r ˉ − s R ( r l , i − r l ˉ ) ∥ 2 \left \| r_{r,i} - \bar{r_r} - sR(r_{l,i} -\bar{r_l}) \right \| ^2 rr,irrˉsR(rl,irlˉ)2和平 r 0 r_0 r0无关,因此可以都删掉,则误差函数可以变为:
1 2 ∑ i = 1 n ∥ e i ∥ 2 = 1 2 ∑ i = 1 n ∥ r r ˉ − R r l ˉ − r 0 ∥ 2 \begin{equation} \begin{split} \frac{1}{2} \sum_{i=1}^{n} \left \| e_i \right \| ^2 & =\frac{1}{2} \sum_{i=1}^{n}\left \| \bar{r_r} - R\bar{r_l} -r0 \right \|^2\end{split}\end{equation} 21i=1nei2=21i=1nrrˉRrlˉr02

step4 求解平移向量r0
可以知道当 r r ˉ − R r l ˉ − r 0 = 0 \bar{r_r} - R\bar{r_l} -r0=0 rrˉRrlˉr0=0时误差最小,由此解得平移向量为:
r 0 = r r ˉ − R r l ˉ \begin{equation} r0=\bar{r_r} - R\bar{r_l}\end{equation} r0=rrˉRrlˉ

4.尺度计算
由于长时间运动会使得相机轨迹的尺度也发生一定的漂移,因此假设候选回环帧和当前关键帧之间是相似变换而非刚体变换。
在这里插入图片描述

4.4利用初始的Scm信息,进行双向重投影,并非线性优化得到更精确的Scm

核心思想是将当前关键帧中的3D地图点投影到每个候选关键帧,基于网格注册信息加速特征匹配过程,通过计算地图点描述子和关键帧特征点描述子距离得到匹配关系

int numProjMatches = matcher.SearchByProjection(mpCurrentKF, mScw, vpMapPoints, vpKeyFrames, vpMatchedMP, vpMatchedKF, 8, 1.5);

4.5利用搜索到的更多的匹配点用Sim3优化投影误差得到的更好的相似变换信息

int numOptMatches = Optimizer::OptimizeSim3(mpCurrentKF, pKFi, vpMatchedMP, gScm, 10, mbFixScale, mHessian7x7, true);

4.6共视几何校验:使用当前关键帧的共视帧验证得到的相似变换矩阵

  1. 取出和当前关键帧共视关系最好的5个关键帧,成为验证组
  2. 通过之前计算的位姿将候选关键帧及其共视帧的地图点投影到验证组关键帧上, 若匹配点大于一定数目的任务成功验证一次
  3. 5次中有连续3次验证成功则几何相似性验证成功
/**
 * @brief 用来验证候选帧的函数, 这个函数的名字取的不好, 函数的本意是想利用候选帧的共视关键帧来验证候选帧,不如改叫做:DetectCommonRegionsFromCoVKF
 * 
 * @param[in] pCurrentKF 当前关键帧的共视关键帧(验证组关键帧之一)
 * @param[in] pMatchedKF 候选帧
 * @param[in] gScw 世界坐标系在验证帧下的Sim3
 * @param[out] nNumProjMatches 最后匹配的数目 
 * @param[out] vpMPs 候选帧的窗口内所有的地图点
 * @param[out] vpMatchedMPs 候选帧的窗口内被匹配到的地图点 
 * @return true 验证成功
 * @return false 验证失败
 */
bool LoopClosing::DetectCommonRegionsFromLastKF(KeyFrame* pCurrentKF, KeyFrame* pMatchedKF, g2o::Sim3 &gScw, int &nNumProjMatches,
                                                std::vector<MapPoint*> &vpMPs, std::vector<MapPoint*> &vpMatchedMPs)

5.时序几何校验

如果在共视几何校验时,通过校验的验证组关键帧数量大于0小于3,则认为共视几何校验失败,但没有完全失败,还可以通过时序几何校验抢救一下。

在上一关键帧进行共视几何校验失败时,会暂时保留之前的候选关键帧和相似变换关系,利用当前关键帧与上一关键帧之间的运动变换,可以得到当前新的关键帧与候选关键帧的运动变换。

然后继续把候选帧局部窗口内的地图点向新进来的关键帧投影来验证回环检测结果,并优化Sim3位姿。

bool bCommonRegion = DetectAndReffineSim3FromLastKF(mpCurrentKF, mpLoopMatchedKF, gScw, numProjMatches, mvpLoopMPs, vpMatchedMPs);

如果时序几何验证成功超过三次,则判定找到了共视区域,根据候选帧处于当前活跃子弟图还是旧的非活跃子弟图,区分是回环情况还是地图融合。

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

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

相关文章

Android Studio实现内容丰富的安卓校园二手交易平台(带聊天功能)

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号083 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看二手商品…

AndroidStudio设置compileSdk33后xml无提示问题

这个非常蛋疼的问题遇到很多次了&#xff0c;AndroidStudio升级compileSdk33后无xml提示。挺久前写一个调研demo时发现了这个问题&#xff0c;但因为那会任务重&#xff0c;也没有去深入研究&#xff0c;就在写代码时用target32&#xff0c;写完打包demo时修改为33&#xff0c;…

附录7-用户列表案例,element-ui

目录 1 效果 1.1 查询所有用户 1.2 添加新用户 1.3 删除用户 1.4 用户详情 2 后端 2.1 查询所有 2.2 添加 2.3 删除 2.4 查询单个 3 前端 3.1 环境 3.2 main.js 3.3 userList.vue 3.4 userInfo.vue 1 效果 1.1 查询所有用户 1.2 添加新用户 …

工厂水电能耗监测系统组成

工厂水电能耗监测系统是一种用于监测工厂水电能耗的系统&#xff0c;可以帮助工厂管理者了解水电能耗情况&#xff0c;提高能源利用效率&#xff0c;降低生产成本。本文将从系统组成、功能、优点等方面进行介绍。 一、系统组成 工厂水电能耗监测系统由多个部分组成&#xff0c…

MySQL第一天

文章目录 作业1 简述MySQL体系结构CetenOS 7的MySQLyum在线安装CetenOS 7的MySQL的二进制方式安装 作业1 简述MySQL体系结构 MySQL是由SQL接口、解析器、优化器、缓存、储存引擎组成的&#xff0c;MySQL的最重要的是它的储存引擎架构&#xff0c;这种设计将查询处理及其系统任…

【运维工程师学习】Debian安装

【运维工程师学习】Debian安装 1、界面说明2、选择语言3、等待探测并挂载安装介质完成4、设置主机名称、用户信息5、磁盘分区6、创建分区7、最终分区为8、安装ssh9、查看ssh状态10、查看内存大小11、查询系统磁盘及分区情况12、查看各磁盘及分区剩余13、查看ip地址 选择镜像文件…

新服务器配环境

本章节的大概思路为&#xff1a; 1、远程连接服务器 直接远程连接&#xff0c;前的是你要连接的目录名称&#xff0c;后为服务器公网IP。 ssh xxxxxx.xxx.xxx.xxx 远程连接服务器不同端口 -p后为端口名称 ssh xxxxxx.xxx.xxx.xxx -p xxxx 之后输入密码就行了。 2、创建子用…

c语言修炼之猜数字游戏

前言 小伙伴们&#xff0c;今天来学习猜数字游戏叭&#xff01;废话不多说&#xff0c;让我们一起开始学习叭! 思路&#xff1a; 一打开游戏就出现一个菜单然后可以让我们选择是进入游戏还是退出游戏&#xff01; #include<stdio.h> void menu() {printf("*****…

详解高性能无锁队列的实现

一、无锁队列 1.1 什么是无锁队列 无锁队列&#xff08;Lock-Free Queue&#xff09;是一种并发数据结构&#xff0c;它允许多个线程在没有锁的情况下进行并发操作。 传统的队列通常通过互斥锁来实现线程安全的操作&#xff0c;但互斥锁在高并发情况下可能会造成竞争和性能瓶…

【后端面经-Java】AQS详解

【后端面经-Java】AQS详解 1. AQS是什么&#xff1f;2. AQS核心思想2.1 基本框架2.1.1 资源state2.1.2 CLH双向队列 2.2 AQS模板 3. 源码分析3.1 acquire(int)3.1.1 tryAcquire(int)3.1.2 addWaiter(Node.EXCLUSIVE)3.1.3 acquireQueued(Node node, int arg) 3.2 release(int)3…

校园水电节能管理解决方案

随着社会经济的不断发展&#xff0c;能源问题日益突出&#xff0c;节能减排成为了各级各类学校必须面对的问题。学校的水电能源消耗是其中的一个重要方面&#xff0c;因此&#xff0c;如何对校园水电进行节能管理成为了一个迫切的问题。本文将从以下几个方面介绍校园水电节能管…

在选择自动化测试工具时需要考虑哪些因素?

自动化测试工具是软件开发中不可或缺的一部分&#xff0c;它可以提高测试效率、减少人力成本、提升软件质量&#xff0c;那在选择自动化测试工具时需要考虑哪些因素&#xff1f; 测试需求&#xff1a;首先要明确自动化测试的需求是什么&#xff0c;不同的测试需求对应着不同的工…

电子电气架构相关安全体系介绍

摘要&#xff1a; 随着电子电气架构技术的不断升级&#xff0c;整车越来越多的系统和组件对功能安全产生影响&#xff0c;为此&#xff0c;功能安全也从部分关键系统开发&#xff0c;向整车各系统全面开发拓展。同时&#xff0c;由于域集中式、中央集中式等新架构形态的出现&a…

文档翻译免费怎么做?三分钟告诉你

小乐&#xff1a;嘿&#xff0c;小阳&#xff0c;你知道吗&#xff1f;我最近在学习文档翻译英文&#xff0c;真是太神奇了&#xff01; 小阳&#xff1a;哇&#xff0c;真的吗&#xff1f;那听起来很厉害啊&#xff01;文档翻译英文是怎么做的呢&#xff1f; 小乐&#xff1…

深入解析Java多态进阶学习

目录 1.动态绑定机制 实例A实例B实例C2.多态数组 3.多态数组的高阶用法 4.多态参数 5.多态参数的高阶用法 1.动态绑定机制 java的动态绑定机制非常重要 实例A 我们来看一个实例&#xff1a; 阅读上面的代码&#xff0c;请说明下面的程序将输出什么结果&#xff1a; 程序将会…

机器学习24:《数据准备和特征工程-II》收集数据

构建数据集常用的步骤如下所示&#xff1a; 收集原始数据。识别特征和标签来源。选择抽样策略。拆分数据。 这些步骤在很大程度上取决于你如何构建 ML 问题。本文主要介绍——数据收集-Collecting Data。 目录 1. 数据集的大小和质量 1.1 数据集的大小 1.2 数据集的质量 …

.NET Core webapi 从零开始在IIS上面发布后端接口

文章目录 原因环境配置windows环境.NET Core安装开发端安装服务端安装 新建ASP.NET项目 原因 .NET core是以后.NET未来的趋势&#xff0c;虽然我感觉Java在web后端的主导地位10年内不会动摇&#xff0c;因为Java占据了先发优势。 不过C#的特点就是&#xff0c;简单&#xff0…

mysql三大日志之我对Binlog的理解

mysql 我们先来看一下MySQL的基本架构&#xff0c;从大的方面来讲&#xff0c;一个server层&#xff0c;一个引擎层。server层就像一个接口&#xff0c;可以对接任何符合规定的引擎。具体的细节可以参考我之前写过的文章mysql的这些坑你踩过吗&#xff1f;快来看看怎么优化mys…

Blazor 自定义可重用基础组件之 带标头排序的Table

实现点击标头按所在列值进行排序&#xff0c;是一个非常有用的功能&#xff0c;其他的UI一般搞得非常复杂&#xff0c;添加标志图标什么的&#xff0c;使得本就不宽裕的表格更加拥挤。我的思路是&#xff0c;点击所在列的标头部位&#xff0c;传递标头值&#xff0c;然后根据标…

裸机搭建k8s报错记录

安装教程参考 修复一、 cd /etc/kubernetes/manifests vim kube-scheduler.yaml注释掉 重启 systemctl restart kubelet.service问题二、 https://github.com/kubernetes/kubernetes/issues/70202 一直处于创建中状态 网络原因 cat << EOF > /run/flannel/subnet.…