【OpenVINO】基于 OpenVINO C++ API 部署 RT-DETR 模型

news2024/11/26 17:50:13

基于 OpenVINO C++ API 部署 RT-DETR 模型

  • 1. RT-DETR
  • 2. OpenVINO
  • 3. 环境配置
  • 4. 模型下载与转换
    • 4.1 模型导出
    • 4.2 模型信息对比
  • 5. C++代码实现
    • 5.1 模型推理类实现
  • 5.2 模型数据处理类RTDETRProcess
  • 6. 预测结果展示
  • 7. 总结

  RT-DETR是在DETR模型基础上进行改进的,一种基于 DETR 架构的实时端到端检测器,它通过使用一系列新的技术和算法,实现了更高效的训练和推理,在前文我们发表了《基于 OpenVINO™ Python API 部署 RT-DETR 模型 | 开发者实战》,在该文章中,我们基于OpenVINO™ Python API 向大家展示了包含后处理的RT-DETR模型的部署流程,但在实际工业应用中,我们为了与当前软件平台集成更多会采用C++平台,因此在本文中,我们将基于OpenVINO™ C++ API 向大家展示了不包含后处理的RT-DETR模型的部署流程,并向大家展示如何导出不包含后处理的RT-DETR模型。
  该项目所使用的全部代码已经在GitHub上开源,并且收藏在OpenVINO-CSharp-API项目里,项目所在目录链接为:

https://github.com/guojin-yan/OpenVINO-CSharp-API/tree/csharp3.0/tutorial_examples

  也可以直接访问该项目,项目链接为:

https://github.com/guojin-yan/RT-DETR-OpenVINO.git

项目首发网址为:基于 OpenVINO™ C++ API 部署 RT-DETR 模型 | 开发者实战

1. RT-DETR

  飞桨在去年 3 月份推出了高精度通用目标检测模型 PP-YOLOE ,同年在 PP-YOLOE 的基础上提出了 PP-YOLOE+。而继 PP-YOLOE 提出后,MT-YOLOv6、YOLOv7、DAMO-YOLO、RTMDet 等模型先后被提出,一直迭代到今年开年的 YOLOv8。
在这里插入图片描述

  YOLO 检测器有个较大的待改进点是需要 NMS 后处理,其通常难以优化且不够鲁棒,因此检测器的速度存在延迟。DETR是一种不需要 NMS 后处理、基于 Transformer 的端到端目标检测器。百度飞桨正式推出了——RT-DETR (Real-Time DEtection TRansformer) ,一种基于 DETR 架构的实时端到端检测器,其在速度和精度上取得了 SOTA 性能。

在这里插入图片描述

  RT-DETR是在DETR模型基础上进行改进的,它通过使用一系列新的技术和算法,实现了更高效的训练和推理。具体来说,RT-DETR具有以下优势:

  • 1、实时性能更佳:RT-DETR采用了一种新的注意力机制,能够更好地捕获物体之间的关系,并减少计算量。此外,RT-DETR还引入了一种基于时间的注意力机制,能够更好地处理视频数据。
  • 2、精度更高:RT-DETR在保证实时性能的同时,还能够保持较高的检测精度。这主要得益于RT-DETR引入的一种新的多任务学习机制,能够更好地利用训练数据。
  • 3、更易于训练和调参:RT-DETR采用了一种新的损失函数,能够更好地进行训练和调参。此外,RT-DETR还引入了一种新的数据增强技术,能够更好地利用训练数据。
    在这里插入图片描述

2. OpenVINO

  英特尔发行版 OpenVINO™工具套件基于oneAPI 而开发,可以加快高性能计算机视觉和深度学习视觉应用开发速度工具套件,适用于从边缘到云的各种英特尔平台上,帮助用户更快地将更准确的真实世界结果部署到生产系统中。通过简化的开发工作流程, OpenVINO™可赋能开发者在现实世界中部署高性能应用程序和算法。
