【深度学习】C++ onnx Yolov8 目标检测推理

【深度学习】C++ onnx Yolov8 目标检测推理

  • 导出onnx模型
  • 代码
    • onnx_detect_infer.h
    • onnx_detect_infer.cpp
    • main.cpp
    • CMAKELIST

导出onnx模型

python 中导出

from ultralytics import YOLO

# Load the YOLOv8 model
model = YOLO("best.pt")

# # Export the model to ONNX format
model.export(format="onnx", dynamic=False, simplify=True, imgsz = (640,640), opset=12, half=False, int8=False)  # creates 'yolov8n.onnx'

代码

onnx_detect_infer.h

#include <iostream>
#include <opencv2/opencv.hpp>
#include <onnxruntime_cxx_api.h>
#include <numeric>

#define _PRINT true

namespace det
{
    struct OutputDet
    {
        int id;
        float confidence;
        cv::Rect box;
    };

    struct param
    {
        int batchSize = 1;
        int netWidth = 640;   //ONNX-net-input-width
        int netHeight = 640;  //ONNX-net-input-height
        bool dynamicShape = true;   //onnx support dynamic shape
    
        float classThreshold = 0.25;
        float nmsThrehold= 0.45;
        float maskThreshold = 0.5;
    };
}

class detectModel
{
public:
    detectModel():m_ortMemoryInfo(Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtDeviceAllocator, OrtMemType::OrtMemTypeCPUOutput)) {};
    ~detectModel()
    { 
        delete m_ortSession;
        m_inputNodeNames.clear();
        m_outputNodeNames.clear();
        m_inputTensorShape.clear();
        m_outputTensorShape.clear();
    };

    bool readModel(const std::string& modelPath, bool isCuda=false, int cudaId=0, bool warmUp=true);
    bool onnxDetect(cv::Mat& srcImg, std::vector<det::OutputDet>& output);
    bool onnxBatchDetect(std::vector<cv::Mat>& srcImgs, std::vector<std::vector<det::OutputDet>>& output);
    void drawPred(cv::Mat& img, std::vector<det::OutputDet> result,
              std::vector<std::string> classNames, std::vector<cv::Scalar> color);
    
    // parameter.
    det::param m_param = {1,640,640,true,0.25,0.45,0.5};

public:
    std::vector<std::string> m_className = {"blackPoint"};

private:
    // ort parameter
    Ort::Env m_ortEnv = Ort::Env(OrtLoggingLevel::ORT_LOGGING_LEVEL_ERROR, "Yolov8n"); // set up your log level and project name.
    Ort::MemoryInfo m_ortMemoryInfo;
    Ort::SessionOptions m_ortSessionOptions = Ort::SessionOptions(); // init. default do not need any parameter.

    Ort::Session* m_ortSession = nullptr;

    std::shared_ptr<char> m_inputName, m_output_name;
    std::vector<char*> m_inputNodeNames; 
    std::vector<char*> m_outputNodeNames; 

    size_t m_inputNodesNum = 0;        
    size_t m_outputNodesNum = 0;      
  
    ONNXTensorElementDataType m_inputNodeDataType;  
    ONNXTensorElementDataType m_outputNodeDataType;
 
    std::vector<int64_t> m_inputTensorShape;  
    std::vector<int64_t> m_outputTensorShape;
 
 private:
    template<typename T>
    T vectorProduct(const std::vector<T>& v)
    {
        return std::accumulate(v.begin(), v.end(), 1, std::multiplies<T>());
    }

    int preProcessing(const std::vector<cv::Mat>& srcImgs,
                    std::vector<cv::Mat>& outSrcImgs,
                    std::vector<cv::Vec4d>& params);

    void letterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape = cv::Size(640, 640),
               bool autoShape = false, bool scaleFill=false, bool scaleUp=true, int stride= 32, const cv::Scalar& color = cv::Scalar(114,114,114));

    bool checkPath(const std::string path);
};

onnx_detect_infer.cpp

#include "onnx_detect_infer.h"
#include <fstream>

using namespace std;
using namespace Ort;
using namespace cv;
using namespace det;

bool detectModel::checkPath(const std::string path) 
{
    string tempPath = path;
    ifstream f(tempPath.c_str());
    return f.good();
}

