ORB SLAM3 构建Frame

news2024/11/22 22:38:33

1.构造Frame

为了构建一帧Frame,主要的步骤如下:

  1. 提取ORB特征点(ExtractORB)
  2. 对提取的特征点进行矫正(cv::undistortPoints)
  3. 计算去畸变后的图像边界(ComputeImageBounds)
  4. 将特征点分配到网格中(AssignFeaturesToGrid)

A.提取ORB特征点

首先需要对当前帧图像进行特征点的提取:计算图像金字塔提取Fast角点四叉树均匀化计算特征点的方向计算特征点的描述子

1.计算图像金字塔

在这里插入图片描述

    void ORBextractor::ComputePyramid(cv::Mat image)
    {
        for (int level = 0; level < nlevels; ++level)
        {
            float scale = mvInvScaleFactor[level];
            Size sz(cvRound((float)image.cols*scale), cvRound((float)image.rows*scale));
            Size wholeSize(sz.width + EDGE_THRESHOLD*2, sz.height + EDGE_THRESHOLD*2);
            Mat temp(wholeSize, image.type()), masktemp;
            mvImagePyramid[level] = temp(Rect(EDGE_THRESHOLD, EDGE_THRESHOLD, sz.width, sz.height));

        // Compute the resized image
		//计算第0层以上resize后的图像
        if( level != 0 )
        {
			//将上一层金字塔图像根据设定sz缩放到当前层级
            resize(mvImagePyramid[level-1],	//输入图像
				   mvImagePyramid[level], 	//输出图像
				   sz, 						//输出图像的尺寸
				   0, 						//水平方向上的缩放系数,留0表示自动计算
				   0,  						//垂直方向上的缩放系数,留0表示自动计算
				   cv::INTER_LINEAR);		//图像缩放的差值算法类型,这里的是线性插值算法

			//把源图像拷贝到目的图像的中央,四面填充指定的像素。图片如果已经拷贝到中间,只填充边界
			//TODO 貌似这样做是因为在计算描述子前,进行高斯滤波的时候,图像边界会导致一些问题,说不明白
			//EDGE_THRESHOLD指的这个边界的宽度,由于这个边界之外的像素不是原图像素而是算法生成出来的,所以不能够在EDGE_THRESHOLD之外提取特征点			
            copyMakeBorder(mvImagePyramid[level], 					//源图像
						   temp, 									//目标图像(此时其实就已经有大了一圈的尺寸了)
						   EDGE_THRESHOLD, EDGE_THRESHOLD, 			//top & bottom 需要扩展的border大小
						   EDGE_THRESHOLD, EDGE_THRESHOLD,			//left & right 需要扩展的border大小
                           BORDER_REFLECT_101+BORDER_ISOLATED);     //扩充方式,opencv给出的解释:
			
			/*Various border types, image boundaries are denoted with '|'
			* BORDER_REPLICATE:     aaaaaa|abcdefgh|hhhhhhh
			* BORDER_REFLECT:       fedcba|abcdefgh|hgfedcb
			* BORDER_REFLECT_101:   gfedcb|abcdefgh|gfedcba
			* BORDER_WRAP:          cdefgh|abcdefgh|abcdefg
			* BORDER_CONSTANT:      iiiiii|abcdefgh|iiiiiii  with some specified 'i'
			*/
			
			//BORDER_ISOLATED	表示对整个图像进行操作
            // https://docs.opencv.org/3.4.4/d2/de8/group__core__array.html#ga2ac1049c2c3dd25c2b41bffe17658a36

        }
        else
        {
			//对于底层图像,直接就扩充边界了
            //?temp 是在循环内部新定义的,在该函数里又作为输出,并没有使用啊!
            copyMakeBorder(image,			//这里是原图像
						   temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,
                           BORDER_REFLECT_101);            
        }
    }

    }
  • 对于level = 0
    • 对原图像的上下左右扩充EDGE_THRESHOLD(19)像素
  • 对于level !=0
    • 对金字塔level-1层图像进行缩放scale得到level层图像
    • level层图像的边界上下左右扩充EDGE_THRESHOLD(19)像素
  • 实际操作:只对原图像进行了一层一层的缩放
    在这里插入图片描述
