ORB-SLAM2学习笔记8之特征点提取、生成描述子的ORBextractor

文章目录

  • 0 引言
  • 1 特征点提取
    • 1.1 提取流程
    • 1.2 ORBextractor.cc
      • 1.2.1 成员函数
      • 1.2.2 成员变量
    • 1.3 构建图像金字塔
      • 1.3.1 为什么要构建图像金字塔
      • 1.3.2 金字塔参数设置
    • 1.4 提取ORB特征点
      • 1.4.1 Fast角点检测
      • 1.4.2 特征点提取流程
      • 1.4.3 八叉树筛选及非极大值抑制
  • 2 描述子生成
    • 2.1 特征点的方向
    • 2.2 高斯模糊
    • 2.3 计算描述子

0 引言

ORB-SLAM2学习笔记7了解了System主类和多线程,如下图,本文主要学习ORB-SLAM2中的图像预处理的ORB部分(Oriented FAST and Rotated BRIEF),也就是视觉特征点提取器ORBextractor,从全称来看,ORB-SLAM2ORB部分主要涉及ORB特征点提取和描述子生成。

  1. 特征点提取
  • ORB特征点提取使用了FASTFeatures from Accelerated Segment Test)算法。FAST算法是一种高效的特征点检测算法,通过比较像素点与其周围邻域像素的亮度差异来确定特征点。
  • ORB中,FAST算法被扩展成了Oriented FAST,它能够在检测到的特征点周围计算出一个主方向。这个主方向在后续的描述子生成中起到了重要作用。
  • 通过对图像的不同尺度(图像金字塔)进行处理,ORB-SLAM2还能够提取多尺度的特征点,以适应不同距离的场景。
  1. 描述子生成
  • ORB中,每个特征点都有一个对应的局部区域。描述子的生成是在这个局部区域内进行的。
  • 首先,计算特征点周围邻域像素的灰度差异。ORB使用了一个256维的灰度差向量,它记录了周围像素与特征点的灰度差异情况。
  • 然后,利用灰度差向量生成一个固定长度的二进制位串,即ORB描述子。生成描述子的方式是将灰度差向量中的每个元素与零进行比较,将比零大的元素置为1,否则置为0
  • 最后,每个特征点都会生成一个固定长度的二进制描述子,用于表示其局部特征信息。

请添加图片描述

1 特征点提取

1.1 提取流程

ORB-SLAM2中的特征点提取前大致流程分以下几个步骤:

  1. main函数中先建立slamTracking线程,以ORB_SLAM2/Examples/Monocular/mono_tum.cc单目为例,main函数中的SLAM.TrackMonocular(im,tframe);建立跟踪线程;
  2. 然后跳转到ORB_SLAM2/src/System.cc进入到TrackMonocular函数中,通过cv::Mat Tcw = mpTracker->GrabImageMonocular(im,timestamp);获取相机位姿;
  3. 再然后跳转到ORB_SLAM2/src/Tracking.cc进入到GrabImageMonocular函数中,输入灰度图,构造mCurrentFrame关键帧;
  4. 再通过Frame跳转到ORB_SLAM2/src/Frame.cc进入到实现帧检测的函数Frame::Frame,其中就调用ExtractORB(0,imGray);来对单目图像进行特征点提取;
  5. 最后跳转到ORB_SLAM2/src/ORBextractor.cc特征点提取的函数实现文件(包含描述子生成)。

1.2 ORBextractor.cc

直接查看ORB_SLAM2/src/ORBextractor.cc文件,或者也可以查看ORB_SLAM2/include/ORBextractor.h头文件也可以清晰的看出特征点提取器的成员函数和成员变量定义。

1.2.1 成员函数

