当前位置: 首页 > article >正文

RK3588部署YOLOv8(2):OpenCV和RGA实现模型前处理对比

目录

前言

1. 结果对比

1.1 时间对比

1.2 CPU和NPU占用对比

2. RGA实现YOLO前处理

2.1 实现思路

2.2 处理类的声明

2.3 处理类的实现

总结


前言

RK平台上有RGA (Raster Graphic Acceleration Unit) 加速,使用RGA可以减少资源占用、加速图片处理速度。因此,在部署YOLOv8是针对RGA和OpenCV的分别进行了实现,并对性能、速度和资源占用进行对比。


1. 结果对比

1.1 时间对比

总共跑100次计算平均时间。

纯OpenCV实现:

OPencv实现resize+pad
[Convert] Step1: Check input pointer => 0 us
[Convert] Step2: define intermediate Mat => 37 us
[Convert] Step3: cv::resize => 9564 us
[Convert] Step4: create pad_img => 1629 us
[Convert] Step5: compute position => 61 us
[Convert] Step6: copyTo => 340 us
[Convert] Step7: return => 54 us
INFO: image resize time 12.15 ms
INFO: total infer time 22.71 ms: model time is 22.45 ms and postprocess time is 0.26ms
Iteration 100 - time: 35.034000 ms
Total execution time: 3770.930000 ms
Average execution time: 37.709300 ms

纯RGA实现:

RGA实现
[Convert] Step1: Check input pointer => 1 us
[Convert] Step2: Set format/bpp => 92 us
[Convert] Step3: Calculate buffer sizes => 13 us
[Convert] Step4: Define variables => 12 us
[Convert] Step5: Compute border => 13 us
[Convert] Step6: Alloc & memcpy src => 10048 us
[Convert] Step7: Alloc resized buffer => 477 us
[Convert] Step8: Alloc dst buffer => 269 us
[Convert] Step9: importbuffer_fd => 3494 us
[Convert] Step10: wrapbuffer_handle => 80 us
[Convert] Step11: imresize => 2714 us
[Convert] Step12: immakeBorder => 1154 us
[Convert] Step13: copy result => 428 us
[Convert] Step14: cleanup => 2607 us
INFO: image resize time 24.26 ms
INFO: total infer time 22.10 ms: model time is 21.84 ms and postprocess time is 0.26ms
Iteration 100 - time: 46.496000 ms
Total execution time: 4398.143000 ms
Average execution time: 43.981430 ms

总结:

(1)从上可以看到OpenCV最占时间的是resize步骤,需要9~10ms,而RGA只要2~3ms。

(2)但使用RGA,如果图片数据不在DMA缓冲区,则需要进行拷贝,导致耗时太久。

(3)最终,导致RGA实现resize要比OpenCV慢了6~7ms。

1.2 CPU和NPU占用对比

跑单个模型持续推理。

纯OpenCV实现:

CPU占用率:120%~140%

NPU占用率:43%~48%

纯RGA实现:

CPU占用率:50%~60%

NPU占用率:35%~40%

总结:

(1)OPenCV使用CPU多线程计算差值,导致CPU占用率较高

(2)RGA在DMA缓冲区使用硬件计算,减少对CPU依赖。

(3)RGA比OpenCV减少了60%的CPU占用和10%的NPU占用。


2. RGA实现YOLO前处理

参考代码:

[1] https://github.com/airockchip/librga

[2] rga_resize_demo.cpp

[3] rga_padding_demo.cpp

2.1 实现思路

        在DMA缓冲区,每有一个形状,便需要一个CPU指针、句柄和缓冲区,导致分配内存、处理起来极其麻烦,且宽度需要16倍对齐(高度没有要求)、同时还存在着4G范围寻址问题。所以,实际应用要起来还是很麻烦的(尤其是自定义的任意尺寸输入)。

        所以,这里仅使用RGA对合规的图片做resize,再使用OpenCV做pad填充。

        由于工资预算有限,这里仅实现摄像头输入的原图尺寸(宽度满足16倍长,主要以1920×1080为主)的图片的前处理。

补充(实现任意尺寸处理的思路):