void cv::copyMakeBorder
(
	InputArray _src_, //输入图像
	OutputArray _dst_,//输出图像
	int _top_,//上边界的大小
	int _bottom_,//下边界的大小
	int _left_,//左边界的大小
	int _right_,//右边界的大小
	int _borderType_,//边界的类型
	const Scalar& _value_ = Scalar()//边界的值
	//BORDER_REPLICATE(复制):     aaaaaa|abcdefgh|hhhhhhh 
	//BORDER_REFLECT(镜像):       fedcba|abcdefgh|hgfedcb  
	//BORDER_REFLECT_101(镜像):   gfedcb|abcdefgh|gfedcba  
	//BORDER_WRAP(包裹):          cdefgh|abcdefgh|abcdefg  
	//BORDER_CONSTANT(常量):      iiiiii|abcdefgh|iiiiiii  with some specified i
)

2.提取Fast角点

对于金字塔的每一层,将其网格化,每个格子大小为 w = 35 w = 35 w=35

  • 左上角(红色): ( m i n B o r d e r X , m i n B o r d e r Y ) \left(minBorderX, minBorderY\right) (minBorderX,minBorderY)
  • 右下角: ( m a x B o r d e r Y , m a x B o r d e r Y ) \left(maxBorderY, maxBorderY\right) (maxBorderY,maxBorderY)
  • 网格的行数: r o w s = ( m a x B o r d e r Y − m i n B o r d e r Y ) w rows=\frac{\left(maxBorderY-minBorderY\right)}{w} rows=w(maxBorderYminBorderY)
  • 网格的列数: c o l s = ( m a x B o r d e r X − m i n B o r d e r X ) w cols=\frac{\left(maxBorderX-minBorderX\right)}{w} cols=w(maxBorderXminBorderX)
    这时候可以在每个格子中提取Fast角点, 其中格子的范围为:
  • i n i X = m i n B o r d e r X + j ⋅ w C e l l iniX = minBorderX + j \cdot wCell iniX=minBorderX+jwCell
  • i n i Y = m i n B o r d e r Y + i ⋅ h C e l l iniY = minBorderY + i \cdot hCell iniY=minBorderY+ihCell
  • m a x X = i n i X + w C e l l + 6 maxX = iniX + wCell + 6 maxX=iniX+wCell+6
  • m a x Y = i n i Y + h C e l l + 6 maxY = iniY + hCell + 6 maxY=iniY+hCell+6
    FAST角点(iniX, iniY, maxX, maxY)范围内提取,这里使用高低阈值
    在这里插入图片描述
FAST(mvImagePyramid[level].rowRange(iniY,maxY).colRange(iniX,maxX),	//待检测的图像,这里就是当前遍历到的图像块
	vKeysCell,			//存储角点位置的容器
	iniThFAST,			//检测阈值
	true);				//使能非极大值抑制
if(vKeysCell.empty())
{
	//那么就使用更低的阈值来进行重新检测
	FAST(mvImagePyramid[level].rowRange(iniY,maxY).colRange(iniX,maxX),	//待检测的图像
		 vKeysCell,		//存储角点位置的容器
		 minThFAST,		//更低的检测阈值
		 true);			//使能非极大值抑制
}

提取到的角点的原点位于紫色,需要将其变换到红色
x = x + j ⋅ w C e l l y = y + i ⋅ h C e l l \begin{array}{c} x = x + j \cdot wCell \\ y = y + i \cdot hCell \end{array} x=x+jwCelly=y+ihCell

2.四叉树均匀化

四叉树的节点如下:

class ExtractorNode
{
public:
    ExtractorNode():bNoMore(false){}

    void DivideNode(ExtractorNode &n1, ExtractorNode &n2, ExtractorNode &n3, ExtractorNode &n4);

    std::vector<cv::KeyPoint> vKeys //该节点下的特征点;
    cv::Point2i UL, UR, BL, BR //上下左右边界;
    std::list<ExtractorNode>::iterator lit //迭代器,指向自己;
    bool bNoMore //当特征点数量为1是,不可再分裂;
};

