0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

C#平臺調(diào)用OpenVINO的可行性

OpenCV學(xué)堂 ? 來源:英特爾物聯(lián)網(wǎng) ? 作者:英特爾物聯(lián)網(wǎng) ? 2022-05-24 09:37 ? 次閱讀

1.1 項目概述

1.1.1 項目介紹

C#調(diào)用OpenVINO工具套件部署Al模型項目開發(fā)項目,簡稱OpenVinoSharp,這是一個示例項目,該項目實現(xiàn)在C#編程語言下調(diào)用Intel推出的 OpenVINO 工具套件,進(jìn)行深度學(xué)習(xí)等Al項目在C#框架下的部署。該項目由C++語言編寫OpenVINO dll庫,并在C#語言下實現(xiàn)調(diào)用。

項目可以實現(xiàn)在C#編程語言下調(diào)用Intel推出的 OpenVINO 工具套件,進(jìn)行深度學(xué)習(xí)等Al項目在C#框架下的部署,目前可以支持的Al模型格式:

■ Paddlepaddle 飛槳模型 (.pdmodel)

■ ONNX 開放式神經(jīng)網(wǎng)絡(luò)交換模型 (.onnx)

■ IR 模型 (.xml, .bin)

目前該項目針對 Paddlepaddle 飛槳現(xiàn)有模型進(jìn)行了測試,主要有:

■ PaddleClas 飛槳圖像識別套件

■ PaddleDetection 目標(biāo)檢測模型套件

1.1.2 OpenVINO

OpenVINO 工具套件是英特爾基于自身現(xiàn)有的硬件平臺開發(fā)的一種可以加快高性能計算機(jī)視覺和深度學(xué)習(xí)視覺應(yīng)用開發(fā)速度工具套件,支持各種英特爾平臺的硬件加速器上進(jìn)行深度學(xué)習(xí),并且允許直接異構(gòu)執(zhí)行。支持在Windows與Linux系統(tǒng),官方支持編程語言為Python與C++語言,但不直接支持C#。

OpenVINO 工具套件2022.1版于2022年3月22日正式發(fā)布,根據(jù)官宣《OpenVINO 迎來迄今為止最重大更新,2022.1新特性搶先看》,OpenVINO 2022.1將是迄今為止最大變化的版本。從開發(fā)者的角度來看,對于提升開發(fā)效率或運行效率有用的特性有:

■ 提供預(yù)處理API函數(shù)

■ ONNX前端API

■ AUTO設(shè)備插件

■ 支持直接讀入飛槳模型

該項目開發(fā)環(huán)境為OpenVINO 2022.1最新版本,因此使用者需在使用時將自己電腦上的OpenVINO 版本升級到2022.1版,不然會有較多的問題。

1.1.3 項目方案

該項目主要通過調(diào)用dll文件方式實現(xiàn)。通過C++調(diào)用OpenVINO ,編寫模型推理接口,將我們所用到的推理方法在C++中實現(xiàn),并將其生成dll文件,在C#調(diào)用dll文件,重寫dll文件接口,并重新組建Core類,用于在C#中進(jìn)行模型的推理,其方案如圖1- 1所示。

8d2ca85a-daac-11ec-ba43-dac502259ad0.png

圖1- 1 項目解決方案

1.1.4 安裝方式

該項目所有文件已經(jīng)上傳到Github和Gitee遠(yuǎn)程代碼倉,大家可以通過Gi在本地進(jìn)行克隆。

● 系統(tǒng)平臺:

Windows

● 軟件要求:

Visual Studio 2022 / 2019 / 2017

OpenCV 4.5.5

OpenVINO 2022.1

● 安裝方式

在Github上克隆下載

git clone https://github.com/guojin-yan/OpenVinoSharp.git

在Gitee上克隆下載:

git clone https://gitee.com/guojin-yan/OpenVinoSharp.git

1.2 軟件安裝

1.2.1 Microsoft Visual Studio 2022安裝

Microsoft Visual Studio(簡稱VS)是美國微軟公司的開發(fā)工具套件系列產(chǎn)品。VS是一個基本完整的開發(fā)工具集,它包括了整個軟件生命周期中所需要的大部分工具,如UML工具、代碼管控工具、集成開發(fā)環(huán)境(IDE)等等。其支持C、C++、C#、F#、J#等多門編程語言。

本次項目所使用的編程語言為C++與C#兩門編程語言,在VS中完全可以實現(xiàn),可選擇安裝版本VS2017、VS2019或VS2022版本。對于VS不同版本的選擇,該項目不做較多要求,就筆者使用來說,VS2017版本推出時間較久,不建議使用,其一些編程語言規(guī)范有一些變動,對于該項目所提供的范例可能會有部分不兼容;VS2019和VS2022版本相對更新,是由起來差異不大,建議選擇這兩個版本,并且新版OpenVINO 支持VS2022版本Cmake。

筆者電腦安裝的為Microsoft Visual Studio Community 2022 版本,其安裝包可由VS官網(wǎng)直接下載,下載時選擇社區(qū)版,按照一般安裝步驟進(jìn)行安裝即可。在安裝中,工作負(fù)荷的選擇圖1- 2所示。

8d4d634c-daac-11ec-ba43-dac502259ad0.png

圖1- 2 Visual Studio 2022安裝負(fù)荷

安裝完成后,可以參照網(wǎng)上相關(guān)教程,進(jìn)行學(xué)習(xí)VS的使用。

1.2.2 OpenVINO 安裝

該項目所使用的OpenVINO 版本為2022.1版本,是Intel公司在2022年第一季度發(fā)布的最新版本。該版本基于之前版本有了較大變動,不在默認(rèn)包含OpenCV工具;其次,對代碼做了更進(jìn)一步的優(yōu)化,使得代碼在使用時更加靈活。其具體安裝方式,參考

https://www.intel.com/content/www/us/en/developer/tools/openvino-toolkit/download.html

1.2.3 OpenCV安裝

由于最新版的OpenVINO 2022.1 版本不在默認(rèn)附帶OpenCV工具,所以我們需要額外安裝OpenCV工具。

01

下載并安裝OpenCV

訪問OpenCV官網(wǎng),選擇Library下的Releases,進(jìn)入到下載頁面,或直接訪問進(jìn)入下載頁面。

8d84a1fe-daac-11ec-ba43-dac502259ad0.png

圖1- 3 OpenCV-4.5.5 版本頁面

根據(jù)負(fù)載使用情況,選擇Windows版本,如圖1- 3所示,跳轉(zhuǎn)頁面后,下載文件名為:opencv-4.5.5-vc14_vc15.exe。下載完成后,直接雙擊打開安裝文件,安裝完成后,打開安裝文件夾,該文件夾下 build、sources文件夾以及LICENSE相關(guān)文件,我們所使用的文件在build文件夾中。

02

配置Path環(huán)境變量

