全流程机器视觉工程开发(四)PaddleDetection C++工程化应用部署到本地DLL以供软件调用

前言

我们之前跑了一个yolo的模型,然后我们通过PaddleDetection的库对这个模型进行了一定程度的调用,但是那个调用还是基于命令的调用,这样的库首先第一个不能部署到客户的电脑上,第二个用起来也非常不方便,那么我们可不可以直接将Paddle的库直接做成一个DLL部署到我们的软件上呢?答案是可以的,接下来我就会全流程地完成这一操作。

流程

部署流程主要参考了几个文档:
Visual Studio 2019 Community CMake 编译指南
PaddleDetection部署c++测试图片视频 (win10+vs2017)

流程的话主要有以下几个步骤

  1. 编译opencv
  2. 下载cuda库(如果之前安装了cudnn和cuda toolkit,那就不用管这一块,我这里演示cpu版本的安装)
  3. 下载PaddlePaddle C++ 预测库 paddle_inference
  4. 编译

内容

编译opencv

这里直接略过吧,这个没什么好说的,而且在我们上文中全流程机器视觉工程开发(三)任务前瞻 - 从opencv的安装编译说起,到图像增强和分割

我们已经完成了opencv的安装和配置,这里就不多说了

下载cuda库

这里由于使用的是CPU版本的推理库,所以这里也直接略过。

下载推理库paddle_inference

在这里插入图片描述

下载安装预测库

下载后解压即可,找个地方摆好备用。

  1. 编译

编译的时候找到PaddleDetection库下的 \PaddleDetection\deploy\cpp 目录
在这里插入图片描述
使用CMake GUI打开这个文件夹,会有很多地方爆红,按照文档中给定的要求填就可以了

在这里插入图片描述在这里插入图片描述
由于我这里没有用CUDA,所以只用填OPencv_dir和paddle_dir即可,如果你不想每次都填,可以直接改写cpp文件夹下的CMakeList.txt

将11 -17行中改成你想要的,比如我下面的改法:


option(WITH_MKL        "Compile demo with MKL/OpenBlas support,defaultuseMKL."          ON)
#我这里不开GPU,所以这个改成off
option(WITH_GPU        "Compile demo with GPU/CPU, default use CPU."                    OFF)
option(WITH_TENSORRT   "Compile demo with TensorRT."                                    OFF)option(WITH_KEYPOINT        "Whether to Compile KeyPoint detector"                    OFF)
option(WITH_MOT       "Whether to Compile MOT detector" OFF)#SET(PADDLE_DIR "" CACHE PATH "Location of libraries")
#SET(PADDLE_LIB_NAME "" CACHE STRING "libpaddle_inference")
#SET(OPENCV_DIR "" CACHE PATH "Location of libraries")
#SET(CUDA_LIB "" CACHE PATH "Location of libraries")
#SET(CUDNN_LIB "" CACHE PATH "Location of libraries")
#SET(TENSORRT_INC_DIR "" CACHE PATH "Compile demo with TensorRT")
#SET(TENSORRT_LIB_DIR "" CACHE PATH "Compile demo with TensorRT")
SET(PADDLE_DIR "D:\\WorkShop\\Python\\paddle_inference")
SET(PADDLE_LIB_NAME "paddle_inference")
SET(OPENCV_DIR "C:\\Program Files (x86)\\opencv")
include(cmake/yaml-cpp.cmake)include_directories("${CMAKE_SOURCE_DIR}/")
include_directories("${CMAKE_CURRENT_BINARY_DIR}/ext/yaml-cpp/src/ext-yaml-cpp/include")
link_directories("${CMAKE_CURRENT_BINARY_DIR}/ext/yaml-cpp/lib")

重新在gui里面configure一下这个工程,就会变成这样:

在这里插入图片描述
点击generate,就在build 文件夹下生成了工程
在这里插入图片描述

在这里插入图片描述

这时候直接build一下总的解决方案就可以了

常见错误

未定义标识符CV_xxxx_xxxx

这个是因为在opencv新版本中将这些标识符都改名了,现在将这些未定义的标识符从CV_xxx_xxx改成cv::xxx_xxx即可,比如:
在这里插入图片描述
改为:
在这里插入图片描述
把报错的地方都改一下就可以了

无法打开源文件 “yaml-cpp/yaml.h”

这个是main工程里的CMakeList.txt的问题,将25行左右按照如下修改一下就可以了:

# 尽量不要用CMAKE_CURRENT_BINARY_DIR,改用CMAKE_BINARY_DIR
#include_directories("${CMAKE_CURRENT_BINARY_DIR}/ext/yaml-cpp/src/ext-yaml-cpp/include")
message(STATUS ".123123${CMAKE_BINARY_DIR}/ext/yaml-cpp/src/ext-yaml-cpp/include")
include_directories(${CMAKE_BINARY_DIR}/ext/yaml-cpp/src/ext-yaml-cpp/include)
#link_directories("${CMAKE_CURRENT_BINARY_DIR}/ext/yaml-cpp/lib")
link_directories(${CMAKE_BINARY_DIR}/ext/yaml-cpp/lib)

无法找到libyaml-cppmt.lib

请使用Release编译,貌似这个库不支持debug编译,因为这里引用似乎没有引用libyaml-cppmtd.lib

修改

我们现在就编译过了这个库,但是现在编译完成的结果其实还有个问题,那就是这玩意还是个exe,当然了我并不需要exe,我希望我的东西是个dll,这样就可以集成到别的项目去了。

这里提一嘴,我这里编译出来的库没有用CMake管理,因为接口比较简单,所以就是直接用windows的那种lib+dll的形式导出的,没有让 cmake直接管理。因为用CMake直接管理引用的话,会比较麻烦,容易造成一些不必要的问题。用静态链接的方式的话,反正直接链接上去掉接口就完了,只要头文件里面不要包含paddle的东西,管你内容是什么呢?

我这里给main函数添加了一个头文件:


//extern "C" __declspec(dllexport) int  main_test();
#include <iostream>
#include <vector>
extern "C" __declspec(dllexport) int add(int a, int b);int add(int a, int b) {return a + b;
}
struct ObjDetector {std::string model_dir;const std::string device = "CPU";bool use_mkldnn = false; int cpu_threads = 1;std::string run_mode = std::string("paddle");int batch_size = 1; int gpu_id = 0;int trt_min_shape = 1;int trt_max_shape = 1280;int trt_opt_shape = 640;bool trt_calib_mode = false;
};using namespace std;class __declspec(dllexport) Lev_ModelInfer
{public:void PrintBenchmarkLog(std::vector<double> det_time, int img_num);static string DirName(const std::string& filepath);static bool PathExists(const std::string& path);static void MkDir(const std::string& path);static void MkDirs(const std::string& path);void GetAllFiles(const char* dir_name, std::vector<std::string>& all_inputs);//void PredictVideo(const std::string& video_path, PaddleDetection::ObjectDetector* det);void PredictImage_(const std::vector<std::string> all_img_paths,const int batch_size,const double threshold,const bool run_benchmark,ObjDetector det,const std::string& output_dir = "output");
private:};

同时修改了main函数如下:

//   Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.#include "Leventure_ModelInfer.h"
#include "include/object_detector.h"
#include <glog/logging.h>#include <dirent.h>
#include <iostream>
#include <string>
#include <vector>
#include <numeric>
#include <sys/types.h>
#include <sys/stat.h>
#include <math.h>
#include <filesystem>
#ifdef _WIN32
#include <direct.h>
#include <io.h>
#elif LINUX
#include <stdarg.h>
#include <sys/stat.h>
#endif#include <gflags/gflags.h>void PrintBenchmarkLog(std::vector<double> det_time, int img_num) {
}
void Lev_ModelInfer::PrintBenchmarkLog(std::vector<double> det_time, int img_num) {PrintBenchmarkLog(det_time, img_num);
}
string Lev_ModelInfer::DirName(const std::string& filepath) {auto pos = filepath.rfind(OS_PATH_SEP);if (pos == std::string::npos) {return "";}return filepath.substr(0, pos);
}bool Lev_ModelInfer::PathExists(const std::string& path) {
#ifdef _WIN32struct _stat buffer;return (_stat(path.c_str(), &buffer) == 0);
#elsestruct stat buffer;return (stat(path.c_str(), &buffer) == 0);
#endif  // !_WIN32
}void Lev_ModelInfer::MkDir(const std::string& path) {if (PathExists(path)) return;int ret = 0;
#ifdef _WIN32ret = _mkdir(path.c_str());
#elseret = mkdir(path.c_str(), 0755);
#endif  // !_WIN32if (ret != 0) {std::string path_error(path);path_error += " mkdir failed!";throw std::runtime_error(path_error);}
}void Lev_ModelInfer::MkDirs(const std::string& path) {if (path.empty()) return;if (PathExists(path)) return;MkDirs(DirName(path));MkDir(path);
}void Lev_ModelInfer::GetAllFiles(const char* dir_name,std::vector<std::string>& all_inputs) {if (NULL == dir_name) {std::cout << " dir_name is null ! " << std::endl;return;}struct stat s;stat(dir_name, &s);if (!S_ISDIR(s.st_mode)) {std::cout << "dir_name is not a valid directory !" << std::endl;all_inputs.push_back(dir_name);return;}else {struct dirent* filename; // return value for readdir()DIR* dir;                // return value for opendir()dir = opendir(dir_name);if (NULL == dir) {std::cout << "Can not open dir " << dir_name << std::endl;return;}std::cout << "Successfully opened the dir !" << std::endl;while ((filename = readdir(dir)) != NULL) {if (strcmp(filename->d_name, ".") == 0 ||strcmp(filename->d_name, "..") == 0)continue;all_inputs.push_back(dir_name + std::string("/") +std::string(filename->d_name));}}
}//void Lev_ModelInfer::PredictVideo(const std::string& video_path,
//	PaddleDetection::ObjectDetector* det) {
//	// Open video
//	cv::VideoCapture capture;
//	if (camera_id != -1) {
//		capture.open(camera_id);
//	}
//	else {
//		capture.open(video_path.c_str());
//	}
//	if (!capture.isOpened()) {
//		printf("can not open video : %s\n", video_path.c_str());
//		return;
//	}
//
//	// Get Video info : resolution, fps
//	int video_width = static_cast<int>(capture.get(CV_CAP_PROP_FRAME_WIDTH));
//	int video_height = static_cast<int>(capture.get(CV_CAP_PROP_FRAME_HEIGHT));
//	int video_fps = static_cast<int>(capture.get(CV_CAP_PROP_FPS));
//
//	// Create VideoWriter for output
//	cv::VideoWriter video_out;
//	std::string video_out_path = "output.avi";
//	video_out.open(video_out_path.c_str(),
//		CV_FOURCC('D', 'I', 'V', 'X'),
//		video_fps,
//		cv::Size(video_width, video_height),
//		true);
//	std::cout << video_out.isOpened();
//	if (!video_out.isOpened()) {
//		printf("create video writer failed!\n");
//		return;
//	}
//
//	std::vector<PaddleDetection::ObjectResult> result;
//	std::vector<int> bbox_num;
//	std::vector<double> det_times;
//	auto labels = det->GetLabelList();
//	auto colormap = PaddleDetection::GenerateColorMap(labels.size());
//	// Capture all frames and do inference
//	cv::Mat frame;
//	int frame_id = 0;
//	bool is_rbox = false;
//	int icu = 0;
//	while (capture.read(frame)) {
//		icu += 1;
//		std::cout << icu << "frame" << std::endl;
//		if (frame.empty()) {
//			break;
//		}
//		std::vector<cv::Mat> imgs;
//		imgs.push_back(frame);
//		det->Predict(imgs, 0.5, 0, 1, &result, &bbox_num, &det_times);
//		for (const auto& item : result) {
//			if (item.rect.size() > 6) {
//				is_rbox = true;
//				printf("class=%d confidence=%.4f rect=[%d %d %d %d %d %d %d %d]\n",
//					item.class_id,
//					item.confidence,
//					item.rect[0],
//					item.rect[1],
//					item.rect[2],
//					item.rect[3],
//					item.rect[4],
//					item.rect[5],
//					item.rect[6],
//					item.rect[7]);
//			}
//			else {
//				printf("class=%d confidence=%.4f rect=[%d %d %d %d]\n",
//					item.class_id,
//					item.confidence,
//					item.rect[0],
//					item.rect[1],
//					item.rect[2],
//					item.rect[3]);
//			}
//		}
//
//		cv::Mat out_im = PaddleDetection::VisualizeResult(
//			frame, result, labels, colormap, is_rbox);
//
//		video_out.write(out_im);
//		frame_id += 1;
//	}
//	capture.release();
//	video_out.release();
//}void PredictImage(const std::vector<std::string> all_img_paths,const int batch_size,const double threshold,const bool run_benchmark,PaddleDetection::ObjectDetector* det,const std::string& output_dir) {std::vector<double> det_t = { 0, 0, 0 };int steps = ceil(float(all_img_paths.size()) / batch_size);printf("total images = %d, batch_size = %d, total steps = %d\n",all_img_paths.size(), batch_size, steps);for (int idx = 0; idx < steps; idx++) {std::vector<cv::Mat> batch_imgs;int left_image_cnt = all_img_paths.size() - idx * batch_size;if (left_image_cnt > batch_size) {left_image_cnt = batch_size;}for (int bs = 0; bs < left_image_cnt; bs++) {std::string image_file_path = all_img_paths.at(idx * batch_size + bs);cv::Mat im = cv::imread(image_file_path, 1);batch_imgs.insert(batch_imgs.end(), im);}// Store all detected resultstd::vector<PaddleDetection::ObjectResult> result;std::vector<int> bbox_num;std::vector<double> det_times;bool is_rbox = false;if (run_benchmark) {det->Predict(batch_imgs, threshold, 10, 10, &result, &bbox_num, &det_times);}else {det->Predict(batch_imgs, threshold, 0, 1, &result, &bbox_num, &det_times);// get labels and colormapauto labels = det->GetLabelList();auto colormap = PaddleDetection::GenerateColorMap(labels.size());int item_start_idx = 0;for (int i = 0; i < left_image_cnt; i++) {std::cout << all_img_paths.at(idx * batch_size + i) << "result" << std::endl;if (bbox_num[i] <= 1) {continue;}for (int j = 0; j < bbox_num[i]; j++) {PaddleDetection::ObjectResult item = result[item_start_idx + j];if (item.rect.size() > 6) {is_rbox = true;printf("class=%d confidence=%.4f rect=[%d %d %d %d %d %d %d %d]\n",item.class_id,item.confidence,item.rect[0],item.rect[1],item.rect[2],item.rect[3],item.rect[4],item.rect[5],item.rect[6],item.rect[7]);}else {printf("class=%d confidence=%.4f rect=[%d %d %d %d]\n",item.class_id,item.confidence,item.rect[0],item.rect[1],item.rect[2],item.rect[3]);}}item_start_idx = item_start_idx + bbox_num[i];}// Visualization resultint bbox_idx = 0;for (int bs = 0; bs < batch_imgs.size(); bs++) {if (bbox_num[bs] <= 1) {continue;}cv::Mat im = batch_imgs[bs];std::vector<PaddleDetection::ObjectResult> im_result;for (int k = 0; k < bbox_num[bs]; k++) {im_result.push_back(result[bbox_idx + k]);}bbox_idx += bbox_num[bs];cv::Mat vis_img = PaddleDetection::VisualizeResult(im, im_result, labels, colormap, is_rbox);std::vector<int> compression_params;compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);compression_params.push_back(95);std::string output_path = output_dir + "\\";std::string image_file_path = all_img_paths.at(idx * batch_size + bs);output_path += std::filesystem::path(image_file_path).filename().string();cv::imwrite(output_path, vis_img, compression_params);printf("Visualized output saved as %s\n", output_path.c_str());//std::string output_path(output_dir);//if (output_dir.rfind(OS_PATH_SEP) != output_dir.size() - 1) {//	output_path += OS_PATH_SEP;//}//std::string image_file_path = all_img_paths.at(idx * batch_size + bs);//output_path += image_file_path.substr(image_file_path.find_last_of('/') + 1);//cv::imwrite(output_path, vis_img, compression_params);//printf("Visualized output saved as %s\n", output_path.c_str());}}det_t[0] += det_times[0];det_t[1] += det_times[1];det_t[2] += det_times[2];}//PrintBenchmarkLog(det_t, all_img_paths.size());
}
void Lev_ModelInfer::PredictImage_(const std::vector<std::string> all_img_paths,const int batch_size,const double threshold,const bool run_benchmark,ObjDetector det,const std::string& output_dir) {PaddleDetection::ObjectDetector* model = new PaddleDetection::ObjectDetector(det.model_dir, det.device, det.use_mkldnn, det.cpu_threads, det.run_mode, det.batch_size, det.trt_min_shape, det.trt_max_shape, det.trt_opt_shape, det.trt_calib_mode);PredictImage(all_img_paths, batch_size, threshold, run_benchmark, model, output_dir);
}
//std::string model_dir;
//std::string image_file;
//std::string video_file;
//std::string image_dir;
//int batch_size = 1;
//bool use_gpu = true;
//int camera_id = -1;
//double threshold = 0.1;
//std::string output_dir = "output";
//std::string run_mode = "fluid";
//int gpu_id = 0;
//bool run_benchmark = false;
//bool use_mkldnn = false;
//double cpu_threads = 0.9;
//bool use_dynamic_shape = false;
//int trt_min_shape = 1;
//int trt_max_shape = 1280;
//int trt_opt_shape = 640;
//bool trt_calib_mode = false;
//
//int main_test() {
//	model_dir = "D:/projects/PaddleDetection/deploy/cpp/out/Release/models";
//	image_file = "D:/projects/PaddleDetection/deploy/cpp/out/Release/images/1.jpg";
//	//video_file = "bb.mp4";
//	//image_dir = "";
//  // Parsing command-line
//  //google::ParseCommandLineFlags(&argc, &argv, true);
//
//	if (model_dir.empty()
//		|| (image_file.empty() && image_dir.empty() && video_file.empty())) {
//		std::cout << "Usage: ./main --model_dir=/PATH/TO/INFERENCE_MODEL/ "
//			<< "--image_file=/PATH/TO/INPUT/IMAGE/" << std::endl;
//	}
//	if (!(run_mode == "fluid" || run_mode == "trt_fp32"
//		|| run_mode == "trt_fp16" || run_mode == "trt_int8")) {
//		std::cout << "run_mode should be 'fluid', 'trt_fp32', 'trt_fp16' or 'trt_int8'.";
//		return -1;
//	}
//	// Load model and create a object detector
//	PaddleDetection::ObjectDetector det(model_dir, use_gpu, use_mkldnn,
//		threshold, run_mode, batch_size, gpu_id, use_dynamic_shape,
//		trt_min_shape, trt_max_shape, trt_opt_shape, trt_calib_mode);
//	// Do inference on input video or image
//	MyClass predictvideo;
//	if (!video_file.empty() || camera_id != -1) {
//		predictvideo.PredictVideo(video_file, &det);
//	}
//	else if (!image_file.empty() || !image_dir.empty()) {
//		if (!predictvideo.PathExists(output_dir)) {
//			predictvideo.MkDirs(output_dir);
//		}
//		std::vector<std::string> all_imgs;
//		if (!image_file.empty()) {
//			all_imgs.push_back(image_file);
//			if (batch_size > 1) {
//				std::cout << "batch_size should be 1, when image_file is not None" << std::endl;
//				batch_size = 1;
//			}
//		}
//		else {
//			predictvideo.GetAllFiles((char*)image_dir.c_str(), all_imgs);
//		}
//		predictvideo.PredictImage(all_imgs, batch_size, threshold, run_benchmark, &det, output_dir);
//	}
//	return 0;
//}int main(int argc, char** argv) {
}