步骤:

  1. 根据宽高比例计算初始的节点数
  2. 根据节点数生成初始化节点
  3. 将特征点分配到对应的节点中(kp.pt.x/hX)
  4. 对于初始化节点,标记那些不能分裂的,删除那些空的节点
  5. 记录状态:
    • preSize: 当前节点特征点的数量
    • nToExpand: 需要分裂的节点数
    • vSizeAndPointerToNode: 可分裂的节点的指针及其特征点数
  6. 分裂
    • 添加子节点
    • 可分裂的子节点加入到可分裂的节点
    • 特征点数量等于1的标记为不可分裂节点
    • 删除当前节点
  7. 结束条件:
    • 当前的节点数已经超过了要求的特征点数
    • 当前所有的节点都不再分了
  8. 对于: 当前节点数 + 即将分裂的节点数 * 3 > N
    • 对即将分裂的节点数按照特征点数量的多少进行排序
    • 按照特征点数量多的节点先分裂的原则进行分裂
    • 如果分裂过程中,满足结束条件,则立即结束。
  9. 非极大值抑制

示例:目标特征点数(20)

  1. 一个初始节点分为4个子节点
  2. 4个节点分裂为16个子节点,其中:
    • 3个子节点中无特征点,删除;
    • 3个子节点中只有一个特征点,标记为不可分
    • 剩余10个子节点,添加到可分裂的节点
  3. 13个节点 + 10个可分节点 * 3 > 20
    • 对10个可分节点排序
    • 当节点数达到20,停止
  4. 对每个节点进行非极大值抑制,选取响应最大的特征点作为该节点最终特征点

在这里插入图片描述
在四叉树均匀化后,将特征点坐标变换到青色
x = x + m i n B o r d e r X y = y + m i n B o r d e r Y \begin{array}{c} x = x + minBorderX \\ y = y + minBorderY \end{array} x=x+minBorderXy=y+minBorderY

3.计算特征点方向

遍历所有金字塔层,计算当前金字塔层所有特征点的方向,步骤:

  1. 计算图像在x, y方向的矩
    m 10 = ∑ x = − R R ∑ y = − R R x I ( x , y ) m 01 = ∑ x = − R R ∑ y = − R R y I ( x , y ) m 00 = ∑ x = − R R ∑ y = − R R I ( x , y ) \begin{array}{l} m_{10}=\sum_{x=-R}^{R} \sum_{y=-R}^{R} x I(x, y) \\ m_{01}=\sum_{x=-R}^{R} \sum_{y=-R}^{R} y I(x, y) \\ m_{00}=\sum_{x=-R}^{R} \sum_{y=-R}^{R} I(x, y) \end{array} m10=x=RRy=RRxI(x,y)m01=x=RRy=RRyI(x,y)m00=x=RRy=RRI(x,y)
  2. 图像的质心为:
    C = ( c x , c y ) = ( m 10 m 00 , m 01 m 00 ) C=\left(c_{x}, c_{y}\right)=\left(\frac{m_{10}}{m_{00}}, \frac{m_{01}}{m_{00}}\right) C=(cx,cy)=(m00m10,m00m01)
  3. 旋转角度:
    θ = arctan ⁡ 2 ( c y , c x ) = arctan ⁡ 2 ( m 01 , m 10 ) \theta=\arctan 2\left(c_{y}, c_{x}\right)=\arctan 2\left(m_{01}, m_{10}\right) θ=arctan2(cy,cx)=arctan2(m01,m10)