成员函数类型定义
static float IC_Angle(const Mat& image, Point2f pt, const vector<int> & u_max)static计算特征点的方向
static void computeOrbDescriptor(const KeyPoint& kpt, const Mat& img, const Point* pattern, uchar* desc)static计算ORB特征点的描述子
ORBextractor::ORBextractor(...)public特征点提取器的构造函数
static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints, const vector<int>& umax)static计算特征点的方向
vector<cv::KeyPoint> ORBextractor::DistributeOctTree(...)protected使用四叉树法对一个图像金字塔图层中的特征点进行平均和分发
void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoints)protected计算四叉树的特征点
void ORBextractor::ComputeKeyPointsOld(std::vector<std::vector<KeyPoint> > &allKeypoints)protected计算特征点的旧方法
static void computeDescriptors(const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors,const vector<Point>& pattern)static计算某层金字塔图像上特征点的描述子
void ORBextractor::operator()( InputArray _image, InputArray _mask, vector<KeyPoint>& _keypoints,OutputArray _descriptors)public用仿函数(重载括号运算符)方法来计算图像特征点
void ORBextractor::ComputePyramid(cv::Mat image)protected构建图像金字塔

1.2.2 成员变量

成员变量类型定义
std::vector<cv::Mat> mvImagePyramidpublic存储图像金字塔的变量,一个元素存储一层图像
std::vector<cv::Point> patternprotected计算描述子的随机采样点集合
int nfeaturesprotected整个图像金字塔中,要提取的特征点数目
double scaleFactorprotected图像金字塔层与层之间的缩放因子
int nlevelsprotected图像金字塔的层数
int iniThFASTprotected初始的FAST响应值阈值
int minThFASTprotected最小的FAST响应值阈值
std::vector<int> mnFeaturesPerLevelprotected分配到每层图像中,要提取的特征点数目
std::vector<int> umaxprotected计算特征点方向的时候,有个圆形的图像区域,这个vector中存储了每行u轴的边界(四分之一,其他部分通过对称获得)
std::vector<float> mvScaleFactorprotected每层图像的缩放因子
std::vector<float> mvInvScaleFactorprotected以及每层缩放因子的倒数
std::vector<float> mvLevelSigma2protected存储每层的sigma^2,即上面每层图像相对于底层图像缩放倍数的平方
std::vector<float> mvInvLevelSigma2protectedsigma^2的倒数

1.3 构建图像金字塔

1.3.1 为什么要构建图像金字塔

ORB-SLAM2中构造图像金字塔的目的是为了实现多尺度的特征点提取和匹配,以增强系统的鲁棒性和适应性。图像金字塔是通过对原始图像进行不同尺度的降采样得到的一系列图像,每个图像都具有不同的分辨率。

图像金字塔把具有最高级别分辨率的图像放在底部,以金字塔形状排列,往上是一系列像素(尺寸)逐渐降低的图像,一直到金字塔的顶部只包含一个像素点的图像,这就构成了传统意义上的图像金字塔。

提醒:向下与向上采样,是对图像的尺寸而言的(和金字塔的方向相反),向下取样(缩小图像),向上取样(放大图像),向下取样是分辨率越来越小(往金字塔塔尖方向),向上取样是增加像素。

请添加图片描述
构造图像金字塔的好处包括:

  • 尺度不变性:在图像中,物体的尺度可能随着距离的变化而变化。通过构建图像金字塔,可以在不同尺度上检测和描述特征点,使ORB-SLAM2对于不同距离的场景具有尺度不变性。这意味着即使物体在图像中的大小不同,ORB-SLAM2仍能够检测到相应的特征点。

  • 增强鲁棒性:构建图像金字塔可以在不同分辨率上进行特征提取,从而使ORB-SLAM2对于图像中的噪声、遮挡和光照变化等干扰因素具有更强的鲁棒性。在低分辨率图像上提取的特征点通常对这些干扰因素更具有抵抗能力。

  • 速度优化:通过在较高分辨率的图像上进行特征点提取,可以提高ORB-SLAM2的精度。然而,在计算资源有限的情况下,仅在高分辨率图像上进行特征提取可能会导致计算效率低下。通过构建图像金字塔,ORB-SLAM2可以根据需要选择适当的分辨率进行特征点提取,从而在保持一定精度的同时提高计算速度。

综上所述,通过构建图像金字塔,ORB-SLAM2能够实现多尺度的特征点提取和匹配,提高系统的鲁棒性、适应性和计算效率。这对于处理不同尺度和复杂度的场景是非常重要的。

1.3.2 金字塔参数设置

下面成员变量从配置文件TUM1.yaml中读入:

成员变量类型定义配置文件变量名
int nfeaturesprotected所有层级提取到的特征点数之和金字塔层数ORBextractor.nFeatures1000
double scaleFactorprotected图像金字塔相邻层级间的缩放系数ORBextractor.scaleFactor1.2
int nlevelsprotected金字塔层级数ORBextractor.nLevels8
int iniThFASTprotected提取特征点的描述子门槛(响应值高)ORBextractor.iniThFAST20
int minThFASTprotected提取特征点的描述子门槛(响应值低)ORBextractor.minThFAST7

其中参数中的响应值和要计算的描述子需要重点解释下:

特征点响应值和描述子的区别

  1. 响应值:该特征点的区分度大小,响应值越大的点越应该被用作特征点。类似于分数,学生分数越高,越应该被录取;
  2. 描述子:特征点的哈希运算,其大小无意义,仅用来再数据库中快速找回某特征点。类似学生的学号,系统随机运算出的一串数,用于快速找到学生。

根据上述变量的值计算出下述成员变量:

成员变量类型定义
std::vector<int> mnFeaturesPerLevelprotected金字塔每层级中提取的特征点数,正比于图层边长,总和为nfeatures{61, 73, 87, 105, 126, 151, 181, 216}
std::vector<float> mvScaleFactorprotected各层级的缩放系数{1, 1.2, 1.44, 1.728, 2.074, 2.488, 2.986, 3.583}
std::vector<float> mvInvScaleFactorprotected各层级缩放系数的倒数{1, 0.833, 0.694, 0.579, 0.482, 0.402, 0.335, 0.2791}
std::vector<float> mvLevelSigma2protected各层级缩放系数的平方{1, 1.44, 2.074, 2.986, 4.300, 6.190, 8.916, 12.838}
std::vector<float> mvInvLevelSigma2protected各层级缩放系数的平方倒数{1, 0.694, 0.482, 0.335, 0.233, 0.162, 0.112, 0.078}

1.4 提取ORB特征点

1.4.1 Fast角点检测

Fast角点检测以速度著称,主要检测局部像素灰度变化明显的地方。核心思想:如果一个像素与它邻域的像素差值较大(过暗或过亮),那它极有可能是角点。

提取步骤:

  1. 在图像中选取像素 p,假设它的亮度为 Ip
  2. 设置一个阈值 T(比如 Ip20%)。
  3. 以像素 p 为中心, 选取半径为 3 的圆上的 16 个像素点。
  4. 假如选取的圆上,有连续的 N 个点的亮度大于 Ip + T 或小于 Ip −T,那么像素 p 可以被认为是特征点 (N 通常取 12,即为 FAST-12。其它常用的 N 取值为 911, 他们分别被称为 FAST-9FAST-11)。
  5. 循环以上四步,对每一个像素执行相同的操作。

请添加图片描述
👉 Fast角点提取文献参考:Machine Learning for High-Speed Corner Detection

1.4.2 特征点提取流程

OpenCV中的FAST角点检测容易出现扎堆现象,后面会结合非极大值抑制(Non-maximal suppression)来优化这点;而且Fast角点本不具有方向,但是由于特征点匹配需要,ORB-SLAM2Fast角点进行了改进,改进后的 FAST 被称为 Oriented FAST,不仅进一步提高了检测效率,还具有旋转和尺度的描述。

前面已经定义并初始化了图像金字塔,Oriented FAST角点检测前,先对金字塔每一层的图像遍历进行特征点检测,而提取特征点最重要的就是希望特征点均匀地分布在图像的所有部分,所以实现的核心的有两步:

  1. 分cell搜索特征点,若某cell内特征点响应值普遍较小的话就按照低响应值int minThFAST(类似降低分数线)再搜索一遍;
  2. 对得到的所有特征点进行八叉树(其实图像算是四叉树)筛选,每个cell区域取响应值最大的那个特征点。

如下流程图和详细实现代码,ORB-SLAM2中的特征点检测时设置每个cell大小为30*30,先用高响应值int iniThFAST检测,如果检测不到,再用低响应值int minThFAST检测,最后把所有检测到特征点再统一做八叉树筛选,比较密集的部分特征点用非极大值抑制,选出最优的特征点。

请添加图片描述

