【opencv】示例-points_classifier.cpp 使用不同机器学习算法在二维空间中对点集进行分类...

news2025/6/8 17:35:49

94d0054ae0ba0d7ff35aadbf072116ea.png

4db1625a5a1856eaa4e9fdee0c7e235d.png

bdd39b4a84bdd382b384c669847bc528.png

#include "opencv2/core.hpp" // 包含OpenCV核心功能的文件
#include "opencv2/imgproc.hpp" // 包含OpenCV图像处理功能的文件
#include "opencv2/ml.hpp" // 包含OpenCV机器学习模块的文件
#include "opencv2/highgui.hpp" // 包含OpenCV用户界面组件的文件


#include <stdio.h>


using namespace std; // 使用标准命名空间
using namespace cv; // 使用OpenCV命名空间
using namespace cv::ml; // 使用OpenCV机器学习命名空间


const Scalar WHITE_COLOR = Scalar(255,255,255); // 定义一个常量表示白色
const string winName = "points"; // 窗口名
const int testStep = 5; // 测试步长


Mat img, imgDst; // 定义两个图像矩阵,img为原图,imgDst为显示结果用
RNG rng; // 随机数生成器


vector<Point> trainedPoints; // 存储训练用的点
vector<int> trainedPointsMarkers; // 存储训练点所属的分类标记
const int MAX_CLASSES = 2; // 最大分类数
vector<Vec3b> classColors(MAX_CLASSES); // 存储每个分类的颜色
int currentClass = 0; // 当前选择的分类
vector<int> classCounters(MAX_CLASSES); // 存储每个分类的计数器


// 定义一些预处理器标志以确定哪些分类器将会被使用
#define _NBC_ 1 // 正态贝叶斯分类器
#define _KNN_ 1 // K最近邻分类器
#define _SVM_ 1 // 支持向量机
#define _DT_  1 // 决策树
#define _BT_  1 // ADA提升
#define _GBT_ 0 // 梯度提升树
#define _RF_  1 // 随机森林
#define _ANN_ 1 // 人工神经网络
#define _EM_  1 // 期望最大化


// 鼠标事件回调函数
static void on_mouse( int event, int x, int y, int /*flags*/, void* )
{
    if( img.empty() )
        return;


    int updateFlag = 0; // 更新标志


    if( event == EVENT_LBUTTONUP ) // 当鼠标左键松开时
    {
        trainedPoints.push_back( Point(x,y) ); // 添加一个点到训练集中
        trainedPointsMarkers.push_back( currentClass ); // 为这个点标记当前的类别
        classCounters[currentClass]++; // 相应类别的计数器加一
        updateFlag = true; // 设置更新标志为真
    }


    // 绘制
    if( updateFlag )
    {
        img = Scalar::all(0); // 将图像设置为黑色


        // 绘制点
        for( size_t i = 0; i < trainedPoints.size(); i++ )
        {
            Vec3b c = classColors[trainedPointsMarkers[i]]; // 获取点的颜色
            circle( img, trainedPoints[i], 5, Scalar(c), -1 ); // 在图像上用这个颜色绘制一个圆
        }


        imshow( winName, img ); // 显示图像
    }
}


// 准备训练样本的辅助函数
static Mat prepare_train_samples(const vector<Point>& pts)
{
    Mat samples;
    Mat(pts).reshape(1, (int)pts.size()).convertTo(samples, CV_32F); // 将Point集合转换为Mat格式并改变数据类型
    return samples;
}


// 准备训练数据的辅助函数
static Ptr<TrainData> prepare_train_data()
{
    Mat samples = prepare_train_samples(trainedPoints); // 准备样本
    return TrainData::create(samples, ROW_SAMPLE, Mat(trainedPointsMarkers)); // 创建训练数据对象
}