static float IC_Angle(const Mat& image, Point2f pt,  const vector<int> & u_max)
{
	//图像的矩,前者是按照图像块的y坐标加权,后者是按照图像块的x坐标加权
    int m_01 = 0, m_10 = 0;

	//获得这个特征点所在的图像块的中心点坐标灰度值的指针center
    const uchar* center = &image.at<uchar> (cvRound(pt.y), cvRound(pt.x));

    // Treat the center line differently, v=0
	//这条v=0中心线的计算需要特殊对待
    //由于是中心行+若干行对,所以PATCH_SIZE应该是个奇数
    for (int u = -HALF_PATCH_SIZE; u <= HALF_PATCH_SIZE; ++u)
		//注意这里的center下标u可以是负的!中心水平线上的像素按x坐标(也就是u坐标)加权
        m_10 += u * center[u];

    // Go line by line in the circular patch  
	//这里的step1表示这个图像一行包含的字节总数。参考[https://blog.csdn.net/qianqing13579/article/details/45318279]
    int step = (int)image.step1();
	//注意这里是以v=0中心线为对称轴,然后对称地每成对的两行之间进行遍历,这样处理加快了计算速度
    for (int v = 1; v <= HALF_PATCH_SIZE; ++v)
    {
        // Proceed over the two lines
		//本来m_01应该是一列一列地计算的,但是由于对称以及坐标x,y正负的原因,可以一次计算两行
        int v_sum = 0;
		// 获取某行像素横坐标的最大范围,注意这里的图像块是圆形的!
        int d = u_max[v];
		//在坐标范围内挨个像素遍历,实际是一次遍历2个
        // 假设每次处理的两个点坐标,中心线下方为(x,y),中心线上方为(x,-y) 
        // 对于某次待处理的两个点:m_10 = Σ x*I(x,y) =  x*I(x,y) + x*I(x,-y) = x*(I(x,y) + I(x,-y))
        // 对于某次待处理的两个点:m_01 = Σ y*I(x,y) =  y*I(x,y) - y*I(x,-y) = y*(I(x,y) - I(x,-y))
        for (int u = -d; u <= d; ++u)
        {
			//得到需要进行加运算和减运算的像素灰度值
			//val_plus:在中心线下方x=u时的的像素灰度值
            //val_minus:在中心线上方x=u时的像素灰度值
            int val_plus = center[u + v*step], val_minus = center[u - v*step];
			//在v(y轴)上,2行所有像素灰度值之差
            v_sum += (val_plus - val_minus);
			//u轴(也就是x轴)方向上用u坐标加权和(u坐标也有正负符号),相当于同时计算两行
            m_10 += u * (val_plus + val_minus);
        }
        //将这一行上的和按照y坐标加权
        m_01 += v * v_sum;
    }

    //为了加快速度还使用了fastAtan2()函数,输出为[0,360)角度,精度为0.3°
    return fastAtan2((float)m_01, (float)m_10);
}

注意: 矩的计算方式
矩在圆中以行的方式进行计算,首先计算v=0行,上下两行中对应的点为 ( x , y ) (x, y) (x,y) ( x , − y ) (x, -y) (x,y),则矩为:
m 10 = ∑ x I ( x , y ) = x I ( x , y ) + x I ( x , − y ) = x ( I ( x , y ) + I ( x , − y ) ) m 01 = ∑ y I ( x , y ) = y I ( x , y ) − y I ( x , − y ) = y ( I ( x , y ) − I ( x , − y ) ) \begin{align} m_{10} & = \sum xI(x,y) \\ & = xI(x,y) + xI(x,-y) \\ & = x(I(x,y) + I(x,-y)) \\ m_{01} & = \sum yI(x,y) \\ & = yI(x,y) - yI(x,-y) \\ & = y(I(x,y) - I(x,-y)) \end{align} m10m01=xI(x,y)=xI(x,y)+xI(x,y)=x(I(x,y)+I(x,y))=yI(x,y)=yI(x,y)yI(x,y)=y(I(x,y)I(x,y))

4.计算特征点的描述子

遍历所有金字塔层,计算当前金字塔层所有特征点的描述子,步骤:

  1. 高斯模糊
  2. 旋转
    Q θ = R θ Q \boldsymbol{Q}_{\theta}=\boldsymbol{R}_{\theta} \boldsymbol{Q} Qθ=RθQ
  3. 计算描述子
    Q θ = ( x 1 , x 2 , ⋯   , x m − 1 , x m y 1 , y 2 , ⋯   , y m − 1 y m ) \boldsymbol{Q_{\theta}}=\left(\begin{array}{c} x_{1}, x_{2}, \cdots, x_{m-1}, x_{m} \\ y_{1}, y_{2}, \cdots, y_{m-1} y_{m} \end{array}\right) Qθ=(x1,x2,,xm1,xmy1,y2,,ym1ym)

选取32组点对,每组点对包含16个点,两两相互比较,生成8位,所以描述子维度: 32 ⋅ 8 = 256 32\cdot8=256 328=256