详情见本人github仓库:

添加链接描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++干货基地】C++引用与指针的区别:深入理解两者特性及选择正确应用场景

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

MYSQL的配置和安装

下载安装 打开官网 MYSQL官网 点击DOWNLOADS 滑到最低下点击&#xff1a;MYSQL Community(GPL) Downlads 点击Download Archives 点击MySQL Community Server进入网站 选择相应版本下载&#xff0c;这里选择的是5.7.24版本,x86 64位【按需选择】 下载解压 配置文件…

GitLab16.8配置webhooks、Jenkins2.4配置GitLab插件实现持续集成、配置宝塔面板实现持续部署(其三)

看本篇文章的前提是已经部署完GItlab和Jenkins服务器&#xff0c;已经可以手动构建成功&#xff0c;并且经过了很多次实践&#xff0c;对这两款软件基本熟悉。 建议大家按以下顺序看 前端自动化&#xff08;其一&#xff09;部署gitlab 前端自动化&#xff08;其二&#xff0…

LeetCode--171

171. Excel 表列序号 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 示例 1: 输入: columnTitle "A" 输出:…

设计模式⑩ :用类来实现

文章目录 一、前言二、Command 模式1. 介绍2.应用3. 总结 三、Interpreter 模式1. 介绍2. 应用3. 总结 参考文章 一、前言 有时候不想动脑子&#xff0c;就懒得看源码又不像浪费时间所以会看看书&#xff0c;但是又记不住&#xff0c;所以决定开始写"抄书"系列。本系…

