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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/73177.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/73177.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/73177.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

破局者登場:中國首款AI原生IDE Trae深度解析--開啟人機協同編程新紀元

摘要 字節跳動于2025年3月3日正式發布中國首款AI原生集成開發環境Trae國內版&#xff0c;以動態協作、全場景AI賦能及本土化適配為核心優勢。Trae內置Doubao-1.5-pro與DeepSeek R1/V3雙引擎&#xff0c;支持基于自然語言生成端到端代碼框架、實時上下文感知與智能Bug修復&…

【PyCharm】Python和PyCharm的相互關系和使用聯動介紹

李升偉 整理 Python 是一種廣泛使用的編程語言&#xff0c;而 PyCharm 是 JetBrains 開發的專門用于 Python 開發的集成開發環境&#xff08;IDE&#xff09;。以下是它們的相互關系和使用聯動的介紹&#xff1a; 1. Python 和 PyCharm 的關系 Python&#xff1a;一種解釋型、…

SNIPAR:快速實現親緣個體的基因型分離與推斷

SNIPAR&#xff1a;快速實現親緣個體的基因型分離與推斷 近日&#xff0c;英國劍橋大學研究團隊在Nature Genetics上發表了最新研究成果——SNIPAR&#xff08;SNP-based Inference of Pedigree relationship, Ancestry, and Recombination&#xff09;。這一強大的工具可以幫助…

3.11記錄

leetcode刷題&#xff1a; 1. 334. 遞增的三元子序列 - 力扣&#xff08;LeetCode&#xff09; 方法一&#xff1a;使用貪心算法求解 class Solution(object):def increasingTriplet(self, nums):first nums[0]second float(inf)for i in nums:if i>second:return Truee…

阿里云操作系統控制臺評測:國產AI+運維 一站式運維管理平臺

阿里云操作系統控制臺評測&#xff1a;國產AI運維 一站式運維管理平臺 引言 隨著云計算技術的飛速發展&#xff0c;企業在云端的運維管理面臨更高的要求。阿里云操作系統控制臺作為一款集運維管理、智能助手和系統診斷等多功能于一體的工具&#xff0c;正逐步成為企業高效管理…

大語言模型學習--向量數據庫Milvus實踐

Milvus是目前比較流行的開源向量數據庫&#xff0c;其官網地址 Milvus 是什么&#xff1f; | Milvus 文檔 1.Milvus簡介 Milvus 是一種高性能、高擴展性的向量數據庫。Milvus 提供強大的數據建模功能&#xff0c;能夠將非結構化或多模式數據組織成結構化的 Collections。它支…

DeepSeek Kimi詳細生成PPT的步驟

以下是使用 DeepSeek 和 Kimi 協作生成 PPT 的詳細步驟&#xff0c;結合了兩者的優勢實現高效創作&#xff1a; 第一步&#xff1a;使用 DeepSeek 生成 PPT 大綱或內容 明確需求并輸入提示詞 在 DeepSeek 的對話界面中&#xff0c;輸入具體指令&#xff0c;要求生成 PPT 大綱或…

Visual Studio 安裝及使用教程(Windows)【安裝】

文章目錄 一、 Visual Studio 下載1. 官網下載2. 其它渠道 二、Visual Studio 安裝三、Visual Studio 使用四、Visual Studio 其它設置1. 桌面快捷方式2. 更改主題、字體大小 軟件 / 環境安裝及配置目錄 一、 Visual Studio 下載 1. 官網下載 安裝地址&#xff1a;https://vi…

Java多線程與高并發專題——阻塞和非阻塞隊列的并發安全原理是什么?

引入 之前我們探究了常見的阻塞隊列的特點&#xff0c;在本文我們就以 ArrayBlockingQueue 為例&#xff0c;首先分析 BlockingQueue &#xff0c;也就是阻塞隊列的線程安全原理&#xff0c;然后再看看它的兄弟——非阻塞隊列的并發安全原理。 ArrayBlockingQueue 源碼分析 …

關于ngx-datatable no data empty message自定義模板解決方案

背景&#xff1a;由于ngx-dataable插件默認沒有數據時顯示的文案是no data to display&#xff0c;且沒有任何樣式。這里希望通過自定義模板來實現。但目前github中有一個案例是通過設置代碼&#xff1a; https://swimlane.github.io/ngx-datatable/empty** <ngx-datatable…

Matlab 雙線性插值(二維)

