特征检测与特征匹配方法笔记+代码分享

news2024/12/25 12:26:18

        在一幅图像中,总能发现其独特的像素点,这些点可以被视为该图像的特征,我们称之为特征点。在计算机视觉领域中,基于特征点的图像特征匹配是一项至关重要的任务,因此,如何定义并识别一幅图像中的特征点显得尤为重要。本文旨在总结计算机视觉领域中最常用的几种特征点及其特征匹配方法。

        在计算机视觉领域,兴趣点(亦称关键点或特征点)的概念已被广泛采纳,应用于目标识别、图像配准、视觉跟踪、三维重建等多个方面。其原理在于,通过对图像中的某些特征点进行局部分析,而非全面审视整幅图像,只要图像中存在足够多可检测且互不相同的稳定兴趣点,并能被精确定位,上述方法便能发挥显著效果。

        以下用于实验的两幅图像分别是:一幅手机抓拍的风景照,以及一幅遥感图像。

 

 1、SURF

        视觉不变性在特征检测中扮演着举足轻重的角色,其中尺度不变性问题的解决尤为棘手。为了攻克这一难题,计算机视觉领域引入了尺度不变特征的概念。其核心思想在于,无论物体在何种尺度下被拍摄,都能检测到一致的关键点,并且每个检测到的特征点都配备了一个尺度因子。在理想状况下,对于两幅图像中不同尺度的同一物体点,其计算所得的尺度因子之比应等于图像尺度的比率。

        近年来,多种尺度不变特征被相继提出,本节将介绍其中的一种:SURF特征。SURF,全称“加速稳健特征”(Speeded Up Robust Feature),它不仅具备尺度不变性,还拥有较高的计算效率。

        接下来,我们将进行常规的特征提取和特征点匹配,以观察其实际效果。

#include "highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"    
#include "opencv2/legacy/legacy.hpp"   
#include <iostream>  
 
using namespace cv;
using namespace std;
 
 
int main()
{
    Mat image01 = imread("2.jpg", 1);    //右图
    Mat image02 = imread("1.jpg", 1);    //左图
    namedWindow("p2", 0);
    namedWindow("p1", 0);
    imshow("p2", image01);
    imshow("p1", image02);
 
    //灰度图转换  
    Mat image1, image2;
    cvtColor(image01, image1, CV_RGB2GRAY);
    cvtColor(image02, image2, CV_RGB2GRAY);
 
 
    //提取特征点    
    SurfFeatureDetector surfDetector(800);  // 海塞矩阵阈值,在这里调整精度,值越大点越少,越精准 
    vector<KeyPoint> keyPoint1, keyPoint2;
    surfDetector.detect(image1, keyPoint1);
    surfDetector.detect(image2, keyPoint2);
 
    //特征点描述,为下边的特征点匹配做准备    
    SurfDescriptorExtractor SurfDescriptor;
    Mat imageDesc1, imageDesc2;
    SurfDescriptor.compute(image1, keyPoint1, imageDesc1);
    SurfDescriptor.compute(image2, keyPoint2, imageDesc2);
 
    //获得匹配特征点,并提取最优配对     
    FlannBasedMatcher matcher;
    vector<DMatch> matchePoints;
 
    matcher.match(imageDesc1, imageDesc2, matchePoints, Mat());
    cout << "total match points: " << matchePoints.size() << endl;
 
 
    Mat img_match;
    drawMatches(image01, keyPoint1, image02, keyPoint2, matchePoints, img_match);
    namedWindow("match", 0);
    imshow("match",img_match);
    imwrite("match.jpg", img_match);
 
    waitKey();
    return 0;
}

        从上述特征点匹配的效果来看,匹配结果并不理想。如果我们基于这样的匹配结果去实现图像拼接或物体追踪,效果肯定会大打折扣。因此,我们需要进一步筛选匹配点,以获取更优质的匹配点,这一过程被称为“去粗取精”。在这里,我们采用了Lowe’s算法来进一步优化匹配点的选择。

        为了剔除因图像遮挡和背景杂乱而产生的无匹配关系的关键点,SIFT算法的提出者Lowe提出了一种基于最近邻距离与次近邻距离比较的SIFT匹配方法。具体而言,对于一幅图像中的一个SIFT关键点,我们在另一幅图像中找出与其欧式距离最近的前两个关键点。如果这两个关键点中,最近距离与次近距离的比率(即ratio)小于某个阈值T,则接受这一对匹配点。由于特征空间的高维性,错误匹配的特征点之间往往存在大量相似的距离,因此其ratio值通常较高。通过降低比例阈值T,虽然SIFT匹配点的数量会减少,但匹配结果会更加稳定;反之,则可能增加错误匹配的数量。

        Lowe推荐的ratio阈值为0.8,但经过对大量存在尺度、旋转和亮度变化的图像进行匹配实验,我们发现ratio的取值在0.4~0.6之间时效果最佳。当ratio小于0.4时,匹配点数量稀少;而当ratio大于0.6时,则可能出现大量错误匹配点。因此,我们建议根据实际需求选择合适的ratio值:

  • 当对匹配准确度要求较高时,ratio可取0.4;
  • 当需要较多的匹配点时,ratio可取0.6;
  • 在一般情况下,ratio可取0.5作为折中选择。