static void computeOrbDescriptor(const KeyPoint& kpt,
                                 const Mat& img, const Point* pattern,
                                 uchar* desc)
{
	//得到特征点的角度,用弧度制表示。kpt.angle是角度制,范围为[0,360)度
    float angle = (float)kpt.angle*factorPI;
	//然后计算这个角度的余弦值和正弦值
    float a = (float)cos(angle), b = (float)sin(angle);

	//获得图像中心指针
    const uchar* center = &img.at<uchar>(cvRound(kpt.pt.y), cvRound(kpt.pt.x));
	//获得图像的每行的字节数
    const int step = (int)img.step;

	//原始的BRIEF描述子不具有方向信息,通过加入特征点的方向来计算描述子,称之为Steer BRIEF,具有较好旋转不变特性
	//具体地,在计算的时候需要将这里选取的随机点点集的x轴方向旋转到特征点的方向。
	//获得随机“相对点集”中某个idx所对应的点的灰度,这里旋转前坐标为(x,y), 旋转后坐标(x',y')推导:
    // x'= xcos(θ) - ysin(θ),  y'= xsin(θ) + ycos(θ)
    #define GET_VALUE(idx) center[cvRound(pattern[idx].x*b + pattern[idx].y*a)*step + cvRound(pattern[idx].x*a - pattern[idx].y*b)]        
    // y'* step
    // x'
	//brief描述子由32*8位组成
	//其中每一位是来自于两个像素点灰度的直接比较,所以每比较出8bit结果,需要16个随机点,这也就是为什么pattern需要+=16的原因
    for (int i = 0; i < 32; ++i, pattern += 16)
    {
		
        int t0, 	//参与比较的一个特征点的灰度值
			t1,		//参与比较的另一个特征点的灰度值	
			val;	//描述子这个字节的比较结果
		
        t0 = GET_VALUE(0); t1 = GET_VALUE(1);
        val = t0 < t1;							//描述子本字节的bit0
        t0 = GET_VALUE(2); t1 = GET_VALUE(3);
        val |= (t0 < t1) << 1;					//描述子本字节的bit1
        t0 = GET_VALUE(4); t1 = GET_VALUE(5);
        val |= (t0 < t1) << 2;					//描述子本字节的bit2
        t0 = GET_VALUE(6); t1 = GET_VALUE(7);
        val |= (t0 < t1) << 3;					//描述子本字节的bit3
        t0 = GET_VALUE(8); t1 = GET_VALUE(9);
        val |= (t0 < t1) << 4;					//描述子本字节的bit4
        t0 = GET_VALUE(10); t1 = GET_VALUE(11);
        val |= (t0 < t1) << 5;					//描述子本字节的bit5
        t0 = GET_VALUE(12); t1 = GET_VALUE(13);
        val |= (t0 < t1) << 6;					//描述子本字节的bit6
        t0 = GET_VALUE(14); t1 = GET_VALUE(15);
        val |= (t0 < t1) << 7;					//描述子本字节的bit7

        //保存当前比较的出来的描述子的这个字节
        desc[i] = (uchar)val;
    }//通过对随机点像素灰度的比较,得出BRIEF描述子,一共是32*8=256位

    //为了避免和程序中的其他部分冲突在,在使用完成之后就取消这个宏定义
    #undef GET_VALUE
}

B.对提取的特征点进行矫正

void cv::undistortPoints
(
	InputArray _src_//观察点坐标 2xN/Nx2 1-channel or 1xN/Nx1 2-channel (CV_32FC2 or CV_64FC2) (or vector<Point2f> )
	OutputArray _dst_//矫正后的坐标 1xN/Nx1 2-channel or vector<Point2f>
	InputArray _cameraMatrix_ //相机内参
	InputArray _distCoeffs_ //相机畸变矩阵
	InputArray _R_ = noArray //新的变换矩阵
	InputArray _P_ = noArray //新的相机矩阵或者投影矩阵
)

C.将特征点分配到网格中

将特征点分配到网格中主要的作用:加速特征点的搜索

  • FRAME_GRID_ROWS:48
  • FRAME_GRID_COLS:64
    p o s X = ( x − m n M i n X ) ⋅ F R A M E _ G R I D _ C O L S m n M a x X − m n M i n X p o s Y = ( y − m n M i n Y ) ⋅ F R A M E _ G R I D _ R O W S m n M a x Y − m n M i n Y \begin{align} posX & = \left (x-mnMinX\right )\cdot \frac{ {\small FRAME\_GRID\_COLS} }{mnMaxX-mnMinX} \\ posY & = \left (y-mnMinY\right )\cdot \frac{ {\small FRAME\_GRID\_ROWS} }{mnMaxY-mnMinY} \end{align} posXposY=(xmnMinX)mnMaxXmnMinXFRAME_GRID_COLS=(ymnMinY)mnMaxYmnMinYFRAME_GRID_ROWS
    在这里插入图片描述

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

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