bool detectModel::readModel(const std::string &modelPath, bool isCuda, int cudaId, bool warmUp)
{
    if(m_param.batchSize < 1)
    {
        m_param.batchSize = 1;
    }

    try
    {
        if (!checkPath(modelPath))
        {
            if(_PRINT)
            {
                cout << "your model path isn't corrent. check up : " << modelPath << endl;
            }
            return false;
        }
        
        // check up whether there is a gpu device.
        std::vector<std::string> available_providers = GetAvailableProviders();
        auto cuda_available = std::find(available_providers.begin(), available_providers.end(), "CUDAExecutionProvider");

        // using cpu threads.
        // m_ortSessionOptions.SetIntraOpNumThreads(4);
        // m_ortSessionOptions.SetExecutionMode(ORT_SEQUENTIAL);

        // gpu mode set up.
        if (isCuda && (cuda_available == available_providers.end()))
        {
            if(_PRINT)
            {
                std::cout << "Your ORT build without GPU. Change to CPU." << std::endl;
                std::cout << "************* Infer model on CPU! *************" << std::endl;
            }
        }
        else if (isCuda && (cuda_available != available_providers.end()))
        {
            if(_PRINT)
            {
                std::cout << "************* Infer model on GPU! *************" << std::endl;
            }
#if ORT_API_VERSION < ORT_OLD_VISON
			OrtCUDAProviderOptions cudaOption;
			cudaOption.device_id = cudaId;
            m_ortSessionOptions.AppendExecutionProvider_CUDA(cudaOption);
#else
			OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(m_ortSessionOptions, cudaId);
#endif
        }
        else
        {
            if(_PRINT)
            {
                std::cout << "************* Infer model on CPU! *************" << std::endl;
            }
        }

        // GraphOptimizationLevel::ORT_DISABLE_ALL -> Disables all optimizations
        // GraphOptimizationLevel::ORT_ENABLE_BASIC -> Enables basic optimizations
        // GraphOptimizationLevel::ORT_ENABLE_EXTENDED -> Enables basic and extended optimizations
        // GraphOptimizationLevel::ORT_ENABLE_ALL -> Enables all available optimizations including layout

        // I have tested all modes, and ort_enable_all had fastest speed.
        m_ortSessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); // ORT_ENABLE_ALL
#ifdef _WIN32
        std::wstring model_path(modelPath.begin(), modelPath.end());
        m_ortSession = new Ort::Session(m_ortEnv, model_path.c_str(), m_ortSessionOptions);
#else
        m_ortSession = new Ort::Session(m_ortEnv, modelPath.c_str(), m_ortSessionOptions);
#endif

        Ort::AllocatorWithDefaultOptions allocator;
        //init input
        m_inputNodesNum = m_ortSession->GetInputCount();
#if ORT_API_VERSION < ORT_OLD_VISON
        m_inputName = _OrtSession->GetInputName(0, allocator);
        m_inputNodeNames.push_back(m_inputName);
#else
        m_inputName = std::move(m_ortSession->GetInputNameAllocated(0, allocator));
        m_inputNodeNames.push_back(m_inputName.get());
#endif

        Ort::TypeInfo inputTypeInfo = m_ortSession->GetInputTypeInfo(0);
        auto input_tensor_info = inputTypeInfo.GetTensorTypeAndShapeInfo();
        m_inputNodeDataType = input_tensor_info.GetElementType();
        m_inputTensorShape = input_tensor_info.GetShape();
 
        if (m_inputTensorShape[0] == -1)
        {
            m_param.dynamicShape = true;
            m_inputTensorShape[0] = m_param.batchSize;
 
        }
        if (m_inputTensorShape[2] == -1 || m_inputTensorShape[3] == -1) {
            m_param.dynamicShape = true;
            m_inputTensorShape[2] = m_param.netHeight;
            m_inputTensorShape[3] = m_param.netWidth;
        }

        // init output
        m_outputNodesNum = m_ortSession->GetOutputCount();
#if ORT_API_VERSION < ORT_OLD_VISON
        m_output_name = _OrtSession->GetOutputName(0, allocator);
        m_outputNodeNames.emplace_back(m_output_name);
#else
        m_output_name = std::move(m_ortSession->GetOutputNameAllocated(0, allocator));
        m_outputNodeNames.emplace_back(m_output_name.get());
#endif
        Ort::TypeInfo type_info_output0(nullptr);
        type_info_output0 = m_ortSession->GetOutputTypeInfo(0);  //output0
 
        auto tensor_info_output0 = type_info_output0.GetTensorTypeAndShapeInfo();
        m_outputNodeDataType = tensor_info_output0.GetElementType();
        m_outputTensorShape = tensor_info_output0.GetShape();

        //warm up
        if (isCuda && warmUp) 
        {
            //draw run
            size_t input_tensor_length = vectorProduct(m_inputTensorShape);
            float* temp = new float[input_tensor_length];
            std::vector<Ort::Value> input_tensors;
            std::vector<Ort::Value> output_tensors;
            input_tensors.push_back(Ort::Value::CreateTensor<float>(
                m_ortMemoryInfo, temp, input_tensor_length, m_inputTensorShape.data(),
                m_inputTensorShape.size()));
            for (int i = 0; i < 3; ++i) 
            {
                output_tensors = m_ortSession->Run(Ort::RunOptions{ nullptr },
                    m_inputNodeNames.data(),
                    input_tensors.data(),
                    m_inputNodeNames.size(),
                    m_outputNodeNames.data(),
                    m_outputNodeNames.size());
            }
 
            delete[]temp;
        }
    }
    catch (const std::exception&)
    {
        return false;
    }
    return true;
}