在这里插入图片描述

  OpenVINO™ 2023.1于2023年9月18日发布,该工具包带来了挖掘生成人工智能全部潜力的新功能。生成人工智能的覆盖范围得到了扩展,通过PyTorch*等框架增强了体验,您可以在其中自动导入和转换模型。大型语言模型(LLM)在运行时性能和内存优化方面得到了提升。聊天机器人、代码生成等的模型已启用。OpenVINO更便携,性能更高,可以在任何需要的地方运行:在边缘、云中或本地。

3. 环境配置

  在上一篇文章中我们以已经向大家提供了RT-DETR模型导出苏需要的环境,此处不再多做展示,为了大家更好的复现该项目代码,此处向大家提供本次开发所使用的C++环境:

openvino: 2023.1.0
opencv: 4.5.5

  大家在复现代码时可以使用相同的环境或者与作者所使用环境发布较为接近的环境进行开发,防止使用时出现不必要的错误;此外该项目提供了两种编译方式,大家可以使用Visual Studio进行编译以及CMake进行编译。

4. 模型下载与转换

  在上一篇文章中我们已经向大家展示了RT-DETR预训练模型的导出方式,该模型是默认包含后处理的;因此在本文中,我们将向大家展示不包含后处理的RT-DETR模型导出方式以及两种模型的差异。

4.1 模型导出

  PaddleDetection官方库向我们提供了十分友好API接口,因此导出不包含后处理的RT-DETR模型也是十分容易的。首先修改配置文件,主要是修改RT-DETR模型的配置文件,配置文件路径为:.\PaddleDetection\configs\rtdetr\_base_\rtdetr_r50vd.yml,在配置文件DETR项目下增加exclude_post_process: True语句,如下图所示:
在这里插入图片描述
  然后重新运行模型导出指令,便可以获取不包含后处理的模型:

python tools/export_model.py -c configs/rtdetr/rtdetr_r50vd_6x_coco.yml -o weights=https://bj.bcebos.com/v1/paddledet/models/rtdetr_r50vd_6x_coco.pdparams trt=True --output_dir=output_inference

  在模型导出后,我们可以转换成ONNX格式以及IR格式,可参考上一篇文章中的模型转换内容。

4.2 模型信息对比

  通过下表我们可以看出,裁剪后的模型,只包含一个输入节点,其输出节点也发生了变化,原本模型输出为处理后的预测输出,经过裁剪后,模型输出节点输出内容发生了较大变化。其中:

  • stack_7.tmp_0.slice_0:该节点表示300种预测结果的预测框信息;
  • stack_8.tmp_0.slice_0:该节点表示300种预测结果的80种分类信息置信度,后续再处理时,需要根据预测结果获取最终的预测分类信息。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

5. C++代码实现

  为了更系统地实现RT-DETR模型的推理流程,我们采用C++特性,封装了RTDETRPredictor模型推理类以及RTDETRProcess模型数据处理类,下面我们将对这两个类中的关键代码进行讲解。

5.1 模型推理类实现

  C++代码中我们定义的RTDETRPredictor模型推理类如下所示:

class RTDETRPredictor
{
public:
    RTDETRPredictor(std::string model_path, std::string label_path, 
        std::string device_name = "CPU", bool postprcoess = true);
    cv::Mat predict(cv::Mat image);
private:
    void pritf_model_info(std::shared_ptr<ov::Model> model);
    void fill_tensor_data_image(ov::Tensor& input_tensor, const cv::Mat& input_image);
    void fill_tensor_data_float(ov::Tensor& input_tensor, float* input_data, int data_size);
private:
    RTDETRProcess rtdetr_process;
    bool post_flag;
    ov::Core core;
    std::shared_ptr<ov::Model> model;
    ov::CompiledModel compiled_model;
    ov::InferRequest infer_request;
};
    1. 模型推理类初始化
      首先我们需要初始化模型推理类,初始化相关信息:
RTDETRPredictor::RTDETRPredictor(std::string model_path, std::string label_path, 
std::string device_name, bool post_flag)
	:post_flag(post_flag){
    INFO("Model path: " + model_path);
    INFO("Device name: " + device_name);
    model = core.read_model(model_path);
    pritf_model_info(model);
    compiled_model = core.compile_model(model, device_name);
    infer_request = compiled_model.create_infer_request();
    rtdetr_process = RTDETRProcess(cv::Size(640, 640), label_path, 0.5);
}

  在该方法中主要包含以下几个输入:

  • model_path:推理模型地址;
  • label_path:模型预测类别文件;
  • device_name:推理设备名称;
  • post_flag:模型是否包含后处理,当post_flag = true时,包含后处理,当post_flag = false时,不包含后处理。
    1. 图片预测API
      这一步中主要是对输入图片进行预测,并将模型预测结果会知道输入图片上,下面是这阶段的主要代码:
cv::Mat RTDETRPredictor::predict(cv::Mat image){
    cv::Mat blob_image = rtdetr_process.preprocess(image);
    if (post_flag) {
        ov::Tensor image_tensor = infer_request.get_tensor("image");
        ov::Tensor shape_tensor = infer_request.get_tensor("im_shape");
        ov::Tensor scale_tensor = infer_request.get_tensor("scale_factor");
        image_tensor.set_shape({ 1,3,640,640 });
        shape_tensor.set_shape({ 1,2 });
        scale_tensor.set_shape({ 1,2 });
        fill_tensor_data_image(image_tensor, blob_image);
        fill_tensor_data_float(shape_tensor, rtdetr_process.get_input_shape().data(), 2);
        fill_tensor_data_float(scale_tensor, rtdetr_process.get_scale_factor().data(), 2);
    } else {
        ov::Tensor image_tensor = infer_request.get_input_tensor();
        fill_tensor_data_image(image_tensor, blob_image);
    }
    infer_request.infer();
    ResultData results;
    if (post_flag) {
        ov::Tensor output_tensor = infer_request.get_tensor("reshape2_95.tmp_0");
        float result[6 * 300] = {0};
        for (int i = 0; i < 6 * 300; ++i) {
            result[i] = output_tensor.data<float>()[i];
        }
        results = rtdetr_process.postprocess(result, nullptr, true);
    } else {
        ov::Tensor score_tensor = infer_request.get_tensor(model->outputs()[1].get_any_name());
        ov::Tensor bbox_tensor = infer_request.get_tensor(model->outputs()[0].get_any_name());
        float score[300 * 80] = {0};
        float bbox[300 * 4] = {0};
        for (int i = 0; i < 300; ++i) {
            for (int j = 0; j < 80; ++j) {
                score[80 * i + j] = score_tensor.data<float>()[80 * i + j];
            }
            for (int j = 0; j < 4; ++j) {
                bbox[4 * i + j] = bbox_tensor.data<float>()[4 * i + j];
            }
        }
        results = rtdetr_process.postprocess(score, bbox, false);
    }
    return rtdetr_process.draw_box(image, results);
}

  上述代码的主要逻辑如下:首先是处理输入图片,调用定义的数据处理类,将输入图片处理成指定的数据类型;然后根据模型的输入节点情况配置模型输入数据,如果使用的是动态模型输入,需要设置输入形状;接下来就是进行模型推理;最后就是对推理结果进行处理,并将结果绘制到输入图片上。

5.2 模型数据处理类RTDETRProcess

    1. 定义RTDETRProcess
class RTDETRProcess
{
public:
    RTDETRProcess() {}
    RTDETRProcess(cv::Size target_size, std::string label_path = NULL, float threshold = 0.5,
        cv::InterpolationFlags interpf = cv::INTER_LINEAR);
    cv::Mat preprocess(cv::Mat image);
    ResultData postprocess(float* score, float* bboxs, bool post_flag);
    std::vector<float> get_im_shape() { return im_shape; }
    std::vector<float> get_input_shape() { return { (float)target_size.width ,(float)target_size.height }; }
    std::vector<float> get_scale_factor() { return scale_factor; }
    cv::Mat draw_box(cv::Mat image, ResultData results);
private:
    void read_labels(std::string label_path);
    template<class T>
    float sigmoid(T data) { return 1.0f / (1 + std::exp(-data));}
    template<class T>
    int argmax(T* data, int length) {
        std::vector<T> arr(data, data + length);
        return (int)(std::max_element(arr.begin(), arr.end()) - arr.begin());
    }
private:
    cv::Size target_size;               // The model input size.
    std::vector<std::string> labels;    // The model classification label.
    float threshold;                    // The threshold parameter.
    cv::InterpolationFlags interpf;     // The image scaling method.
    std::vector<float> im_shape;
    std::vector<float> scale_factor;
};
    1. 输入数据处理方法