文章目錄 一、簡介二、實現代碼三、實現效果參考資料一、簡介 雙線性插值是一種 二維插值方法,用于計算 柵格(Grid) 或 像素點 之間的插值值。它主要用于 圖像縮放、旋轉、變換 等操作,以在新像素位置估算灰度值或顏色值。 如上圖所示,假設存在一個二維離散函數(如圖像)…

coding ability 展開第二幕(雙指針——鞏固篇)超詳細!!!!

文章目錄 前言有效的三角形個數思路 查找總價格為目標值的兩個商品思路 兩數之和思路 三數之和思路 四數之和思路 總結 前言 本專欄的上篇&#xff0c;講述了雙指針的一些基礎的算法習題 今天我們來學習更進一步的雙指針用法吧 其實也是大相徑庭&#xff0c;和前面的差不多&…

L1-056 猜數字

L1-056 猜數字 - 團體程序設計天梯賽-練習集 (pintia.cn) 題解 這道題要求&#xff1a;一群人坐在一起&#xff0c;每人猜一個 100 以內的數&#xff0c;誰的數字最接近大家平均數的一半就贏。現在需要編寫程序來計算&#xff0c;其中需要存入玩家的名字&#xff08;字符串&a…

處理Java中的異常

處理Java中的異常 在 Java 中&#xff0c;異常處理是通過 try-catch-finally 語句來實現的。Java 提供了一種強大的機制&#xff0c;用于捕捉和處理程序運行中的各種錯誤和異常。通過這種方式&#xff0c;你可以有效地捕捉到可能導致程序崩潰的錯誤&#xff0c;并做出相應的處…

一維數組的增刪改查:對元素的影響

一維數組的增刪改查:對元素的影響(C語言) 在C語言中,一維數組是一種存儲一組相同類型元素的數據結構。它在內存中是連續存儲的,每個元素都可以通過索引來訪問和修改。在這篇博文中,我們將詳細探討一維數組的增、刪、改、查操作,并分析它們對數組元素的影響。 1. 一維數…

項目實操分享:一個基于 Flask 的音樂生成系統,能夠根據用戶指定的參數自動生成 MIDI 音樂并轉換為音頻文件

在線體驗音樂創作&#xff1a;AI Music Creator - AI Music Creator 體驗者賬號密碼admin/admin123 系統架構 1.1 核心組件 MusicGenerator 類 負責音樂生成的核心邏輯 包含 MIDI 生成和音頻轉換功能 管理音樂參數和音軌生成 FluidSynth 集成 用于 MIDI 到音頻的轉換 …

關于MCP SSE 服務器的工作原理

模型上下文協議&#xff08;Model Context Protocol&#xff0c;簡稱MCP&#xff09; 是一種全新的開放協議&#xff0c;專門用于標準化地為大語言模型&#xff08;LLMs&#xff09;提供應用場景和數據背景。 你可以把MCP想象成AI領域的“USB-C接口”&#xff0c;它能讓不同的A…

計算機:基于深度學習的Web應用安全漏洞檢測與掃描

目錄 前言 課題背景和意義 實現技術思路 一、算法理論基礎 1.1 網絡爬蟲 1.2 漏洞檢測 二、 數據集 三、實驗及結果分析 3.1 實驗環境搭建 3.2 模型訓練 最后 前言 &#x1f4c5;大四是整個大學期間最忙碌的時光,一邊要忙著備考或實習為畢業后面臨的就業升學做準備,…

win32匯編環境,網絡編程入門之二

;運行效果 ;win32匯編環境,網絡編程入門之二 ;本教程在前一教程的基礎上,研究一下如何得到服務器的返回的信息 ;正常的邏輯是連接上了,然后我發送什么,它返回什么,但是這有一個很尷尬的問題。 ;就是如何表現出來。因為網絡可能有延遲,這個延遲并不確定有多久。 ;而程序是順…

【高分論文密碼】AI大模型和R語言的全類型科研圖形繪制,從畫圖、標注、改圖、美化、組合、排序分解科研繪圖每個步驟

在科研成果競爭日益激烈的當下&#xff0c;「一圖勝千言」已成為高水平SCI期刊的硬性門檻——數據顯示很多情況的拒稿與圖表質量直接相關。科研人員普遍面臨的工具效率低、設計規范缺失、多維數據呈現難等痛點&#xff0c;因此科研繪圖已成為成果撰寫中的至關重要的一個環節&am…