bool detectModel::onnxBatchDetect(std::vector<cv::Mat> &srcImgs, std::vector<std::vector<OutputDet> > &output)
{
    vector<Vec4d> params;
    vector<Mat> input_images;
    cv::Size input_size(m_param.netWidth, m_param.netHeight);
 
    // preProcessing.
    preProcessing(srcImgs, input_images, params);
    // [0~255] --> [0~1]; BGR2RGB.
    Mat blob = cv::dnn::blobFromImages(input_images, 1 / 255.0, input_size, Scalar(0,0,0), true, false);
 
    // get output result.
    int64_t input_tensor_length = vectorProduct(m_inputTensorShape);
    std::vector<Ort::Value> input_tensors;
    std::vector<Ort::Value> output_tensors;
    input_tensors.push_back(Ort::Value::CreateTensor<float>(m_ortMemoryInfo, (float*)blob.data,
                                                            input_tensor_length, m_inputTensorShape.data(),
                                                            m_inputTensorShape.size()));
 
    output_tensors = m_ortSession->Run(Ort::RunOptions{ nullptr },
        m_inputNodeNames.data(), input_tensors.data(), m_inputNodeNames.size(),
        m_outputNodeNames.data(), m_outputNodeNames.size() );
 
    //post-process
    int net_width = m_className.size() + 4;
    float* all_data = output_tensors[0].GetTensorMutableData<float>(); // outputs of the first picture.
    m_outputTensorShape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape(); // output dimension [1, 84, 8400]
 
    int64_t one_output_length = vectorProduct(m_outputTensorShape) / m_outputTensorShape[0]; // the length of the memory of the output of a picture 8400*84

    for (int img_index = 0; img_index < srcImgs.size(); ++img_index)
    {
        Mat output0 = Mat(Size((int)m_outputTensorShape[2], (int)m_outputTensorShape[1]), CV_32F, all_data).t(); // [1, 84 ,8400] -> [1, 8400, 84]
 
        all_data += one_output_length; // point to the adress of the picture. 
 
        float* pdata = (float*)output0.data; // [x,y,w,h,class1,class2.....class80]
        int rows = output0.rows; 
 
        // predict box.
        vector<int> class_ids;
        vector<float> confidences;
        vector<Rect> boxes;
        for (int r=0; r<rows; ++r) // can not support yolov5, if use v5, need to change it 
        {
            Mat scores(1, m_className.size(), CV_32F, pdata + 4); // score
 
            Point classIdPoint;
            double max_class_soces;
            minMaxLoc(scores, 0, &max_class_soces, 0, &classIdPoint);
            max_class_soces = (float)max_class_soces;
 
            if (max_class_soces >= m_param.classThreshold)
            {
                // rect [x,y,w,h]
                float x = (pdata[0] - params[img_index][2]) / params[img_index][0]; //x
                float y = (pdata[1] - params[img_index][3]) / params[img_index][1]; //y
                float w = pdata[2] / params[img_index][0]; //w
                float h = pdata[3] / params[img_index][1]; //h
 
                int left = MAX(int(x - 0.5 *w +0.5), 0);
                int top = MAX(int(y - 0.5*h + 0.5), 0);
 
                class_ids.push_back(classIdPoint.x);
                confidences.push_back(max_class_soces);
                boxes.push_back(Rect(left, top, int(w + 0.5), int(h + 0.5)));
            }
            pdata += net_width; // next box
        }
 
        // nms process
        vector<int> nms_result;
        cv::dnn::NMSBoxes(boxes, confidences, m_param.classThreshold, m_param.nmsThrehold, nms_result); // 还需要classThreshold?
 	    
         cv::Rect holeImgRect(0, 0, m_param.netWidth, m_param.netHeight);
        
        // get predict output.
        vector<OutputDet> temp_output;
        for (size_t i=0; i<nms_result.size(); ++i)
        {
            int idx = nms_result[i];
            OutputDet result;
            result.id = class_ids[idx];
            result.confidence = confidences[idx];
            result.box = boxes[idx] & holeImgRect;
            temp_output.push_back(result);
        }
        output.push_back(temp_output);
    }
    if (output.size())
        return true;
    else
        return false;
}

