【深度学习】C++ Tensorrt Yolov8 目标检测推理
C++ Tensorrt Yolov8 目标检测推理
- 模型导出
- 代码
- yolov8.h
- yolov8.cpp
- common.hpp
- CMakeList
- main.cpp
C++ tensorrt对yolov8目标检测模型进行推理。
Windows版本下只需要修改common.hpp对文件的判断S_ISREG 和对文件夹的判断S_ISDIR即可,非核心代码,不调用删掉都可以。亲测可行。
模型导出
python 导出onnx
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'
tensorRT自带bin下的trtexec导出engine模型
## export trt/
(base) xiaoxin@xiaoxin:/usr/local/TensorRT-8.6.1.6/bin$ sudo ./trtexec --onnx=/home/xiaoxin/Documents/ultralytics-main/best.onnx --saveEngine=/home/xiaoxin/Documents/ultralytics-main/best.engine --workspace=1024 --fp16# Key Value Description
# format 'torchscript' format to export to
# imgsz 640 image size as scalar or (h, w) list, i.e. (640, 480)
# keras False use Keras for TF SavedModel export
# optimize False TorchScript: optimize for mobile
# half False FP16 quantization
# int8 False INT8 quantization
# dynamic False ONNX/TF/TensorRT: dynamic axes
# simplify False ONNX: simplify model
# opset None ONNX: opset version (optional, defaults to latest)
# workspace 4 TensorRT: workspace size (GB)
# nms False CoreML: add NMS
代码
yolov8.h
#ifndef YOLOV8_H
#define YOLOV8_H
#include "NvInferPlugin.h"
#include "common.hpp"
#include "fstream"
using namespace det;#define _PRINT true
// #define BATCHED_NMS
// #define assert(_Expression) ((void)0)class YOLOv8 {
public:explicit YOLOv8(const std::string& engine_file_path);~YOLOv8();void makePipe(bool warmup = true);void copyFromMat(const cv::Mat& image);void copyFromMat(const cv::Mat& image, cv::Size& size);void letterBox(const cv::Mat& image, cv::Mat& out, cv::Size& size);void infer();void postprocess(std::vector<Object>& objs,float score_thres = 0.25f,float iou_thres = 0.65f,int topk = 100,int num_labels = 1);static void draw_objects(const cv::Mat& image,cv::Mat& res,const std::vector<Object>& objs,const std::vector<std::string>& CLASS_NAMES,const std::vector<std::vector<unsigned int>>& COLORS);public:int num_bindings;int num_inputs = 0;int num_outputs = 0;std::vector<Binding> input_bindings;std::vector<Binding> output_bindings;std::vector<void*> host_ptrs;std::vector<void*> device_ptrs;PreParam pparam;Parameter param;private:nvinfer1::ICudaEngine* engine = nullptr;nvinfer1::IRuntime* runtime = nullptr;nvinfer1::IExecutionContext* context = nullptr;cudaStream_t stream = nullptr;Logger gLogger{nvinfer1::ILogger::Severity::kERROR};
};
#endif // YOLOV8_H
yolov8.cpp
#include "yolov8.h"// init engine model
YOLOv8::YOLOv8(const std::string& engine_file_path)
{// 1. make sure this file can be open by binary mode.std::ifstream file(engine_file_path, std::ios::binary);if(!file.good()){if(_PRINT){std::cout << "[ERROR] can not open file, please check up your engine file!" << std::endl;}return;}// 2. move pointer to the end.file.seekg(0, std::ios::end);// 3. get the location of current pointer.auto size = file.tellg();// 4. move pointer to start.file.seekg(0, std::ios::beg);char* trtModelStream = new char[size];assert(trtModelStream);file.read(trtModelStream, size);file.close();// 5. create runtime object deserialization/// important tip ///// in order to use initLibNvInferPlugins, link to nvinfer_plugin.so or nvinfer_plugin.dll.// if you have some errors in this method, check up your .so or .dll files. you can put them in program directory.initLibNvInferPlugins(&this->gLogger, "");this->runtime = nvinfer1::createInferRuntime(this->gLogger);assert(this->runtime != nullptr);this->engine = this->runtime->deserializeCudaEngine(trtModelStream, size);assert(this->engine != nullptr);delete[] trtModelStream;// 6. create some space to store intermediate activation values.this->context = this->engine->createExecutionContext();assert(this->context != nullptr);cudaStreamCreate(&this->stream);// 7. get number of input tensor and output tensor.this->num_bindings = this->engine->getNbBindings();// 8. get binding dimensions, this process can support different dimensions.for (int i = 0; i < this->num_bindings; ++i) {Binding binding;nvinfer1::Dims dims;nvinfer1::DataType dtype = this->engine->getBindingDataType(i);std::string name = this->engine->getBindingName(i);binding.name = name;binding.dsize = type_to_size(dtype);bool IsInput = engine->bindingIsInput(i);if (IsInput) {this->num_inputs += 1;dims = this->engine->getProfileDimensions(i, 0, nvinfer1::OptProfileSelector::kMAX);binding.size = get_size_by_dims(dims);binding.dims = dims;this->input_bindings.push_back(binding);// set max opt shapethis->context->setBindingDimensions(i, dims);}else {dims = this->context->getBindingDimensions(i);binding.size = get_size_by_dims(dims);binding.dims = dims;this->output_bindings.push_back(binding);this->num_outputs += 1;}}
}YOLOv8::~YOLOv8()
{this->context->destroy();this->engine->destroy();this->runtime->destroy();cudaStreamDestroy(this->stream);for (auto& ptr : this->device_ptrs) {CHECK(cudaFree(ptr));}for (auto& ptr : this->host_ptrs) {CHECK(cudaFreeHost(ptr));}
}// warm up.
void YOLOv8::makePipe(bool warmup)
{for (auto& bindings : this->input_bindings) {void* d_ptr;CHECK(cudaMallocAsync(&d_ptr, bindings.size * bindings.dsize, this->stream));this->device_ptrs.push_back(d_ptr);}for (auto& bindings : this->output_bindings) {void * d_ptr, *h_ptr;size_t size = bindings.size * bindings.dsize;CHECK(cudaMallocAsync(&d_ptr, size, this->stream));CHECK(cudaHostAlloc(&h_ptr, size, 0));this->device_ptrs.push_back(d_ptr);this->host_ptrs.push_back(h_ptr);}if (warmup) {for (int i = 0; i < 5; i++) {for (auto& bindings : this->input_bindings) {size_t size = bindings.size * bindings.dsize;void* h_ptr = malloc(size);memset(h_ptr, 0, size);CHECK(cudaMemcpyAsync(this->device_ptrs[0], h_ptr, size, cudaMemcpyHostToDevice, this->stream));free(h_ptr);}this->infer();}if(_PRINT){printf("model warmup 5 times\n");}}
}void YOLOv8::letterBox(const cv::Mat& image, cv::Mat& out, cv::Size& size)
{const float inp_h = size.height;const float inp_w = size.width;float height = image.rows;float width = image.cols;float r = std::min(inp_h / height, inp_w / width);int padw = std::round(width * r);int padh = std::round(height * r);cv::Mat tmp;if ((int)width != padw || (int)height != padh) {cv::resize(image, tmp, cv::Size(padw, padh));}else {tmp = image.clone();}float dw = inp_w - padw;float dh = inp_h - padh;dw /= 2.0f;dh /= 2.0f;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));cv::copyMakeBorder(tmp, tmp, top, bottom, left, right, cv::BORDER_CONSTANT, {114, 114, 114});cv::dnn::blobFromImage(tmp, out, 1 / 255.f, cv::Size(), cv::Scalar(0, 0, 0), true, false, CV_32F);this->pparam.ratio = 1 / r;this->pparam.dw = dw;this->pparam.dh = dh;this->pparam.height = height;this->pparam.width = width;
}void YOLOv8::copyFromMat(const cv::Mat& image)
{cv::Mat nchw;auto& in_binding = this->input_bindings[0];auto width = in_binding.dims.d[3];auto height = in_binding.dims.d[2];cv::Size size{width, height};this->letterBox(image, nchw, size);this->context->setBindingDimensions(0, nvinfer1::Dims{4, {1, 3, height, width}});CHECK(cudaMemcpyAsync(this->device_ptrs[0], nchw.ptr<float>(), nchw.total() * nchw.elemSize(), cudaMemcpyHostToDevice, this->stream));
}void YOLOv8::copyFromMat(const cv::Mat& image, cv::Size& size)
{cv::Mat nchw;this->letterBox(image, nchw, size);this->context->setBindingDimensions(0, nvinfer1::Dims{4, {1, 3, size.height, size.width}});CHECK(cudaMemcpyAsync(this->device_ptrs[0], nchw.ptr<float>(), nchw.total() * nchw.elemSize(), cudaMemcpyHostToDevice, this->stream));
}void YOLOv8::infer()
{this->context->enqueueV2(this->device_ptrs.data(), this->stream, nullptr);for (int i = 0; i < this->num_outputs; i++) {size_t osize = this->output_bindings[i].size * this->output_bindings[i].dsize;CHECK(cudaMemcpyAsync(this->host_ptrs[i], this->device_ptrs[i + this->num_inputs], osize, cudaMemcpyDeviceToHost, this->stream));}cudaStreamSynchronize(this->stream);
}void YOLOv8::postprocess(std::vector<Object>& objs, float score_thres, float iou_thres, int topk, int num_labels)
{if(param.setPam){score_thres = param.score_thres;iou_thres = param.iou_thres;topk = param.topk;num_labels = param.num_labels;}objs.clear();auto num_channels = this->output_bindings[0].dims.d[1];auto num_anchors = this->output_bindings[0].dims.d[2];auto& dw = this->pparam.dw;auto& dh = this->pparam.dh;auto& width = this->pparam.width;auto& height = this->pparam.height;auto& ratio = this->pparam.ratio;std::vector<cv::Rect> bboxes;std::vector<float> scores;std::vector<int> labels;std::vector<int> indices;cv::Mat output = cv::Mat(num_channels, num_anchors, CV_32F, static_cast<float*>(this->host_ptrs[0]));output = output.t();for (int i = 0; i < num_anchors; i++) {auto row_ptr = output.row(i).ptr<float>();auto bboxes_ptr = row_ptr;auto scores_ptr = row_ptr + 4;auto max_s_ptr = std::max_element(scores_ptr, scores_ptr + num_labels);float score = *max_s_ptr;if (score > score_thres) {float x = *bboxes_ptr++ - dw;float y = *bboxes_ptr++ - dh;float w = *bboxes_ptr++;float h = *bboxes_ptr;float x0 = clamp((x - 0.5f * w) * ratio, 0.f, width);float y0 = clamp((y - 0.5f * h) * ratio, 0.f, height);float x1 = clamp((x + 0.5f * w) * ratio, 0.f, width);float y1 = clamp((y + 0.5f * h) * ratio, 0.f, height);int label = max_s_ptr - scores_ptr;cv::Rect_<float> bbox;bbox.x = x0;bbox.y = y0;bbox.width = x1 - x0;bbox.height = y1 - y0;bboxes.push_back(bbox);labels.push_back(label);scores.push_back(score);}}#ifdef BATCHED_NMScv::dnn::NMSBoxesBatched(bboxes, scores, labels, score_thres, iou_thres, indices);
#elsecv::dnn::NMSBoxes(bboxes, scores, score_thres, iou_thres, indices);
#endifint cnt = 0;for (auto& i : indices) {if (cnt >= topk) {break;}Object obj;obj.rect = bboxes[i];obj.prob = scores[i];obj.label = labels[i];objs.push_back(obj);cnt += 1;}
}void YOLOv8::draw_objects(const cv::Mat& image,cv::Mat& res,const std::vector<Object>& objs,const std::vector<std::string>& CLASS_NAMES,const std::vector<std::vector<unsigned int>>& COLORS)
{res = image.clone();for (auto& obj : objs) {cv::Scalar color = cv::Scalar(COLORS[obj.label][0], COLORS[obj.label][1], COLORS[obj.label][2]);cv::rectangle(res, obj.rect, color, 2);char text[256];sprintf(text, "%s %.1f%%", CLASS_NAMES[obj.label].c_str(), obj.prob * 100);int baseLine = 0;int x = (int)obj.rect.x;int y = (int)obj.rect.y + 1;y > res.rows ? res.rows : y;/ you can choose whether you need a background for text. // cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.4, 1, &baseLine);// cv::rectangle(res, cv::Rect(x, y, label_size.width, label_size.height + baseLine), {0, 0, 255}, -1);cv::putText(res, text, cv::Point(x, y), cv::FONT_HERSHEY_SIMPLEX, 0.4, {0, 0, 255}, 1);}
}
common.hpp
#ifndef COMMON_HPP
#define COMMON_HPP
#include "NvInfer.h"
#include "opencv2/opencv.hpp"
#include <sys/stat.h>
#include <unistd.h>#define CHECK(call) \do { \const cudaError_t error_code = call; \if (error_code != cudaSuccess) { \printf("CUDA Error:\n"); \printf(" File: %s\n", __FILE__); \printf(" Line: %d\n", __LINE__); \printf(" Error code: %d\n", error_code); \printf(" Error text: %s\n", cudaGetErrorString(error_code)); \exit(1); \} \} while (0)class Logger: public nvinfer1::ILogger
{
public:nvinfer1::ILogger::Severity reportableSeverity;explicit Logger(nvinfer1::ILogger::Severity severity = nvinfer1::ILogger::Severity::kINFO):reportableSeverity(severity){}void log(nvinfer1::ILogger::Severity severity, const char* msg) noexcept override{if (severity > reportableSeverity) {return;}switch (severity) {case nvinfer1::ILogger::Severity::kINTERNAL_ERROR:std::cerr << "INTERNAL_ERROR: ";break;case nvinfer1::ILogger::Severity::kERROR:std::cerr << "ERROR: ";break;case nvinfer1::ILogger::Severity::kWARNING:std::cerr << "WARNING: ";break;case nvinfer1::ILogger::Severity::kINFO:std::cerr << "INFO: ";break;default:std::cerr << "VERBOSE: ";break;}std::cerr << msg << std::endl;}
};inline int get_size_by_dims(const nvinfer1::Dims& dims)
{int size = 1;for (int i = 0; i < dims.nbDims; i++) {size *= dims.d[i];}return size;
}inline int type_to_size(const nvinfer1::DataType& dataType)
{switch (dataType) {case nvinfer1::DataType::kFLOAT:return 4;case nvinfer1::DataType::kHALF:return 2;case nvinfer1::DataType::kINT32:return 4;case nvinfer1::DataType::kINT8:return 1;case nvinfer1::DataType::kBOOL:return 1;default:return 4;}
}inline static float clamp(float val, float min, float max)
{return val > min ? (val < max ? val : max) : min;
}inline bool IsPathExist(const std::string& path)
{if (access(path.c_str(), 0) == F_OK) {return true;}return false;
}inline bool IsFile(const std::string& path)
{if (!IsPathExist(path)) {printf("%s:%d %s not exist\n", __FILE__, __LINE__, path.c_str());return false;}struct stat buffer;return (stat(path.c_str(), &buffer) == 0 && S_ISREG(buffer.st_mode));
}inline bool IsFolder(const std::string& path)
{if (!IsPathExist(path)) {return false;}struct stat buffer;return (stat(path.c_str(), &buffer) == 0 && S_ISDIR(buffer.st_mode));
}namespace det
{struct Binding {size_t size = 1;size_t dsize = 1;nvinfer1::Dims dims;std::string name;};struct Object {cv::Rect_<float> rect;int label = 0;float prob = 0.0;};struct PreParam {float ratio = 1.0f;float dw = 0.0f;float dh = 0.0f;float height = 0;float width = 0;};struct Parameter{bool setPam = false;float score_thres = 0.25f;float iou_thres = 0.65f;int topk = 100;int num_labels = 1;};
} // namespace det
#endif // COMMON_HPP
CMakeList
cmake_minimum_required(VERSION 3.1)set(CMAKE_CUDA_ARCHITECTURES 60 61 62 70 72 75 86 89 90)
set(CMAKE_CUDA_COMPILER /usr/local/cuda/bin/nvcc)project(yolov8 LANGUAGES CXX CUDA)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_BUILD_TYPE Release)
option(CUDA_USE_STATIC_CUDA_RUNTIME OFF)# CUDA
find_package(CUDA REQUIRED)
message(STATUS "CUDA Libs: \n${CUDA_LIBRARIES}\n")
get_filename_component(CUDA_LIB_DIR ${CUDA_LIBRARIES} DIRECTORY)
message(STATUS "CUDA Headers: \n${CUDA_INCLUDE_DIRS}\n")# OpenCV
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV Libs: \n${OpenCV_LIBS}\n")
message(STATUS "OpenCV Libraries: \n${OpenCV_LIBRARIES}\n")
message(STATUS "OpenCV Headers: \n${OpenCV_INCLUDE_DIRS}\n")# TensorRT
set(TensorRT_INCLUDE_DIRS /usr/include/x86_64-linux-gnu)
set(TensorRT_LIBRARIES /usr/lib/x86_64-linux-gnu)message(STATUS "TensorRT Libs: \n${TensorRT_LIBRARIES}\n")
message(STATUS "TensorRT Headers: \n${TensorRT_INCLUDE_DIRS}\n")list(APPEND INCLUDE_DIRS${CUDA_INCLUDE_DIRS}${OpenCV_INCLUDE_DIRS}${TensorRT_INCLUDE_DIRS}include)list(APPEND ALL_LIBS${CUDA_LIBRARIES}${CUDA_LIB_DIR}${OpenCV_LIBRARIES}${TensorRT_LIBRARIES})include_directories(${INCLUDE_DIRS})add_executable(${PROJECT_NAME}main.cppyolov8.cppcommon.hpp)target_link_directories(${PROJECT_NAME} PUBLIC ${ALL_LIBS})
target_link_libraries(${PROJECT_NAME} PRIVATE nvinfer nvinfer_plugin cudart ${OpenCV_LIBS})if (${OpenCV_VERSION} VERSION_GREATER_EQUAL 4.7.0)message(STATUS "Build with -DBATCHED_NMS")add_definitions(-DBATCHED_NMS)
endif ()
main.cpp
#include "chrono"
#include "opencv2/opencv.hpp"
#include "yolov8.h"
#include <iostream>using namespace std;const std::vector<std::string> CLASS_NAMES = {"blackPoint"};const std::vector<std::vector<unsigned int>> COLORS = {{0, 0, 255}};int main(int argc, char** argv)
{// cuda:0cudaSetDevice(0);const std::string engine_file_path{"/home/xiaoxin/Documents/ultralytics-main/last.engine"};const std::string path{"/home/xiaoxin/Documents/ultralytics-main/datasets/Tray/labelImg"};std::vector<std::string> imagePathList;bool isVideo{false};auto yolov8 = new YOLOv8(engine_file_path);yolov8->makePipe(true);if (IsFile(path)){std::string suffix = path.substr(path.find_last_of('.') + 1);if (suffix == "jpg" || suffix == "jpeg" || suffix == "png") {imagePathList.push_back(path);}else if (suffix == "mp4" || suffix == "avi" || suffix == "m4v" || suffix == "mpeg" || suffix == "mov"|| suffix == "mkv") {isVideo = true;}else {printf("suffix %s is wrong !!!\n", suffix.c_str());std::abort();}}else if (IsFolder(path)) {cv::glob(path + "/*.png", imagePathList);}cv::Mat res, image;cv::Size size = cv::Size{640, 640};yolov8->param.setPam = true;yolov8->param.num_labels = 1;yolov8->param.topk = 100;yolov8->param.score_thres = 0.25f;yolov8->param.iou_thres = 0.35f; // 0.65fstd::vector<Object> objs;cv::namedWindow("result", cv::WINDOW_AUTOSIZE);if (isVideo) {cv::VideoCapture cap(path);if (!cap.isOpened()) {printf("can not open %s\n", path.c_str());return -1;}while (cap.read(image)) {objs.clear();yolov8->copyFromMat(image, size);auto start = std::chrono::system_clock::now();yolov8->infer();auto end = std::chrono::system_clock::now();yolov8->postprocess(objs);yolov8->draw_objects(image, res, objs, CLASS_NAMES, COLORS);auto tc = (double)std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() / 1000.;printf("cost %2.4lf ms\n", tc);cv::imshow("result", res);if (cv::waitKey(10) == 'q') {break;}}}else {for (auto& path : imagePathList) {objs.clear();image = cv::imread(path);yolov8->copyFromMat(image, size);auto start = std::chrono::system_clock::now();yolov8->infer();yolov8->postprocess(objs);yolov8->draw_objects(image, res, objs, CLASS_NAMES, COLORS);auto end = std::chrono::system_clock::now();auto tc = (double)std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() / 1000.;printf("cost %2.4lf ms\n", tc);resize(res, res, cv::Size(0,0), 3, 3);cv::imshow("result", res);cv::waitKey(0);}}cv::destroyAllWindows();delete yolov8;return 0;
}
相关文章:
【深度学习】C++ Tensorrt Yolov8 目标检测推理
C Tensorrt Yolov8 目标检测推理 模型导出代码yolov8.hyolov8.cppcommon.hppCMakeListmain.cpp C tensorrt对yolov8目标检测模型进行推理。 Windows版本下只需要修改common.hpp对文件的判断S_ISREG 和对文件夹的判断S_ISDIR即可,非核心代码,不调用删掉都…...