cv::Mat RTDETRProcess::preprocess(cv::Mat image){
    im_shape = { (float)image.rows, (float)image.cols };
    scale_factor = { 640.0f / (float)image.rows, 640.0f / (float)image.cols};
    cv::Mat blob_image;
    cv::cvtColor(image, blob_image, cv::COLOR_BGR2RGB); 
    cv::resize(blob_image, blob_image, target_size, 0, 0, cv::INTER_LINEAR);
    std::vector<cv::Mat> rgb_channels(3);
    cv::split(blob_image, rgb_channels);
    for (auto i = 0; i < rgb_channels.size(); i++) {
        rgb_channels[i].convertTo(rgb_channels[i], CV_32FC1, 1.0 / 255.0);
    }
    cv::merge(rgb_channels, blob_image);
    return blob_image;
}
    1. 预测结果数据处理方法
ResultData RTDETRProcess::postprocess(float* score, float* bbox, bool post_flag)
{
    ResultData result;
    if (post_flag) {
        for (int i = 0; i < 300; ++i) {
            if (score[6 * i + 1] > threshold) {
                result.clsids.push_back((int)score[6 * i ]);
                result.labels.push_back(labels[(int)score[6 * i]]);
                result.bboxs.push_back(cv::Rect(score[6 * i + 2], score[6 * i + 3],
                    score[6 * i + 4] - score[6 * i + 2],
                    score[6 * i + 5] - score[6 * i + 3]));
                result.scores.push_back(score[6 * i + 1]);
            }
        }
    } else {
        for (int i = 0; i < 300; ++i) {
            float s[80];
            for (int j = 0; j < 80; ++j) {
                s[j] = score[80 * i + j];
            }
            int clsid = argmax<float>(s, 80);
            float max_score = sigmoid<float>(s[clsid]);
            if (max_score > threshold) {
                result.clsids.push_back(clsid);
                result.labels.push_back(labels[clsid]);
                float cx = bbox[4 * i] * 640.0 / scale_factor[1];
                float cy = bbox[4 * i + 1] * 640.0 / scale_factor[0];
                float w = bbox[4 * i + 2] * 640.0 / scale_factor[1];
                float h = bbox[4 * i + 3] * 640.0 / scale_factor[0];
                result.bboxs.push_back(cv::Rect((int)(cx - w / 2), (int)(cy - h / 2), w, h));
                result.scores.push_back(max_score);
            }
        }
    }
    return result;
}

  此处对输出结果做一个解释,由于我们提供了两种模型的输出,此处提供了两种模型的输出数据处理方式,主要区别在于是否对预测框进行还原以及对预测类别进行提取,具体区别大家可以查看上述代码。

6. 预测结果展示

  最后通过上述代码,我们最终可以直接实现RT-DETR模型的推理部署,RT-DETR与训练模型采用的是COCO数据集,最终我们可以获取预测后的图像结果,如图所示:
在这里插入图片描述
  上图中展示了RT-DETR模型预测结果,同时,我们对模型图里过程中的关键信息以及推理结果进行了打印:

[INFO]  This is an RT-DETR model deployment case using C++!
[INFO]  Model path: E:\\Model\\RT-DETR\\RTDETR_cropping\\rtdetr_r50vd_6x_coco.onnx
[INFO]  Device name: CPU
[INFO]  Inference Model
[INFO]    Model name: Model from PaddlePaddle.
[INFO]    Input:
[INFO]       name: image
[INFO]       type: float
[INFO]       shape: [?,3,640,640]
[INFO]    Output:
[INFO]       name: stack_7.tmp_0_slice_0
[INFO]       type: float
[INFO]       shape: [?,300,4]
[INFO]       name: stack_8.tmp_0_slice_0
[INFO]       type: float
[INFO]       shape: [?,300,80]
[INFO]  Infer result:
[INFO]    class_id : 0, label : person, confidence : 0.928, left_top : [215, 327], right_bottom: [259, 468]
[INFO]    class_id : 0, label : person, confidence : 0.923, left_top : [260, 343], right_bottom: [309, 460]
[INFO]    class_id : 0, label : person, confidence : 0.893, left_top : [402, 346], right_bottom: [451, 478]
[INFO]    class_id : 0, label : person, confidence : 0.796, left_top : [456, 369], right_bottom: [507, 479]
[INFO]    class_id : 0, label : person, confidence : 0.830, left_top : [519, 360], right_bottom: [583, 479]
[INFO]    class_id : 33, label : kite, confidence : 0.836, left_top : [323, 159], right_bottom: [465, 213]
[INFO]    class_id : 33, label : kite, confidence : 0.805, left_top : [329, 64], right_bottom: [388, 85]
[INFO]    class_id : 33, label : kite, confidence : 0.822, left_top : [282, 217], right_bottom: [419, 267]
[INFO]    class_id : 0, label : person, confidence : 0.834, left_top : [294, 384], right_bottom: [354, 443]
[INFO]    class_id : 33, label : kite, confidence : 0.793, left_top : [504, 195], right_bottom: [522, 214]
[INFO]    class_id : 33, label : kite, confidence : 0.524, left_top : [233, 22], right_bottom: [242, 29]
[INFO]    class_id : 33, label : kite, confidence : 0.763, left_top : [116, 178], right_bottom: [136, 190]
[INFO]    class_id : 0, label : person, confidence : 0.601, left_top : [497, 380], right_bottom: [529, 479]
[INFO]    class_id : 33, label : kite, confidence : 0.764, left_top : [460, 251], right_bottom: [478, 268]
[INFO]    class_id : 33, label : kite, confidence : 0.605, left_top : [176, 236], right_bottom: [256, 257]
[INFO]    class_id : 0, label : person, confidence : 0.732, left_top : [154, 380], right_bottom: [210, 420]
[INFO]    class_id : 33, label : kite, confidence : 0.574, left_top : [221, 264], right_bottom: [342, 312]
[INFO]    class_id : 33, label : kite, confidence : 0.588, left_top : [97, 316], right_bottom: [155, 359]
[INFO]    class_id : 33, label : kite, confidence : 0.523, left_top : [171, 317], right_bottom: [227, 357]
[INFO]    class_id : 33, label : kite, confidence : 0.657, left_top : [363, 120], right_bottom: [375, 129]
[INFO]    class_id : 0, label : person, confidence : 0.698, left_top : [26, 341], right_bottom: [57, 425]
[INFO]    class_id : 33, label : kite, confidence : 0.798, left_top : [242, 124], right_bottom: [263, 135]
[INFO]    class_id : 33, label : kite, confidence : 0.528, left_top : [218, 178], right_bottom: [451, 241]
[INFO]    class_id : 33, label : kite, confidence : 0.685, left_top : [430, 29], right_bottom: [449, 43]
[INFO]    class_id : 33, label : kite, confidence : 0.640, left_top : [363, 120], right_bottom: [375, 129]
[INFO]    class_id : 33, label : kite, confidence : 0.559, left_top : [161, 193], right_bottom: [171, 199]