// 使用模型进行预测并绘制结果的辅助函数
static void predict_and_paint(const Ptr<StatModel>& model, Mat& dst)
{
    Mat testSample( 1, 2, CV_32FC1 ); // 创建一个包含两个float类型数值的测试样本
    for( int y = 0; y < img.rows; y += testStep ) // 按步长遍历图像所有的y坐标
    {
        for( int x = 0; x < img.cols; x += testStep ) // 按步长遍历图像所有的x坐标
        {
            testSample.at<float>(0) = (float)x; // 设置样本x值
            testSample.at<float>(1) = (float)y; // 设置样本y值


            int response = (int)model->predict( testSample ); // 使用模型进行预测
            dst.at<Vec3b>(y, x) = classColors[response]; // 根据预测结果上色
        }
    }
}


// 下面的一系列#if预处理器指令是为了在最终的程序中包含或者排除某些分类器的相关代码


#if _NBC_
// 使用正态贝叶斯分类器找出决策边界
static void find_decision_boundary_NBC()
{
    // 学习分类器
    Ptr<NormalBayesClassifier> normalBayesClassifier = StatModel::train<NormalBayesClassifier>(prepare_train_data());
    // 预测并绘制决策边界
    predict_and_paint(normalBayesClassifier, imgDst);
}
#endif


#if _KNN_
// 使用K最近邻分类器找出决策边界,并设置K值
static void find_decision_boundary_KNN( int K )
{
    // 创建KNN对象
    Ptr<KNearest> knn = KNearest::create();
    // 设置K值
    knn->setDefaultK(K);
    // 设置为分类模式
    knn->setIsClassifier(true);
    // 训练模型
    knn->train(prepare_train_data());
    // 预测并绘制决策边界
    predict_and_paint(knn, imgDst);
}
#endif


#if _SVM_
// 使用支持向量机找出决策边界,并设置错误惩罚参数C
static void find_decision_boundary_SVM( double C )
{
    // 创建SVM对象
    Ptr<SVM> svm = SVM::create();
    // 设置SVM类型为C-SVC
    svm->setType(SVM::C_SVC);
    // 设置核函数为多项式核
    svm->setKernel(SVM::POLY); // 也可以选用线性核SVM::LINEAR;
    // 设置多项式核参数degree
    svm->setDegree(0.5);
    // 设置核函数参数gamma
    svm->setGamma(1);
    // 设置核函数参数coef0
    svm->setCoef0(1);
    // 设置SVM参数Nu
    svm->setNu(0.5);
    // 设置SVM参数P
    svm->setP(0);
    // 设置训练算法的终止条件
    svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 1000, 0.01));
    // 设置错误惩罚参数C
    svm->setC(C);
    // 训练模型
    svm->train(prepare_train_data());
    // 预测并绘制决策边界
    predict_and_paint(svm, imgDst);


    // 绘制支持向量
    Mat sv = svm->getSupportVectors();
    for( int i = 0; i < sv.rows; i++ )
    {
        const float* supportVector = sv.ptr<float>(i);
        circle( imgDst, Point(saturate_cast<int>(supportVector[0]),saturate_cast<int>(supportVector[1])), 5, Scalar(255,255,255), -1 );
    }
}
#endif


#if _DT_
// 使用决策树找出决策边界
static void find_decision_boundary_DT()
{
    // 创建决策树对象
    Ptr<DTrees> dtree = DTrees::create();
    // 设置决策树最大深度
    dtree->setMaxDepth(8);
    // 设置节点最小样本数
    dtree->setMinSampleCount(2);
    // 设置是否使用代理分割
    dtree->setUseSurrogates(false);
    // 设置交叉验证折数
    dtree->setCVFolds(0); // 0表示不进行交叉验证
    // 设置是否使用1SE规则
    dtree->setUse1SERule(false);
    // 设置是否修剪被减枝的决策树
    dtree->setTruncatePrunedTree(false);
    // 训练模型
    dtree->train(prepare_train_data());
    // 预测并绘制决策边界
    predict_and_paint(dtree, imgDst);
}
#endif