右擊我的電腦,進(jìn)入屬性設(shè)置,選擇高級系統(tǒng)設(shè)置進(jìn)入系統(tǒng)屬性,點擊環(huán)境變量,進(jìn)入到環(huán)境變量設(shè)置,編輯系統(tǒng)變量下的Path變量,增加以下地址變量:

E:OpenCV Sourceopencv-4.5.5uildx64vc15in

E:OpenCV Sourceopencv-4.5.5uildx64vc15lib

E:OpenCV Sourceopencv-4.5.5uildinclude

E:OpenCV Sourceopencv-4.5.5uildincludeopencv2

其中為本機(jī)安裝OpenCV安裝路徑。安裝完成后,如想在VS中使用,還需要再VS編輯器中設(shè)置相關(guān)配置,具體配置會在下文中說明。

1.3 OpenVINO 推理模型

與測試數(shù)據(jù)集

1.3.1 模型種類與下載方式

為了測試該項目,我們提供并整合了訓(xùn)練好的 Paddlepaddle 模型,主要針對 PaddleClas 以及 PaddleDetection 現(xiàn)有的模型,提供了 PaddleClas 下的花卉分類模型以及 PaddleDetection 中的 Vehicle Detection 模型,并針對該模型,提供了pdmodel、onnx以及IR格式。

該項目所使用的測試模型以及數(shù)據(jù)集,均可以在本文下的gitee上下載,下載鏈接為:

https://gitee.com/guojin-yan/OpenVinoSharp

1.3.2 PaddleDetection 模型

PaddleDetection 為飛槳 PaddlePaddle 的端到端目標(biāo)檢測套件,提供多種主流目標(biāo)檢測、實例分割、跟蹤、關(guān)鍵點檢測算法,配置化的網(wǎng)絡(luò)模塊組件、數(shù)據(jù)增強(qiáng)策略、損失函數(shù)等。該項目在此處主要使用的為PaddleDetection應(yīng)用中的目標(biāo)檢測功能,使用的網(wǎng)絡(luò)為YOLOv3網(wǎng)絡(luò),表1- 1 給出了YOLOv3網(wǎng)絡(luò)輸出與輸入的相關(guān)信息。

表1- 1 YOLOv3模型輸入與輸出節(jié)點信息

8d9e22aa-daac-11ec-ba43-dac502259ad0.png

注:None表示batch維度,H、W 分別為圖片的高和寬,Num表示識別結(jié)果的數(shù)量。

本次測試使用的為 PaddleDetection 中 Vehicle Detection 模型,我們可以在 PaddleDetection gitee 上下載。該模型輸入圖片要求為3×608×608大小,輸出為預(yù)測框信息,其信息組成為[class_id, score, x1, y1, x2, y2],分別代表分類編號、分類得分以及預(yù)測框?qū)琼旤c坐標(biāo)。

1.3.3 PaddleClas 模型

飛槳圖像識別套件 PaddleClas 是飛槳為工業(yè)界和學(xué)術(shù)界提供的的一個圖像識別任務(wù)的工具集,該模型經(jīng)過數(shù)據(jù)集訓(xùn)練,可以識別多種物品。在該項目中,我們使用flower數(shù)據(jù)集,使用ResNet50網(wǎng)絡(luò)訓(xùn)練識別102種花卉,關(guān)于該模型的輸入與輸出節(jié)點信息如所示

表1- 2 ResNet50模型輸入與輸出節(jié)點信息

8dc816f0-daac-11ec-ba43-dac502259ad0.png

注:None表示batch維度,H、W 分別為圖片的高和寬,Class表示分類數(shù)量。

花卉訓(xùn)練模型要求圖片輸入為3×224×224大小,輸出結(jié)果為102中預(yù)測結(jié)果概率。

1.4 創(chuàng)建OpenVINO 方法

C++動態(tài)鏈接庫

1.4.1 新建解決方案以及項目文件

打開vs2022,首先新建一個C++空項目文件,并將同時新建一個解決方案命名為:OpenVinoSharp,用于存放后續(xù)其他項目文件。將C++項目命名為:CppOpenVinoAPI。

進(jìn)入項目后,右擊源文件,選擇添加→新建項→C++文件(cpp),進(jìn)行的文件的添加。具體操作如圖1- 4所示。

8de5855a-daac-11ec-ba43-dac502259ad0.png

圖1- 4 新建項目解決方案及C++項目

本次我們需要添加OpenVinoAPIcpp以及Source.def兩個文件,如圖1- 5所示。

8e2088da-daac-11ec-ba43-dac502259ad0.png

圖1- 5 CppOpenVinoAPIl函數(shù)方法所需文件

1.4.2 配置C++項目屬性

右擊項目,點擊屬性,進(jìn)入到屬性設(shè)置,此處需要設(shè)置項目的配置類型包含目錄、庫目錄以及附加依賴項,本次項目選擇Release模式下運行,因此以Release情況進(jìn)行配置。

01

(1)設(shè)置配置與平臺

進(jìn)入屬性設(shè)置后,在最上面,將配置改為Release,平臺改為x64。具體操作如圖1- 6所示。

8e4b06d2-daac-11ec-ba43-dac502259ad0.png

圖1- 6 C++項目屬性配置與平臺設(shè)置

02

設(shè)置常規(guī)屬性

常規(guī)設(shè)置下,點擊輸出目錄,將輸出位置設(shè)置為,即將生成文件放置在項目文件夾下的dll文件夾下;其次將目標(biāo)文件名修改為:OpenVinoSharp;最后將配置類型改為:動態(tài)庫(.dll),讓其生成dll文件。具體操作如圖1- 7所示。

8e78bb9a-daac-11ec-ba43-dac502259ad0.png

圖1- 7 C++項目常規(guī)屬性設(shè)置

03

設(shè)置包含目錄

點擊VC++目錄,然后點擊包含目錄,進(jìn)行編輯,在彈出的新頁面中,添加以下路徑:

E:OpenCV Sourceopencv-4.5.5uildinclude

E:OpenCV Sourceopencv-4.5.5uildincludeopencv2

C:Program Files (x86)Intelopenvino_2022.1.0.643 untimeinclude

C:Program Files (x86)Intelopenvino_2022.1.0.643 untimeincludeie

其中路徑為OpenCV的安裝路徑,為OpenVINO安裝路徑,個人根據(jù)自己安裝的位置及版本確定。操作過程如圖1- 8所示。

8ea6c242-daac-11ec-ba43-dac502259ad0.png

圖1- 8 C++項目屬性庫目錄設(shè)置

04

設(shè)置庫目錄

同樣的方式,在VC++目錄下,點擊下方的庫目錄,點擊編輯,在彈出來的頁面中增加以下路徑:

E:OpenCV Sourceopencv-4.5.5uildx64vc15lib

C:Program Files (x86)Intelopenvino_2022.1.0.643 untimelibintel64Release

如果時配置Debug模式,則需要將Release文件路徑改為Debug即可。

05

設(shè)置附加依賴項

點擊展開鏈接器,點擊輸入,在附加依賴項中點擊編輯,在彈出來的新的頁面,添加以下文件名:

opencv_world455.lib

