使用单目相机前后帧特征点匹配进行3D深度估计的方法

在计算机视觉和机器人领域,三维空间感知是实现环境理解和交互的核心技术之一。特别是在资源受限的场合,使用针孔模型的单目相机进行深度估计成为了一种既经济又实用的解决方案。单目深度估计技术依赖于从连续视频帧中提取和匹配特征点,以估计场景中物体的三维位置。本文将探讨几种基于单目相机前后帧特征点匹配的3D深度估计方法。通过详细分析特征点匹配及其对深度恢复的贡献,我们旨在提供一种既精确又实用的深度估计技术,适用于从自动驾驶到增强现实等多种应用场景。

一、通过多视角立体几何 (Multi-view Stereo, MVS)的方法    

1. 原理

        特征点三角化是VSLAM中的一个基础问题,用于根据特征点在多个相机中的投影来恢复其在3D坐标中的位置。其的基本思想是:在某个相机中观测到的特征点可以通过相机位姿和观测向量来确定一条从相机中心出发的观测射线。当存在多个相机位姿观测时,会生成多条观测射线。理想情况下,这些观测射线会在空间中的一个点相交。通过求解所有观测射线的交点,可以确定特征点在3D空间中的位置。

        然而,在实际应用中,由于存在噪声,观测射线往往不会精确交于一点。为了确定特征点的坐标,有以下几种思路:

  1. 直观方法:寻找一个与所有观测射线距离都很近的三维点,将其作为特征点。

  2. 重投影误差最小化:认为误差源于二维图像观测,因此将特征点投影到每个相机平面,最小化所有二维投影点与对应观测点之间的距离(特征点的线性三角化(Triangulation)方法)。

  3. 在线滤波:三角化常常是在线进行的,即边获取观测边估计特征点。利用滤波器估计特征点的概率分布(通常为高斯分布),旧观测信息隐式存储在概率分布中。当新观测到来时,用其更新特征点的概率分布,节省计算量。这是滤波方法的基本思想。

        设3D特征点w_{\boldsymbol{p}_i}M个相机观测到,已知:相机姿态$\{_w^{c_j}R,{}^wt_{c_j}\}_{j=1,...,M}$,相机内参K,特征点在各相机的图像观测$\{z_{ij}\}_{j=1,...,M}$,求:特征点的3D坐标w_{\boldsymbol{p}_i}

$\left\{\{_{w}^{​{c_{j}}}R,{}^{w}t_{​{c_{j}}},z_{ij}\}_{j=1,...,M}\text{,}K\right\}\to{}^{w}p_{i}$

不考虑误差的情况有如下投影关系:

$s\begin{bmatrix}u_{ij}\\v_{ij}\\1\end{bmatrix}=K[_w^{c_j}R|-_w^{c_j}R^wt_{c_j}]\begin{bmatrix}x_i\\y_i\\z_i\\1\end{bmatrix}$

通过多视角立体几何 (Multi-view Stereo, MVS)的这类方法中,重点介绍思路2:重投影误差最小化。

设特征点齐次坐标$\mathbf{\bar{x}}=(x,y,z,1)$,在第j个相机的图像观测点齐次坐标为$\bar{\mathbf{z}}_{j}=(u_{j},v_{j},1)$投影矩阵为$P_j=K[R_j|t_j]$,投影模型如下:

$s\bar{\mathbf{z}}_j=s\begin{bmatrix}u_j\\v_j\\1\end{bmatrix}=K[R_j|t_j]\begin{bmatrix}x\\y\\z\\1\end{bmatrix}=P_j\bar{\mathbf{x}}=\begin{bmatrix}P_j^{(1)}\\P_j^{(2)}\\P_j^{(3)}\end{bmatrix}\bar{\mathbf{x}}$

\bar{\mathbf{z}}_j\times\bar{\mathbf{z}}_j=0可得\lfloor\bar{\mathbf{z}}_{j_\times}\rfloor P_j\bar{\mathbf{x}}=0,将其展开:

\begin{bmatrix}0&-1&v_j\\1&0&-u_j\\-v_j&u_j&0\end{bmatrix}\begin{bmatrix}P_j^{(1)}\\P_j^{(2)}\\P_j^{(3)}\end{bmatrix}\bar{\mathbf{x}}=\begin{bmatrix}-P_j^{(2)}+v_jP_j^{(3)}\\P_j^{(1)}-u_jP_j^{(3)}\\-v_jP_j^{(1)}+u_jP_j^{(2)}\end{bmatrix}\bar{\mathbf{x}}=\begin{bmatrix}0\\0\\0\end{bmatrix}

        所以只有两个线性无关的方程,每个相机观测有两个线性方程,将M个相机观测的约束方程合并得到2M个线性方程:

\underbrace{\left[\begin{array}{c} -P_1^{(2)} + v_1 P_1^{(3)} \\ P_1^{(1)} - u_1 P_1^{(3)} \\ -P_2^{(2)} + v_2 P_2^{(3)} \\ P_2^{(1)} - u_2 P_2^{(3)} \\ \vdots \\ -P_M^{(2)} + v_M P_M^{(3)} \\ P_M^{(1)} - u_M P_M^{(3)} \end{array}\right]}_{\mathbf{H}} \bar{\mathbf{x}} = 0

这里可以使用SVD求解,齐次坐标\bar{\mathrm{x}}即为 H的最小奇异值的奇异向量。

2. 代码

 代码来自:

orbslam2_learn/linear_triangular at master · yepeichu123/orbslam2_learn · GitHubicon-default.png?t=N7T8https://github.com/yepeichu123/orbslam2_learn/tree/master/linear_triangular

这里给代码添加了中文注释。

main.cpp