(1) 设传入的宽和高为:[H,W],目标宽高(模型输入大小)为:[H_T, W_T],INT_UP表示向上取整函数。
(2) 原16倍宽度 W_16 为: INT_UP(W / 16) * 16,则现将原图先填充(仅右边填充)到尺寸[H, W_16]。
(3) 计算放缩比 R = min(H / H_T, W_16 / W_t)。
(4) 继续计算得到目标放缩尺寸宽度的16倍 W_T_16 为:INT_UP(W_T_16 / 16) * 16。
(5) 然后更新放缩比 R = min(H / H_T, W_T_16 / R / W_T),此过程可能需要迭代。
(6) 得到放缩比 R 后,计算原图真正要填充到的尺寸为:[H_T / R, W_T_16 / R]。
(7) 然后对原图仅做右边和下面的填充,这样就把原图对齐到16倍长(放缩前后均是)。

2.2 处理类的声明

#include <iostream>
#include <memory>
#include <numeric>
#include <vector>
#include <algorithm>
#include "opencv2/opencv.hpp"
#include "common.h"
// 增加RGA库实现pad resize
#include <rga/RgaApi.h>
#include <rga/im2d.hpp>
#include <rga/rga.h>
#include <rga/RgaUtils.h>
#include <dma/dma_alloc.h>
// 打印时间
#include <sys/time.h>
#include <stdint.h>
#include <stdio.h>// RGA 版本的 Pad Resize 处理类
class ImagePreProcessRGA {public:// 构造函数:输入图像为 width x height,目标尺寸为正方形 target_size x target_sizeImagePreProcessRGA(int width, int height, int target_size);// 构造函数:输入图像为 width x height,目标尺寸为 target_width x target_heightImagePreProcessRGA(int width, int height, int target_width, int target_height);// 对输入图像数据进行pad resize处理,返回处理后的图像数据(unique_ptr管理)std::unique_ptr<uint8_t[]> Convert(const det_model_input& input);// 获取letterbox信息const letterbox_t &get_letter_box() { return letterbox_; }private:double scale_;  // 缩放比例int input_width_, input_height_;            // 输入图像尺寸int real_input_width_, real_input_height_;  // 输入的实际尺寸int target_width_, target_height_;          // 目标图像尺寸int new_width_, new_height_;                // 缩放后图像的尺寸(填输入的尺寸缩放后,经过填充才能变成目标尺寸)int padding_x_, padding_y_;                 // pad的总尺寸(左右、上下)letterbox_t letterbox_;     // letterbox信息记录缩放比例及左右/上下填充(一般为居中填充)
};

2.3 处理类的实现

        实现RGB的3通道或者4通道的图片。