openvino.lib

具體操作步驟參考如圖1-9所示。新版OpenCV與OpenVINO 都將依賴庫文件合成到了一個文件中,這極大地簡化了使用,如果使用老版本的,需要將所有的.lib文件放置在此處即可。

8ee7cc7e-daac-11ec-ba43-dac502259ad0.png

圖1- 9 C++項目屬性附加依賴項設(shè)置

1.4.3 編寫C++代碼

01

推理引擎結(jié)構(gòu)體

Core是OpenVINO 工具套件里的推理核心類,該類下包含多個方法,可用于創(chuàng)建推理中所使用的其他類。在此處,需要在各個方法中傳遞的僅僅是所使用的幾個變量,因此選擇構(gòu)建一個推理引擎結(jié)構(gòu)體,用于存放各個變量。

// @brief 推理核心結(jié)構(gòu)體

typedef struct openvino_core {

ov::Core core; // core對象

std::shared_ptr model_ptr; // 讀取模型指針

ov::CompiledModel compiled_model; // 模型加載到設(shè)備對象

ov::InferRequest infer_request; // 推理請求對象

} CoreStruct;

其中Core是OpenVINO 工具套件里的推理機(jī)核心,該模塊只需要初始化;shared_ptr是讀取本地模型的方法,新版更新后,該方法發(fā)生了較大改動,可支持讀取Paddlepaddle飛槳模型、onnx模型以及IR模型;CompiledModel指的是一個已編譯的模型類,其主要是將讀取的本地模型應(yīng)用多個優(yōu)化轉(zhuǎn)換,然后映射到計算內(nèi)核,由所指定的設(shè)備編譯模型;InferRequest是一個推理請求類,在推理中主要用于對推理過程的操作。

02

接口方法規(guī)劃

經(jīng)典的OpenVINO 進(jìn)行模型推理,一般需要八個步驟,主要是:初始化Core對象、讀取本地推理模型、配置模型輸入&輸出、載入模型到執(zhí)行硬件、創(chuàng)建推理請求、準(zhǔn)備輸入數(shù)據(jù)、執(zhí)行推理計算以及處理推理計算結(jié)果。我們根據(jù)原有的八個步驟,對步驟進(jìn)行重新整合,并根據(jù)推理步驟,調(diào)整方法接口。

對于方法接口,主要設(shè)置為:推理初始化、配置輸入數(shù)據(jù)形狀、配置輸入數(shù)據(jù)、模型推理、讀取推理結(jié)果數(shù)據(jù)以及刪除內(nèi)存地址六個大類,其中配置輸入數(shù)據(jù)形狀要細(xì)分為配置圖片數(shù)據(jù)形狀以及普通數(shù)據(jù)形狀,配置輸入數(shù)據(jù)要細(xì)分為配置圖片輸入數(shù)據(jù)與配置普通數(shù)據(jù)輸入,讀取推理結(jié)果數(shù)據(jù)細(xì)分為讀取float數(shù)據(jù)和int數(shù)據(jù),因此,總共有6類方法接口,9個方法接口。

03

初始化推理模型

OpenVINO 推理引擎結(jié)構(gòu)體是聯(lián)系各個方法的橋梁,后續(xù)所有操作都是在推理引擎結(jié)構(gòu)體中的變量上操作的,為了實現(xiàn)數(shù)據(jù)在各個方法之間的傳輸,因此在創(chuàng)建推理引擎結(jié)構(gòu)體時,采用的是創(chuàng)建結(jié)構(gòu)體指針,并將創(chuàng)建的結(jié)構(gòu)體地址作為函數(shù)返回值返回。推理初始化接口主要整合了原有推理的初始化Core對象、讀取本地推理模型、載入模型到執(zhí)行硬件和創(chuàng)建推理請求步驟,并將這些步驟所創(chuàng)建的變量放在推理引擎結(jié)構(gòu)體中。

初始化推理模型接口方法為:

extern "C" __declspec(dllexport) void* __stdcall core_init(const wchar_t* model_file_wchar, const wchar_t* device_name_wchar);

該方法返回值為CoreStruct結(jié)構(gòu)體指針,其中model_file_wchar為推理模型本地地址字符串指針,device_name_wchar為模型運行設(shè)備名指針,在后面使用上述變量時,需要將其轉(zhuǎn)換為string字符串,利用wchar_to_string()方法可以實現(xiàn)將其轉(zhuǎn)換為字符串格式:

std::string model_file_path = wchar_to_string(model_file_wchar);

std::string device_name = wchar_to_string(device_name_wchar);

模型初始化功能主要包括:初始化推理引擎結(jié)構(gòu)體和對結(jié)構(gòu)體里面定義的其他變量進(jìn)行賦值操作,其主要是利用InferEngineStruct中創(chuàng)建的Core類中的方法,對各個變量進(jìn)行初始化操作:

CoreStruct* p = new CoreStruct(); // 創(chuàng)建推理引擎指針

p->model_ptr = p->core.read_model(model_file_path); // 讀取推理模型

p->compiled_model = p->core.compile_model(p->model_ptr, ?CPU“); // 將模型加載到設(shè)備

p->infer_request = p->compiled_model.create_infer_request(); // 創(chuàng)建推理請求

04

配置輸入數(shù)據(jù)形狀

在新版OpenVINO 2022.1 中,新增加了對Paddlepaddle 模型以及onnx模型的支持,Paddlepaddle 模型不支持指定指定默認(rèn)bath通道數(shù)量,因此需要在模型使用時指定其輸入;其次,對于onnx模型,也可以在轉(zhuǎn)化時不指定固定形狀,因此在配置輸入數(shù)據(jù)前,需要配置輸入節(jié)點數(shù)據(jù)形狀。其方法接口為:

extern "C" __declspec(dllexport) void* __stdcall set_input_image_sharp(void* core_ptr, const wchar_t* input_node_name_wchar, size_t * input_size);

extern "C" __declspec(dllexport) void* __stdcall set_input_data_sharp(void* core_ptr, const wchar_t* input_node_name_wchar, size_t * input_size);

由于需要配置圖片數(shù)據(jù)輸入形狀與普通數(shù)據(jù)的輸入形狀,在此處設(shè)置了兩個接口,分別設(shè)置兩種不同輸入的形狀。該方法返回值是CoreStruct結(jié)構(gòu)體指針,但該指針?biāo)鶎?yīng)的數(shù)據(jù)中已經(jīng)包含了對輸入形狀的設(shè)置。第一個輸入參數(shù)core_ptr是CoreStruct指針,在當(dāng)前方法中,我們要讀取該指針,并將其轉(zhuǎn)換為CoreStruct類型:

CoreStruct* p = (CoreStruct*)core_ptr;

input_node_name_wchar 為待設(shè)置網(wǎng)絡(luò)節(jié)點名,input_size 為形狀數(shù)據(jù)數(shù)組,對圖片數(shù)據(jù),需要設(shè)置 [batch, dim, height, width] 四個維度大小,所以input_size數(shù)組傳入4個數(shù)據(jù),其設(shè)置在形狀主要使用Tensor類下的set_shape()方法:

std::string input_node_name = wchar_to_string(input_node_name_wchar); // 將節(jié)點名轉(zhuǎn)為string類型

ov::Tensor input_image_tensor = p->infer_request.get_tensor(input_node_name); // 讀取指定節(jié)點Tensor

input_image_tensor.set_shape({ input_size[0],input_size[1],input_size[2],input_size[3] }); // 設(shè)置節(jié)點數(shù)據(jù)形狀

05

配置輸入數(shù)據(jù)

在新版OpenVINO 中,Tensor類的T* data()方法,其返回值為當(dāng)前節(jié)點Tensor的數(shù)據(jù)內(nèi)存地址,通過填充Tensor的數(shù)據(jù)內(nèi)存,實現(xiàn)推理數(shù)據(jù)的輸入。對于圖片數(shù)據(jù),其最終也是將其轉(zhuǎn)為一維數(shù)據(jù)進(jìn)行輸入,不過為方便使用,此處提供了配置圖片數(shù)據(jù)和普通數(shù)據(jù)的接口,對于輸入為圖片的方法接口:

extern "C" __declspec(dllexport) void* __stdcall load_image_input_data(void* core_ptr, const wchar_t* input_node_name_wchar, uchar * image_data, size_t image_size);

該方法返回值是CoreStruct結(jié)構(gòu)體指針,但該指針?biāo)鶎?yīng)的數(shù)據(jù)中已經(jīng)包含了加載的圖片數(shù)據(jù)。第一個輸入?yún)?shù)core_ptr是CoreStruct指針,在當(dāng)前方法中,我們要讀取該指針,并將其轉(zhuǎn)換為CoreStruct類型;第二個輸入?yún)?shù)input_node_name_wchar為待填充節(jié)點名,先將其轉(zhuǎn)為string字符串:

std::string input_node_name = wchar_to_string(input_node_name_wchar);

在該項目中,我們主要使用的是以圖片作為模型輸入的推理網(wǎng)絡(luò),模型主要的輸入為圖片的輸入。其圖片數(shù)據(jù)主要存儲在矩陣image_data和矩陣長度image_size兩個變量中。需要對圖片數(shù)據(jù)進(jìn)行整合處理,利用創(chuàng)建的data_to_mat () 方法,將圖片數(shù)據(jù)讀取到OpenCV中:

cv::Mat input_image = data_to_mat(image_data, image_size);

接下來就是配置網(wǎng)絡(luò)圖片數(shù)據(jù)輸入,對于節(jié)點輸入是圖片數(shù)據(jù)的網(wǎng)絡(luò)節(jié)點,其配置網(wǎng)絡(luò)輸入主要分為以下幾步:

首先,獲取網(wǎng)絡(luò)輸入圖片大小。

使用InferRequest類中的get_tensor ()方法,獲取指定網(wǎng)絡(luò)節(jié)點的Tensor,其節(jié)點要求輸入大小在Shape容器中,通過獲取該容器,得到圖片的長寬信息:

ov::Tensor input_image_tensor = p->infer_request.get_tensor(input_node_name);

int input_H = input_image_tensor.get_shape()[2]; //獲得“image“節(jié)點的Height

int input_W = input_image_tensor.get_shape()[3]; //獲得“image“節(jié)點的Width

其次,按照輸入要求,處理輸入圖片。

在這一步,我們除了要按照輸入大小對圖片進(jìn)行放縮之外,還要根據(jù) PaddlePaddle 對模型輸入的要求進(jìn)行處理。因此處理圖片其主要分為交換RGB通道、放縮圖片以及對圖片進(jìn)行歸一化處理。在此處我們借助OpenCV來實現(xiàn)。

OpenCV讀取圖片數(shù)據(jù)并將其放在Mat類中,其讀取的圖片數(shù)據(jù)是BGR通道格式,PaddlePaddle 要求輸入格式為RGB通道格式,其通道轉(zhuǎn)換主要靠一下方式實現(xiàn):

cv::cvtColor(input_image, blob_image, cv::COLOR_BGR2RGB);

接下來就是根據(jù)網(wǎng)絡(luò)輸入要求,對圖片進(jìn)行壓縮處理:

cv::resize(blob_image, blob_image, cv::Size(input_H, input_W), 0, 0, cv::INTER_LINEAR);

最后就是對圖片進(jìn)行歸一化處理,其主要處理步驟就是減去圖像數(shù)值均值,并除以方差。查詢PaddlePaddle模型對圖片的處理,其均值mean = [0.485, 0.456, 0.406],方差std = [0.229, 0.224, 0.225],利用OpenCV中現(xiàn)有函數(shù),對數(shù)據(jù)進(jìn)行歸一化處理:

std::vectormean_values{ 0.485 * 255, 0.456 * 255, 0.406 * 255 };

std::vectorstd_values{ 0.229 * 255, 0.224 * 255, 0.225 * 255 };

std::vectorrgb_channels(3);

cv::split(blob_image, rgb_channels); // 分離圖片數(shù)據(jù)通道

for (auto i = 0; i < rgb_channels.size(); i++){

//分通道依此對每一個通道數(shù)據(jù)進(jìn)行歸一化處理

rgb_channels[i].convertTo(rgb_channels[i], CV_32FC1, 1.0 / std_values[i], (0.0 – mean_values[i]) / std_values[i]);

}

cv::merge(rgb_channels, blob_image); // 合并圖片數(shù)據(jù)通道

最后,將圖片數(shù)據(jù)輸入到模型中。

在此處,我們重寫了網(wǎng)絡(luò)賦值方法,并將其封裝到 fill_tensor_data_image(ov::Tensor& input_tensor, const cv::Mat& input_image)方法中,input_tensor為模型輸入節(jié)點Tensor類,input_image為處理過的圖片Mat數(shù)據(jù)。因此節(jié)點賦值只需要調(diào)用該方法即可:

fill_tensor_data_image(input_image_tensor, blob_image);

對于普通數(shù)據(jù)的輸入,其方法接口如下:

extern "C" __declspec(dllexport) void* __stdcall load_input_data(void* core_ptr, const wchar_t* input_node_name_wchar, float* input_data);

與配置圖片數(shù)據(jù)不同點,在于輸入數(shù)據(jù)只需要輸入input_data數(shù)組即可。其數(shù)據(jù)處理哦在外部實現(xiàn),只需要將處理后的數(shù)據(jù)填充到輸入節(jié)點的數(shù)據(jù)內(nèi)存中即可,通過調(diào)用自定義的fill_tensor_data_float(ov::Tensor& input_tensor, float* input_data, int data_size) 方法即可實現(xiàn):

std::string input_node_name = wchar_to_string(input_node_name_wchar);

ov::Tensor input_image_tensor = p->infer_request.get_tensor(input_node_name); // 讀取指定節(jié)點tensor

int input_size = input_image_tensor.get_shape()[1]; //獲得輸入節(jié)點的長度