#include "linear_triangular.h"
// c++
#include <iostream>
#include <vector>
// opencv
#include <opencv2/calib3d/calib3d.hpp>
// pcl
#include <pcl-1.8/pcl/io/pcd_io.h>
#include <pcl-1.8/pcl/point_types.h>
#include <pcl-1.8/pcl/point_cloud.h>
#include <pcl-1.8/pcl/common/impl/io.hpp>
#include <pcl-1.8/pcl/visualization/cloud_viewer.h>using namespace cv;
using namespace std;
using namespace pcl;// 从图像中提取 ORB 特征并计算描述子
void featureExtraction( const Mat& img, vector<KeyPoint>& kpt, Mat& desp );// 通过暴力匹配方法进行特征匹配
// 根据匹配得分的阈值选择一些良好的匹配对
void featureMatching( const Mat& rDesp, const Mat& cDesp, vector<DMatch>& matches,const vector<KeyPoint>& rKpt, const vector<KeyPoint>& cKpt,vector<Point2d>& goodRKpt, vector<Point2d>& goodCKpt );// 通过对极几何(Epipolar geometry)估计运动
bool motionEstimation( const vector<Point2d>& goodRKpt, const vector<Point2d>& goodCKpt,const Mat& K, Mat& Rcr, Mat& tcr );// 比较我们的方法和 OpenCV 的三角化误差
void triangularByOpencv( const vector<Point2d>& RKpt, const vector<Point2d>& CKpt, const Mat& Trw, const Mat& Tcw, const Mat& K,vector<Point2d>& nRKpt, vector<Point2d>& nCKpt,vector<Point3d>& Pw3dCV );int main( int argc, char** argv )
{// 确保我们有正确的输入数据if( argc < 3 ){cout << "Please enter ./linear_triangular currImg refImg" << endl;return -1;}// 从输入路径读取图像Mat currImg = imread( argv[1], 1 );Mat refImg = imread( argv[2], 1 );// 根据数据集设置相机参数Mat K = ( Mat_<double>(3,3) << 517.3, 0, 318.6, 0, 516.5, 255.3, 0, 0, 1 );// 检测 ORB 特征并计算 ORB 描述子vector<KeyPoint> ckpt, rkpt;Mat cdesp, rdesp;featureExtraction( currImg, ckpt, cdesp );featureExtraction( refImg, rkpt, rdesp );cout << "finish feature extration!" << endl;// 特征匹配vector<DMatch> matches;vector<Point2d> goodCKpt, goodRKpt;featureMatching( rdesp, cdesp, matches, rkpt, ckpt, goodRKpt, goodCKpt );cout << "finish feature matching!" << endl;// 运动估计Mat Rcr, tcr;if( !motionEstimation(goodRKpt, goodCKpt, K, Rcr, tcr) ){return -1;}cout << "finish motion estimation!" << endl;// 构造变换矩阵Mat Trw = Mat::eye(4,4,CV_64F);Mat Tcr = (Mat_<double>(3,4) << Rcr.at<double>(0,0), Rcr.at<double>(0,1), Rcr.at<double>(0,2), tcr.at<double>(0),Rcr.at<double>(1,0), Rcr.at<double>(1,1), Rcr.at<double>(1,2), tcr.at<double>(1),Rcr.at<double>(2,0), Rcr.at<double>(2,1), Rcr.at<double>(2,2), tcr.at<double>(2),0, 0, 0, 1);// 传播变换Mat Tcw = Tcr * Trw;Trw = Trw.rowRange(0,3).clone();Tcw = Tcw.rowRange(0,3).clone();                             cout << "Tcw = " << Tcw << endl;cout << "Trw = " << Trw << endl;cout << "现在我们通过线性三角化来三角化匹配对。" << endl;// 根据我们的博客开始三角化vector<Point3d> Pw3d;vector<Point2d> Pr2d;XIAOC::LinearTriangular myTriangular( K, Trw, Tcw );for( int i = 0; i < matches.size(); ++i ){Point3d pw;bool result = myTriangular.TriangularPoint( goodRKpt[i], goodCKpt[i], pw );// 检查三角化是否成功if( !result ){continue;}//cout << "pw in world coordinate is " << pw << endl;// 保存世界坐标系下的 3D 点Pw3d.push_back( pw );Pr2d.push_back( goodRKpt[i] );}// 根据 OpenCV 进行三角化vector<Point3d> Pw3dCV;vector<Point2d> nRKpt, nCKpt;triangularByOpencv( goodRKpt, goodCKpt, Trw, Tcw, K, nRKpt, nCKpt, Pw3dCV);// 重投影误差double errorOurs = 0, errorOpencv = 0;for( int i = 0; i < Pw3dCV.size(); ++i ){// 我们的三角化结果Point3d Pw = Pw3d[i];Point2d ppc = Point2d( Pw.x/Pw.z,Pw.y/Pw.z );// OpenCV 的三角化结果Point3d Pcv = Pw3dCV[i];Point2d ppcv = Point2d( Pcv.x/Pcv.z, Pcv.y/Pcv.z );// 参考归一化平面上的特征坐标Point2d ppr = nRKpt[i];errorOurs += norm( ppc - ppr );errorOpencv += norm( ppcv - ppr );}cout << "我们的总误差是 " << errorOurs << endl;cout << "OpenCV 的总误差是 " << errorOpencv << endl;cout << "我们的平均误差是 " << errorOurs / Pw3d.size() << endl;cout << "OpenCV 的平均误差是 " << errorOpencv / Pw3dCV.size() << endl;// 显示关键点Mat currOut;drawKeypoints( currImg, ckpt, currOut, Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS );imshow( "CurrOut", currOut );waitKey(0);// 显示良好的匹配结果Mat goodMatchOut;drawMatches( refImg, rkpt, currImg, ckpt, matches, goodMatchOut );imshow( "goodMatchOut", goodMatchOut );waitKey(0);// 将 3D 点转换为点云进行显示PointCloud<PointXYZRGB>::Ptr cloud( new PointCloud<PointXYZRGB> );for( int i = 0; i < Pw3d.size(); ++i ){   PointXYZRGB point;Point3d p = Pw3d[i];Point2d pixel = Pr2d[i];point.x = p.x;point.y = p.y;point.z = p.z;point.r = refImg.at<Vec3b>(pixel.y,pixel.x)[0];point.g = refImg.at<Vec3b>(pixel.y,pixel.x)[1];point.b = refImg.at<Vec3b>(pixel.y,pixel.x)[2];cloud->push_back( point );}cout << "点云的数量是 " << cloud->size() << endl;visualization::CloudViewer viewer( "Viewer" );viewer.showCloud( cloud );while( !viewer.wasStopped() ){// loop loop loop~~~}cout << "成功!" << endl;return 0;
}// 特征提取并计算描述子
void featureExtraction( const Mat& img, vector<KeyPoint>& kpt, Mat& desp )
{// 设置要提取的特征数量Ptr<FeatureDetector> detector = ORB::create( 10000 );Ptr<DescriptorExtractor> descriptor = ORB::create();detector->detect( img, kpt );descriptor->compute( img, kpt, desp );
}// 通过暴力匹配方法进行特征匹配并找到良好的匹配
void featureMatching( const Mat& rDesp, const Mat& cDesp, vector<DMatch>& matches, const vector<KeyPoint>& rKpt, const vector<KeyPoint>& cKpt,vector<Point2d>& goodRKpt, vector<Point2d>& goodCKpt )
{// 通过暴力匹配方法进行粗匹配,以汉明距离为度量Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create( "BruteForce-Hamming" );vector<DMatch> initMatches;matcher->match( rDesp, cDesp, initMatches );cout << "初始匹配完成!" << endl;// 计算最大距离和最小距离double min_dist = min_element( initMatches.begin(), initMatches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;} )->distance;double max_dist = max_element( initMatches.begin(), initMatches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;} )->distance;// 找到良好的匹配并记录相应的像素坐标for( int i = 0; i < initMatches.size(); ++i ){if( initMatches[i].distance <= max(min_dist*2, 30.0) ){matches.push_back( initMatches[i] );goodRKpt.push_back( rKpt[initMatches[i].queryIdx].pt );goodCKpt.push_back( cKpt[initMatches[i].trainIdx].pt );}}
}// 估计当前帧和参考帧之间的运动
bool motionEstimation( const vector<Point2d>& goodRKpt, const vector<Point2d>& goodCKpt,const Mat& K, Mat& Rcr, Mat& tcr )
{// 根据对极几何计算本质矩阵Mat E = findEssentialMat( goodRKpt, goodCKpt, K, RANSAC );// 从本质矩阵恢复姿态int inliers = recoverPose( E, goodRKpt, goodCKpt, K, Rcr, tcr );// 确保我们有足够的内点进行三角化return inliers > 100;
}// 比较我们的方法和 OpenCV 的三角化误差
void triangularByOpencv( const vector<Point2d>& RKpt, const vector<Point2d>& CKpt, const Mat& Trw, const Mat& Tcw, const Mat& K, vector<Point2d>& nRKpt, vector<Point2d>& nCKpt,vector<Point3d>& Pw3dCV )
{Mat pts_4d;// 将特征点反投影到归一化平面for( int i = 0; i < RKpt.size(); ++i ){Point2d pr( (RKpt[i].x-K.at<double>(0,2))/K.at<double>(0,0),(RKpt[i].y-K.at<double>(1,2))/K.at<double>(1,1) );Point2d pc( (CKpt[i].x-K.at<double>(0,2))/K.at<double>(0,0),(CKpt[i].y-K.at<double>(1,2))/K.at<double>(1,1) );nRKpt.push_back( pr );nCKpt.push_back( pc );                }// 三角化点triangulatePoints( Trw, Tcw, nRKpt, nCKpt, pts_4d );// 从齐次坐标中恢复位置for( int i = 0; i < pts_4d.cols; ++i ){Mat x = pts_4d.col(i);x /= x.at<double>(3,0);Point3d pcv( x.at<double>(0,0), x.at<double>(1,0), x.at<double>(2,0));Pw3dCV.push_back( pcv );}  cout << "pw3d 的大小 =  " << Pw3dCV.size() << endl;
}