// 构造函数1:只传一个target_size,默认目标是正方形
ImagePreProcessRGA::ImagePreProcessRGA(int width, int height, int target_size): input_width_(width), input_height_(height), target_width_(target_size), target_height_(target_size){// ------------------【Step1:根据最大边计算放缩比例】---------------------// 如果原图是 (width x height),目标是 (target_size x target_size),则 scale = target_size / max(width, height)scale_ = static_cast<double>(target_size) / std::max(input_width_, input_height_);// ------------------【Step2:计算缩放后尺寸】----------------------------new_width_  = static_cast<int>(input_width_  * scale_);new_height_ = static_cast<int>(input_height_ * scale_);// ------------------【Step3:计算在目标图像中的剩余填充】------------------padding_x_ = target_size - new_width_;padding_y_ = target_size - new_height_;// ------------------【Step4:更新 letterbox】--------------------------letterbox_.scale = scale_;letterbox_.x_pad = padding_x_ / 2;letterbox_.y_pad = padding_y_ / 2;// ------------------【可选:打印结果】-----------------------------------// printf(">>> After => new_width_=%d, new_height_=%d, scale=%.3f\n", new_width_, new_height_, scale_);// printf(">>> padding_x_=%d, padding_y_=%d\n", padding_x_, padding_y_);
}// 构造函数2:传入独立的target_width和target_height,可能目标不是正方形
ImagePreProcessRGA::ImagePreProcessRGA(int width, int height, int target_width, int target_height): input_width_(width), input_height_(height), target_width_(target_width), target_height_(target_height){// ------------------【Step1:分别计算宽高缩放比例】-----------------------double width_scale  = static_cast<double>(target_width_)  / input_width_;double height_scale = static_cast<double>(target_height_) / input_height_;// 取较小的缩放比例scale_ = std::min(width_scale, height_scale);// ------------------【Step2:计算缩放后尺寸】----------------------------new_width_  = static_cast<int>(input_width_  * scale_);new_height_ = static_cast<int>(input_height_ * scale_);// ------------------【Step3:计算填充大小】------------------------------padding_x_ = target_width_  - new_width_;padding_y_ = target_height_ - new_height_;// ------------------【Step4:更新 letterbox】---------------------------letterbox_.scale = scale_;letterbox_.x_pad = padding_x_ / 2;letterbox_.y_pad = padding_y_ / 2;// ------------------【可选:打印结果】-----------------------------------// printf(">>> After => new_width_=%d, new_height_=%d, scale=%.3f\n", new_width_, new_height_, scale_);// printf(">>> padding_x_=%d, padding_y_=%d\n", padding_x_, padding_y_);
}// 核心函数:基于RGA对输入图像进行pad resize,并返回处理后的图像数据
std::unique_ptr<uint8_t[]> ImagePreProcessRGA::Convert(const det_model_input& input){// -------------------【Step0:在函数开头声明所有变量】-------------------// 中间处理函数返回值int ret = 0;// DMA fdint src_dma_fd     = -1;int resized_dma_fd = -1;// CPU指针uint8_t *src_buf     = nullptr;uint8_t *resized_buf = nullptr;// RGA handlerga_buffer_handle_t src_handle     = 0;rga_buffer_handle_t resized_handle = 0;// RGA bufferrga_buffer_t rga_src;rga_buffer_t rga_resized;memset(&rga_src, 0, sizeof(rga_src));memset(&rga_resized, 0, sizeof(rga_resized));// 最终的返回结果std::unique_ptr<uint8_t[]> final_data;// 其他局部变量int bpp_src    = 0;int bpp_dst    = 3;  // 目标一定3通道int src_format = 0;int dst_format = RK_FORMAT_RGB_888;// 源图大小和resize后大小int src_size     = 0;  int resized_size = 0;  // 用于 pad 的边界int left=0, right=0, top=0, bottom=0;// 常用114作为灰度cv::Scalar pad_color(114,114,114);// -------------------【Step1:基础检查】------------------------------------if (!input.data || input.width <= 0 || input.height <= 0 || (input.channel != 3 && input.channel != 4)){fprintf(stderr, "ERROR: invalid input data or channel.\n");return nullptr;}// 根据通道数决定 bpp & formatbpp_src    = (input.channel == 4) ? 4 : 3;src_format = (input.channel == 4) ? RK_FORMAT_RGBA_8888 : RK_FORMAT_RGB_888;// 源图大小src_size   = input.width  * input.height  * bpp_src;// resize后大小int out_size_w = new_width_;   // 由构造函数算好int out_size_h = new_height_;  // 由构造函数算好resized_size = out_size_w * out_size_h * bpp_dst;std::unique_ptr<uint8_t[]> resized_cpu(new uint8_t[resized_size]);// 用于后面 OpenCV padleft   = padding_x_ / 2;right  = padding_x_ - left;top    = padding_y_ / 2;bottom = padding_y_ - top;// -------------------【Step2:分配 src_buf, resized_buf】-------------------ret = dma_buf_alloc(DMA_HEAP_DMA32_PATH, src_size, &src_dma_fd, (void**)&src_buf);if (ret < 0 || !src_buf) {fprintf(stderr, "ERROR: alloc src_buf failed.\n");return nullptr;}ret = dma_buf_alloc(DMA_HEAP_DMA32_PATH, resized_size, &resized_dma_fd, (void**)&resized_buf);if (ret < 0 || !resized_buf) {fprintf(stderr, "ERROR: alloc resized_buf failed.\n");goto cleanup;}// 不考虑16对齐等,只做最原始的 YOLO思路。只需将 input.data 拷贝到 src_bufmemcpy(src_buf, input.data, src_size);// -------------------【Step3:import & wrap】-------------------------------src_handle     = importbuffer_fd(src_dma_fd,     src_size);resized_handle = importbuffer_fd(resized_dma_fd, resized_size);if (!src_handle || !resized_handle) {fprintf(stderr, "ERROR: importbuffer_fd failed.\n");ret = -1;goto cleanup;}rga_src     = wrapbuffer_handle(src_handle,     input.width,  input.height,  src_format);rga_resized = wrapbuffer_handle(resized_handle, out_size_w,   out_size_h,    dst_format);// -------------------【Step4:RGA仅做 resize or color convert+resize】-------------------if (input.channel == 4) {// RGBA => color convert => resizedIM_STATUS st_cvt = imcvtcolor(rga_src, rga_resized, RK_FORMAT_RGBA_8888, RK_FORMAT_RGB_888);if (st_cvt != IM_STATUS_SUCCESS) {fprintf(stderr, "ERROR: imcvtcolor failed: %s.\n", imStrError(st_cvt));ret = -1;goto cleanup;}}else {// channel=3 => 直接 resizeIM_STATUS st_resize = imresize(rga_src, rga_resized, 0, 0, INTER_LINEAR);if (st_resize != IM_STATUS_SUCCESS) {fprintf(stderr, "ERROR: imresize failed: %s.\n", imStrError(st_resize));ret = -1;goto cleanup;}}// -------------------【Step5:将 resized_buf 拷回 CPU】-------------------// 拿到 resize 后的 RGB 图像数据memcpy(resized_cpu.get(), resized_buf, resized_size);// -------------------【Step6:用OpenCV进行 pad】-------------------{// 1) 构造一个 cv::Mat 指向 resized_cpucv::Mat resized_mat(new_height_, new_width_, CV_8UC3, resized_cpu.get());// 2) 构造一个 pad_mat (target_height_ x target_width_),初始颜色(114,114,114)cv::Mat pad_mat(target_height_, target_width_, CV_8UC3, pad_color);// 3) 计算在 pad_mat 中的放置位置// left=padding_x_/2, top=padding_y_/2cv::Rect roi(left, top, resized_mat.cols, resized_mat.rows);// 4) 拷贝 resized_mat 到 pad_mat 对应区域resized_mat.copyTo(pad_mat(roi));// 5) 将 pad_mat 拷到 final_dataint final_size = target_width_ * target_height_ * 3; // 3通道final_data.reset(new uint8_t[final_size]);memcpy(final_data.get(), pad_mat.data, final_size);}cleanup:// -------------------【Step7:释放资源】-------------------if (src_handle)     releasebuffer_handle(src_handle);if (resized_handle) releasebuffer_handle(resized_handle);if (src_buf)     dma_buf_free(src_size,   &src_dma_fd,     src_buf);if (resized_buf) dma_buf_free(resized_size,&resized_dma_fd, resized_buf);// 若 ret!=0, 返回 nullptrif (ret != 0) {return nullptr;}// 否则返回 final_data,即 "pad后" 的图像return final_data;
}