#include "highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"    
#include "opencv2/legacy/legacy.hpp"   
#include <iostream>  
 
using namespace cv;
using namespace std;
 
 
int main()
{
 
    Mat image01 = imread("g2.jpg", 1);    
    Mat image02 = imread("g4.jpg", 1);    
    imshow("p2", image01);
    imshow("p1", image02);
 
    //灰度图转换  
    Mat image1, image2;
    cvtColor(image01, image1, CV_RGB2GRAY);
    cvtColor(image02, image2, CV_RGB2GRAY);
 
 
    //提取特征点    
    SurfFeatureDetector surfDetector(2000);  // 海塞矩阵阈值,在这里调整精度,值越大点越少,越精准 
    vector<KeyPoint> keyPoint1, keyPoint2;
    surfDetector.detect(image1, keyPoint1);
    surfDetector.detect(image2, keyPoint2);
 
    //特征点描述,为下边的特征点匹配做准备    
    SurfDescriptorExtractor SurfDescriptor;
    Mat imageDesc1, imageDesc2;
    SurfDescriptor.compute(image1, keyPoint1, imageDesc1);
    SurfDescriptor.compute(image2, keyPoint2, imageDesc2);
 
    FlannBasedMatcher matcher;
    vector<vector<DMatch> > matchePoints;
    vector<DMatch> GoodMatchePoints;
 
    vector<Mat> train_desc(1, imageDesc1);
    matcher.add(train_desc);
    matcher.train();
 
    matcher.knnMatch(imageDesc2, matchePoints, 2);
    cout << "total match points: " << matchePoints.size() << endl;
 
    // Lowe's algorithm,获取优秀匹配点
    for (int i = 0; i < matchePoints.size(); i++)
    {
        if (matchePoints[i][0].distance < 0.6 * matchePoints[i][1].distance)
        {
            GoodMatchePoints.push_back(matchePoints[i][0]);
        }
    }
    Mat first_match;
    drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match);
    imshow("first_match ", first_match);
    waitKey();
    return 0;
}

2、SIFT算法

        SURF算法作为SIFT算法的加速版本,在特征点检测速度上有了显著提升,因此在实时视频流物体匹配等应用中具有显著优势。相比之下,SIFT(尺度不变特征转换,Scale-Invariant Feature Transform)算法虽然特征计算量大,导致特征点提取过程耗时较长,在一些追求速度的场合难以应用,但其基于浮点内核计算特征点的特性,使得SIFT算法在空间和尺度上的定位通常更为精确。因此,在匹配精度要求极高且对匹配速度无严格要求的场合,SIFT算法仍是一个值得考虑的选择。

        值得一提的是,SIFT特征检测的代码实现与SURF算法的代码实现非常相似,仅需要对SURF代码进行微小的修改即可适用于SIFT特征检测。