bool detectModel::onnxDetect(cv::Mat &srcImg, std::vector<OutputDet> &output)
{
    vector<Mat> input_data = {srcImg};
    vector<vector<OutputDet>> temp_output;
 
    if(onnxBatchDetect(input_data, temp_output))
    {
        output = temp_output[0];
        return true;
    }
    else return false;
}
 
int detectModel::preProcessing(const std::vector<cv::Mat> &SrcImgs,
                              std::vector<cv::Mat> &OutSrcImgs,
                              std::vector<cv::Vec4d> &params)
{
    OutSrcImgs.clear();
    Size input_size = Size(m_param.netWidth, m_param.netHeight);
 
    for (size_t i=0; i<SrcImgs.size(); ++i)
    {
        Mat temp_img = SrcImgs[i];
        Vec4d temp_param = {1,1,0,0};
        if (temp_img.size() != input_size)
        {
            Mat borderImg;
            letterBox(temp_img, borderImg, temp_param, input_size, false, false, true, 32);
            OutSrcImgs.push_back(borderImg);
            params.push_back(temp_param);
        }
        else 
        {
            OutSrcImgs.push_back(temp_img);
            params.push_back(temp_param);
        }
    }
 
    int lack_num = m_param.batchSize - SrcImgs.size();
    if (lack_num > 0)
    {
        Mat temp_img = Mat::zeros(input_size, CV_8UC3);
        Vec4d temp_param = {1,1,0,0};
        OutSrcImgs.push_back(temp_img);
        params.push_back(temp_param);
    }
    return 0;
}

void detectModel::letterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,
               bool autoShape, bool scaleFill, bool scaleUp, int stride, const cv::Scalar& color)
{
    // get smaller scale size.
    cv::Size shape = image.size();
    float r = std::min((float)newShape.height / (float)shape.height,
                       (float)newShape.width / (float)shape.width);
    if (!scaleUp)
        r = std::min(r, 1.0f);
 
    // source image size
    float ratio[2]{r,r};
    int new_un_pad[2] = { (int)std::round((float)shape.width  * r), (int)std::round((float)shape.height * r)};
 
    // detect the plexs of the size of detect object.
    auto dw = (float)(newShape.width - new_un_pad[0]);
    auto dh = (float)(newShape.height - new_un_pad[1]);
    if (autoShape)
    {
        dw = (float)((int)dw % stride);
        dh = (float)((int)dh % stride);
    }
    else if (scaleFill)
    {
        dw = 0.0f;
        dh = 0.0f;
        new_un_pad[0] = newShape.width;
        new_un_pad[1] = newShape.height;
        ratio[0] = (float)newShape.width / (float)shape.width;
        ratio[1] = (float)newShape.height / (float)shape.height;
    }
 
    dw /= 2.0f;
    dh /= 2.0f;
 
    // resize
    if (shape.width != new_un_pad[0] && shape.height != new_un_pad[1])
    {
        cv::resize(image, outImage, cv::Size(new_un_pad[0], new_un_pad[1]));
    }
    else{
        outImage = image.clone();
    }
 
    // padding, make every pictures have the same size.
    int top = int(std::round(dh - 0.1f));
    int bottom = int(std::round(dh + 0.1f));
    int left = int(std::round(dw - 0.1f));
    int right = int(std::round(dw + 0.1f));
    params[0] = ratio[0]; // scale of width
    params[1] = ratio[1]; // scale of height
    params[2] = left; // the number of padding from left to right
    params[3] = top; //the number of padding from top to bottom
    cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);
}
 