#if _BT_
// 使用提升树算法找出决策边界
static void find_decision_boundary_BT()
{
    // 创建提升树对象
    Ptr<Boost> boost = Boost::create();
    // 设置提升类型
    boost->setBoostType(Boost::DISCRETE);
    // 设置弱分类器数量
    boost->setWeakCount(100);
    // 设置权重修剪率
    boost->setWeightTrimRate(0.95);
    // 设置最大深度
    boost->setMaxDepth(2);
    // 设置是否使用代理分割
    boost->setUseSurrogates(false);
    // 设置类别先验概率
    boost->setPriors(Mat());
    // 训练模型
    boost->train(prepare_train_data());
    // 预测并绘制决策边界
    predict_and_paint(boost, imgDst);
}
#endif


#if _GBT_
// 使用梯度提升树算法找出决策边界
static void find_decision_boundary_GBT()
{
    // 设置GBT模型参数
    GBTrees::Params params( GBTrees::DEVIANCE_LOSS, // 损失函数类型
                         100, // 弱分类器数量
                         0.1f, // 收缩率
                         1.0f, // 子采样比例
                         2, // 最大深度
                         false // 是否使用代理分割
                         );


    // 创建梯度提升树对象
    Ptr<GBTrees> gbtrees = StatModel::train<GBTrees>(prepare_train_data(), params);
    // 预测并绘制决策边界
    predict_and_paint(gbtrees, imgDst);
}
#endif


#if _RF_
// 使用随机森林算法找出决策边界
static void find_decision_boundary_RF()
{
    // 创建随机森林对象
    Ptr<RTrees> rtrees = RTrees::create();
    // 设置最大深度
    rtrees->setMaxDepth(4);
    // 设置节点最小样本数
    rtrees->setMinSampleCount(2);
    // 设置回归精度
    rtrees->setRegressionAccuracy(0.f);
    // 设置是否使用代理分割
    rtrees->setUseSurrogates(false);
    // 设置类别数量
    rtrees->setMaxCategories(16);
    // 设置类别先验概率
    rtrees->setPriors(Mat());
    // 设置是否计算变量重要性
    rtrees->setCalculateVarImportance(false);
    // 设置活跃变量数量
    rtrees->setActiveVarCount(1);
    // 设置训练算法的终止条件
    rtrees->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 5, 0));
    // 训练模型
    rtrees->train(prepare_train_data());
    // 预测并绘制决策边界
    predict_and_paint(rtrees, imgDst);
}
#endif


#if _ANN_
// 使用人工神经网络找出决策边界
static void find_decision_boundary_ANN( const Mat& layer_sizes )
{
    // 创建类别标签矩阵
    Mat trainClasses = Mat::zeros( (int)trainedPoints.size(), (int)classColors.size(), CV_32FC1 );
    for( int i = 0; i < trainClasses.rows; i++ )
    {
        trainClasses.at<float>(i, trainedPointsMarkers[i]) = 1.f; // 对应类别置为1
    }


    // 准备训练样本
    Mat samples = prepare_train_samples(trainedPoints);
    // 创建训练数据对象
    Ptr<TrainData> tdata = TrainData::create(samples, ROW_SAMPLE, trainClasses);


    // 创建人工神经网络对象
    Ptr<ANN_MLP> ann = ANN_MLP::create();
    // 设置网络层大小
    ann->setLayerSizes(layer_sizes);
    // 设置激活函数
    ann->setActivationFunction(ANN_MLP::SIGMOID_SYM, 1, 1);
    // 设置训练算法的终止条件
    ann->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 300, FLT_EPSILON));
    // 设置训练方法,这里使用反向传播算法
    ann->setTrainMethod(ANN_MLP::BACKPROP, 0.001);
    // 训练模型
    ann->train(tdata);
    // 预测并绘制决策边界
    predict_and_paint(ann, imgDst);
}
#endif