#include "highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"    
#include "opencv2/legacy/legacy.hpp"   
#include <iostream>  
 
using namespace cv;
using namespace std;
 
 
int main()
{
    Mat image01 = imread("1.jpg", 1);    //右图
    Mat image02 = imread("2.jpg", 1);    //左图
    namedWindow("p2", 0);
    namedWindow("p1", 0);
    imshow("p2", image01);
    imshow("p1", image02);
 
    //灰度图转换  
    Mat image1, image2;
    cvtColor(image01, image1, CV_RGB2GRAY);
    cvtColor(image02, image2, CV_RGB2GRAY);
 
 
    //提取特征点    
    SiftFeatureDetector siftDetector(2000);  // 海塞矩阵阈值,在这里调整精度,值越大点越少,越精准 
    vector<KeyPoint> keyPoint1, keyPoint2;
    siftDetector.detect(image1, keyPoint1);
    siftDetector.detect(image2, keyPoint2);
 
    //特征点描述,为下边的特征点匹配做准备    
    SiftDescriptorExtractor SiftDescriptor;
    Mat imageDesc1, imageDesc2;
    SiftDescriptor.compute(image1, keyPoint1, imageDesc1);
    SiftDescriptor.compute(image2, keyPoint2, imageDesc2);
 
    //获得匹配特征点,并提取最优配对     
    FlannBasedMatcher matcher;
    vector<DMatch> matchePoints;
 
    matcher.match(imageDesc1, imageDesc2, matchePoints, Mat());
    cout << "total match points: " << matchePoints.size() << endl;
 
 
    Mat img_match;
    drawMatches(image01, keyPoint1, image02, keyPoint2, matchePoints, img_match);
 
    imshow("match",img_match);
    imwrite("match.jpg", img_match);
 
    waitKey();
    return 0;
}

没有经过点筛选的匹配效果同样糟糕。下面继续采用Lowe‘s的算法选出优秀匹配点。

#include "highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"    
#include "opencv2/legacy/legacy.hpp"   
#include <iostream>  
 
using namespace cv;
using namespace std;
 
 
int main()
{
 
    Mat image01 = imread("1.jpg", 1);
    Mat image02 = imread("2.jpg", 1);
    imshow("p2", image01);
    imshow("p1", image02);
 
    //灰度图转换  
    Mat image1, image2;
    cvtColor(image01, image1, CV_RGB2GRAY);
    cvtColor(image02, image2, CV_RGB2GRAY);
 
 
    //提取特征点    
    SiftFeatureDetector siftDetector(800);  // 海塞矩阵阈值,在这里调整精度,值越大点越少,越精准 
    vector<KeyPoint> keyPoint1, keyPoint2;
    siftDetector.detect(image1, keyPoint1);
    siftDetector.detect(image2, keyPoint2);
 
    //特征点描述,为下边的特征点匹配做准备    
    SiftDescriptorExtractor SiftDescriptor;
    Mat imageDesc1, imageDesc2;
    SiftDescriptor.compute(image1, keyPoint1, imageDesc1);
    SiftDescriptor.compute(image2, keyPoint2, imageDesc2);
 
    FlannBasedMatcher matcher;
    vector<vector<DMatch> > matchePoints;
    vector<DMatch> GoodMatchePoints;
 
    vector<Mat> train_desc(1, imageDesc1);
    matcher.add(train_desc);
    matcher.train();
 
    matcher.knnMatch(imageDesc2, matchePoints, 2);
    cout << "total match points: " << matchePoints.size() << endl;
 
    // Lowe's algorithm,获取优秀匹配点
    for (int i = 0; i < matchePoints.size(); i++)
    {
        if (matchePoints[i][0].distance < 0.6 * matchePoints[i][1].distance)
        {
            GoodMatchePoints.push_back(matchePoints[i][0]);
        }
    }
    Mat first_match;
    drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match);
    imshow("first_match ", first_match);
    imwrite("first_match.jpg", first_match);
    waitKey();
    return 0;
}

