全流程机器视觉工程开发(四)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.mzph.cn/news/666865.shtml

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

相关文章

Java八大常用排序算法

1冒泡排序 对于冒泡排序相信我们都比较熟悉了&#xff0c;其核心思想就是相邻元素两两比较&#xff0c;把较大的元素放到后面&#xff0c;在一轮比较完成之后&#xff0c;最大的元素就位于最后一个位置了&#xff0c;就好像是气泡&#xff0c;慢慢的浮出了水面一样 Jave 实现 …

2024 RTE行业(实时互动行业)人才发展学习总结

解决方案 人才画像 开发者人才素质要求&#xff1a; 具备多个领域的技术知识注重团队合作&#xff0c;具备协作能力以用户为导向的用户体验意识具备创新思维和解决问题的能力需快速响应行业变化和持续的学习能力具备项目管理能力 学习和吸收新知识的渠道 RTE人才分类

操作系统透视:从历史沿革到现代应用,剖析Linux与网站服务架构

目录 操作系统 windows macos Linux 服务器搭建网站 关于解释器的流程 curl -I命令 名词解释 dos bash/terminal&#xff0c;(终端) nginx/apache&#xff08;Linux平台下的&#xff09; iis&#xff08;Windows平台下的&#xff09; GUI(图形化管理接口&#xff…

【51单片机系列】应用设计——8路抢答器的设计

51单片机应用——8路抢答器设计 文章设计文件及代码&#xff1a;资源链接。 文章目录 要求&#xff1a;设计思路软件设计仿真结果 要求&#xff1a; &#xff08;1&#xff09; 按下”开始“按键后才开始抢答&#xff0c;且抢答允许指示灯亮&#xff1b; &#xff08;2&…

聚道云软件连接器助力餐饮企业实现数字化管理

客户介绍 某餐饮有限责任公司是一家历史悠久、口碑良好的连锁餐饮公司。公司总部位于北京市&#xff0c;拥有多家门店&#xff0c;覆盖了北京市内的各个区域。每家门店都以独特的装修风格和优雅的环境为顾客营造温馨舒适的用餐氛围。作为一家知名的连锁餐饮公司&#xff0c;在…

过好“苏州年”!沉浸式名城非遗文化体验展 2月10日正式启幕

擦亮非遗文化底色&#xff0c;绘就历史文化名城金名片 天工开画卷&#xff0c;苏作见匠心&#xff0c;在2024龙年到来之际&#xff0c;“匠海拾遗-沉浸式名城非遗文化体验展” 将于2月10日在江苏省省级文物保护单位——江苏按察使署旧址内举办。此次非物质文化遗产&#xff08;…

记录Git无法连接Github(443报错)的一种可能——代理问题

参考文章&#xff1a; Git安装配置与使用&#xff08;超级详细&#xff09;_git配置-CSDN博客 github代理报错_valueerror: unable to determine socks version from-CSDN博客 速通 如果在使用 git 时遇到了这样的报错&#xff1a; OpenSSL SSL_connect: SSL_ERROR_SYSCAL…

机器学习周报第二十八周 PINNs2

文章目录 week28 PINNs2摘要Abstract一、Lipschitz条件二、文献阅读1. 题目数据驱动的偏微分方程2. 连续时间模型3. 离散时间模型4.结论 三、CLSTM1. 任务要求2. 实验结果3. 实验代码3.1模型构建3.2训练过程代码 小结参考文献 week28 PINNs2 摘要 本文主要讨论PINN。本文简要…

机器学习 | 解析聚类算法在数据检测中的应用

目录 初识聚类算法 聚类算法实现流程 模型评估 算法优化 特征降维 探究用户对物品类别的喜好细分(实操) 初识聚类算法 聚类算法是一种无监督学习方法&#xff0c;用于将数据集中的对象按照相似性分组。它旨在发现数据中的内在结构和模式&#xff0c;将具有相似特征的数据…

MySQL进阶之锁(行锁,间隙锁,临键锁)

行级锁 介绍 行级锁&#xff0c;每次操作锁住对应的行数据。锁定粒度最小&#xff0c;发生锁冲突的概率最低&#xff0c;并发度最高。应用在 InnoDB存储引擎中。 InnoDB的数据是基于索引组织的&#xff0c;行锁是通过对索引上的索引项加锁来实现的&#xff0c;而不是对记录加…