liner_triangular.cpp


#include "linear_triangular.h"
#include <iostream>// 构造函数:设置相机参数和变换矩阵
XIAOC::LinearTriangular::LinearTriangular(const cv::Mat& K, const cv::Mat& Trw, const cv::Mat& Tcw):mK_(K), mTrw_(Trw), mTcw_(Tcw)
{}// 从两个视图的特征点三角化出 3D 点
// 输入:2D pr 和 2D pc,分别是参考帧和当前帧中的像素坐标
// 输出:3D Pw,即世界坐标系下的 3D 坐标
bool XIAOC::LinearTriangular::TriangularPoint(const cv::Point2d& pr, const cv::Point2d& pc, cv::Point3d& Pw )
{// 反投影到归一化平面UnprojectPixel( pr, pc );// 构造矩阵 AConstructMatrixA( mPrn_, mPcn_, mTrw_, mTcw_ );// 获取 3D 位置if( CompBySVD( mA_, mPw_ ) ){Pw = mPw_;return true;}return false;
}// 将像素点反投影到归一化平面
void XIAOC::LinearTriangular::UnprojectPixel(const cv::Point2d& pr, const cv::Point2d& pc)
{// X = (u-cx)/fx;// Y = (v-cy)/fy;mPrn_.x = (pr.x - mK_.at<double>(0,2))/mK_.at<double>(0,0);mPrn_.y = (pr.y - mK_.at<double>(1,2))/mK_.at<double>(1,1);mPrn_.z  = 1;mPcn_.x = (pc.x - mK_.at<double>(0,2))/mK_.at<double>(0,0);mPcn_.y = (pc.y - mK_.at<double>(1,2))/mK_.at<double>(1,1);mPcn_.z = 1;
}// 根据我们的博客构造矩阵 A
void XIAOC::LinearTriangular::ConstructMatrixA(const cv::Point3d& Prn, const cv::Point3d& Pcn, const cv::Mat& Trw, const cv::Mat& Tcw )
{// ORBSLAM 方法/* cv::Mat A(4,4,CV_64F);A.row(0) = Prn.x*Trw.row(2)-Trw.row(0);A.row(1) = Prn.y*Trw.row(2)-Trw.row(1);A.row(2) = Pcn.x*Tcw.row(2)-Tcw.row(0);A.row(3) = Pcn.y*Tcw.row(2)-Tcw.row(1);A.copyTo( mA_ );*/// 我博客中的原始方法cv::Mat PrnX = (cv::Mat_<double>(3,3) << 0, -Prn.z, Prn.y, Prn.z, 0, -Prn.x,-Prn.y, Prn.x, 0);cv::Mat PcnX = (cv::Mat_<double>(3,3) << 0, -Pcn.z, Pcn.y, Pcn.z, 0, -Pcn.x,-Pcn.y, Pcn.x, 0);// A = [prX*Trw; pcX*Tcw ]// APw = 0cv::Mat B = PrnX * Trw;cv::Mat C = PcnX * Tcw;cv::vconcat( B, C, mA_ );}//  通过计算 SVD 求解问题
bool XIAOC::LinearTriangular::CompBySVD(const cv::Mat& A, cv::Point3d& Pw )
{if( A.empty() ){return false;}// 计算矩阵 A 的 SVDcv::Mat w, u, vt;cv::SVD::compute( A, w, u, vt, cv::SVD::MODIFY_A|cv::SVD::FULL_UV );// 归一化cv::Mat Pw3d;Pw3d = vt.row(3).t();if( Pw3d.at<double>(3) == 0 ){return false;}Pw3d = Pw3d.rowRange(0,3)/Pw3d.at<double>(3);// 保存位置的值Pw.x = Pw3d.at<double>(0);Pw.y = Pw3d.at<double>(1);Pw.z = Pw3d.at<double>(2);return true;
}// 检查两个视图之间特征点的角度
bool XIAOC::LinearTriangular::CheckCrossAngle( const cv::Point3d& Prn, const cv::Point3d& Pcn, const cv::Mat& Trw, const cv::Mat& Tcw )
{// 待办:通过角度检查是否适合三角化
}// 检查我们三角化得到的点的深度是否正确
bool XIAOC::LinearTriangular::CheckDepth( const cv::Point3d& Pw3d )
{// 待办:通过深度检查是否适合接受
}

CMakeList.txt 

cmake_minimum_required( VERSION 2.8 )
project( linear_triangular )set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std=c++11" )
set( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin )
set( LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib )find_package( OpenCV 3.0 REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )find_package( PCL REQUIRED )
include_directories( ${PCL_INCLUDE_DIRS} )
link_directories( ${PCL_LIBRARY_DIRS} )
add_definitions( ${PCL_DEFINITIONS} )include_directories( ${PROJECT_SOURCE_DIR}/include )
#add_subdirectory( ${PROJECT_SOURCE_DIR} )add_executable( linear_triangular src/linear_triangular.cpp src/main.cpp ) 
target_link_libraries( linear_triangular ${OpenCV_LIBS} ${PCL_LIBRARIES} ) 

3. 结果 

二、通过端到端深度学习方法估计单目深度---DPT

      Ranftl et al. (2020) - 提出了一种基于Transformer的深度估计方法,称为Vision Transformer for Dense Prediction (DPT)。该方法利用了Transformer强大的全局建模能力,通过self-attention机制学习像素之间的长距离依赖关系。同时,他们还设计了一种多尺度融合策略,以结合不同层次的特征信息。DPT在多个数据集上都取得了最先进的性能。

1. 原理

        根据论文 "Vision Transformers for Dense Prediction" 的内容,Dense Prediction Transformers (DPT) 的主要原理可以总结如下:DPT在编码器-解码器架构中利用视觉transformer (ViT)作为骨干网络,用于深度估计和语义分割等密集预测任务。与逐步下采样特征图的卷积骨干网络不同,ViT骨干网络通过对分块/令牌进行操作,在整个过程中保持恒定的空间分辨率。在每个阶段,ViT通过自注意力机制具有全局感受野。这允许在高分辨率下捕获长距离依赖关系。来自不同ViT阶段的令牌被重组为多尺度的类图像特征。然后,卷积解码器融合这些特征并对其进行上采样,以获得最终的密集预测。通过在每个阶段保持高分辨率并具有全局感受野,与全卷积网络相比,DPT能够提供细粒度和全局连贯的预测。当有大量训练数据可用时,DPT在先前技术的基础上大幅改进,在具有挑战性的数据集上设置了新的最先进水平。
        总之,DPT的创新之处在于使用了ViT骨干,该骨干在每个阶段以全局上下文处理高分辨率特征,然后由卷积解码器将其合并为细粒度预测,从而在密集预测任务上显著提高了性能。
不是搞深度学习的我也看不懂啊,读者自行分别吧。这个坑后面再填

2. 代码

代码连接: https://github.com/intel-isl/DPTicon-default.png?t=N7T8https://github.com/intel-isl/DPT论文连接:

https://arxiv.org/pdf/2103.13413icon-default.png?t=N7T8https://arxiv.org/pdf/2103.13413

3. 结果


 

参考文章:

 VSLAM中的特征点三角化 - 知乎 (zhihu.com)

SLAM--三角化求解3D空间点_jacobisvd(eigen::computefullv).matrixv()-CSDN博客

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

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

相关文章

RT-Thread中使用Mqtt

环境&#xff1a; 开发板&#xff1a;Panduola&#xff08;stm32L475&#xff09; KEIL5 开发环境 rtthread 4.0.3内核 使用ENV 配置Rtt MQTT 1.MQTT介绍 ​ 客户端 Client 使用MQTT的程序或设备。客户端总是通过网络连接到服务端。它可以发布应用消息给其它相关的客户端。订…

RocketMQ:新增consumer消费组group从最新消息开始消费skip last offset message

场景 想创建一个新的consumer去消费一个已经再使用的topic时&#xff0c;默认情况下会从topic中的第一条消息开始消费&#xff0c;大多数情况是需要从最新的消息开始。然后再使用CONSUME_FROM_LAST_OFFSET设置时并不会对新的consumer生效&#xff0c;它只是在停用consumer重新启…

Google I/O 2024:探索未来AI技术的无限可能

近日&#xff0c;Google I/O 2024大会圆满落幕&#xff0c;带给我们一场关于人工智能的盛宴。在这场大会上&#xff0c;Google推出了一系列令人激动的AI新功能和工具&#xff0c;让我们得以一窥未来的科技发展。今天&#xff0c;就让我来为大家总结一下这些亮点吧&#xff01; …

压力测试及常用的压测工具!

前言 压力测试是一种评估系统性能的方法&#xff0c;通过模拟大量用户同时访问系统或执行特定操作&#xff0c;以测试系统的负载能力和稳定性。 压力测试可以帮助发现系统在高负载情况下的性能瓶颈、错误或故障&#xff0c;从而提前进行优化和改进。在进行压力测试时&#xf…

吴恩达深度学习笔记:优化算法 (Optimization algorithms)2.7

目录 第二门课: 改善深层神经网络&#xff1a;超参数调试、正 则 化 以 及 优 化 (Improving Deep Neural Networks:Hyperparameter tuning, Regularization and Optimization)第二周&#xff1a;优化算法 (Optimization algorithms)2.7 RMSprop 第二门课: 改善深层神经网络&am…

「Python绘图」绘制同心圆

python 绘制同心圆 一、预期结果 二、核心代码 import turtle print("开始绘制同心圆") # 创建Turtle对象 pen turtle.Turtle() pen.shape("turtle") # 移动画笔到居中位置 pen.pensize(2) #设置外花边的大小 # 设置填充颜色 pen.fillcolor("green&…

【大数据】计算引擎MapReduce

目录 1.概述 1.1.前言 1.2.大数据要怎么计算&#xff1f; 1.3.什么是MapReduce&#xff1f; 2.架构 3.工作流程 4.shuffle 4.1.map过程 4.2.reduce过程 1.概述 1.1.前言 本文是作者大数据系列专栏的其中一篇&#xff0c;专栏地址&#xff1a; https://blog.csdn.ne…

NVM镜像源报错:Could not retrieve https://npm.taobao.org/mirrors/node/index.json.

NVM镜像源报错&#xff1a;Could not retrieve https://npm.taobao.org/mirrors/node/index.json. 淘宝前端node镜像源已更换 NVM安装教程&#xff1a;http://t.csdnimg.cn/dihmG 背景 笔者在安装版本切换工具NVM时&#xff0c;配置完镜像源后&#xff0c;在控制台输入&#x…

使用FFmpeg处理RTSP视频流并搭建RTMP服务器实现图片转直播全流程

目录 一、FFmpeg安装与配置二、搭建并配置Nginx RTMP服务器三、从RTSP视频流提取帧并保存为图片四、将图片序列转换为视频五、将视频推送为直播流六、将图片序列推送为直播流七、播放实时流 场景&#xff1a;如何通过FFmpeg工具链&#xff0c;从RTSP视频流中按秒抽取帧生成图片…

六西格玛管理培训对企业有哪些实际帮助?

当下&#xff0c;企业要想脱颖而出&#xff0c;不仅要有创新思维和敏锐的市场洞察力&#xff0c;更要有高效的管理体系和严谨的质量控制手段。而六西格玛管理培训正是这样一项能够帮助企业实现提质增效、提升竞争力的关键举措。那么&#xff0c;六西格玛管理培训对企业究竟有哪…

超级数据查看器 教程合集 整理版本 pdf格式 1-31集

点击下载 超级数据查看器 教程合集整理版本 pdf格式https://download.csdn.net/download/qq63889657/89311725?spm1001.2014.3001.5501

SQL Server共享功能目录显示灰色无法自行选择

SQL Server共享功能目录显示灰色无法自行调整 一、 将之前安装SQL Server卸载干净 二、 清空注册表 1. 打开注册表&#xff0c;winR&#xff0c;输入regedit 2. 注册表-》编辑-》查找&#xff0c;输入C:\Program Files\Microsoft SQL Server\ 3. 注册表-》编辑-》查找&#x…

量子计算机接入欧洲最快超算!芬兰加快混合架构算法开发

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 文丨浪味仙 排版丨沛贤 深度好文&#xff1a;1900字丨7分钟阅读 摘要&#xff1a;芬兰技术研究中心&#xff08;VTT&#xff09;与 CSC 展开合作&#xff0c;基于量子计算机超算架构进行算法开…

Git大文件无法直接push用git lfs track 上传大文件具体操作

Git 因为大文件push失败 回退到git add前用git lfs track单独添加大文件 以下work flow仅代表个人解决问题的办法&#xff0c;有优化流程的欢迎交流 回退到git add前 以下指令回退一个commit git reset --soft HEAD~1以下指令撤销所有git add操作&#xff0c;但不删除本地修…

泰盈科技IPO终止:客户集中度高,业绩未达目标,高管薪酬较高

近日&#xff0c;上海证券交易所披露的信息显示&#xff0c;泰盈科技集团股份有限公司&#xff08;下称“泰盈科技”&#xff09;及其保荐人中金公司撤回上市申请文件。因此&#xff0c;上海证券交易所决定终止对该公司首次公开发行股票并在主板上市的审核。 据贝多财经了解&am…

STM32 HAL TM1638读取24个按键

本文分享一下天微电子的另一款数码管按键驱动芯片TM1638的单片机C语言驱动程序。 笔者采用的MCU是STM32单片机&#xff0c;STM32CubeMX Keil5开发&#xff0c;使用了HAL库。 一、TM1638介绍 1、基础信息 TM1638属于一款LED驱动控制专用电路&#xff0c;其特性如下&#xf…

【文献阅读】李井林等2021ESG促企业绩效的机制研究——基于企业创新的视角

ESG促进企业绩效的机制 摘要 0.引言与文献综述 1.理论分析与研究假设 1.1企业ESG表现与企业绩效 假设1a&#xff1a;企业的环境表现对企业绩效存在正向影响效应。 假设1b&#xff1a;企业的社会表现对企业绩效存在正向影响效应。 假设1c&#xff1a;企业的公司治理表现对企业…

PCIE V3.0物理层协议学习笔记

一、说明 PCI-Express(peripheral component interconnect express)是一种高速串行计算机扩展总线标准&#xff0c;它原来的名称为“3GIO”&#xff0c;是由英特尔在2001年提出的&#xff0c;旨在替代旧的PCI&#xff0c;PCI-X和AGP总线标准。 PCIe属于高速串行点对点双通道高…

JVM---垃圾回收

目录 一、C/C的内存管理 二、Java的内存管理 三、垃圾回收的对比 四、Java的内存管理和自动垃圾回收 五、方法区的回收 手动触发回收 六、堆回收 如何判断堆上的对象可以回收&#xff1f; 引用计数法 可达性分析算法 五种对象引用 软引用 软引用的使用场景-缓存 弱引用 虚…

【Python-爬虫】

Python-爬虫 ■ 爬虫分类■ 1. 通用网络爬虫&#xff1a;&#xff08;搜索引擎使用&#xff0c;遵守robots协议&#xff09;■ robots协议&#xff08;君子协议&#xff09; ■ 2. 聚集网络爬虫&#xff1a;自己写的爬虫程序 ■ urllib.request&#xff08;请求模块&#xff09…