3、ORB算法

        ORB,全称Oriented BRIEF,是BRIEF算法的改进版本。与SIFT算法相比,ORB算法的运行速度快了100倍;与SURF算法相比,则快了10倍。在计算机视觉领域,ORB算法因其在各种测评中展现出的卓越综合性能,而被广泛认为是一种顶尖的特征提取算法。

        既然ORB算法是对BRIEF算法的改进,我们首先要了解BRIEF算法的不足之处。BRIEF算法的优势在于其极高的运行速度,但其缺点也较为明显:不具备旋转不变性,对噪声敏感,以及缺乏尺度不变性。针对其中的前两个缺点,ORB算法提出了一种全新的解决方案。然而,值得注意的是,ORB算法并未解决尺度不变性的问题。

#include "highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"    
#include "opencv2/legacy/legacy.hpp"   
#include <iostream>  
 
using namespace cv;
using namespace std;
 
 
int main()
{
 
    Mat image01 = imread("g2.jpg", 1);
    Mat image02 = imread("g4.jpg", 1);
    imshow("p2", image01);
    imshow("p1", image02);
 
    //灰度图转换  
    Mat image1, image2;
    cvtColor(image01, image1, CV_RGB2GRAY);
    cvtColor(image02, image2, CV_RGB2GRAY);
 
 
    //提取特征点    
    OrbFeatureDetector OrbDetector(1000);  // 在这里调整精度,值越小点越少,越精准 
    vector<KeyPoint> keyPoint1, keyPoint2;
    OrbDetector.detect(image1, keyPoint1);
    OrbDetector.detect(image2, keyPoint2);
 
    //特征点描述,为下边的特征点匹配做准备    
    OrbDescriptorExtractor OrbDescriptor;
    Mat imageDesc1, imageDesc2;
    OrbDescriptor.compute(image1, keyPoint1, imageDesc1);
    OrbDescriptor.compute(image2, keyPoint2, imageDesc2);
 
    flann::Index flannIndex(imageDesc1, flann::LshIndexParams(12, 20, 2), cvflann::FLANN_DIST_HAMMING);
 
    vector<DMatch> GoodMatchePoints;
 
    Mat macthIndex(imageDesc2.rows, 2, CV_32SC1), matchDistance(imageDesc2.rows, 2, CV_32FC1);
    flannIndex.knnSearch(imageDesc2, macthIndex, matchDistance, 2, flann::SearchParams());
 
    // Lowe's algorithm,获取优秀匹配点
    for (int i = 0; i < matchDistance.rows; i++)
    {
        if (matchDistance.at<float>(i,0) < 0.6 * matchDistance.at<float>(i, 1))
        {
            DMatch dmatches(i, macthIndex.at<int>(i, 0), matchDistance.at<float>(i, 0));
            GoodMatchePoints.push_back(dmatches);
        }
    }
    Mat first_match;
    drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match);
    imshow("first_match ", first_match);
    imwrite("first_match.jpg", first_match);
    waitKey();
    return 0;
}