#if _EM_
// 使用期望最大化算法找出决策边界
static void find_decision_boundary_EM()
{
    img.copyTo(imgDst); // 将当前图像复制给目标图像


    Mat samples = prepare_train_samples(trainedPoints); // 准备训练样本


    int i, j, nmodels = (int)classColors.size(); // 分类数量
    vector<Ptr<EM>> em_models(nmodels); // 存储每个类别对应的EM模型
    Mat modelSamples;


    // 遍历所有分类来训练EM模型
    for (i = 0; i < nmodels; i++)
    {
        const int componentCount = 3; // 每个模型的分量数


        modelSamples.release(); // 释放模型样本空间
        // 提取当前类别的所有样本
        for (j = 0; j < samples.rows; j++)
        {
            if (trainedPointsMarkers[j] == i)
                modelSamples.push_back(samples.row(j));
        }


        // 训练模型
        if (!modelSamples.empty()) // 如果当前类别有样本
        {
            Ptr<EM> em = EM::create(); // 创建EM模型
            em->setClustersNumber(componentCount); // 设置聚类数量
            em->setCovarianceMatrixType(EM::COV_MAT_DIAGONAL); // 设置协方差类型为对角线
            em->trainEM(modelSamples, noArray(), noArray(), noArray()); // 训练EM模型
            em_models[i] = em; // 存储训练好的模型
        }
    }


    // 使用贝叶斯分类器对坐标平面的点进行分类
    // y(x) = arg max_i=1_modelsCount likelihoods_i(x)
    Mat testSample(1, 2, CV_32FC1); // 测试样本
    Mat logLikelihoods(1, nmodels, CV_64FC1, Scalar(-DBL_MAX)); // 存储每个样本的概率


    // 遍历图像上的每个点
    for (int y = 0; y < img.rows; y += testStep) 
    {
        for (int x = 0; x < img.cols; x += testStep)
        {
            testSample.at<float>(0) = (float)x;
            testSample.at<float>(1) = (float)y;


            for (i = 0; i < nmodels; i++)
            {
                if (!em_models[i].empty()) // 如果EM模型有效
                    // 计算测试样本的对数似然概率
                    logLikelihoods.at<double>(i) = em_models[i]->predict2(testSample, noArray())[0];
            }
            Point maxLoc;
            // 找到概率最大的类别
            minMaxLoc(logLikelihoods, 0, 0, 0, &maxLoc);
            // 将图像对应位置染成最大概率类别的颜色
            imgDst.at<Vec3b>(y, x) = classColors[maxLoc.x];
        }
    }
}
#endif