【项目日记(二)】搜索引擎-索引制作
❣博主主页: 33的博客❣ ▶️文章专栏分类:项目日记◀️ 🚚我的代码仓库: 33的代码仓库🚚 🫵🫵🫵关注我带你了解更多项目内容 目录 1.前言2.索引结构2.1创捷索引2.2根据索引查询2.3新增文档2.4内存索引保存到磁盘2.5把…...

K 近邻、K-NN 算法图文详解
1. 为什么学习KNN算法 KNN是监督学习分类算法,主要解决现实生活中分类问题。根据目标的不同将监督学习任务分为了分类学习及回归预测问题。 KNN(K-Nearest Neihbor,KNN)K近邻是机器学习算法中理论最简单,最好理解的算法…...

Eclipse + GDB + J-Link 的单片机程序调试实践
Eclipse GDB J-Link 的调试实践 本文介绍如何创建Eclipse的调试配置,如何控制调试过程,如何查看修改各种变量。 对 Eclipse 的要求 所用 Eclipse 应当安装了 Eclipse Embedded CDT 插件。从 https://www.eclipse.org/downloads/packages/ 下载 Ecli…...
前端代码生成辅助工具
1,Axure Axure设计的界面如何生成HTML文件 https://blog.csdn.net/qq_43279782/article/details/112387511 Axure 生成HTML 文件,并用Chrome打开 https://blog.csdn.net/qq_30718137/article/details/80621025 2,OpenUI [开源] OpenUI …...
静态库与动态库总结
一、库文件和头文件 所谓库文件,可以将其理解为压缩包文件,该文件内部通常包含不止一个目标文件(也就是二进制文件)。 值得一提的是,库文件中每个目标文件存储的代码,并非完整的程序,而是一个…...
深入解析tcpdump:网络数据包捕获与分析的利器
引言 在网络技术日新月异的今天,网络数据包的捕获与分析成为了网络管理员、安全专家以及开发人员不可或缺的技能。其中,tcpdump作为一款强大的网络数据包捕获分析工具,广泛应用于Linux系统中。本文将从技术人的角度,详细分析tcpdu…...