7. 总结

  在本项目中,我们介绍了OpenVINO C++ API 部署自带后处理的RT-DETR模型的案例,并结合该模型的处理方式封装完整的代码案例,实现了在 Intel 平台使用OpenVINO 加速深度学习模型,有助于大家以后落地RT-DETR模型在工业上的应用。
  在下一篇文章《基于 OpenVINO Python C# 部署 RT-DETR 模型》中,我们将基于C# API接口,实现RT-DETR 模型的部署,并且基于开发的代码,对比不同平台的推理速度。如果大家有兴趣,可以先关注本项目代码仓库,获取项目实现源码。

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

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

相关文章

JAR 文件规范详解

介绍 JAR文件是基于ZIP文件格式的一种文件格式&#xff0c;用来将许多文件整合成一个文件。一个JAR文件本质上是包含可选目录META-INF的zip文件&#xff0c;可以通过命令行jar工具或者在Java平台上使用java.util.jar中的API来创建。JAR文件的命名没有严格的要求&#xff0c;可…

Flink SQL Regular Join 、Interval Join、Temporal Join、Lookup Join 详解

Flink ⽀持⾮常多的数据 Join ⽅式&#xff0c;主要包括以下三种&#xff1a; 动态表&#xff08;流&#xff09;与动态表&#xff08;流&#xff09;的 Join动态表&#xff08;流&#xff09;与外部维表&#xff08;⽐如 Redis&#xff09;的 Join动态表字段的列转⾏&#xf…

Redis5 分布式系统之主从模式

目录 分布式系统 引子 分布式系统类型 主从模式 一个主节点和多个从节点 创建多个节点方法 配置主从结构 主从模式知识 主从复制 拓扑结构 1.一主一从 2.一主多从 3.树形主从 主从实现原理 psync数据同步 全量复制和部分复制 psync流程 1.全量数据同步 2.部…

Android Studio代码无法自动补全

Android Studio代码自动无法补全问题解决 在写layout布局文件时&#xff0c;代码不提示&#xff0c;不自动补全&#xff0c;可以采用如下方法&#xff1a; 点击File—>Project Structure&#xff0c;之后如图所示&#xff0c;找到左侧Modules&#xff0c;修改SDK版本号&…

2023年广东省安全员C证第四批(专职安全生产管理人员)证考试题库及广东省安全员C证第四批(专职安全生产管理人员)试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年广东省安全员C证第四批&#xff08;专职安全生产管理人员&#xff09;证考试题库及广东省安全员C证第四批&#xff08;专职安全生产管理人员&#xff09;试题解析是安全生产模拟考试一点通结合&#xff08;安监…

船舶IMO识别码是什么?

船舶编码和编码体系比较多&#xff0c;主要有船舶登记号、船检登记号、船舶呼号、IMO号、船舶MMSI、船体号等。 船舶的IMO Number&#xff08;国际海事组织识别码&#xff0c;下称IMO识别码&#xff09;是独一无二的&#xff0c;相当于船舶的身份证号码&#xff0c;并且此号码…

Uniapp实现多语言切换

前言 之前做项目过程中&#xff0c;也做过一次多语言切换&#xff0c;大致思想都是一样的&#xff0c;想了解的可以看下之前的文章C#WinForm实现多语言切换 使用i18n插件 安装插件 npm install vue-i18n --saveMain.js配置 // 引入 多语言包 import VueI18n from vue-i18n…

【MySQL--->索引】

文章目录 [TOC](文章目录) 一、索引概念二、B树与B树1.B树的特点:2.B树的特点:3.为什么使用B树而不使用B树 三、聚簇索引和非聚簇索引四、索引操作1.创建索引2. 删除索引3.全文索引 一、索引概念 mysql的查询的过程是从文件中提取到内存中查询,MySQL启动时会在内存中维护一个b…

fastjson 1.2.24 rce漏洞复现

一、漏洞特征 fastjson是阿里巴巴的开源JSON解析库&#xff0c;它可以解析JSON格式的字符串&#xff0c;支持将Java Bean序列化为JSON字符串&#xff0c;也可以从JSON字符串反序列化到JavaBean。即fastjson的主要功能就是将Java Bean序列化成JSON字符串&#xff0c;这样得到字符…

VR全景如何助力乡村振兴,乡村发展在哪些方面用到VR全景技术