int main()
{
    cout << "Use:" << endl
         << "  key '0' .. '1' - switch to class #n" << endl
         << "  left mouse button - to add new point;" << endl
         << "  key 'r' - to run the ML model;" << endl
         << "  key 'i' - to init (clear) the data." << endl << endl;


    cv::namedWindow("points", 1); // 创建一个名为"points"的窗口
    img.create(480, 640, CV_8UC3); // 创建一个大小为480x640的图像
    imgDst.create(480, 640, CV_8UC3); // 创建一个用于显示结果的图像


    imshow("points", img); // 显示原始图像
    setMouseCallback("points", on_mouse); // 设置鼠标回调函数,response to mouse events


    // 初始化两个分类的颜色,第一个分类颜色为绿色,第二个分类颜色为红色
    classColors[0] = Vec3b(0, 255, 0);
    classColors[1] = Vec3b(0, 0, 255);


    // 主循环
    for (;;)
    {
        char key = (char)waitKey(); // 等待按键


        if (key == 27) break; // 如果按键是ESC,退出程序


        if (key == 'i') // 初始化
        {
            img = Scalar::all(0); // 清除图像


            trainedPoints.clear(); // 清除训练点
            trainedPointsMarkers.clear(); // 清除训练点标记
            classCounters.assign(MAX_CLASSES, 0); // 重置类别计数器


            imshow(winName, img); // 显示清除后的图像
        }


        if (key == '0' || key == '1') // 切换类别
        {
            currentClass = key - '0'; // 根据按键设置当前类别
        }


        if (key == 'r') // 运行机器学习模型
        {
            double minVal = 0;
            minMaxLoc(classCounters, &minVal, 0, 0, 0); // 检查每个类别至少有一个点
            if (minVal == 0)
            {
                printf("each class should have at least 1 point\n"); // 否则提示并继续循环
                continue;
            }
            img.copyTo(imgDst); // 将图像复制到目标图像上
#if _NBC_
            find_decision_boundary_NBC(); // 执行NBC算法找决策边界
            imshow("NormalBayesClassifier", imgDst); // 显示NBC的结果
#endif
#if _KNN_
// 使用K-最近邻算法找出决策边界,这里展示了两种不同的K值
            find_decision_boundary_KNN(3); // 使用k值为3来找到决策边界
            imshow("kNN", imgDst); // 显示k值为3的结果


            find_decision_boundary_KNN(15); // 使用k值为15来找到决策边界
            imshow("kNN2", imgDst); // 显示k值为15的结果
#endif


#if _SVM_
// 使用支持向量机算法找出决策边界
            find_decision_boundary_SVM(1); // 使用C值为1来找到决策边界
            imshow("classificationSVM1", imgDst); // 显示C值为1的结果


            find_decision_boundary_SVM(10); // 使用C值为10来找到决策边界
            imshow("classificationSVM2", imgDst); // 显示C值为10的结果
#endif


#if _DT_
// 使用决策树算法找出决策边界
            find_decision_boundary_DT(); // 执行决策树算法找到决策边界
            imshow("DT", imgDst); // 显示决策树的结果
#endif


#if _BT_
// 使用提升树算法找出决策边界
            find_decision_boundary_BT(); // 执行提升树算法找到决策边界
            imshow("BT", imgDst); // 显示提升树的结果
#endif


#if _GBT_
// 使用梯度提升树算法找出决策边界
            find_decision_boundary_GBT(); // 执行梯度提升树算法找到决策边界
            imshow("GBT", imgDst); // 显示梯度提升树的结果
#endif


#if _RF_
// 使用随机森林算法找出决策边界
            find_decision_boundary_RF(); // 执行随机森林算法找到决策边界
            imshow("RF", imgDst); // 显示随机森林的结果
#endif


#if _ANN_
// 使用人工神经网络算法找出决策边界
            Mat layer_sizes1(1, 3, CV_32SC1); // 设置神经网络的层数和每层的节点数
            layer_sizes1.at<int>(0) = 2; // 输入层节点数
            layer_sizes1.at<int>(1) = 5; // 隐藏层节点数
            layer_sizes1.at<int>(2) = (int)classColors.size(); // 输出层节点数,即类别数
            find_decision_boundary_ANN(layer_sizes1); // 执行人工神经网络算法找到决策边界
            imshow("ANN", imgDst); // 显示人工神经网络的结果
#endif
#if _EM_
            // 执行EM算法找决策边界
            find_decision_boundary_EM();
            // 显示EM算法的结果
            imshow("EM", imgDst);
#endif
        }
    }


    return 0; // 程序结束
}

这段代码实现了一个简单的机器视觉和机器学习应用程序。其主要功能是在图形用户界面中用鼠标标记出不同的类别点,然后通过多种机器学习模型(如正态贝叶斯分类器、K最近邻分类器、支持向量机等),学习这些点的分布规律,并预测整个图像坐标面中每个点的类别,并进行着色以区分不同类别。

代码的核心部分包括鼠标回调函数(on_mouse),它处理用户的鼠标事件,根据用户点击添加新的类别点;数据准备辅助函数,用于将标记的点转换为训练模型所需的格式;模型训练和预测函数,包括每个分类器独立的训练和预测逻辑;以及主函数,它负责初始化应用程序界面、处理用户输入并触发机器学习模型的训练和预测。

这段代码展示了多个不同的机器学习算法在机器视觉和机器人技术应用程序中确定决策边界的方法。每个#if块介绍了如何使用一个特定的算法来训练一个模型用于分类,并预测图像上每个像素点的类别,并用不同的颜色来表示不同类别的决策区域。具体来说,包括:

  1. 使用正态贝叶斯分类器(NBC)确定决策边界。

  2. 使用K最邻近算法(KNN)确定决策边界,K值可以调整。

  3. 使用支持向量机(SVM)确定决策边界,其中C为错误项的惩罚系数。

  4. 使用决策树(DT)来确定决策边界。

  5. 使用提升树(Boosted Trees, BT)来确定决策边界。

  6. 使用梯度提升树(Gradient Boosted Trees, GBT)来确定决策边界。

  7. 使用随机森林(Random Forest, RF)来确定决策边界。

  8. 使用人工神经网络(Artificial Neural Network, ANN)来确定决策边界,其中层的大小可以调整,通常由输入层、一个或多个隐藏层和输出层构成。