相关文章

某程序员哀叹:月薪四五万,却每天极度焦虑痛苦,已有生理性不适,又不敢裸辞,该怎么办?

高薪能买来快乐吗&#xff1f; 来看看这位程序员的哀叹&#xff1a; 实在是扛不住了&#xff0c;每天都在极度焦虑和痛苦中度过&#xff0c;早上起来要挣扎着做心理建设去上班&#xff0c;已经产生生理性的头晕恶心食欲不振。有工作本身的原因&#xff0c;更多是自己心态的问…

如何在CSDN获得铁粉

文章目录 前言关于铁粉方法总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 铁粉512位即可参加此活动 完成一篇如何获得铁粉&#xff0c;或者相关的文章且质量分达到80分以上即可 关于铁粉 简单地说&#xff0c;就是在过去 N 个月内&#xff0c;一…

vscode配置flutter开发环境,不需要安装第三方安卓模拟器

1.获取Flutter SDK 点击下方的安装包&#xff0c;获取 stable 发行通道的 Flutter SDK 最新版本&#xff1a;Flutter SDK 将压缩包解压&#xff0c;然后把其中的 flutter 目录整个放在你想放置 Flutter SDK 的路径中**&#xff08;注意不要出现中文目录&#xff09;** 配置Wi…

Spring Boot配置文件(5/27)

1.Spring Boot 配置文件的分类和作用 整个项目所有重要的数据都是在配置文件中配置的 1.数据库连接信息&#xff08;包含用户名和密码的设置&#xff09; 2.项目的启动窗口&#xff1b; 3.第三方系统调用密匙等信息 4.用于发现和定位问题的普通日志和异常日志等等 大体上可以分…

基于FPGA的Bayer转RGB算法实现

1 概述 Bayer转RGB在图像处理中被称为去马赛克&#xff08;Demosaic&#xff09;&#xff0c;是机器视觉ISP流程中的一个基础且重要的算法&#xff0c;主要完成彩色图像传感器原始的Bayer格式图像到RGB格式图像的转换。 关于Bayer图像的相关概念和知识&#xff0c;本文不作介绍…

jquery data和data-属性不一致问题

延申val和value属性同样不一致 <script src"https://code.jquery.com/jquery-3.7.0.min.js"></script> <input type"text" value"F119-PW110" data-tag"F119" id"txtEngine" name"Engine" placeh…

第十六届全国大学生信息安全竞赛创新实践能力赛(CISCN)

目录 Misc 1、被加密的生产流量 Crypto 2、Sign_in_passwd Web 3、unzip 4、dumpit Re 5、babyRE Pwn 6、funcanary Misc 1、被加密的生产流量 下载附件解压后是一段流量&#xff0c;使用wireshark打开 最开始做的时候找错了方向&#xff0c;追踪到了另一个东西 …

阿里云服务器配置怎么选择合适?CPU内存带宽配置

阿里云服务器配置如何选择&#xff1f;个人用户选择通用算力型u1云服务器或轻量应用服务器&#xff0c;2核2G、2核4G配置即可&#xff0c;企业公司用户可以选择独享型ECS计算型c7、通用型g7等&#xff0c;4核8G、8核16G、4核32G等配置&#xff0c;阿里云百科来详细说下不同用户…

实验二十一、积分运算电路的输出波形分析

一、题目 利用 Multisim 分析图1所示两个积分运算电路的输出波形&#xff0c;输入电压为 200 Hz、幅值为 1 V 的方波信号。 图 1 图1\,\, 图1 二、仿真电路 在 Multism 中搭建图1所示的两个电路&#xff0c;如图2所示。为了防止电路中的直流增益过大&#xff0c;故在电容上…

node.js与内置模块

一、目标 能够知道什么是Node.js能够知道Node.js可以做什么能够说出Node.js中的JavaScript的组成部分能够使用fs模块读写操作文件能够使用path模块处理路径能够使用http模块写一个基本的web服务器 二、目录 初始Node.jsfs文件系统模块path路径模块http模块 1.初始Node.js …