fill_tensor_data_float(input_image_tensor,input_data, input_size); // 將數(shù)據(jù)填充到tensor數(shù)據(jù)內(nèi)存上

06

模型推理

上一步中我們將推理內(nèi)容的數(shù)據(jù)輸入到了網(wǎng)絡(luò)中,在這一步中,我們需要進(jìn)行數(shù)據(jù)推理,這一步中我們留有一個推理接口:

extern "C" __declspec(dllexport) void* __stdcall core_infer(void* core_ptr)

進(jìn)行模型推理,只需要調(diào)用CoreStruct結(jié)構(gòu)體中的infer_request對象中的infer()方法即可:

CoreStruct* p = (CoreStruct*)core_ptr;

p->infer_request.infer();

07

讀取推理數(shù)據(jù)

上一步我們對數(shù)據(jù)進(jìn)行了推理,這一步就需要查詢上一步推理的結(jié)果。對于我們所使用的模型輸出,主要有float數(shù)據(jù)和int數(shù)據(jù),對此,留有了兩種數(shù)據(jù)的查詢接口,其方法為:

extern "C" __declspec(dllexport) void __stdcall read_infer_result_F32(void* core_ptr, const wchar_t* output_node_name_wchar, int data_size, float* infer_result);

extern "C" __declspec(dllexport) void __stdcall read_infer_result_I32(void* core_ptr, const wchar_t* output_node_name_wchar, int data_size, int* infer_result);

其中data_size為讀取數(shù)據(jù)長度,infer_result 為輸出數(shù)組指針。讀取推理結(jié)果數(shù)據(jù)與加載推理數(shù)據(jù)方式相似,依舊是讀取輸出節(jié)點處數(shù)據(jù)內(nèi)存的地址:

const ov::Tensor& output_tensor = p->infer_request.get_tensor(output_node_name);

const float* results = output_tensor.data();

針對讀取整形數(shù)據(jù),其方法一樣,只是在轉(zhuǎn)換類型時,需要將其轉(zhuǎn)換為整形數(shù)據(jù)即可。我們讀取的初始數(shù)據(jù)為二進(jìn)制數(shù)據(jù),因此要根據(jù)指定類型轉(zhuǎn)換,否則數(shù)據(jù)會出現(xiàn)錯誤。將數(shù)據(jù)讀取出來后,將其放在數(shù)據(jù)結(jié)果指針中,并將所有結(jié)果賦值到輸出數(shù)組中:

for (int i = 0; i < data_size; i++) {

*inference_result = results[i];

inference_result++;

}

08

刪除推理核心結(jié)構(gòu)體指針

推理完成后,我們需要將在內(nèi)存中創(chuàng)建的推理核心結(jié)構(gòu)地址刪除,防止造成內(nèi)存泄露,影響電腦性能,其接口該方法為:

extern "C" __declspec(dllexport) void __stdcall core_delet(void* core_ptr);

在該方法中,我們只需要調(diào)用delete命令,將結(jié)構(gòu)體指針刪除即可。

1.4.4 編寫模塊定義文件

我們在定義接口方法時,在原有方法的基礎(chǔ)上,增加了extern "C" 、 __declspec(dllexport) 以及__stdcall 三個標(biāo)識,其主要原因是為了讓編譯器識別我們的輸出方法。其中,extern ?C“是指示編譯器這部分代碼按C語言(而不是C++)的方式進(jìn)行編譯;__declspec(dllexport)用于聲明導(dǎo)出函數(shù)、類、對象等供外面調(diào)用;__stdcall是一種函數(shù)調(diào)用約定。通過上面三個標(biāo)識,我們在C++種所寫的接口方法,會在dll文件中暴露出來,并且可以實現(xiàn)在C#中的調(diào)用。

不過上面所說內(nèi)容,我們在編輯器中可以通過模塊定義文件(.def)所實現(xiàn),在模塊定義文件中,添加以下代碼:

LIBRARY

"OpenVinoSharp"

EXPORTS

core_init

set_input_image_sharp

set_input_data_sharp

load_image_input_data

load_input_data

core_infer

read_infer_result_F32

read_infer_result_I32

core_delet

LIBRARY后所跟的為輸出文件名,EXPORTS后所跟的為輸出方法名。僅需要以上語句便可以替代extern "C" 、 __declspec(dllexport) 以及__stdcall的使用。

1.4.5 生成dll文件

前面我們將項目配置輸出設(shè)置為了生成dll文件,因此該項目不是可以執(zhí)行的exe文件,只能生成不能運行。右鍵項目,選擇重新生成/生成。在沒有錯誤的情況下,會看到項目成功的提示。可以看到dll文件在解決方案同級目錄下x64Release文件夾下。

使用dll文件查看器打開dll文件,如圖1- 10所示;可以看到,我們創(chuàng)建的四個方法接口已經(jīng)暴露在dll文件中。

8f17535e-daac-11ec-ba43-dac502259ad0.png

圖1- 10 dll文件方法輸出目錄

1.5 C#構(gòu)建Core類

1.5.1 新建C#類庫

右擊解決方案,添加->新建項目,選擇添加C#類庫,項目名命名為OpenVinoSharp,項目框架根據(jù)電腦中的框架選擇,此處使用的是.NET 5.0。新建完成后,然后右擊項目,選擇添加->新建項,選擇類文件,添加Core.cs和NativeMethods.cs兩個類文件。

1.5.2 引入dll文件中的方法

在NativeMethods.cs文件下,我們通過[DllImport()]方法,將dll文件中所有的方法讀取到C#中。讀取方式如下:

[DllImport(openvino_dll_path, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]

public extern static IntPtr core_init(string model_file, string device_name);

其中openvino_dll_path為dll文件路徑,CharSet = CharSet.Unicode代表支持中文編碼格式字符串,CallingConvention = CallingConvention.Cdecl指示入口點的調(diào)用約定為調(diào)用方清理堆棧。

上述所列出的為初始化推理模型,dlii文件接口在匹配時,是通過方法名字匹配的,因此,方法名要保證與dll文件中一致。其次就是方法的參數(shù)類型要進(jìn)行對應(yīng),在上述方法中,函數(shù)的返回值在C++中為void* ,在C#中對應(yīng)的為IntPtr類型,輸入?yún)?shù)中,在C++中為wchar_t* 字符指針,在C#中對應(yīng)的為string字符串。通過方法名與參數(shù)類型一一對應(yīng),在C#可以實現(xiàn)對方法的調(diào)用。其他方法的引用類似,在此處不在一一贅述,具體可以參照項目提供的源代碼。

1.5.3 創(chuàng)建Core類

為了更方便地調(diào)用我們通過dll引入的OpenVINO 方法,減少使用時的函數(shù)方法接口,我們在C#中重新組建我們自己的推理類,命名為Class Core,其主要成員變量和方法如圖1- 11所示。

8f4a8170-daac-11ec-ba43-dac502259ad0.png

圖1- 11 Core類圖

在Core.類中,我們只需要創(chuàng)建一個地址變量,作為Core類的成員變量,用于接收接口函數(shù)返回的推理核心指針,該成員變量我們只需要在當(dāng)前類下訪問,因此將其設(shè)置為私有變量:

private IntPtr ptr = new IntPtr();

接下來,構(gòu)建類的構(gòu)造函數(shù),在類的初始化時,我們需要輸入模型地址以及設(shè)備類型,通過掉用dll文件中引入的方法,獲取初始化指針,對成員變量進(jìn)行賦值,實現(xiàn)類的初始化:

public Core(string model_file, string device_name) {

ptr = NativeMethods.core_init(model_file, device_name);

}

然后構(gòu)其中的方法,在構(gòu)建設(shè)置數(shù)據(jù)輸入形狀時,我們需要提供的為節(jié)點名以及形狀數(shù)據(jù),為了簡化該方法,我們合并了圖片形狀設(shè)置與普通數(shù)據(jù)形狀設(shè)置接口,通過判斷輸入數(shù)組的長度,來確定是對那一個形狀的設(shè)置:

public void set_input_sharp(string input_node_name, ulong[] input_size);

對于該類中方法的構(gòu)建,可以參考源碼文件,在此處不做詳述。并且其他方法構(gòu)建方式基本相似,此處不在一一贅述,具體可以參考源碼文檔。

1.5.4 編譯Core類庫

右擊項目,點擊生成/重新生成,出現(xiàn)如下圖1- 12所示,表示編譯成功。

8f770f88-daac-11ec-ba43-dac502259ad0.png

圖1- 12 Core類編譯輸出

1.6 C#實現(xiàn)OpenVINO

方法的調(diào)用

1.6.1 新建C#項目

右擊解決方案,添加->新建項目,選擇添加C#控制臺項目,項目框架根據(jù)電腦中的框架選擇,此處使用的是.NET 5.0。

8f9a2220-daac-11ec-ba43-dac502259ad0.png

圖1- 13 C#項目設(shè)置

1.6.2 添加OpenCVsharp

右擊項目,選擇管理NuGet程序包,在新頁面中選擇瀏覽,在搜索框中輸入opencvsharp3,在搜索結(jié)果中,找到OpenCvSharp3-AnyCPU,然后右側(cè)點擊安裝,具體操作步驟如圖1- 14所示。

8fbc90bc-daac-11ec-ba43-dac502259ad0.png

圖1- 14 NuGet程序包安裝

1.6.3添加項目引用

上一步中我們將dll文件中的方法引入到C#中,并組建了Core類,在這一步中,我們主要通過調(diào)用Core類,進(jìn)行Al模型的部署,所以需要引入上一步的項目。

右擊當(dāng)前項目,選擇添加,選擇項目引用,在出現(xiàn)的窗體中,選擇上一步中創(chuàng)建的項目OpenVinoSharp,點擊確定;然后在當(dāng)前項目下,添加using OpenVinoSharp命名空間。具體操作如圖1- 15所示。

8ff0cada-daac-11ec-ba43-dac502259ad0.png

圖1- 15 添加項目引用

1.6.4 編寫代碼測試花卉分類模型

在該項目中,我們提供了兩種推理模型,此處我們以花卉分類模型為例,簡介如何通過C#調(diào)用OpenVINO 進(jìn)行Al模型的部署。

01

引入相關(guān)變量

string device_name = "CPU";

string model_file = "E:/Text_Model/flowerclas/flower_rec.onnx";

string image_file = "E:/Text_dataset/flowers102/jpg/image_00001.jpg";

string input_node_name = "x";

string output_node_name = "softmax_1.tmp_0";

為了讓大家更加清晰的看懂后續(xù)代碼,在此處對引入的相關(guān)變量進(jìn)行解釋:

device_name:設(shè)備類型名稱,可為CPU、GPU以及AUTO(均可);

model_file:模型地址,可以為onnx、pdmodel或者xml格式;

image_file:測試圖片地址;

input_node_name:輸入模型節(jié)點名,當(dāng)多輸入時,可以為數(shù)組;

output_node_name:輸出模型節(jié)點名,當(dāng)多輸出時,可以為數(shù)組。

02

初始化Core類

在此處我們直接調(diào)用Core類的構(gòu)造函數(shù),進(jìn)行初始化:

Core ie = new Core(model_file_paddle, device_name);

03

配置模型輸入

花卉分類模型輸入只有一個,即待分類花卉圖片。如果我們調(diào)用的模型未指定輸入大小,需要在輸入數(shù)據(jù)前,調(diào)用模型輸入數(shù)據(jù)形狀設(shè)置方法,設(shè)置節(jié)點輸入數(shù)據(jù)形狀。圖片數(shù)據(jù)為三維數(shù)組,再加一個batchsize,最終為四維數(shù)據(jù),將形狀數(shù)據(jù)放在數(shù)組中,調(diào)用set_input_sharp()方法:

ulong[] image_sharp = new ulong[] { 1, 3, 224, 224 };

ie.set_input_sharp(input_node_name, image_sharp);

對于圖片數(shù)據(jù),需要將其轉(zhuǎn)為轉(zhuǎn)為矩陣數(shù)據(jù),在此處,我們可以直接使用opencvsharp中的編解碼方法,將圖片數(shù)據(jù)放置在byte數(shù)組中:

Mat image = new Mat(image_file);

byte[] image_data = new byte[2048 * 2048 * 3];

ulong image_size = new ulong();

image_data = image.ImEncode(".bmp");

image_size = Convert.ToUInt64(image_data.Length);

就最后調(diào)用Core類中的load _input_data()方法,將數(shù)據(jù)加載到推理網(wǎng)絡(luò)中:

ie.load_input_data(input_node_name, image_data, image_size);

在配置完輸入數(shù)據(jù)后,調(diào)用模型推理方法,對輸入數(shù)據(jù)進(jìn)行推理:

ie.infer();

接下來就是讀取推理結(jié)果,對于模型的推理結(jié)果輸出一般為數(shù)組數(shù)據(jù),可以通過調(diào)用Core類中讀取推理數(shù)據(jù)結(jié)果的方法,對與花卉分類模型的輸出,其結(jié)果為長度為102的浮點型數(shù)據(jù),所以直接調(diào)用read_inference_result ()方法讀取即可:

float[] result = new float[102];

result = ie.read_infer_result(output_node_name, 102);

在讀取推理數(shù)據(jù)時,我們一定要根據(jù)模型的書名讀取正確的結(jié)果數(shù)據(jù),因為如果超出實際輸出長度,其結(jié)果數(shù)據(jù)會摻雜其他干擾數(shù)據(jù)。

最后一步就是處理輸出數(shù)據(jù)。對于不同的推理模型,其結(jié)果處理方式是不同的,對于花卉分類模型,其輸出為102種分類情況打分,因此,在處理數(shù)據(jù)時,需要找出得分最高的哪一類即可。在此處,我們提供了一個方法,該方法可以實現(xiàn)提取數(shù)組中前N個max數(shù)據(jù)的位置,通過調(diào)用該方法,我們可以獲取分類結(jié)果中分?jǐn)?shù)最高的幾個結(jié)果,并將結(jié)果打印輸出:

int[] index = find_array_max(result,5);

for (int i = 0; i < 5; i++){

Console.WriteLine("the index is {0} , the score is {1} ", index[i], result[index[i]]);

}

最終輸出結(jié)果如圖1- 16所示,該頁面打印出來了推理結(jié)果預(yù)測分?jǐn)?shù)最大的前五個分?jǐn)?shù)和其對應(yīng)的索引值,最后可以通過索引值查詢flowers102_label_list.txt文件中對應(yīng)的花卉名稱。

9017a6c8-daac-11ec-ba43-dac502259ad0.png

圖1- 16 花卉分類結(jié)果

在程序最后,我們該需要將前面在內(nèi)存上創(chuàng)建推理引擎結(jié)構(gòu)體進(jìn)行刪除,只需要調(diào)用Core類下的delet()即可。

1.6.5 編寫代碼測試車輛識別模型

對于車輛識別模型此處不再進(jìn)行詳細(xì)講解,具體實現(xiàn)可以參考源碼文件,此處只對一些不同點進(jìn)行分析。

在配置輸入時,除了需要配置圖片數(shù)據(jù)輸入,還需要配置圖片長寬數(shù)據(jù)以及長寬縮放比例數(shù)據(jù),在配置時,只需要將數(shù)據(jù)放置在數(shù)組中,通過調(diào)用load_input_data()方法實現(xiàn),對于設(shè)置縮放比例數(shù)據(jù)輸入,如下所示:

float scale_h = 608.00f / image.Height;

float scale_w = 608.00f / image.Width;

float[] scale_factor = new float[] { scale_h, scale_w };

ie.load_input_data(input_node_name[1], scale_factor);

對于該模型推理結(jié)果數(shù)據(jù),總共有兩個節(jié)點輸出,一個是識別結(jié)果數(shù)量,一個為識別結(jié)果信息。對于識別結(jié)果數(shù)量,其數(shù)據(jù)類型為整形數(shù)據(jù),對于單圖片輸入,只需要讀取一位即可,利用該數(shù)據(jù),確定識別結(jié)果信息長度。識別結(jié)果信息為6列N行數(shù)據(jù),在數(shù)據(jù)讀取時,我們將其轉(zhuǎn)化為一維數(shù)據(jù),所以在處理數(shù)據(jù)時,以6位數(shù)據(jù)為一組,進(jìn)行處理。

識別結(jié)果信息數(shù)據(jù)中,第1位為識別標(biāo)簽,第2位為識別得分,第3位到第6位四個數(shù)據(jù)為位置矩形框?qū)屈c坐標(biāo),通過每6位讀取一次數(shù)據(jù),獲取識別結(jié)果。在此處,我們提供了專門的結(jié)果處理方法,通過該方法們可以實現(xiàn)直接將結(jié)果繪制在原圖片上:

image = draw_image_resule(image, resule_num[0], result, lable, 0.2f);

其中image為原圖片,resule_num[0]為識別結(jié)果數(shù)量,result為識別結(jié)果數(shù)組,lable為結(jié)果標(biāo)簽,0.2f為評價得分下限。通過結(jié)果處理,將識別結(jié)果標(biāo)注在圖片中,并把識別結(jié)果以及得分情況打印在圖片中,最終識別結(jié)果如圖1- 17所示。

906c92e6-daac-11ec-ba43-dac502259ad0.png

圖1- 17 車輛類型識別結(jié)果輸出

1.7 程序時間分析

為了對比C++、C#以及Python這三個平臺下調(diào)用OpenVINO 所使用的時間,我們通過測試flower_clas以及vehicle_yolov3_darknet模型運行時間進(jìn)行對比,在同一臺電腦相同運行環(huán)境之下,以及對模型的處理方式在不同編程語言下盡量做到相同,在程序測試100次之后,得到結(jié)果表1- 3如所示。

表1- 3 程序運行時間

90f4cfbc-daac-11ec-ba43-dac502259ad0.png

在本次檢測中,我們通過C++、C#以及Python分別調(diào)用OpenVINO 進(jìn)行模型的部署與推理,通過上述表格,一方面可以看出,C#通過調(diào)用C++的dll,實現(xiàn)模型的部署與推理,并沒有太大的影響程序的運行速度;另一方面,C++與C#部署模型推理,在總時間上來看,運行速度是優(yōu)于Python的。

測試模型運行時間所使用的測試代碼,已同步到遠(yuǎn)程成代碼托管倉庫gitee與github中,具體在https://gitee.com/guojin-yan/OpenVinoSharp/tree/master/openvino_run_time文件夾下,使用人員可以根據(jù)自己的設(shè)備對C++、C#和Python三個平臺進(jìn)行測試。

1.8 項目總結(jié)

該項目通過C++調(diào)用OpenVINO ,創(chuàng)建推理方法接口,并通過調(diào)用dll文件的方式,在C#中進(jìn)行重新構(gòu)建Core模型推理類,并測試了花卉分類模型以及車輛識別模型,在預(yù)測結(jié)果精度以及預(yù)測時間上,和C++相比,并沒有較大的差異。

該項目所提供的方法,證實了C#平臺調(diào)用OpenVINO 的可行性,為后續(xù)在C#部署OpenVINO 模型提供了一個技術(shù)途徑。本文所有源代碼參見:

https://gitee.com/guojin-yan/OpenVinoSharp

審核編輯 :李倩

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 英特爾
    +關(guān)注

    關(guān)注

    60

    文章

    9866

    瀏覽量

    171326
  • 編程語言
    +關(guān)注

    關(guān)注

    10

    文章

    1931

    瀏覽量

    34553
  • 深度學(xué)習(xí)
    +關(guān)注

    關(guān)注

    73

    文章

    5471

    瀏覽量

    120904

原文標(biāo)題:在C#中調(diào)用OpenVINO? 模型 | 開發(fā)者實戰(zhàn)