void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoints)	{
    for (int level = 0; level < nlevels; ++level)
        // 计算图像边界
        const int minBorderX = EDGE_THRESHOLD-3;		
        const int minBorderY = minBorderX;				
        const int maxBorderX = mvImagePyramid[level].cols-EDGE_THRESHOLD+3;
        const int maxBorderY = mvImagePyramid[level].rows-EDGE_THRESHOLD+3;
        const float width = (maxBorderX-minBorderX);
        const float height = (maxBorderY-minBorderY);
        const int nCols = width/W;				// 每一列有多少cell
        const int nRows = height/W;				// 每一行有多少cell
        const int wCell = ceil(width/nCols);	// 每个cell的宽度
        const int hCell = ceil(height/nRows);	// 每个cell的高度

        // 存储需要进行平均分配的特征点
        vector<cv::KeyPoint> vToDistributeKeys;
		
    	// step1. 遍历每行和每列,依次分别用高低阈值搜索FAST特征点
        for(int i=0; i<nRows; i++) {
            const float iniY = minBorderY + i * hCell;
            const float maxY = iniY + hCell + 6;
            for(int j=0; j<nCols; j++) {
                const float iniX =minBorderX + j * wCell;
                const float maxX = iniX + wCell + 6;
                vector<cv::KeyPoint> vKeysCell;
				
                // 先用高阈值搜索FAST特征点
                FAST(mvImagePyramid[level].rowRange(iniY,maxY).colRange(iniX,maxX),	vKeysCell, iniThFAST, true);
                // 高阈值搜索不到的话,就用低阈值搜索FAST特征点
                if(vKeysCell.empty()) {
                    FAST(mvImagePyramid[level].rowRange(iniY,maxY).colRange(iniX,maxX),	vKeysCell, minThFAST, true);
                }
				// 把 vKeysCell 中提取到的特征点全添加到 容器vToDistributeKeys 中
                for(KeyPoint point :vKeysCell) {
                    point.pt.x+=j*wCell;
                    point.pt.y+=i*hCell;
                    vToDistributeKeys.push_back(point);
                }
            }
        }
		
    	// step2. 对提取到的特征点进行八叉树筛选,见 DistributeOctTree() 函数
        keypoints = DistributeOctTree(vToDistributeKeys, minBorderX, maxBorderX, minBorderY, maxBorderY, mnFeaturesPerLevel[level], level);
    }				
}

1.4.3 八叉树筛选及非极大值抑制

主要通过函数DistributeOctTree()进行八叉树筛选(非极大值抑制),如下图,不断将记录特征点的图像区域进行4等分,直到分出了足够多的分区,每个分区内只保留响应值最大的特征点

请添加图片描述

2 描述子生成

2.1 特征点的方向

利用非极大值抑制得到更加均分分布的优质特征点之后,还需要用灰度质心法来求特征点的方向。灰度质心(Gray-level centroid)是一个用于计算图像或图像区域灰度分布中心的指标。详细的数学原理定义如下:

假设选择图像块B,定义图像块B的矩 m p q m_{pq} mpq定义为:
m p q = ∑ x , y ∈ B x p y q I ( x , y ) , p , q = 0 , 1 (1) m_{pq}=\sum_{{x,y}\in B}x^py^qI(x,y),\quad\quad p,q={0,1} \tag{1} mpq=x,yBxpyqI(x,y)p,q=0,1(1)
其中 x , y x,y x,y表示像素坐标, I ( x , y ) I(x,y) I(x,y)表示此像素坐标的灰度值;

图像块B的质心C可以通过公式(1)中的矩来进一步计算:
m 00 = ∑ x , y ∈ B I ( x , y ) , m 10 = ∑ x , y ∈ B x ∗ I ( x , y ) , m 01 = ∑ x , y ∈ B y ∗ I ( x , y ) (2) m_{00}=\sum_{{x,y}\in B}I(x,y), \quad m_{10}=\sum_{{x,y}\in B}x*I(x,y), \quad m_{01}=\sum_{{x,y}\in B}y*I(x,y) \tag{2} m00=x,yBI(x,y),m10=x,yBxI(x,y),m01=x,yByI(x,y)(2)

C = ( c x , c y ) = ( m 10 m 00 , m 01 m 00 ) (3) C=(c_x,c_y)=\left (\frac{m_{10}}{m_{00}}, \frac{m_{01}}{m_{00}} \right ) \tag{3} C=(cx,cy)=(m00m10,m00m01)(3)