4、FAST特征检测算子

       FAST,全称Features from Accelerated Segment Test,是一种专门用于快速检测兴趣点的算子。其工作原理极为简洁,仅通过对比少数几个像素的强度值,即可迅速判断一个点是否为关键点。

        与Harris检测器类似,FAST算法同样基于对角点的定义进行工作。它通过对候选特征点周围的图像强度值进行分析,来判断该点是否为关键点。具体而言,以某个点为中心作一个圆,然后检查圆上像素的强度值。如果存在一段连续长度超过圆周长3/4的圆弧,且该圆弧上所有像素的强度值都与圆心的强度值存在显著差异(要么全部更暗,要么全部更亮),则认定该点为关键点。

        由于FAST算法检测兴趣点的速度极快,因此非常适合那些对速度有严格要求的应用场景,如实时视觉跟踪和目标识别等。在这些应用中,需要在实时视频流中快速跟踪或匹配多个点,FAST算法的高效性显得尤为重要。

        在OpenCV中,我们可以使用FastFeatureDetector进行特征点提取。然而,由于OpenCV并未提供针对FAST的专用描述子提取器,因此我们可以借助SiftDescriptorExtractor来实现描述子的提取。

#include "highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"    
#include "opencv2/legacy/legacy.hpp"   
#include <iostream>  
 
using namespace cv;
using namespace std;
 
 
int main()
{
 
    Mat image01 = imread("1.jpg", 1);
    Mat image02 = imread("2.jpg", 1);
    imshow("p2", image01);
    imshow("p1", image02);
 
    //灰度图转换  
    Mat image1, image2;
    cvtColor(image01, image1, CV_RGB2GRAY);
    cvtColor(image02, image2, CV_RGB2GRAY);
 
 
    //提取特征点    
    FastFeatureDetector Detector(50);  //阈值 
    vector<KeyPoint> keyPoint1, keyPoint2;
    Detector.detect(image1, keyPoint1);
    Detector.detect(image2, keyPoint2);
 
    //特征点描述,为下边的特征点匹配做准备    
    SiftDescriptorExtractor   Descriptor;
    Mat imageDesc1, imageDesc2;
    Descriptor.compute(image1, keyPoint1, imageDesc1);
    Descriptor.compute(image2, keyPoint2, imageDesc2);
 
    BruteForceMatcher< L2<float> > matcher;   
    vector<vector<DMatch> > matchePoints;
    vector<DMatch> GoodMatchePoints;
 
    vector<Mat> train_desc(1, imageDesc1);
    matcher.add(train_desc);
    matcher.train();
 
    matcher.knnMatch(imageDesc2, matchePoints, 2);
    cout << "total match points: " << matchePoints.size() << endl;
 
    // Lowe's algorithm,获取优秀匹配点
    for (int i = 0; i < matchePoints.size(); i++)
    {
        if (matchePoints[i][0].distance < 0.6 * matchePoints[i][1].distance)
        {
            GoodMatchePoints.push_back(matchePoints[i][0]);
        }
    }
    Mat first_match;
    drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match);
    imshow("first_match ", first_match);
    imwrite("first_match.jpg", first_match);
    waitKey();
    return 0;
}

如果我们把描述子换成SurfDescriptorExtractor,即FastFeatureDetector + SurfDescriptorExtractor的组合,看看效果

可以看出,这种组合下的特征点匹配并不精确。

如果我们把描述子换成SurfDescriptorExtractor,即FastFeatureDetector + BriefDescriptorExtractor 的组合,看看效果

        尽管FAST特征点检测速度飞快,但其精度却略显不足。这可能会引发一些疑问:既然FAST特征点检测速度这么快,为什么我们还需要借助SiftDescriptorExtractor或其他描述子提取器来提取特征呢?

        对此,我有以下理解:特征点匹配的首要步骤是识别并提取每幅图像的特征点,这被称为特征检测。例如,我们使用FastFeatureDetector或SiftFeatureDetector等工具来完成这一任务。然而,仅仅识别特征点并不足以实现精确匹配,我们还需要对这些特征点进行更深入的分析,通过数学特征(如梯度直方图、局部随机二值特征等)进行描述。在这一步骤中,我们可以选择使用不同的描述子提取器来对特征点进行描述,从而更精确地实现特征点的匹配。

        在OpenCV库中,SURF、ORB和SIFT算法不仅包含特征检测器(FeatureDetector),还配备了描述子提取器(DescriptorExtractor)。因此,在使用这些算法进行特征匹配时,我们通常会直接使用它们自带的配套方法。

        那么,如果我们希望使用FAST角点检测来进行特征点匹配,应该怎么办呢?此时,我们可以采用FastFeatureDetector与BriefDescriptorExtractor的组合方式,这种组合实际上就是著名的ORB算法。因此,特征点检测和特征点匹配是两个独立的步骤,我们可以根据项目需求自由组合这两个步骤的方法。