void detectModel::drawPred(cv::Mat& img, std::vector<OutputDet> result,
              std::vector<std::string> classNames,
              std::vector<cv::Scalar> color)
{
    for (size_t i=0; i<result.size(); i++)
    {
        int  left,top;
        left = result[i].box.x;
        top = result[i].box.y;
 
        // rectangle the object.
        rectangle(img, result[i].box,color[result[i].id], 2, 8);
 
        // put text.
        string label = to_string(result[i].confidence); //classNames[result[i].id] + ":" + to_string(result[i].confidence);
        int baseLine;
        Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
        top = max(top, labelSize.height);
        putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 1, color[result[i].id], 2);
    }
}

main.cpp

 
#include <iostream>
#include <opencv2/opencv.hpp>
#include "onnx_detect_infer.h"
#include <sys/time.h>
 
using namespace std;
using namespace cv;
using namespace cv::dnn;
 
int main()
{
    string model_path = "/home/xiaoxin/Documents/ultralytics-main/last.onnx";
    detectModel yolov8;
    if (!yolov8.readModel(model_path))
    {
        return -1;
    }
 
    yolov8.m_param.batchSize = 1;
    yolov8.m_param.netWidth = 640;
    yolov8.m_param.netHeight = 640;
    yolov8.m_param.dynamicShape = false;
    yolov8.m_param.classThreshold = 0.25;
    yolov8.m_param.nmsThrehold= 0.45;
    yolov8.m_param.maskThreshold = 0.5;

    // random color
    vector<Scalar> color;
    srand((time(0)));
    for (int i=0; i<80; i++)
    {
        int b = rand() %  256;
        int g = rand() % 256;
        int r = rand() % 256;
        color.push_back(Scalar(b,g,r));
    }
 
    string inputPath = "/home/xiaoxin/Documents/ultralytics-main/datasets/Tray/labelImg";
    vector<String> vPaths;
    glob(inputPath,vPaths,true);
    for(int i = 0; i < vPaths.size(); ++i)
    {
        Mat frame = imread(vPaths[i], 1);
        struct timeval t1, t2;
        double timeuse;

        vector<det::OutputDet> reuslt;

        gettimeofday(&t1, NULL);      
        for(int i = 0; i < 50 ; i++)
        {
            bool find = yolov8.onnxDetect(frame, reuslt);
        }
        gettimeofday(&t2, NULL);
        yolov8.drawPred(frame, reuslt, yolov8.m_className, color);

        timeuse = (t2.tv_sec - t1.tv_sec) +
                (double)(t2.tv_usec -t1.tv_usec)/1000000; //s
        cout << timeuse*1000 << endl;
        resize(frame, frame, Size(0,0), 3, 3);
        imshow("result", frame);
        waitKey(0);
    }

    return 0;
}

CMAKELIST

CMAKE_MINIMUM_REQUIRED(VERSION 3.0.0)
project(YOLOv8)


SET (OpenCV_DIR path/to/opencv/build)  #opencv root
#SET (ONNXRUNTIME_DIR path/to/onnxruntime)
Set(ONNXRUNTIME_DIR ${PROJECT_SOURCE_DIR}/onnxruntime-linux-x64-gpu-1.18.0)


FIND_PACKAGE(OpenCV REQUIRED)
#include_directories("")
ADD_EXECUTABLE(YOLOv8 main.cpp onnx_detect_infer.cpp)

SET(CMAKE_CXX_STANDARD 14)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)