文章出處:【微信號:CVSCHOOL,微信公眾號:OpenCV學(xué)堂】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    單CPU 雙項目開發(fā)實現(xiàn)更好的維護(hù)可行性應(yīng)用說明

    電子發(fā)燒友網(wǎng)站提供《單CPU 雙項目開發(fā)實現(xiàn)更好的維護(hù)可行性應(yīng)用說明.pdf》資料免費下載
    發(fā)表于 09-12 09:42 ?0次下載
    單CPU 雙項目開發(fā)實現(xiàn)更好的維護(hù)<b class='flag-5'>性</b>和<b class='flag-5'>可行性</b>應(yīng)用說明

    使用OpenVINO C# API部署YOLO-World實現(xiàn)實時開放詞匯對象檢測

    的快速準(zhǔn)確識別,并通過AR技術(shù)將虛擬元素與真實場景相結(jié)合,為用戶帶來沉浸式的交互體驗。在本文中,我們將結(jié)合OpenVINO C# API使用最新發(fā)布的OpenVINO 2024.0部署 YOLO-World實現(xiàn)實時開放詞匯對象檢
    的頭像 發(fā)表于 08-30 16:27 ?527次閱讀
    使用<b class='flag-5'>OpenVINO</b> <b class='flag-5'>C#</b> API部署YOLO-World實現(xiàn)實時開放詞匯對象檢測

    OpenVINO2024 C++推理使用技巧

    很多人都使用OpenVINO新版的C++ 或者Python的SDK,都覺得非常好用,OpenVINO2022之后的版本C++ SDK做了大量的優(yōu)化與整理,已經(jīng)是非常貼近開發(fā)的使用習(xí)慣與
    的頭像 發(fā)表于 07-26 09:20 ?724次閱讀

    人臉識別技術(shù)的可行性在于矛盾具有什么

    人臉識別技術(shù)的可行性在于矛盾具有普遍。 一、引言 人臉識別技術(shù)作為人工智能領(lǐng)域的一項重要技術(shù),近年來得到了廣泛的關(guān)注和應(yīng)用。然而,隨著技術(shù)的發(fā)展,人臉識別技術(shù)也面臨著越來越多的挑戰(zhàn)和問題。本文將從
    的頭像 發(fā)表于 07-04 09:28 ?414次閱讀

    防靜電的可行性措施

    靜電防護(hù)是一種具有系統(tǒng)、站體化、全過程的綜合工作,不但需要相當(dāng)復(fù)雜的相關(guān)技術(shù)措施,而且需要強(qiáng)有力的和健全的治理措施;不但要求工程技術(shù)人員參和,理要求操作人員、使用及維護(hù)人員參和。
    的頭像 發(fā)表于 07-03 15:54 ?235次閱讀

    OpenVINO C# API在intel平臺部署YOLOv10目標(biāo)檢測模型

    的模型設(shè)計策略,從效率和精度兩個角度對YOLOs的各個組成部分進(jìn)行了全面優(yōu)化,大大降低了計算開銷,增強(qiáng)了性能。在本文中,我們將結(jié)合OpenVINO C# API使用最新發(fā)布的OpenVINO 2024.1部署YOLOv10目標(biāo)檢
    的頭像 發(fā)表于 06-21 09:23 ?918次閱讀
    用<b class='flag-5'>OpenVINO</b> <b class='flag-5'>C#</b> API在intel<b class='flag-5'>平臺</b>部署YOLOv10目標(biāo)檢測模型

    振弦采集儀在巖土工程地質(zhì)災(zāi)害監(jiān)測中的可行性研究

    振弦采集儀在巖土工程地質(zhì)災(zāi)害監(jiān)測中的可行性研究 引言: 巖土工程地質(zhì)災(zāi)害是指在巖土體中由于自然力和人類活動等因素引起的,對人類生活、財產(chǎn)以及環(huán)境造成威脅的災(zāi)害。為了及時發(fā)現(xiàn)并準(zhǔn)確監(jiān)測地質(zhì)災(zāi)害的發(fā)生
    的頭像 發(fā)表于 05-28 14:09 ?285次閱讀
    振弦采集儀在巖土工程地質(zhì)災(zāi)害監(jiān)測中的<b class='flag-5'>可行性</b>研究

    關(guān)于電化學(xué)儲能的BMS可行性方案

    基于嵌入式ARM核心板實現(xiàn)的BMS可行性方案,希望可幫助相關(guān)企業(yè)作為參考。 二、電池管理系統(tǒng)(BMS)BMS主要由電池陣列管理單元(BAMS)、電池蔟管理單元(BCMS)以及電池管理單元(BMU)組成
    發(fā)表于 05-16 17:08

    千萬不要忽視了零件選型調(diào)用

    選型和調(diào)用,是確保產(chǎn)品設(shè)計質(zhì)量、可靠和制造可行性的基礎(chǔ)。隨著供應(yīng)鏈短缺和信賴性要求提高,這一環(huán)節(jié)變得越發(fā)重要。設(shè)計工具的元器件庫集成和智能搜索功能,可以極大提高
    的頭像 發(fā)表于 05-14 13:28 ?467次閱讀
    千萬不要忽視了零件選型<b class='flag-5'>調(diào)用</b>

    振弦采集儀在地下水位監(jiān)測中的可行性研究與實踐

    振弦采集儀在地下水位監(jiān)測中的可行性研究與實踐 地下水位的監(jiān)測對于水資源管理和地下水環(huán)境保護(hù)具有重要意義。傳統(tǒng)的地下水位監(jiān)測方法主要包括井水位計、壓力傳感器和雨水入滲監(jiān)測等。然而,這些方法存在著一些
    的頭像 發(fā)表于 04-08 13:38 ?242次閱讀
    振弦采集儀在地下水位監(jiān)測中的<b class='flag-5'>可行性</b>研究與實踐

    高壓探頭測量相間電壓的可行性與注意事項

    可行性,并介紹在使用高壓探頭測量相間電壓時需要注意的事項。 高壓探頭的原理: 高壓探頭是一種專門設(shè)計用于測量高電壓的探頭。它通常由絕緣材料包圍,以確保安全,并具有適當(dāng)?shù)碾姎馓匦詠硖幚砀唠妷骸8邏禾筋^通過
    的頭像 發(fā)表于 04-07 14:24 ?451次閱讀
    高壓探頭測量相間電壓的<b class='flag-5'>可行性</b>與注意事項

    七段式SVPWM優(yōu)化電機(jī)電磁噪聲的量產(chǎn)可行性驗證

    七段式SVPWM優(yōu)化電機(jī)電磁噪聲的量產(chǎn)可行性驗證
    的頭像 發(fā)表于 03-21 17:28 ?1054次閱讀
    七段式SVPWM優(yōu)化電機(jī)電磁噪聲的量產(chǎn)<b class='flag-5'>可行性</b>驗證

    C#網(wǎng)絡(luò)串口調(diào)試助手源碼

    非常牛B網(wǎng)絡(luò)串口調(diào)試助手C#源碼,支持添加多條協(xié)議
    發(fā)表于 12-27 09:45 ?4次下載

    如何使用OpenVINO C++ API部署FastSAM模型

    象的位置和邊界。本文將介紹如何使用 OpenVINO C++ API 部署 FastSAM 模型,以實現(xiàn)快速高效的語義分割。在前文中我們發(fā)表了《基于 OpenVINO Python API 部署
    的頭像 發(fā)表于 11-17 09:53 ?840次閱讀
    如何使用<b class='flag-5'>OpenVINO</b> <b class='flag-5'>C</b>++ API部署FastSAM模型

    車用LED照明的可行性和先進(jìn)

    電子發(fā)燒友網(wǎng)站提供《車用LED照明的可行性和先進(jìn).doc》資料免費下載
    發(fā)表于 11-15 10:59 ?0次下載
    車用LED照明的<b class='flag-5'>可行性</b>和先進(jìn)<b class='flag-5'>性</b>