9. 期望最大化(Expectation Maximization, EM)算法在寻找决策边界的实现方式。EM是一种迭代优化算法,用于参数估计,特别适合处理有隐变量的概率模型。它通常用于聚类或者潜在变量模型的估计。在find_decision_boundary_EM函数中,这个算法先是为每个类别训练了一个EM模型。接着通过遍历图像上的每个像素,计算该像素属于每个模型的概率,然后选择概率最大的模型对应的类别,为该像素分配颜色。

这些算法通常用于机器视觉中的模式识别、分类任务或者机器人路径规划中的决策制定等应用场景。

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

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

相关文章

docker部署Prometheus+AlertManager实现邮件告警

文章目录 一、环境准备1、硬件准备&#xff08;虚拟机&#xff09;2、关闭防火墙&#xff0c;selinux3、所有主机安装docker 二、配置Prometheus1、docker启动Prometheus 三、添加监控节点1、docker启动node-exporter 四、Prometheus配置node-exporter1、修改prometheus.yml配置…

使用Python实现自动化网页答题功能-模拟考试篇

介绍 在驾驶员考试网站上进行模拟考试python自动答题 自动化原理 该脚本使用了自动化模块 DrissionPage 中的 ChromiumPage 类来实现网页的自动化操作。通过定位网页元素和模拟点击操作&#xff0c;完成了选择答案和提交答卷的过程。 用途与注意事项 用途&#xff1a;该脚本…

kafka学习笔记03

SpringBoot2.X项目搭建整合Kafka客户端依赖配置 用自己对应的jdk版本。 先加上我们的web依赖。 添加kafka依赖: SpringBoot2.x整合Kafka客户端adminApi单元测试 设置端口号。 新建一个kafka测试类&#xff1a; 创建一个初始化的Kafka服务。 设置kafka的名称。 测试创建kafka。…

在vue中配置样式 max-width:100px时,发现和width:100px一样没有对应的递增到最大宽度的效果?怎么回事?怎么解决?

原因&#xff1a; 可能时vue的样式大部分和display相关&#xff0c;有很多的联系&#xff0c;导致不生效 解决&#xff1a; 对设置max-width样式的元素设置display:inline-block;属性&#xff0c;即可生效&#xff0c;实现随着子元素的扩展而扩展并增加固定到最大的宽度

使用Postman发送跨域请求实验

使用Postman发送跨域请求 1 跨域是什么&#xff1f;2 何为同源呢?3 跨域请求是如何被检测到的&#xff1f;4 Postman跨域请求测试4.1 后端准备4.2 测试用例4.2.1 后端未配置跨域请求(1) 前端不跨域&#xff08;2&#xff09;前端跨域 4.2.2 后端配置跨域信息&#xff08;1&…

Springboot整合mybatis_plus + redis(使用原生的方式)

首次&#xff0c;创建一个springboot项目&#xff0c;勾选相应的依赖Lombok、Web 添加依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>…

基于Python的深度学习的中文情感分析系统(V2.0),附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

13 Php学习:面向对象

PHP 面向对象 面向对象&#xff08;Object-Oriented&#xff0c;简称 OO&#xff09;是一种编程思想和方法&#xff0c;它将程序中的数据和操作数据的方法封装在一起&#xff0c;形成"对象"&#xff0c;并通过对象之间的交互和消息传递来完成程序的功能。面向对象编…

理想大模型实习面试题6道|含解析

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总…

在 Google Cloud 上轻松部署开放大语言模型