TARGET_INCLUDE_DIRECTORIES(YOLOv8 PRIVATE "${ONNXRUNTIME_DIR}/include")

TARGET_COMPILE_FEATURES(YOLOv8 PRIVATE cxx_std_14)
TARGET_LINK_LIBRARIES(YOLOv8 ${OpenCV_LIBS})

if (WIN32)
    TARGET_LINK_LIBRARIES(YOLOv8 "${ONNXRUNTIME_DIR}/lib/onnxruntime.lib")
endif(WIN32)	

if (UNIX)
    TARGET_LINK_LIBRARIES(YOLOv8 "${ONNXRUNTIME_DIR}/lib/libonnxruntime.so")
endif(UNIX)

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

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

相关文章

期货散户应该如何有效的管理仓位呢?

期货散户应该如何有效的管理仓位呢?首先,他们要意识到自己所做的决定是很重要的。其次,还要注意自己的风险承受能力。最后,要做好风险管理,以便避免出现任何问题。 1&#xff1a;散户如何管理仓位 散户在进行期货交易时&#xff0c;要想有效地管理仓位&#xff0c;需要遵循一…

Windwos +vs 2022 编译openssl 1.0.2 库

一 前言 先说 结论&#xff0c;编译64位报错&#xff0c;查了一圈没找到解决方案&#xff0c;最后换了32位的。 使用qt访问web接口&#xff0c;因为是https&#xff0c;没有openssl库会报错 QNetworkReply* reply qobject_cast<QNetworkReply*>(sender());if (reply){…

vivo 互联网自研代码评审 VCR 落地实践

作者&#xff1a;vivo 互联网效能平台团队- Chi Wei 本文介绍了vivo工程效能团队基于 Gitlab、Gerrit等开源工具搭建的VCR平台&#xff0c;代码评审idea插件开发及开发过程中遇到的挑战、困难&#xff0c;并分享了相应的应对策略和优化方案。 代码评审是软件质量保证一种活动&…

5年成为10亿级大单品,海天如何策划黄豆酱的极致产品力?

在当今的调味品市场中&#xff0c;酱料作为一个重要的细分品类&#xff0c;正迅速成为消费者日常饮食中不可或缺的一部分。随着人们对烹饪品质和口味多样化的追求不断提升&#xff0c;酱料市场的前景愈发广阔。而在这片广阔的市场中&#xff0c;海天味业&#xff0c;作为中国调…

ElasticSearch-Windows系统ElasticSearch(ES)的下载及安装

前言 下载ElasticSearch 可以进入ElasticSearch官方下载地址&#xff0c;选择与电脑系统相对应的版本&#xff1b;博主已经上传资源&#xff0c;或者点此直接免费下载&#xff0c;本次演示版本为8.14.1。 注意&#xff1a; Elasticsearch 5 需要 Java 8 以上版本&#xff1b;…

Excel 宏录制与VBA编程 ——VBA编程技巧篇一 (Union方法、Resize方法、Cells方法、UseSelect方法、With用法)

Uniom方法 使用Union方法可以将多个非连续区域连接起来成为一个区域&#xff0c;从而可以实现对多个非连续区域一起进行操作。 Resize方法 使用Range对象的Resize属性调整指定区域的大小&#xff0c;并返回调整大小后的单元格区域。 Cells方法 Cells属性返回一个Range对象。 Us…

基于Java的大学生租房系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架&#xff0c;MVC模式 工具&#xff1a;Vscode&#xff0c;MySQL&#xff0c;B/S架构…

计算机网络之OSI七层体系结构

目录 1.物理层 1.1物理层组成 1.2物理层功能 1.3物理层服务 1.4物理层标准 1.5物理层接口 2.数据链路层 2.1基于物理层的问题 2.2数据链路层功能 2.3数据链路层服务 2.4数据链路层协议 3.网络层 3.1基于DL层的问题 3.2网络层功能 3.3网络层服务 3.4网络层协议 …

根据肥胖类型选择减调方向收获窈窕身材

我们生活中胖子很多&#xff0c;从胖到瘦的人也不少&#xff0c;但瘦了后对自己身材满意的人却是不多的&#xff0c;很多人瘦了也只是减掉了身上的赘肉而已&#xff0c;大体的身形却是没有变化的&#xff0c;因此&#xff0c;并不感到满意。因为他们本身的形体是固定的&#xf…