5、Harris角点检测

        在图像中搜寻有价值的特征点时,角点无疑是一种高效且实用的方法。角点作为图像中易于定位的局部特征,广泛存在于人造物体中,如墙壁、门、窗户、桌子等形成的角落。这些角点之所以具有价值,是因为它们作为两条边缘线的交汇点,不仅是一种显著的二维特征,而且能够被精确地定位,甚至达到子像素级别的精度。

        相比之下,位于图像均匀区域或物体轮廓上的点,以及在同一物体的不同图像上难以重复精确定位的点,其应用价值就相对较低。为了有效地检测这些角点,Harris特征检测算法应运而生,它成为了检测角点的经典方法之一。

        在这里,我们将展示如何利用GoodFeaturesToTrackDetector(一个用于检测图像中可跟踪特征点的OpenCV工具)与SiftDescriptorExtractor(一个用于提取SIFT描述子的OpenCV工具)的组合方式来进行角点检测和描述子提取。当然,除了这种组合方式,还存在其他多种可能的组合,但在此我们不再一一展示。

#include "highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"    
#include "opencv2/legacy/legacy.hpp"   
#include <iostream>  
 
using namespace cv;
using namespace std;
 
 
int main()
{
 
    Mat image01 = imread("1.jpg", 1);
    Mat image02 = imread("2.jpg", 1);
    imshow("p2", image01);
    imshow("p1", image02);
 
    //灰度图转换  
    Mat image1, image2;
    cvtColor(image01, image1, CV_RGB2GRAY);
    cvtColor(image02, image2, CV_RGB2GRAY);
 
 
    //提取特征点    
    GoodFeaturesToTrackDetector Detector(500);  //最大点数,值越大,点越多
    vector<KeyPoint> keyPoint1, keyPoint2;
    Detector.detect(image1, keyPoint1);
    Detector.detect(image2, keyPoint2);
 
    //特征点描述,为下边的特征点匹配做准备    
    SiftDescriptorExtractor  Descriptor;
    Mat imageDesc1, imageDesc2;
    Descriptor.compute(image1, keyPoint1, imageDesc1);
    Descriptor.compute(image2, keyPoint2, imageDesc2);
 
    BruteForceMatcher< L2<float> > matcher;   
    vector<vector<DMatch> > matchePoints;
    vector<DMatch> GoodMatchePoints;
 
    vector<Mat> train_desc(1, imageDesc1);
    matcher.add(train_desc);
    matcher.train();
 
    matcher.knnMatch(imageDesc2, matchePoints, 2);
    cout << "total match points: " << matchePoints.size() << endl;
 
    // Lowe's algorithm,获取优秀匹配点
    for (int i = 0; i < matchePoints.size(); i++)
    {
        if (matchePoints[i][0].distance < 0.6 * matchePoints[i][1].distance)
        {
            GoodMatchePoints.push_back(matchePoints[i][0]);
        }
    }
    Mat first_match;
    drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match);
    imshow("first_match ", first_match);
    imwrite("first_match.jpg", first_match);
    waitKey();
    return 0;
}

 

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

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

相关文章

补: 力扣145 : 二叉树的后序遍历

天才的回归 ---- 二叉树的后序遍历 描述&#xff1a; **给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 ** 示例&#xff1a; 解法&#xff1a;递归就不说了&#xff0c;看下遍历法&#xff0c;与先序和中序略有不同 简单来说注意两个点&#xff1a; 1&…

Centos8 安装 JDK / Python / MySQL / Redis / Nginx