而我们要求的特征点方向,即是图像块B的几何中心O和质心C连接在一起的方向向量 O C ⃗ \vec{OC} OC ,所以定义特征点的方向 θ \theta θ为:
θ = a r c t a n 2 ( c y , c x ) = a r c t a n 2 ( m 01 m 10 ) (4) \theta =arctan2(cy,cx)=arctan2(\frac{m_{01}}{m_{10}}) \tag{4} θ=arctan2(cy,cx)=arctan2(m10m01)(4)

特别说明:ORB-SLAM2中的图像块B不是矩形块,是圆形块,因为相对于矩形,圆形才能保证关键点的旋转不变性

详细的实现代码如下,主要是 computeOrientation()IC_Angle两个函数:

// 计算特征点的方向
static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints, const vector<int>& umax)
{
	// 遍历所有的特征点
    for (vector<KeyPoint>::iterator keypoint = keypoints.begin(),
         keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
    {
		// 调用IC_Angle 函数计算这个特征点的方向
        keypoint->angle = IC_Angle(image, 			//特征点所在的图层的图像
								   keypoint->pt, 	//特征点在这张图像中的坐标
								   umax);			//每个特征点所在图像区块的每行的边界 u_max 组成的vector
    }
}

// 这个函数用于计算特征点的方向,这里是返回角度作为方向。
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);
}

2.2 高斯模糊

为了让尺度体现其连续性,还需对图像金字塔每层图像使用不同参数做高斯模糊,主要抑制图像中的噪声和细节信息,更好的计算描述子。提取特征点时使用的是清晰的原图像,而计算描述子是需要先进行高斯模糊。

高斯模糊的代码如下,主要是GaussianBlur函数来实现:

        // preprocess the resized image 
        //  Step 5 对图像进行高斯模糊
		// 深拷贝当前金字塔所在层级的图像
        Mat workingMat = mvImagePyramid[level].clone();

		// 注意:提取特征点的时候,使用的是清晰的原图像;这里计算描述子的时候,为了避免图像噪声的影响,使用了高斯模糊
        GaussianBlur(workingMat, 		//源图像
					 workingMat, 		//输出图像
					 Size(7, 7), 		//高斯滤波器kernel大小,必须为正的奇数
					 2, 				//高斯滤波在x方向的标准差
					 2, 				//高斯滤波在y方向的标准差
					 BORDER_REFLECT_101);//边缘拓展点插值类型

2.3 计算描述子

👉 Brief描述子文献参考:https://www.cs.ubc.ca/~lowe/525/papers/calonder_eccv10.pdf

计算BRIEF描述子的核心步骤是在特征点周围半径为16的圆域内选取256对点对,在圆内随机挑选(挑选策略:均匀分布采样、高斯分布采样、完全随机采样等)点对,点对里第一个点像素值如果大于第二个点的像素值,则描述子对应位的值为1,否则为0,共得到256位的描述子,为保计算的一致性,工程上使用特定设计的点对pattern,在程序里被硬编码为成员变量了。