拼多多面试总结

文章目录 一面自我介绍提问算法反问结果 二面提问算法反问结果 主管面主管面试准备算法题其他个人提问准备 提问数据库普通索引和覆盖索引的区别索引是什么&#xff1f;索引怎么加快数据库查询的&#xff1f;索引具体怎么实现的&#xff1f;以B树为例&#xff0c;节点放了什么&…

java生成excel,uniapp微信小程序接收excel并打开

java引包&#xff0c;引的是apache.poi <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency> 写一个测试类&#xff0c;把excel输出到指定路径 public s…

leetcode494. 目标和

1.思想方法 2.代码 class Solution { public int findTargetSumWays(int[] nums, int target) {int sum 0;for(int num : nums)sum num;if(sum < Math.abs(target) || (targetsum)%2 ! 0)return 0;int x (targetsum) / 2,n nums.length;//基于滚动数组的方法int[] dp…

JavaWeb-day28_HTML

今日内容 零、 复习昨日 一、HTML 零、 复习昨日 一、Web开发 前端三大件 HTML ,页面展现CSS , 样式JS (JavaScript) , 动起来 二、HTML 2.1 HTML概念 ​ 网页&#xff0c;是网站中的一个页面&#xff0c;通常是网页是构成网站的基本元素&#xff0c;是承载各种网站应用的平台…

MySQL高级-SQL优化- count 优化 - 尽量使用count(*)

文章目录 1、count 优化2、count的几种用法3、count(*)4、count(id)5、count(profession)6、count(null)7、 count(1) 1、count 优化 MyISAM引擎把一个表的总行数存在了磁盘上&#xff0c;因此执行count&#xff08;*&#xff09;的时候会直接返回这个数&#xff0c;效率很高&a…

阿里云nginx更新证书后依旧显示旧证书

尝试的解决办法 重启nginx服务删除服务器上的旧证书清除浏览器缓存检查是否使用CDN服务 最后的解决办法 云服务器开启了WAF服务&#xff0c;在WAF服务中配置证书

MySQL学习(5):SQL语句之数据查询语言:DQL

1.DQL语法 select 字段列表 from 表名列表 #DQL是可以进行多表查询的 where 条件列表 group by 分组字段列表 having 分组后条件列表 order by 排序字段列表 limit 分页参数 2.基本查询&#xff08;select&#xff09; 2.1查询多字段 select 字段1,字段2,字段3,......fro…

重要通知:据最新TEMU要求所有欧区车灯都需要能效标签(eu energy lable)

重要通知&#xff1a; 据最新TEMU要求&#xff0c;所有“欧区车灯”都需要能效标签&#xff08;eu energy lable&#xff09;&#xff0c;目前已下架欧区站点&#xff0c;上传成功后可恢复。 灯具类欧盟EU ENERGY LABEL 近日有不少欧洲站卖家收到TEMU平台商品要求卖家们发布的…

SHELL脚本学习(十二)sed进阶

一、多行命令 概述 sed 编辑器的基础命令都是对一行文本进行操作。如果要处理的数据分布在多行中&#xff0c;sed基础命令是没办法处理的。 幸运的是&#xff0c;sed编辑器的设计人员已经考虑了这个问题的解决方案。sed编辑器提供了3个处理多行文本的特殊命令。 命令描述N加…

大数据学习之分布式数据采集系统Flume学习

分布式数据采集系统Flume学习 一、Flume架构 1.1 Hadoop业务开发流程 1.2 Flume概述 flume是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。 支持在日志系统中定制各类数据发送方&#xff0c;用于收集数据; 同时&#xff0c;Flume提供对数据进行简单处理&…

如何在720漫游中设置付费观看?

1. 进入720漫游作品编辑器&#xff0c;点击 「全局设置-营销设置-付费观看设置」 即可打开付费观看设置栏&#xff1b; 720漫游编辑器-全局设置 2. 开启付费观看功能后&#xff0c;设置「付费金额」&#xff0c;选择「付费场景」即可 720漫游编辑器-全局设置-付费观看设置 3.…