总结

这样实现资源占用还是约等于纯RGA实现,在推理单张图的时候,速度还可能更快一些:

RGA-resize+OpenCV-pad:
>>> After => new_width_=640, new_height_=360, scale=0.333
>>> padding_x_=0, padding_y_=24
[Convert] Step1: check => 9 usOriginal Input => width=1920, height=1080, channel=3Resize => new_width_=640, new_height_=360Pad => target_width_=640, target_height_=384
[Convert] Step2: alloc => 187 us
[Convert] StepFILL => copy input => 6220800 bytes
[Convert] StepFILL => 1709 us
rga_api version 1.10.1_[0]
[Convert] Step3: wrap => src=(1920x1080), resized=(640x360)
[Convert] Step3 => 892 us
[Convert] Step4: imresize => done
[Convert] Step4 => 2294 us
[Convert] Step5: copy resized => 691200 bytes
[Convert] Step5 => 543 us
[Convert] Step6: OpenCV pad => final_size=737280
[Convert] Step6 => 1314 us
[Convert] Step7: cleanup => 648 us
INFO: image resize time 7.64 ms
INFO: total infer time 28.11 ms: model time is 27.93 ms and postprocess time is 0.18ms
Iteration 1 - time: 35.846000 ms
Total execution time: 35.846000 ms
Average execution time: 35.846000 msOpenCV:
INFO: image resize time 9.49 ms
INFO: total infer time 23.12 ms: model time is 23.09 ms and postprocess time is 0.03ms
Iteration 1 - time: 32.688000 ms