今天&#xff0c;“在 Google Cloud 上部署”功能正式上线&#xff01; 这是 Hugging Face Hub 上的一个新功能&#xff0c;让开发者可以轻松地将数千个基础模型使用 Vertex AI 或 Google Kubernetes Engine (GKE) 部署到 Google Cloud。 Model Garden (模型库) 是 Google Clou…

Qt | 视频播放器(multimedia、multimediawidgets)

QT +=multimedia 通俗解释: 此代码行告诉编译器在构建应用程序时包含多媒体库。这意味着您的应用程序将能够播放和显示音频和视频文件。 使用分步说明构建模型: 创建一个新的 Qt 项目。 在 .pro 文件中添加以下行: QT += multimedia 导入必要的多媒体头文件: #include &l…

Android 加密之 打包为arr 项目依赖或者为jar

Android 加密之 打包为arr 项目依赖或者为jar 1. 修改build.gradle plugins {//id com.android.application// 1. 修改为libraryid com.android.library }android {namespace com.dzq.iccid2compileSdk 33defaultConfig {//applicationId "com.dzq.iccid2"// 2. 注…

嵌入式驱动学习第七周——I2C子系统

前言 I2C子系统详解&#xff0c;本篇博客从内核源码的角度来看I2C子系统。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博主并订阅本专栏&#xff0c;一起讨论一起学习。现在关注就是老粉啦…

爱奇艺APP Android低端机性能优化

01 背景介绍 在智能手机市场上&#xff0c;高端机型经常备受瞩目&#xff0c;但低端机型亦占据了不可忽视的份额。众多厂商为满足低端市场的需求&#xff0c;不断推出低配系列手机。另外过去几年的中高端机型&#xff0c;随着系统硬件的快速迭代&#xff0c;现已经被归类为低端…

学习Rust的第4天:常见编程概念

欢迎来到学习Rust的第四天&#xff0c;基于Steve Klabnik的《The Rust Programming Language》一书。昨天我们做了一个 猜谜游戏 &#xff0c;今天我们将探讨常见的编程概念&#xff0c;例如&#xff1a; Variables 变量Constants 常数Shadowing 阴影Data Types 数据类型Functi…

错题记录(2)

来源&#xff1a; FPGA开发/数字IC笔试系列(10) 笔试刷题 笔试 | 海思2022数字IC模拟卷&#xff08;真题模拟&#xff0c;带解析&#xff09; 运算符优先级

【C++算法竞赛 · 图论】图的存储

前言 图的存储 邻接矩阵 方法 复杂度 应用 例题 题解 邻接表 方法 复杂度 应用 前言 上一篇文章中&#xff08;【C算法竞赛 图论】图论基础&#xff09;&#xff0c;介绍了图论相关的概念和一种图的存储的方法&#xff0c;这篇文章将会介绍剩下的两种方法&#xff…

【黑马头条】-day09用户行为-精度丢失-点赞收藏关注

文章目录 1 long类型精度丢失问题1.1 解决1.2 导入jackson序列化工具1.3 自定义注解1.4 原理1.5 测试 2 用户行为要求3 创建微服务behavior3.1 微服务创建3.2 添加启动类3.3 创建bootstrap.yml3.4 在nacos中配置redis3.5 引入redis依赖3.6 更新minio 4 跳过 1 long类型精度丢失…

视频批量高效剪辑,支持将视频文件转换为音频文件,轻松掌握视频格式

在数字化时代&#xff0c;视频内容日益丰富&#xff0c;管理和编辑这些视频变得愈发重要。然而&#xff0c;传统的视频剪辑软件往往操作复杂&#xff0c;难以满足高效批量处理的需求。现在&#xff0c;一款全新的视频批量剪辑神器应运而生&#xff0c;它支持将视频文件一键转换…

【vue】slot 匿名插槽 / 具名插槽

slot父组件向子组件传递数据 匿名插槽–直接写 具名插槽–指定名称 父组件中 子组件中&#xff1a; 代码 App.vue <template><h2>App.vue</h2><!-- 匿名插槽 --><Header><a href"1234567890.com">1234567890</a>&…