【JS逆向实战-入门篇】某gov网站加密参数分析与Python算法还原

文章目录 1. 写在前面2. 请求分析3. 断点分析4. 算法还原 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣的朋…

PPT、PDF全文档翻译相关产品调研笔记

主要找一下是否有比较给力的全文档翻译 文章目录 1 百度翻译2 小牛翻译3 腾讯交互翻译4 DeepL5 languagex6 云译科技7 快翻:qtrans8 simplifyai9 officetranslator10 火山引擎翻译-无文档翻译1 百度翻译 地址: https://fanyi.baidu.com/ 配套的比较完善,对于不同行业也有区…

【大厂AI课学习笔记】1.3 人工智能产业发展(2)

&#xff08;注&#xff1a;腾讯AI课学习笔记。&#xff09; 1.3.1 需求侧 转型需求&#xff1a;人口红利转化为创新红利。 场景丰富&#xff1a;超大规模且多样的应用场景。主要是我们的场景大&#xff0c;数据资源丰富。 抗疫加速&#xff1a;疫情常态化&#xff0c;催生新…

DataX介绍

一、介绍 DataX 是一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 github地址 详细文档 操作手册 支持数据框架如下&#xff1a; 架构 Reader&#xff1…

干货!收藏!一文讲清楚数据治理到底是什么?