相关文章:

RK3588部署YOLOv8(2):OpenCV和RGA实现模型前处理对比

目录 前言 1. 结果对比 1.1 时间对比 1.2 CPU和NPU占用对比 2. RGA实现YOLO前处理 2.1 实现思路 2.2 处理类的声明 2.3 处理类的实现 总结 前言 RK平台上有RGA (Raster Graphic Acceleration Unit) 加速&#xff0c;使用RGA可以减少资源占用、加速图片处理速度。因此…...

打造智能钉钉机器人:借助智谱GLM-4-Flash实现高效智能回复(文末附源码)

文章目录 前言一、准备工作&#xff08;一&#xff09;钉钉机器人&#xff08;二&#xff09;智谱 GLM-4-Flash&#xff08;三&#xff09;内网穿透工具 cpolar&#xff08;四&#xff09;需要准备的工具和环境 二、钉钉机器人的创建与配置步骤1&#xff1a;创建钉钉机器人步骤…...

使用Mermaid语法绘制的C语言程序从Linux移植到Windows的流程图

以下是使用Mermaid语法绘制的C语言程序从Linux移植到Windows的流程图&#xff1a; graph TDA[开始移植] --> B[代码兼容性检查]B --> C[检查系统调用差异\nfork/exec -> CreateProcess]B --> D[检查文件路径格式\n/ vs \\]B --> E[检查依赖库兼容性\nPOSIX vs …...

入门到入土,Java学习 day16(算法1)

利用循环遍历来判断是否相等 二分查找/折半查找 前提条件&#xff1a;数组中的数据有序 每次排除一般的查找范围 用min,max,mid来处理&#xff0c;最大加最小除2&#xff0c;比较&#xff0c;然后得到在中间左边还是右边然后更新最大最小 public class Two {// 二分查找方法…...

Vulnhub 靶机 VulnOSv2 write up opendocman cms 32075 sql注入 账号密码 ssh连接 37292.c 脏牛提权

Vulnhub 靶机 VulnOSv2 write up opendocman cms 32075 sql注入 账号密码 ssh连接 37292.c 脏牛提权 一、信息收集 1、首先拿到靶场先扫一下ip arp-scan -l 3、 2、指纹扫描 nmap -sS -sV 192.168.66.178nmap -p- -sV -A 192.168.66.253 PORT STATE SERVICE VERSION 22…...

Unity辅助工具_头部与svn