[Nacos] Nacos Server处理订阅请求 (九)

文章目录 1.InstanceController#list()2.InstanceController#doSrvIpxt()3.总结 1.InstanceController#list() Nacos Server处理订阅请求 主要还是从请求中获取参数, 比如namespceId、serviceName、agent(指定提交请求的客户端是哪种类型)、clusters、clusterIP、udpPort(后续…

2023全国酒店数据

数据内容字段结构 hotel_id int(11) NOT NULL, name varchar(100) DEFAULT NULL, name_en varchar(100) DEFAULT NULL, short_name varchar(100) DEFAULT NULL, province varchar(20) DEFAULT NULL, city_id int(11) DEFAULT NULL, city varchar(20…

R语言实践——使用rWCVP在WCVP中匹配名称

使用rWCVP在WCVP中匹配名称 加载库工作流1. 示例数据&#xff1a;IUCN红色名录2. 将匹配的名称解析为接受名2.1 模糊匹配2.2 多项匹配2.3 将评估与接受的名称相关联 3. 可视化匹配过程4. 得到最终数据集 加载库 世界维管植物名录提供了所有已知维管植物物种的全球共识观点&…

LabView中条件结构的使用方法1

LabView中的条件结构包含一个或多个子程序框图&#xff0c;即分支&#xff0c;当满足某个条件时&#xff0c;相应的分支会被执行。也就是说&#xff0c;在条件结构执行时&#xff0c;仅有一个分支被执行。当程序存在两种或多种可能性时&#xff0c;可以使用条件结构。 1 创建条…

攻防世界安卓逆向练习

一.easy-so jadx分析程序逻辑 可以看到关键在于cyberpeace.CheckString()函数 双击跟进之后可以发现是native层函数 ida查看so文件 程序逻辑: 将字符串保存到新的空间buffer中第一个判断是将buffer的前16个字符和后16个字符进行交换第二个判断是将buffer的2个相邻的字符互换位…

算法|10.从暴力递归到动态规划3

算法|10.从暴力递归到动态规划3 1.纸牌游戏 题意&#xff1a;给定一个整型数组arr&#xff08;都是正数&#xff09;&#xff0c;代表数值不同的纸牌排成一条线。玩家A和玩家B依次拿走每张纸牌&#xff0c;规定玩家A先拿&#xff0c;玩家B后拿。但是每个玩家每次只能拿走最左…

(10) 朴素贝叶斯

文章目录 1 概述2 不同分布下的贝叶斯2.1 高斯朴素贝叶斯GaussianNB2.1.1 认识高斯朴素贝叶斯2.1.2 探索贝叶斯&#xff1a;高斯朴素贝叶斯擅长的数据集2.1.3 探索贝叶斯&#xff1a;高斯朴素贝叶斯的拟合效果与运算速度 2.2 概率类模型的评估指标2.2.1 布里尔分数Brier Score2…

PCIE知识点-022:PCIe 时钟结构

图1&#xff1a;参考时钟结构示意图[4] 1. Common Refclk Architecture Common Refclk Architecture&#xff0c;即同源参考时钟架构&#xff0c;PCIe收发设备共用一个时钟源&#xff0c;是目前是使用最为广泛的方案。 缺点&#xff1a; 对于适用同一 Common Clock 作为参考时…

大数据入门(十三)- HDFS的Shell操作

零.HDFS的Shell操作 一.进程启停管理 1.一键启停脚本 Hadoop HDFS组件内置了HDFS集群的一键启停脚本。 1&#xff09;$HADOOP_HOME/sbin/start-dfs.sh&#xff0c;一键启动HDFS集群 执行原理&#xff1a; &#xff08;1&#xff09;在执行此脚本的机器上&#xff0c;启动Secon…

动态规划2:题目

目录 第1题 Fibonacci 第2题 字符串分割(Word Break) .第3题 三角矩阵(Triangle) 第4题 路径总数(Unique Paths) 第5题 最小路径和(Minimum Path Sum) 第6题 背包问题 第7题 回文串分割(Palindrome Partitioning) 第8题 编辑距离(Edit Distance) 第9题 不同子序列(Dist…