//下面就是预先定义好的随机点集,256是指可以提取出256bit的描述子信息,每个bit由一对点比较得来;4=2*2,前面的2是需要两个点(一对点)进行比较,后面的2是一个点有两个坐标
static int bit_pattern_31_[256*4] =
{
    8,-3, 9,5/*mean (0), correlation (0)*/,				
    4,2, 7,-12/*mean (1.12461e-05), correlation (0.0437584)*/,
    ...

请添加图片描述
但如下图所示,Brief描述子对旋转敏感,可在做特征点匹配中,希望的是特征描述子是与旋转无关的,这就用到了刚刚灰度质心法计算的特征点主方向,计算描述子时,会把特征点周围像素旋转到特征点主方向上来计算,为了编程方便,代码中是对pattern进行旋转。

请添加图片描述
计算描述子的代码如下,主要是通过computeOrientation()函数来实现:

/**
 * @brief 计算某层金字塔图像上特征点的描述子
 * 
 * @param[in] image                 某层金字塔图像
 * @param[in] keypoints             特征点vector容器
 * @param[out] descriptors          描述子
 * @param[in] pattern               计算描述子使用的固定随机点集
 */
static void computeDescriptors(const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors,
                               const vector<Point>& pattern)
{
	//清空保存描述子信息的容器
    descriptors = Mat::zeros((int)keypoints.size(), 32, CV_8UC1);

	//开始遍历特征点
    for (size_t i = 0; i < keypoints.size(); i++)
		//计算这个特征点的描述子
        computeOrbDescriptor(keypoints[i], 				//要计算描述子的特征点
							 image, 					//以及其图像
							 &pattern[0], 				//随机点集的首地址
							 descriptors.ptr((int)i));	//提取出来的描述子的保存位置
}

至此,详细学习了ORB-SLAM2中的ORBextractor特征点提取器的核心原理和实现细节,后续在此基础上继续学习ORB-SLAM2中的特征点匹配、地图点、关键帧及三大线程等。

Reference:

  • https://github.com/raulmur/ORB_SLAM2
  • https://github.com/electech6/ORB_SLAM2_detailed_comments/tree/master
  • Machine Learning for High-Speed Corner Detection
  • https://www.cs.ubc.ca/~lowe/525/papers/calonder_eccv10.pdf
  • https://blog.csdn.net/ncepu_Chen/article/details/116784563



须知少时凌云志,曾许人间第一流。



⭐️👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍🌔

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Blender增强现实3D模型制作指南【AR】

推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 将静态和动画 3D 内容集成到移动增强现实 (AR) 体验中是增强用户沉浸感和参与度的高效方法。 然而&#xff0c;为 AR 创建 3D 对象可能相当艰巨&#xff0c;尤其是对于那些缺乏 3D 建模经验的人来说。 与添加视频或照片 AR…

基于深度学习创建-表情符号--附源码

表情符号深度学习概述 如今,我们使用多种表情符号或头像来表达我们的心情或感受。它们充当人类的非语言线索。它们成为情感识别、在线聊天、品牌情感、产品评论等的关键部分。针对表情符号驱动的故事讲述的数据科学研究不断增加。 从图像中检测人类情绪非常流行,这可能是由…

算法:滑动窗口解决连续区间子数组问题

文章目录 实现原理实现思路典型例题长度最小的子数组无重复字符的最小字串最大连续1的个数III将x减到0的最小操作水果成篮找到字符串中所有字母异位词(哈希表比较优化)对哈希表内元素比较的优化 总结 本篇积累的是滑动窗口的问题&#xff0c;滑动窗口在算法实现中有重要作用&am…

PP-TS基于启发式搜索和集成方法的时序预测模型,使预测更加准确

时间序列数据在各行业和领域中无处不在&#xff0c;如物联网传感器的测量结果、每小时的销售额业绩、金融领域的股票价格等等&#xff0c;都是时间序列数据的例子。时间序列预测就是运用历史的多维数据进行统计分析&#xff0c;推测出事物未来的发展趋势。 为加快企业智能化转型…

JRebel插件扩展-mac版

前言 上一篇分享了mac开发环境的搭建&#xff0c;但是欠了博友几个优化的债&#xff0c;今天先还一个&#xff0c;那就是idea里jRebel插件的扩展。 一、场景回眸 这个如果在win环境那扩展是分分钟&#xff0c;一个exe文件点点就行。现在在mac环境就没有这样的dmg可以执行的&…

十七、地物识别

描述了使用2D卷积神经网络图像识别的全过程。下载和安装标注工具,对图像进行标注,生成标注后的图像。然后对数据进行增强,划分训练集和测试集。最后通过神经网络建立分类模型,对现有图片进行分类应用。 1、Labelme工具 Labelme工具是语义分割标注工具,在地物类型或建…

汽车领域专业术语

1. DMS/OMS/RMS/IMS DMS&#xff1a;即Driver Monitoring System&#xff0c;监测对象为Driver&#xff08;驾驶员&#xff09;。DMS三大核心&#xff1a; OMS&#xff1a;即Occupancy Monitoring System&#xff0c;监测对象为乘客。 RMS&#xff1a;后排盲区检测系统 IMS&…

代理模式概述

1.代理模式概述 学习内容 1&#xff09;概述 为什么要有 “代理” &#xff1f; 生活中就有很多例子&#xff0c;比如委托业务&#xff0c;黄牛&#xff08;票贩子&#xff09;等等代理就是被代理者没有能力或者不愿意去完成某件事情&#xff0c;需要找个人代替自己去完成这…

micropython SSD1306/SSD1315驱动

目录 简介 代码 功能 显示ASCII字符 ​编辑 画任意直线 画横线 画竖线 画矩形 画椭圆 画立方体 画点阵图 翻转 反相 滚动 横向滚动 纵向滚动 奇葩滚动 简介 我重新写了一个驱动&#xff0c;增加了一些功能&#xff0c;由于我的硬件是128*64oled单色I2C&#xff0c;我只…

Android Shape 的使用

目录 什么是Shape? shape属性 子标签属性 corners &#xff08;圆角&#xff09; solid &#xff08;填充色&#xff09; gradient &#xff08;渐变&#xff09; stroke &#xff08;描边&#xff09; padding &#xff08;内边距&#xff09; size &#xff08;大小…

视频高效剪辑,轻松平均分割视频,生成高质量M3U8

您是否在处理视频剪辑时常常面临繁琐的切分工作&#xff1f;是否希望能够快速而精准地平均分割视频&#xff0c;并生成适用于在线播放的高质量m3u8文件&#xff1f;现在&#xff0c;我们的智能视频剪辑大师为您提供了一种简便而高效的解决方案&#xff01;无需复杂操作&#xf…

【MySQL系列】--初识数据库

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

软件报错msvcr90.dll丢失的解决方法,亲测可以修复

我曾经遇到过一个令人头疼的问题&#xff1a;msvcr90.dll丢失。这个问题导致了我的程序无法正常运行&#xff0c;让我感到非常苦恼。然而&#xff0c;在经过一番努力后&#xff0c;我终于成功地修复了这个问题&#xff0c;这让我感到非常欣慰和满足。 msvcr90.dll丢失的原因可能…

大模型基础03:Embedding 实战本地知识问答

大模型基础:Embedding 实战本地知识问答 Embedding 概述 知识在计算机内的表示是人工智能的核心问题。从数据库、互联网到大模型时代,知识的储存方式也发生了变化。在数据库中,知识以结构化的数据形式储存在数据库中,需要机器语言(如SQL)才能调用这些信息。互联网时代,…

117页数字化转型与产业互联网发展趋势及机会分析报告PPT

导读&#xff1a;原文《》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 喜欢文章&#xff0c;您可以点赞评论转发本文&#xff0c;了解更多内容请私信&#xff1a;方…

__format__和__del__

目录 一、__format__ 二、__del__ python从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129328397?spm1001.2014.3001.5502 一、__format__ 自定制格式化字符串 date_dic {ymd: {0.year}:{0.month}:{0.day},dmy: {0.day}/{0.month}/…

力扣 198. 打家劫舍

题目来源&#xff1a;https://leetcode.cn/problems/house-robber/description/ C题解&#xff1a;因为是间接偷窃&#xff0c;所以偷nums[i]家前&#xff0c;一定偷过第i-2或者i-3家&#xff0c;因为i-1不能偷。 例如12345共5家&#xff0c;先偷第1家&#xff0c;那么2不能偷…

Oracle切割字符串的方法,SQL语句完成。

Oracle用正则的方式循环切割字符串 需求&#xff1a;有一个这样子的 Str “‘CNJ-520-180500000001|CNJ-520-181200000001|CNJ-520-190300000001|CNJ-520-190100000001|CNJ-520-181200000002’” &#xff0c;然后我需要拿到每一个单号&#xff0c;每一个单号都要走一遍固定的…

神经网络基础-神经网络补充概念-03-逻辑回归损失函数

概念 逻辑回归使用的损失函数通常是"对数损失"&#xff08;也称为"交叉熵损失"&#xff09;或"逻辑损失"。这些损失函数在训练过程中用于衡量模型预测与实际标签之间的差异&#xff0c;从而帮助模型逐步调整权重参数&#xff0c;以更好地拟合数…

vue3小知识点汇总——基础积累

下面的小知识点比较零散&#xff0c;但是脑子不太好使&#xff0c;只能先记录一下啦&#xff0c;后面知识丰富起来后&#xff0c;慢慢就懂了。 1.最新版node.js已经不兼容vue2的项目了&#xff0c;学习vue3势在必行 node.js的安装及vue的搭建详细步骤&#xff1a;http://t.cs…