【漏洞复现】科立讯通信有限公司指挥调度管理平台uploadgps.php存在SQL注入
0x01 产品简介 科立讯通信指挥调度管理平台是一个专门针对通信行业的管理平台。该产品旨在提供高效的指挥调度和管理解决方案,以帮助通信运营商或相关机构实现更好的运营效率和服务质量。该平台提供强大的指挥调度功能,可以实时监控和管理通信网络设备、…...

什么是自然语言处理(NLP)?详细解读文本分类、情感分析和机器翻译的核心技术
什么是自然语言处理? 自然语言处理(Natural Language Processing,简称NLP)是人工智能的一个重要分支,旨在让计算机理解、解释和生成人类的自然语言。打个比方,你和Siri对话,或使用谷歌翻译翻译一…...
【linux】gcc快速入门教程
目录 一.gcc简介 二.gcc常用命令 一.gcc简介 gcc 是GNU Compiler Collection(GNU编译器套件)。就是一个编译器。编译一个源文件的时候可以直接使用,但是源文件数量太多时,就很不方便,于是就出现了make 工具 二.gcc…...

【多维动态规划】Leetcode 97. 交错字符串【中等】
交错字符串 给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串 子字符串 是字符串中连续的 非空 字符序列。 s s1 s2 … snt…...
【JavaScript脚本宇宙】精通前端开发:六大热门CSS框架详解
前端开发的利器:深入了解六大CSS框架 前言 在现代Web开发中,选择适合的前端框架和工具包是构建高效、响应式和美观的网站或应用程序的关键。本文将详细介绍六个广受欢迎的CSS框架:Bootstrap、Bulma、Tailwind CSS、Foundation、Materialize…...