Linux——权限管理

1、ACL权限 在普通权限中&#xff0c;用户对文件只有三种身份&#xff0c;就是属主、属组和其他人&#xff1b;每种用户身份拥有读&#xff08;read&#xff09;、写&#xff08;write&#xff09;和执行&#xff08;execute&#xff09;三种权限。但是在实际工作中&#xff0…

uniapp使用u-popup组件弹窗出现页面还可滑动

*1、问题所在&#xff1a; 弹窗遮罩层出现了页面依旧可以上下滑动 2、要求: 为了用户更好交互体验&#xff0c;弹窗出现后应禁止页面往下滑动 3、实现思路&#xff1a; 在弹窗盒子外层添加个阻止触摸冒泡事件&#xff0c;使用touchmove.stop.prevent 4、代码如下&#xff…

Django学习记录01

1.项目结构 djangoProject02 ├── manage.py 【项目的管理&#xff0c;启动项目、创建app、数据管理】【不要动】【常常用】 └── jangoProject02 ├── __init__.py ├── settings.py 【项目配置】 【常常修改】 ├── urls.py …

软件IIC读取MPU6050

软件IIC读取MPU6050 最终现象一、GY-521 MPU6050三维角度传感器简介二、程序分析1、mpu6050.c2、MPU6050_reg.h 最终现象 一、GY-521 MPU6050三维角度传感器简介 一共八个引脚&#xff0c;一般只用到四个&#xff0c;其余的我也没有试过。 VCC、GND分别接5V电源和地&#xff1b…

如何用ETL工具实现API调用

一、API调用的好处 API调用有很多好处&#xff0c;下面列举了几个主要的优势&#xff1a; 模块化和可重用性&#xff1a;API调用使得软件开发过程更加模块化和可用。通过将功能封装在API中&#xff0c;可以将其用作独立的模块&#xff0c;并在不同的应用程序或系统中进行重复使…

父类之王“Object”类和内部类

&#x1f468;‍&#x1f4bb;作者简介&#xff1a;&#x1f468;&#x1f3fb;‍&#x1f393;告别&#xff0c;今天 &#x1f4d4;高质量专栏 &#xff1a;☕java趣味之旅 欢迎&#x1f64f;点赞&#x1f5e3;️评论&#x1f4e5;收藏&#x1f493;关注 &#x1f496;衷心的希…

NLP深入学习:《A Survey of Large Language Models》详细学习(一)

文章目录 1. 前言2. 摘要部分3. 引言部分4. Overview 部分4.1 LLMs 背景4.2 GPT 系列模型的技术演变 5. 参考 1. 前言 最近正在读这边 LLM 论文的综述&#xff0c;鉴于读得费劲&#xff0c;如果将整个论文读完再来写会比较费劲。当前采取的策略是部分内容走读记录&#xff0c;…

3 编辑器(Vim)

1.完成 vimtutor。备注&#xff1a;它在一个 80x24&#xff08;80 列&#xff0c;24 行&#xff09; 终端窗口看起来效果最好。 2.下载我们提供的 vimrc&#xff0c;然后把它保存到 ~/.vimrc。 通读这个注释详细的文件 &#xff08;用 Vim!&#xff09;&#xff0c; 然后观察 …

ref和reactive, toRefs的使用

看尤雨溪说&#xff1a;为什么Vue3 中应该使用 Ref 而不是 Reactive&#xff1f; toRefs import { ref, toRefs } from vue;// 定义一个响应式对象 const state ref({count: 0,name: Vue });// 使用toRefs转换为响应式引用对象 const reactiveState toRefs(state);// 现在你…

深入理解TCP网络协议(3)

目录 1.前言 2.流量控制 2.阻塞控制 3.延时应答 4.捎带应答 5.面向字节流 6.缓冲区 7.粘包问题 8.TCP异常情况 9.小结 1.前言 在前面的博客中,我们重点介绍了TCP协议的一些属性,有连接属性的三次握手和四次挥手,还有保证数据安全的重传机制和确认应答,还有为了提高效率…