Unity调用者按钮增加PlaySideButton using QQu; using UnityEditor; using UnityEngine; [InitializeOnLoad] public class PlaySideButton {static PlaySideButton(){UnityEditorToolbar.RightToolbarGUI.Add(OnRightToolbarGUI);UnityEditorToolbar.LeftToolbarGUI.Add(OnLe…...

2025最新Postman、Apipost和Apifox API 协议与工具选择方案解析

作为一个一个每天和 API“打交道”的全栈开发者&#xff0c;我的日常就是在一堆请求回应之间探寻系统间的“沟通艺术”。熟悉 API 的各种协议和工具&#xff0c;几乎成了我的谋生技能。今天&#xff0c;我就把自己积累多年的“血泪教训”和经验打包成一篇文章&#xff0c;献给和…...

ARM SVC指令

在 ARM 汇编中&#xff0c;SVC&#xff08;Supervisor Call&#xff09;指令用于从用户模式切换到特权模式&#xff08;如 Supervisor 模式&#xff09;&#xff0c;以便执行操作系统内核提供的服务。它通常用于系统调用。 具体作用 触发异常&#xff1a;执行 SVC 指令时&…...

MicroPython 智能硬件开发完整指南

第一部分&#xff1a;MicroPython 基础 1. MicroPython简介 定义&#xff1a;专为微控制器设计的精简Python 3实现&#xff0c;支持硬件直接操作。特点&#xff1a; 语法兼容Python 3&#xff0c;但移除复杂功能&#xff08;如多线程&#xff09;。支持GPIO、PWM、I2C、SPI等…...

DeepLabv3+改进8:在主干网络中添加SIM注意力机制|助力涨点

🔥【DeepLabv3+改进专栏!探索语义分割新高度】 🌟 你是否在为图像分割的精度与效率发愁? 📢 本专栏重磅推出: ✅ 独家改进策略:融合注意力机制、轻量化设计与多尺度优化 ✅ 即插即用模块:ASPP+升级、解码器 PS:订阅专栏提供完整代码 论文简介 在本文中,我们提出了…...

vue-cli3+vue2+elementUI+avue升级到vite+vue3+elementPlus+avue总结

上一个新公司接手了一个vue-cli3vue2vue-router3.0elementUI2.15avue2.6的后台管理项目&#xff0c;因为vue2在2023年底已经不更新维护了&#xff0c;elementUI也只支持到vue2&#xff0c;然后总结了一下vue3的优势&#xff0c;最后批准升级成为了vitevue3vue-router4.5element…...

电路原理(电容 集成电路NE555)

电容 1.特性&#xff1a;充放电&#xff0c;隔直流&#xff0c;通交流 2.电容是通过聚集正负电荷来存储电能的 3.电容充放电过程可等效为导通回路 4.多电容并联可以把容量叠加&#xff0c;但是多电容串联就不会&#xff0c;只会叠加电容的耐压值。 6.电容充放电时相当于通路&a…...

QEMU源码全解析 —— 块设备虚拟化(2)

接前一篇文章:QEMU源码全解析 —— 块设备虚拟化(1) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM源码解析与应用》 —— 李强,机械工业出版社 特此致谢! 上一回讲解了几种虚拟化方式(全虚拟化、半虚拟化和硬件辅助虚拟化)的优缺点及其对比…...

[C++面试] 对通透比较器了解多少?(较少涉及,可跳过)

一、入门 1、什么是比较器 在 C 中&#xff0c;比较器是一个可调用对象&#xff08;函数、函数对象或 Lambda 表达式&#xff09;&#xff0c;用于定义元素之间的比较规则。 用途&#xff1a;通常作为参数传递给标准库中的排序函数或关联容器&#xff0c;以指定元素的顺序。…...

nslookup的使用

nslookup 是一个网络管理命令行工具&#xff0c;用于查询域名系统 (DNS) 服务器来获取有关主机名和IP地址的信息。它可以帮助你检查DNS记录、解析域名到IP地址或者执行反向查找&#xff08;从IP地址找到对应的域名&#xff09;。下面是 nslookup 的一些基本用法&#xff1a; 基…...

ES5 vs ES6:JavaScript 演进之路

ES5 vs ES6&#xff1a;JavaScript 演进之路 JavaScript版本演进ES5 (ECMAScript 5)ES6 (ECMAScript 2015)版本演进时间线为什么ES6如此重要&#xff1f; ES5 vs ES61. 变量声明对比2. 函数特性对比3. 类和对象4. 模块化5. 解构和展开6. 字符串和模板字面量7. 数组和对象新方法…...

函数式编程的核心

函数式编程 函数式编程&#xff08;funcitonal programming&#xff09;其实是个很古老的概念。 高阶函数和内存分析 函数式一阶公民 函数式编程最鲜明的特点就是&#xff1a;函数式一等公民&#xff0c;指的是函数与其他数据类型一样&#xff0c;处于平等地位&#xff0c;可…...

【易康eCognition实验教程】006:在影像上添加文本

在某些情况下&#xff0c;希望能在影像上面显示文本文字&#xff0c;例如&#xff0c;一个地图的名称或者是多时相影像分析的年或月的显示。此外&#xff0c;文本如果作为一个规则集导出的部分则可以被纳入数字影像中。如下图所示&#xff1a; 若要添加文本&#xff0c;在影像视…...

Django ORM自定义排序的实用示例

在使用Django进行开发时&#xff0c;ORM&#xff08;对象关系映射&#xff09;是一个非常强大的工具。它让我们可以用Python代码直接操作数据库&#xff0c;而不需要写SQL语句。当我们需要对数据进行排序时&#xff0c;Django ORM同样提供了丰富的功能。今天&#xff0c;我们就…...

【后端】【ubuntu】 ubuntu目录权限查看的几种方法

在Ubuntu中&#xff0c;有多种方式可以查看目录或文件的权限&#xff0c;以下为你详细介绍常见的指令及其使用方法&#xff1a; 1. ls -l 命令 这是最常用的查看文件和目录权限的命令&#xff0c;-l 选项用于以长格式列出文件和目录的详细信息&#xff0c;其中就包含权限信息…...

C++【类和对象】(超详细!!!)

C【类和对象】 1.运算符重载2.赋值运算符重载3.日期类的实现 1.运算符重载 (1).C规定类类型运算符使用时&#xff0c;必须转换成调用运算符重载。 (2).运算符重载是具有特殊名字的函数&#xff0c;名字等于operator加需要使用的运算符&#xff0c;具有返回类型和参数列表及函数…...

如何简单预估大模型运行所需的显存

模型消耗的显存主要来源于模型参数&#xff0c;前向/反向&#xff0c;梯度以及优化器…… 1、为什么显存很重要 显存就是显卡的“仓库”和“高速公路”。 容量越大&#xff0c;能存储的图形数据就越多&#xff0c;就能支持更高分辨率、更高纹理质量的游戏或图形程序。 速度越…...

Excel 中如何实现数据透视表?

Excel 中如何实现数据透视表&#xff1f; 数据透视表&#xff08;PivotTable&#xff09;是 Excel 中强大的数据分析工具&#xff0c;能够快速汇总、分析和展示大量数据。本文将详细介绍如何在 Excel 中创建和使用数据透视表。 1. 数据透视表的基本概念 数据透视表是一种交互…...

C语言中getchar和putchar函数详解,理解多组数据输入的问题中的EOF(-1)

引言 C语言中getchar和putchar函数详解&#xff0c;理解多组数据输入的问题中的EOF&#xff08;-1&#xff09;。 1.getchar() 函数原型&#xff1a; int getchar ( void ); getchar() 函数返回用户从键盘输入的一个字符&#xff0c;使用时不带有任何参数。 程序运行到这个命…...

python基础知识补充

一.区分列表、元组、集合、字典&#xff1a; 二.输出&#xff1a; <1>格式化输出字符串&#xff1a; 格式符号转换%s字符串%d有符号的十进制整数%f浮点数%c字符%u无符号十进制整数%o八进制整数%x十六进制整数&#xff08;小写ox&#xff09;%X十六进制整数(大写OX)%e科…...

MySql自动安装脚本

一、脚本安装流程 1. 添加MySQL的Repository 使用wget命令从MySQL官方网站下载Yum Repository的RPM包。使用rpm -ivh命令安装下载的RPM包&#xff0c;以添加MySQL的Yum Repository。 2. 安装mysql-community-server 使用yum install -y mysql-community-server --nogpgchec…...

STM32-I2C通信外设

目录 一&#xff1a;I2C外设简介 二&#xff1a;I2C外设数据收发 三&#xff1a;I2C的复用端口 四&#xff1a;主机发送和接收 五&#xff1a;硬件I2C读写MPU6050 相关函数&#xff1a; 1.I2C_ GenerateSTART 2.I2C_ GenerateSTOP 3.I2C_ AcknowledgeConfig 4.I2C…...

【脚本】Linux一键扩大虚拟内存的大小

Linux增加虚拟内存其实很简单 就那几个命令&#xff0c;free、mkswap、swapon 但是方便起见我写成了脚本 使用方法 进入你的目录&#xff0c; nano ./install_swap.sh 下面的脚本全文复制&#xff0c;粘贴进去之后&#xff0c;按ctrlx后按y保存 然后运行以下命令 sudo bash …...

信号隔离器 0-20mA/0-10V模拟信号隔离模块变送器 一进二出高精度

信号隔离器 0-20mA/0-10V模拟信号隔离模块变送器 一进二出高精度https://item.taobao.com/item.htm?ftt&id766022047828 型号 一进二出 0-20mA 转0-20mA/0-10V MS-C12 一进二出 0-10V 转 0-20mA/0-10V MS-V12 信号隔离器 单组输出 MS-C1/V1 双组输出 MS-C12/V12 用于…...

Nat. Methods | scPerturb——单细胞扰动数据的标准化资源与统计分析方法

《Nature Methods》提出scPerturb资源平台&#xff0c;整合44个单细胞扰动数据集&#xff08;涵盖转录组、表观组、蛋白组读值&#xff09;&#xff0c;并通过能量统计量&#xff08;E-statistics&#xff09;量化扰动效应&#xff0c;旨在解决单细胞扰动数据的互操作性差、缺乏…...