数据治理的两个目标&#xff1a;一个是提质量&#xff0c;一个是控安全。通过业务流程优化&#xff0c;规范数据从产生、处理、使用到销毁的整个生命周期&#xff0c;使得数据在各阶段、各流程环节安全可控&#xff0c;合规使用。 数据治理治的是“数据”吗&#xff1f; 数据是…

Ubuntu搭建国标平台wvp-GB28181-pro

目录 简介安装和编译1.查看操作系统信息2.安装最新版的nodejs3.安装java环境4.安装mysql5.安装redis6.安装编译器7.安装cmake8.安装依赖库9.编译ZLMediaKit9.1.编译结果说明 10.编译wvp-GB28181-pro10.1.编译结果说明 配置1.WVP-PRO配置文件1.1.Mysql数据库配置1.2.REDIS数据库…

GPT-5的功能界面曝光。。。

最近网络上流传的照片是否真实尚不可知&#xff0c;我们需要进一步的核实与分析。 GPT-5的预期发布已经引起了业界的极大关注。根据Roemmele的透露&#xff0c;GPT-5将是一个革命性的多模态模型&#xff0c;能够支持语音、图像、编程代码和视频等多种格式&#xff0c;这标志着…

【Linux】多线程(线程概念+线程控制)

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

负载均衡下的webshell上传+nginx解析漏洞

负载均衡下的webshell上传 一&#xff0c;负载均衡下webshell上传的四大难点 难点一&#xff1a;需要在每一台节点的相同位置上传相同内容的webshell 我们需要在每一台节点的相同位置都上传相同内容的 WebShell一旦有一台机器上没有&#xff0c;那么在请求轮到这台机器上的时…

二分查找-迭代法

Go 算法 每天5道&#xff0c;开心快乐每一天 一点都不开心 哈哈哈哈哈哈 -2.1 day 1 1.22&#xff08;1.23 1.25 1.29&#xff09; 1.23 已复习 704. 二分查找 力扣题目链接 //左闭右开 func search(nums []int, target int) int { right : len(nums) left : 0; for le…

React18-模拟列表数据实现基础表格功能

文章目录 分页功能分页组件有两种接口参数分页类型用户列表参数类型 模拟列表数据分页触发方式实现目录 分页功能 分页组件有两种 table组件自带分页 <TableborderedrowKey"userId"rowSelection{{ type: checkbox }}pagination{{position: [bottomRight],pageSi…

海外多语言盲盒App开发:机遇与挑战并存

随着全球化进程的加速&#xff0c;跨文化交流成为人们日常生活和工作中的重要部分。在此背景下&#xff0c;多语言盲盒App的开发成为了一个具有巨大潜力的市场。本文将探讨海外多语言盲盒App开发的机遇与挑战&#xff0c;以及如何应对这些挑战。 一、海外多语言盲盒App开发的机…

AI赋能编程 | 自动化工具助力高效办公

前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言泡泡AI工具卡片思维导图Markdown编辑器 其他工具文件免费处理工具结语 合集…

C++引用详解

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间…

使用 Paimon + StarRocks 极速批流一体湖仓分析

摘要&#xff1a;本文整理自阿里云智能高级开发工程师王日宇&#xff0c;在 Flink Forward Asia 2023 流式湖仓&#xff08;二&#xff09;专场的分享。本篇内容主要分为以下四部分&#xff1a; StarRocksPaimon 湖仓分析的发展历程使用 StarRocksPaimon 进行湖仓分析主要场景和…