安装 JDK 华为镜像 JDK 下载地址&#xff1a;https://repo.huaweicloud.com:8443/artifactory/java-local/jdk/ 这里安装 JDK8 为例&#xff1a; # 这里直接通过 wget 下载 wget https://repo.huaweicloud.com:8443/artifactory/java-local/jdk/8u202-b08/jdk-8u202-linux-x…

使用轻易云平台高效集成聚水潭与南网订单数据

高效实现聚水潭与南网供应商对接的数据集成方案 普通发货对接南网供应商配送通知接口 在现代数据集成项目中&#xff0c;如何高效、可靠地实现不同系统之间的数据对接是一个关键挑战。本文将聚焦于一个实际案例&#xff1a;将聚水潭平台的数据集成到南方电网商城平台&#xff…

【经验分享】一招解决VMware虚拟机存储空间越来越大的问题

【经验分享】一招解决VMware虚拟机硬盘空间越来越大的问题 前言一、解决办法二、补充说明 前言 在使用虚拟机过程中&#xff0c;会出现用着用着虚拟机硬盘占用空间越来越大的问题。即使删除了文件&#xff0c;依然会占用宿主机的硬盘空间。如果虚拟机一开始分配的硬盘空间过大…

使用Element UI实现一个拖拽图片上传,并可以Ctrl + V获取图片实现文件上传

要在 Element UI 的拖拽上传组件中实现 Ctrl V 图片上传功能&#xff0c;可以通过监听键盘事件来捕获粘贴操作&#xff0c;并将粘贴的图片数据上传到服务器。 版本V1&#xff0c;实现获取粘贴板中的文件 注意&#xff0c;本案例需要再你已经安装了Element UI并在项目中正确配…

Ascend Extension for PyTorch是个what?

1 Ascend Extension for PyTorch Ascend Extension for PyTorch 插件是基于昇腾的深度学习适配框架&#xff0c;使昇腾NPU可以支持PyTorch框架&#xff0c;为PyTorch框架的使用者提供昇腾AI处理器的超强算力。 项目源码地址请参见Ascend/Pytorch。 昇腾为基于昇腾处理器和软…

strtok_s详解,实现使用strtok_s分割字符串,并返回包含分割符的子串

1.strtok_s函数原型 strtok_s 是一个线程安全的字符串分割函数&#xff0c;它是 strtok 的一个变体&#xff0c;用于将字符串分割成一系列的标记&#xff08;tokens&#xff09;。与 strtok 不同&#xff0c;strtok_s 需要一个额外的参数来保存上下文信息&#xff0c;这样它就…

Docker--Docker是什么和对Docker的了解

Docker 的本质 Docker的本质是LXC&#xff08;Linux容器&#xff09;之类的增强版&#xff0c;它本身不是容器&#xff0c;而是容器的易用工具。 Docker通过虚拟化技术&#xff0c;将代码、依赖项和运行环境打包成一个容器&#xff0c;并利用隔离机制来使得容器之间互相独立、…