开发技术-Java集合(List)删除元素的几种方式
文章目录 1. 错误的删除2. 正确的方法2.1 倒叙删除2.2 迭代器删除2.3 removeAll() 删除2.4 removeIf() 最简单的删除 3. 总结 1. 错误的删除 在写代码时,想将其中的一个元素删除,就遍历了 list ,使用了 remove(),发现效果并不是想…...
c++ 递归
递归函数是指在函数定义中调用自身的函数。C语言也支持递归函数。 下面是一个使用递归函数计算阶乘的例子: #include <iostream> using namespace std;int factorial(int n) {// 基本情况,当 n 等于 0 或 1 时,阶乘为 1if (n 0 || n…...

RedHat9 | podman容器
1、容器技术介绍 传统问题 应用程序和依赖需要一起安装在物理主机或虚拟机上的操作系统应用程序版本比当前操作系统安装的版本更低或更新两个应用程序可能需要某一软件的不同版本,彼此版本之间不兼容 解决方式 将应用程序打包并部署为容器容器是与系统的其他部分…...
边缘计算项目有哪些
边缘计算项目在多个领域得到了广泛的应用,以下是一些典型的边缘计算项目案例: 1. **智能交通系统**:通过在交通信号灯、监控摄像头等设备上部署边缘计算,可以实时分析交通流量,优化交通信号控制,减少拥堵&…...
计算fibonacci数列每一项时所需的递归调用次数
斐波那契数列是一个经典的数列,其中每一项是前两项的和,定义为: [ F(n) F(n-1) F(n-2) ] 其中,( F(0) 0 ) 和 ( F(1) 1 )。 对于计算斐波那契数列的第 ( n ) 项,如果使用简单的递归方法,其时间复杂度是…...

【教学类65-05】20240627秘密花园涂色书(中四班练习)
【教学类65-03】20240622秘密花园涂色书03(通义万相)(A4横版1张,一大 68张纸136份)-CSDN博客 背景需求: 打印以下几款秘密花园样式(每款10份)给中四班孩子玩一下,看看效果 【教学类…...
Python 学习之基础语法(一)
Python的语法基础主要包括以下几个方面,下面将逐一进行分点表示和归纳: 一、基本语法 1. 注释 a. 单行注释:使用#开头,例如# 这是一个单行注释。 b. 多行注释:使用三引号(可以是三个单引号或三个双引号&…...

日志分析-windows系统日志分析
日志分析-windows系统日志分析 使用事件查看器分析Windows系统日志 cmd命令 eventvwr 筛选 清除日志、注销并重新登陆,查看日志情况 Windows7和Windowserver2008R2的主机日志保存在C:\Windows\System32\winevt\Logs文件夹下,Security.evtx即为W…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...

tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...

Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...