引言&#xff1a; 乡村振兴是当今中国发展的重要战略&#xff0c;也是推动农村经济社会全面发展的关键举措。在这一过程中&#xff0c;虚拟现实&#xff08;VR&#xff09;全景技术正逐渐崭露头角&#xff0c;为乡村振兴提供了机遇。 一&#xff0e;VR全景技术的概念和应用 1…

vue项目中订单完成提交按钮动画

1. 动画1 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>Order</title><!-- <link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/re…

CreateProcess error=206, 文件名或扩展名太长

IDEA编译启动springboot项目时&#xff0c;提示这个异常&#xff0c;可以使用以下方式解决&#xff1a; 打开run-->edit configurations-->选择你启动报错的AppLication&#xff0c;如下图配置即可&#xff08;仅限于楼主的解决方式&#xff0c;不保证百分百覆盖&#x…

docker部署mysql nginx redis

一.创建网络 # 创建网络 docker network create liming # 查看网络 docker network ls二.部署mysql 删除并重新创建mysql容器&#xff0c;并完成本地目录挂载&#xff1a; 挂载/software/mysql/data到容器内的/var/lib/mysql目录挂载/software/mysql/init到容器内的/docker-…

微型导轨在医疗设备中起什么作用?

微型导轨因其高精度、小型化和轻量化的特点&#xff0c;被广泛应用于各种需要高精度和小型化的机器中&#xff0c;如数控机床、工业机器人、光学仪器、医疗设备和自动化设备等&#xff0c;尤其是医疗领域&#xff0c;其应用最为广泛。 1、手术机器人&#xff1a;手术机器人是医…

HackTheBox-Starting Point--Tier 1---Bike

文章目录 一 题目二 实验过程三 服务器端模版引擎注入&#xff08;SSTI&#xff09;1.什么是模版引擎2.SSTI3.挖掘SSTI4.执行payload 一 题目 Tags Web、Injection、Custom Applications、NodeJS、Reconnaissance、Remote Code Execution、Server Side Template Injection (S…

Maven中的继承与聚合

一&#xff0c;继承 前面我们将项目拆分成各个小模块&#xff0c;但是每个小模块中有很多相同的依赖于是我们创建一个父工程将模块中相同的依赖定义在父工程中&#xff0c;然后子工程继承父工程Maven作用&#xff1a;简化依赖配置&#xff0c;统一依赖管理,可以实现多重继承像J…

uniapp使用vue3和ts开发小程序自定义tab栏,实现自定义凸出tabbar效果

要实现自定义的tabbar效果&#xff0c;可以使用自定义tab覆盖主tab来实现&#xff0c;当程序启动或者从后台显示在前台时隐藏自带的tab来实现。自定义一个tab组件&#xff0c;然后在里面实现自定义的逻辑。 组件中所使用的组件api可以看&#xff1a;Tabbar 底部导航栏 | uView…

Digicert证书是什么?

DigiCert是全球领先的数字信任提供商&#xff0c;使个人和企业能够自信地在线参与&#xff0c;相信他们在数字世界中的足迹是安全的。DigiCert通过塑造全球行业标准、提供卓越的全球合规性和运营、为公共和私人信任提供证书生命周期管理以及将信任扩展到供应链和互联生态系统&a…

IO多路复用笔记

O多路复用是一种同步的IO模型。利用IO多路复用模型&#xff0c;可以实现一个线程监视多个文件句柄&#xff1b;一旦某个文件句柄就绪&#xff0c;就能够通知到对应应用程序进行相应的读写操作&#xff1b;没有文件句柄就绪时就会阻塞应用程序&#xff0c;从而释放出CPU资源。 …

mysql之备份和恢复

&#xff08;一&#xff09;备份 1、备份的种类 &#xff08;1&#xff09;完全备份&#xff1a;将整个数据库完整的进行备份 &#xff08;2&#xff09;增量备份&#xff1a;在完全备份的基础上&#xff0c;对后续新增的内容进行备份 2、备份的需求 &#xff08;1&#x…