大数据新视界 -- 大数据大厂之 Impala 性能优化:优化数据加载的实战技巧(下)(16/30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【测试框架篇】单元测试框架pytest(3):用例执行参数详解

一、前言 上一篇内容介绍了用例编写的规则以及执行用例&#xff0c;执行用例时我们发现有些print输出内容&#xff0c;结果没有给我们展示&#xff0c;这是因为什么原因呢&#xff1f;接下来我们会针对这些问题进行阐述。 二、参数大全 我们可以在cmd中通过输入 pytest -h 或…

设计模式-七个基本原则之一-开闭原则 + SpringBoot案例

开闭原则:(SRP) 面向对象七个基本原则之一 对扩展开放&#xff1a;软件实体&#xff08;类、模块、函数等&#xff09;应该能够通过增加新功能来进行扩展。对修改关闭&#xff1a;一旦软件实体被开发完成&#xff0c;就不应该修改它的源代码。 要看实际场景&#xff0c;比如组内…

Android Room框架使用指南

Room框架使用指南 项目效果创建应用,配置Gradle1、在app Module的build.gradle配置kapt插件2、配置依赖:3、配置依赖包版本号创建实体类创建DAO1、DAO简介2、WordDao设计以及相关注解说明3、监听数据变化添加Room数据库1、Room数据库简介2、实现Room数据库实现存储库实现View…

前端开发中常用的包管理器(npm、yarn、pnpm、bower、parcel)

文章目录 1. npm (Node Package Manager)2. Yarn (Yarn Package Manager)3. pnpm4. Bower5. Parcel总结 前端开发中常用的包管理器主要有以下几个&#xff1a; 1. npm (Node Package Manager) 简介&#xff1a; npm 是 Node.js 的默认包管理器&#xff0c;也是最广泛使用的包…

C++builder中的人工智能(23):在现代C++ Windows上轻松录制声音

在这篇文章中&#xff0c;我们将探讨如何在现代C Windows上轻松录制声音。声音以波形和数字形式存在&#xff0c;其音量随时间变化。在C Builder中&#xff0c;使用Windows设备进行录音非常简单。要录制声音&#xff0c;在多设备应用程序中&#xff0c;必须使用FMX.Media.hpp头…

科目一汇总笔记2024

知识点&#xff0c;一天看一遍&#xff1b;提前一周即可&#xff1b;真实考试比“驾校宝典”模拟题简单。 1 知识点汇总 2 错题总结 增驾1轻 2中 3重 能见度 200 100 50 速度60 40 20 两条车道是:100 60 三条车道是:110 90 60 四条车道是:110 90 90 60 高速小车最高120其…

【详细】如何优雅地删除 Docker 容器与镜像

内容预览 ≧∀≦ゞ 镜像与容器的区别删除容器和镜像的具体步骤1. 删除容器步骤 1&#xff1a;查看当前运行的容器步骤 2&#xff1a;停止容器步骤 3&#xff1a;删除容器 2. 删除镜像步骤 1&#xff1a;查看镜像列表步骤 2&#xff1a;删除镜像 3. 删除所有容器和镜像 使用 1Pa…

华为eNSP:AAA认证(pap和chap)telnet/ssh

pap模式 一、拓扑图 二、配置过程 1、这个型号路由器是不带串口的&#xff0c;所以需要添加串口板卡 2、加入串行接口卡槽 右击路由&#xff0c;选择设置&#xff0c;将串口板卡拖动到路由器扩展槽&#xff0c;并开机即可 3、认证方路由器配置 [r8]aaa #进入aaa认证 [r8-a…

HCIP—快速生成树协议(RSTP)实验配置

一、回顾STP和STP的缺点和不足 1.STP的概述&#xff1a; STP&#xff08;生成树协议&#xff09;是一种用于在网络中防止产生环路的链路管理协议。 2.STP的作用&#xff1a; 解决二层环路&#xff0c;防止广播报文产生。但是网络拓扑收敛较慢&#xff0c;影响通信质量。 3…

qt QSyntaxHighlighter详解

1、概述 QSyntaxHighlighter是Qt文本处理框架中的一个强大工具&#xff0c;它专门用于实现文本编辑器中的语法高亮功能。通过自定义高亮规则&#xff0c;QSyntaxHighlighter可以实现对代码编辑器、富文本编辑器中的关键字、注释等内容的高亮显示。这一功能对于提升代码的可读性…

PyQt5 加载UI界面与资源文件

步骤一: 使用 Qt Designer 创建 XXX.ui文件 步骤二: 使用 Qt Designer 创建 资源文件 步骤三: Python文件中创建相关类, 使用 uic.loadUi(mainwidget.ui, self ) 加载UI文件 import sys from PyQt5 import QtCore, QtWidgets, uic from PyQt5.QtCore import Qt f…