【OpenVINO™】在 MacOS 上使用 OpenVINO™ C# API 部署 Yolov5

来源:https://www.cnblogs.com/guojin-blogs/p/18009621
-Advertisement-
Play Games

YOLOv5 是革命性的 "單階段"對象檢測模型的第五次迭代,旨在實時提供高速、高精度的結果,是世界上最受歡迎的視覺人工智慧模型,代表了Ultralytics對未來視覺人工智慧方法的開源研究,融合了數千小時研發中積累的經驗教訓和最佳實踐。同時官方發佈的模型已經支持 OpenVINO™ 部署工具加速模... ...


在 MacOS 上使用 OpenVINO™ C# API 部署 Yolov5
項目介紹

YOLOv5 是革命性的 "單階段"對象檢測模型的第五次迭代,旨在實時提供高速、高精度的結果,是世界上最受歡迎的視覺人工智慧模型,代表了Ultralytics對未來視覺人工智慧方法的開源研究,融合了數千小時研發中積累的經驗教訓和最佳實踐。同時官方發佈的模型已經支持 OpenVINO™ 部署工具加速模型推理,因此在該項目中,我們將結合之前開發的 OpenVINO™ C# API 部署 YOLOv5 DET 模型實現物體對象檢測。

項目鏈接為:

https://github.com/guojin-yan/OpenVINO-CSharp-API

項目源碼鏈接為:

https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/tree/master/model_samples/yolov5/yolov5_det_opencvsharp
https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/tree/master/model_samples/yolov5/yolov5_det_emgucv

目錄

1. 前言

1.1 OpenVINO™ C# API

英特爾發行版 OpenVINO™ 工具套件基於 oneAPI 而開發,可以加快高性能電腦視覺和深度學習視覺應用開發速度工具套件,適用於從邊緣到雲的各種英特爾平臺上,幫助用戶更快地將更準確的真實世界結果部署到生產系統中。通過簡化的開發工作流程,OpenVINO™ 可賦能開發者在現實世界中部署高性能應用程式和演算法。

OpenVINO™ 2023.2 於 2023 年 11 月 16 日發佈,該工具包帶來了挖掘生成人工智慧全部潛力的新功能。更多的生成式 AI 覆蓋和框架集成,以最大限度地減少代碼更改,並且擴展了對直接 PyTorch 模型轉換的模型支持。支持更多新的模型,包括 LLaVA、chatGLM、Bark 和 LCM 等著名模型。支持更廣泛的大型語言模型(LLM)和更多模型壓縮技術,支持運行時推理支持以下 Int4 模型壓縮格式,通過神經網路壓縮框架(NNCF) 進行本機 Int4 壓縮等一系列新的功能。

OpenVINO™ C# API 是一個 OpenVINO™ 的 .Net wrapper,應用最新的 OpenVINO™ 庫開發,通過 OpenVINO™ C API 實現 .Net 對 OpenVINO™ Runtime 調用,使用習慣與 OpenVINO™ C++ API 一致。OpenVINO™ C# API 由於是基於 OpenVINO™ 開發,所支持的平臺與 OpenVINO™ 完全一致,具體信息可以參考 OpenVINO™。通過使用 OpenVINO™ C# API,可以在 .NET、.NET Framework等框架下使用 C# 語言實現深度學習模型在指定平臺推理加速。

1.2 YOLOv5

​ YOLOv5 是革命性的 "單階段"對象檢測模型的第五次迭代,旨在實時提供高速、高精度的結果,是世界上最受歡迎的視覺人工智慧模型,代表了Ultralytics對未來視覺人工智慧方法的開源研究,融合了數千小時研發中積累的經驗教訓和最佳實踐。

2. 模型下載與轉換

2.1 環境安裝

首先創建Yolov5模型下載與轉換環境,此處為了更好的管理環境,使用Anaconda創建一個虛擬環境用於安裝Yolov5模型下載與轉換環境,首先使用conda創建一個虛擬環境,在命令行中依次輸入以下指令:

conda create -n yolo python=3.10
conda activate yolo

接下來安裝Yolov5模型下載與轉換環境,基礎的Yolov5模型下載需要通過克隆官方源碼實現,在命令行中依次輸入以下指令實現環境的安裝與配置即可:

git clone https://github.com/ultralytics/yolov5
cd yolov5
pip install -r requirements.txt
pip install --upgrade openvino-nightly

2.2 Yolov5 模型下載

Yolov5 官方提供了模型導出與轉換的方式,用戶只需要調用該介面便可以,在命令行中輸入以下指令便可以直接導出Yolov5模型:

cd yolov5
python export.py --weights yolov5s.pt --include onnx

結果輸出如下圖所示:

使用Netron工具打開模型文件,查看模型結構,如下圖所示:

官方預訓練模型是在COCO數據集上訓練的,因此導出的模型可以識別80種物體。模型輸入節點為images,輸入為歸一化後的圖像數據,其輸入大小為640×640;模型的輸出節點為output0,輸出大小為25200×85,其中25200(640÷8=80,640÷16=40,640÷32=20,3×80×80+3×40×40+3×20×20=25200)表示識別結果個數,85表示[cx, cy, w, h, confidence, score0, ···,score79],分別為識別框信息、識別結果中最大置信度以及80中類別結果的分數。

2.3 轉換IR模型

接下來直接使用 OpenVINO™ 工具直接進行模型轉換,在CMD中輸入以下指令即可:

ovc yolov5s.onnx

3. Yolov5 DET 項目配置(OpenCvSharp版)

3.1 項目創建

如果開發者第一次在MacOS系統上使用C#編程語言,可以參考《在MacOS系統上配置OpenVINO™ C# API》文章進行配置。

首先使用dotnet創建一個測試項目,在終端中輸入一下指令:

dotnet new console --framework net6.0 --use-program-main -o yolov5-det 

3.2 添加項目依賴

MacOS系統目前主要分為兩類,一類是使用intel處理器的X64位的系統,一類是使用M系列晶元的arm64位系統,目前OpenVINO官方針對這兩種系統都提供了編譯後的系統,所以目前OpenVINO.CSharp.API針對這兩種系統都提供了支持。

此處以M系列處理器的MacOS平臺為例安裝項目依賴,首先是安裝OpenVINO™ C# API項目依賴,在命令行中輸入以下指令即可:

dotnet add package OpenVINO.CSharp.API
dotnet add package OpenVINO.runtime.macos-arm64
dotnet add package OpenVINO.CSharp.API.Extensions
dotnet add package OpenVINO.CSharp.API.Extensions.OpenCvSharp

關於在MacOS上搭建 OpenVINO™ C# API 開發環境請參考以下文章: 在MacOS上搭建OpenVINO™C#開發環境

接下來安裝使用到的圖像處理庫 OpenCvSharp,在命令行中輸入以下指令即可:

dotnet add package OpenCvSharp4
dotnet add package OpenCvSharp4.Extensions
dotnet add package OpenCvSharp4.runtime.osx_arm64 --prerelease

關於在MacOS上搭建 OpenCvSharp 開發環境請參考以下文章: 【OpenCV】在MacOS上使用OpenCvSharp

添加完成項目依賴後,項目的配置文件如下所示:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <RootNamespace>yolov5_det</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="OpenCvSharp4" Version="4.9.0.20240103" />
    <PackageReference Include="OpenCvSharp4.Extensions" Version="4.9.0.20240103" />
    <PackageReference Include="OpenCvSharp4.runtime.osx_arm64" Version="4.8.1-rc" />
    <PackageReference Include="OpenVINO.CSharp.API" Version="2023.2.0.4" />
    <PackageReference Include="OpenVINO.CSharp.API.Extensions" Version="1.0.1" />
    <PackageReference Include="OpenVINO.CSharp.API.Extensions.OpenCvSharp" Version="1.0.4" />
    <PackageReference Include="OpenVINO.runtime.macos-arm64" Version="2023.3.0.1" />
  </ItemGroup>

</Project>

3.3 定義預測方法

(1) 使用常規方式部署模型

Yolov5 屬於比較經典單階段目標檢測模型,其模型輸入為640*640的歸一化處理後的圖像數據,輸出為未進行NMS的推理結果,因此在獲取推理結果後,需要進行NMS,其實現代碼如下所示:

static void yolov5_det(string model_path, string image_path, string device)
{
    // -------- Step 1. Initialize OpenVINO Runtime Core --------
    Core core = new Core();
    // -------- Step 2. Read inference model --------
    Model model = core.read_model(model_path);
    OvExtensions.printf_model_info(model);
    // -------- Step 3. Loading a model to the device --------
    start = DateTime.Now;
    CompiledModel compiled_model = core.compile_model(model, device);
    // -------- Step 4. Create an infer request --------
    InferRequest infer_request = compiled_model.create_infer_request();
    // -------- Step 5. Process input images --------
    Mat image = new Mat(image_path); // Read image by opencvsharp
    int max_image_length = image.Cols > image.Rows ? image.Cols : image.Rows;
    Mat max_image = Mat.Zeros(new OpenCvSharp.Size(max_image_length, max_image_length), MatType.CV_8UC3);
    Rect roi = new Rect(0, 0, image.Cols, image.Rows);
    image.CopyTo(new Mat(max_image, roi));
    float factor = (float)(max_image_length / 640.0);
    // -------- Step 6. Set up input data --------
    Tensor input_tensor = infer_request.get_input_tensor();
    Shape input_shape = input_tensor.get_shape();
    Mat input_mat = CvDnn.BlobFromImage(max_image, 1.0 / 255.0, new OpenCvSharp.Size(input_shape[2], input_shape[3]), 0, true, false);
    float[] input_data = new float[input_shape[1] * input_shape[2] * input_shape[3]];
    Marshal.Copy(input_mat.Ptr(0), input_data, 0, input_data.Length);
    input_tensor.set_data<float>(input_data);
    // -------- Step 7. Do inference synchronously --------
    infer_request.infer();
    // -------- Step 8. Get infer result data --------
    Tensor output_tensor = infer_request.get_output_tensor();
    int output_length = (int)output_tensor.get_size();
    float[] output_data = output_tensor.get_data<float>(output_length);

    // -------- Step 9. Process reault  --------
    Mat result_data = new Mat(25200, 85, MatType.CV_32F, output_data);
    // Storage results list
    List<Rect> position_boxes = new List<Rect>();
    List<int> class_ids = new List<int>();
    List<float> confidences = new List<float>();
    // Preprocessing output results
    for (int i = 0; i < result_data.Rows; i++)
    {
        float confidence = result_data.At<float>(i, 4);
        if (confidence < 0.5)
        {
            continue;
        }
        Mat classes_scores = new Mat(result_data, new Rect(5, i, 80, 1));
        OpenCvSharp.Point max_classId_point, min_classId_point;
        double max_score, min_score;
        // Obtain the maximum value and its position in a set of data
        Cv2.MinMaxLoc(classes_scores, out min_score, out max_score,
            out min_classId_point, out max_classId_point);
        // Confidence level between 0 ~ 1
        // Obtain identification box information
        if (max_score > 0.25)
        {
            float cx = result_data.At<float>(i, 0);
            float cy = result_data.At<float>(i, 1);
            float ow = result_data.At<float>(i, 2);
            float oh = result_data.At<float>(i, 3);
            int x = (int)((cx - 0.5 * ow) * factor);
            int y = (int)((cy - 0.5 * oh) * factor);
            int width = (int)(ow * factor);
            int height = (int)(oh * factor);
            Rect box = new Rect();
            box.X = x;
            box.Y = y;
            box.Width = width;
            box.Height = height;

            position_boxes.Add(box);
            class_ids.Add(max_classId_point.X);
            confidences.Add((float)confidence);
        }
    }
    // NMS non maximum suppression
    int[] indexes = new int[position_boxes.Count];
    CvDnn.NMSBoxes(position_boxes, confidences, 0.5f, 0.5f, out indexes);
    for (int i = 0; i < indexes.Length; i++)
    {
        int index = indexes[i];
        Cv2.Rectangle(image, position_boxes[index], new Scalar(0, 0, 255), 2, LineTypes.Link8);
        Cv2.Rectangle(image, new OpenCvSharp.Point(position_boxes[index].TopLeft.X, position_boxes[index].TopLeft.Y + 30),
            new OpenCvSharp.Point(position_boxes[index].BottomRight.X, position_boxes[index].TopLeft.Y), new Scalar(0, 255, 255), -1);
        Cv2.PutText(image, class_ids[index] + "-" + confidences[index].ToString("0.00"),
            new OpenCvSharp.Point(position_boxes[index].X, position_boxes[index].Y + 25),
            HersheyFonts.HersheySimplex, 0.8, new Scalar(0, 0, 0), 2);
    }
    string output_path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(image_path)),
        Path.GetFileNameWithoutExtension(image_path) + "_result.jpg");
    Cv2.ImWrite(output_path, image);
    Slog.INFO("The result save to " + output_path);
    Cv2.ImShow("Result", image);
    Cv2.WaitKey(0);
}

(2) 使用模型結構處理處理數據

目前 OpenVINO™ 已經支持在模型結構中增加數據的前後處理流程,並且在 OpenVINO™ C# API 中也已經實現了該功能介面,所以在此處演示瞭如何將模型輸入數據處理流程封裝到模型中,通過 OpenVINO™ 進行數據處理的加速處理,如下麵代碼所示:

static void yolov5_det_with_process(string model_path, string image_path, string device)
{
    ······
    // -------- Step 2. Read inference model --------
    start = DateTime.Now;
    Model model = core.read_model(model_path);
    OvExtensions.printf_model_info(model);
    PrePostProcessor processor = new PrePostProcessor(model);
    Tensor input_tensor_pro = new Tensor(new OvType(ElementType.U8), new Shape(1, 640, 640, 3));
    InputInfo input_info = processor.input(0);
    InputTensorInfo input_tensor_info = input_info.tensor();
    input_tensor_info.set_from(input_tensor_pro).set_layout(new Layout("NHWC")).set_color_format(ColorFormat.BGR);
    PreProcessSteps process_steps = input_info.preprocess();
    process_steps.convert_color(ColorFormat.RGB).resize(ResizeAlgorithm.RESIZE_LINEAR)
        .convert_element_type(new OvType(ElementType.F32)).scale(255.0f).convert_layout(new Layout("NCHW"));
    Model new_model = processor.build();
    // -------- Step 3. Loading a model to the device --------
    CompiledModel compiled_model = core.compile_model(new_model, device);
    // -------- Step 4. Create an infer request --------
    InferRequest infer_request = compiled_model.create_infer_request();
    // -------- Step 5. Process input images --------
    Mat image = new Mat(image_path); // Read image by opencvsharp
    int max_image_length = image.Cols > image.Rows ? image.Cols : image.Rows;
    Mat max_image = Mat.Zeros(new OpenCvSharp.Size(max_image_length, max_image_length), MatType.CV_8UC3);
    Rect roi = new Rect(0, 0, image.Cols, image.Rows);
    image.CopyTo(new Mat(max_image, roi));
    Cv2.Resize(max_image, max_image, new OpenCvSharp.Size(640, 640));
    float factor = (float)(max_image_length / 640.0);
    // -------- Step 6. Set up input data --------
    Tensor input_tensor = infer_request.get_input_tensor();
    Shape input_shape = input_tensor.get_shape();
    byte[] input_data = new byte[input_shape[1] * input_shape[2] * input_shape[3]];
    Marshal.Copy(max_image.Ptr(0), input_data, 0, input_data.Length);
    IntPtr destination = input_tensor.data();
    Marshal.Copy(input_data, 0, destination, input_data.Length);
    // -------- Step 7. Do inference synchronously --------
    ······
}

由於目前還沒有完全實現所有的 OpenVINO™ 的預處理介面,因此只能實現部分預處理過程封裝到模型中,此處主要是做了以下處理:

  • 數據類型轉換:byte->float
  • 數據維度轉換:NHWC->NCHW
  • 圖像色彩空間轉換:BGR->RGB
  • 數據歸一化處理:[0,1]->[0,255]

因此將一些數據處理流程封裝到模型中後,在進行模型推理時,只需要將讀取到的圖片數據Resize為640*640後,就可以直接將數據載入到模型即可。

(3) 使用 OpenVINO™ C# API 封裝的介面

YOLOv5 是當前工業領域十分流行的目標檢測模型,因此在封裝 OpenVINO™ C# API 時,提供了快速部署 Yolov5 模型的介面,實現代碼如下所示:

static void yolov5_det_using_extensions(string model_path, string image_path, string device)
{
    Yolov5DetConfig config = new Yolov5DetConfig();
    config.set_model(model_path);
    Yolov5Det yolov8 = new Yolov5Det(config);
    Mat image = Cv2.ImRead(image_path);
    DetResult result = yolov8.predict(image);
    Mat result_im = Visualize.draw_det_result(result, image);
    Cv2.ImShow("Result", result_im);
    Cv2.WaitKey(0);
}

3.4 預測方法調用

定義好上述方法後,便可以直接在主函數中調用該方法,只需要在主函數中增加以下代碼即可:

yolov5_det("yolov5s.xml", "test_image.png", "AUTO");
yolov5_det_with_process("yolov5s.xml", "test_image.png", "AUTO");
yolov5_det_using_extensions("yolov5s.xml", "test_image.png", "AUTO");

如果開發者自己沒有進行模型下載與轉換,又同時想快速體驗該項目,我此處提供了線上的轉換後的模型以及帶預測圖片,開發者可以直接在主函數中增加以下代碼,便可以直接自動下載模型以及推理數據,並調用推理方法,實現程式直接運行。

static void Main(string[] args)
{
    string model_path = "";
    string image_path = "";
    string device = "AUTO";
    if (args.Length == 0)
    {
        if (!Directory.Exists("./model"))
        {
            Directory.CreateDirectory("./model");
        }
        if (!File.Exists("./model/yolov5s.bin") && !File.Exists("./model/yolov5s.bin"))
        {
            if (!File.Exists("./model/yolov5s.tar"))
            {
                _ = Download.download_file_async("https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/releases/download/Model/yolov5s.tar",
                    "./model/yolov5s.tar").Result;
            }
            Download.unzip("./model/yolov585s.tar", "./model/");
        }

        if (!File.Exists("./model/test_image.jpg"))
        {
            _ = Download.download_file_async("https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/releases/download/Image/test_det_02.jpg",
                "./model/test_image.jpg").Result;
        }
        model_path = "./model/yolov5s.xml";
        image_path = "./model/test_image.jpg";
    }
    else if (args.Length >= 2)
    {
        model_path = args[0];
        image_path = args[1];
        device = args[2];
    }
    else
    {
        Console.WriteLine("Please enter the correct command parameters, for example:");
        Console.WriteLine("> 1. dotnet run");
        Console.WriteLine("> 2. dotnet run <model path> <image path> <device name>");
    }
    // -------- Get OpenVINO runtime version --------

    OpenVinoSharp.Version version = Ov.get_openvino_version();

    Slog.INFO("---- OpenVINO INFO----");
    Slog.INFO("Description : " + version.description);
    Slog.INFO("Build number: " + version.buildNumber);

    Slog.INFO("Predict model files: " + model_path);
    Slog.INFO("Predict image  files: " + image_path);
    Slog.INFO("Inference device: " + device);
    Slog.INFO("Start yolov8 model inference.");

    yolov5_det(model_path, image_path, device);
    //yolov5_det_with_process(model_path, image_path, device);
    //yolov5_det_using_extensions(model_path, image_path, device);
}

為了減少文章篇幅,所以此處只提供了有差異的代碼,如果想獲取完整代碼,請訪問GitHub代碼倉庫,獲取項目源碼,鏈接為:

https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/tree/master/model_samples/yolov5/yolov5_det_opencvsharp

4. Yolov5 DET 項目配置(Emgu.CV 版)

同樣地,為了滿足Emgu.CV開發者的需求,此處同樣地提供了Emgu.CV版本的Yolov5的模型部署代碼以及使用流程,此處為了簡化文章內容,對於和上文重覆的步驟不在進行展開講述。

4.1 添加項目依賴

首先是安裝OpenVINO™ C# API項目依賴,在命令行中輸入以下指令即可:

dotnet add package OpenVINO.CSharp.API
dotnet add package OpenVINO.runtime.macos-arm64
dotnet add package OpenVINO.CSharp.API.Extensions
dotnet add package OpenVINO.CSharp.API.Extensions.EmguCV

接下來安裝使用到的圖像處理庫 Emgu.CV,在命令行中輸入以下指令即可:

dotnet add package Emgu.CV
dotnet add package Emgu.CV.runtime.mini.macos

關於在MacOS上搭建 OpenCvSharp 開發環境請參考以下文章: 【OpenCV】在MacOS上使用Emgu.CV

添加完成項目依賴後,項目的配置文件如下所示:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <RootNamespace>yolov5_det</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Emgu.CV" Version="4.8.1.5350" />
    <PackageReference Include="Emgu.CV.runtime.mini.macos" Version="4.8.1.5350" />
    <PackageReference Include="OpenVINO.CSharp.API" Version="2023.2.0.4" />
    <PackageReference Include="OpenVINO.CSharp.API.Extensions" Version="1.0.1" />
    <PackageReference Include="OpenVINO.CSharp.API.Extensions.EmguCV" Version="1.0.4.1" />
    <PackageReference Include="OpenVINO.runtime.macos-arm64" Version="2023.3.0.1" />
  </ItemGroup>

</Project>

4.2 定義預測方法

模型部署流程與上一節中使用OpenCvSharp的基本一致,主要是替換了圖像處理的工具,同時提供瞭如上一節中所展示的三種部署方式。此處為了減少文章篇幅,此處不在展示詳細的部署代碼,如果想獲取相關代碼,請訪問項目GitHub,下載所有的測試代碼,項目鏈接為:

https://github.com/guojin-yan/OpenVINO-CSharp-API-Samples/tree/master/model_samples/yolov5/yolov5_det_emgucv

5. 項目運行與演示

5.1 項目編譯

接下來輸入項目編譯指令進行項目編譯,輸入以下指令即可:

dotnet build

程式編譯後輸出為:

5.2 項目文件運行

接下來運行編譯後的程式文件,在CMD中輸入以下指令,運行編譯後的項目文件:

dotnet run --no-build

運行後項目輸出為:

6. 總結

在該項目中,我們結合之前開發的 OpenVINO C# API 項目部署YOLOv5模型,成功實現了對象目標檢測,並且根據不同開發者的使用習慣,同時提供了OpenCvSharp以及Emgu.CV兩種版本,供各位開發者使用。最後如果各位開發者在使用中有任何問題,歡迎大家與我聯繫。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 工商銀行和華為雲牽頭,並聯合7家金融機構共同編製的《金融行業開放平臺資料庫轉型白皮書》榮獲2023年度十佳課題。 ...
  • 優秀的程式應該儘可能地規避問題。因此,以後在服務商系統里,當定義包含漢字的欄位時,使用 nvarchar2,而非 varchar2。 因此,在服務商系統作為我司系統的小眾系統的背景下,Oracle的技術特性我們不一一曉知是可以理解和接受的。而如何在不一一曉知這些技術特性的情況下,能夠規避這些技術特性... ...
  • 環境 MySQL 5.7 非GTID模式多線程複製。 現象 某MySQL資料庫從節點因故障宕機(因故障直接宕機,非正常關閉),重啟之後發現複製狀態異常,show slave的結果中Slave_SQL_Running為No,錯誤代碼為1062 error code,從系統表performance_sc ...
  • 一、為什麼要做診斷引擎 毓數平臺是奇富科技公司自主研發的一站式大數據管理、開發、分析平臺,覆蓋大數據資產管理、數據開發及任務調度、自助分析及可視化、統一指標管理等多個數據生命周期流程,讓用戶使用數據的同時,挖掘數據最大的價值。而毓數平臺的大數據任務調度底層是基於Apache DolphinSched ...
  • 作者,祝青平,華為雲資料庫內核高級工程師。擅長資料庫優化器內核研發,9年資料庫內核研發經驗,參與多個TP以及AP資料庫的研發工作。 近日,華為雲資料庫社區下麵有這樣一條用戶提問留言:請問,如何通過MySQL提升DISTINCT,尤其是多表連接下DISTINCT的查詢效率? 在回答這個問題之前,我們先 ...
  • Hello 大家好,先祝福大家新年快樂。 AgileConfig 1.9.0 版本終於趕在農曆年前發佈了。 Mongodb 當前做為一款非常成熟的 Nosql 產品,已經有越來越多的產品或項目基於它來構建。在 AgileConfig 開源的這幾年之間,陸陸續續收到不少同學問為啥不支持 M ...
  • 引言: 在現代互聯網應用程式的開發和部署中,選擇一個可靠、高性能的Web伺服器是至關重要的。Nginx是一個備受推崇的選擇,它以其卓越的性能和可靠性在開發者社區中享有盛譽。本文將介紹Nginx的概念、優勢,以及如何使用Nginx作為Web伺服器和反向代理。 什麼是Nginx? Nginx(發音為“e ...
  • 折騰Docker 有幾天了,整別的都沒這個糟心。目前已經順利部署運行起來了。順便給大家分享下處理在Windows上使用.NET部署到Docker的相關問題解決方法。 1. Docker無法安裝問題 (下圖是網上找了個類似的安裝失敗截圖,頁面大致一樣,就是提示內容是 Docker Desktop 只能 ...
一周排行
    -Advertisement-
    Play Games
  • 最近做項目過程中,使用到了海康相機,官方只提供了C/C++的SDK,沒有搜尋到一個合適的封裝了的C#庫,故自己動手,簡單的封裝了一下,方便大家也方便自己使用和二次開發 ...
  • 前言 MediatR 是 .NET 下的一個實現消息傳遞的庫,輕量級、簡潔高效,用於實現進程內的消息傳遞機制。它基於中介者設計模式,支持請求/響應、命令、查詢、通知和事件等多種消息傳遞模式。通過泛型支持,MediatR 可以智能地調度不同類型的消息,非常適合用於領域事件處理。 在本文中,將通過一個簡 ...
  • 前言 今天給大家推薦一個超實用的開源項目《.NET 7 + Vue 許可權管理系統 小白快速上手》,DncZeus的願景就是做一個.NET 領域小白也能上手的簡易、通用的後臺許可權管理模板系統基礎框架。 不管你是技術小白還是技術大佬或者是不懂前端Vue 的新手,這個項目可以快速上手讓我們從0到1,搭建自 ...
  • 第1章:WPF概述 本章目標 瞭解Windows圖形演化 瞭解WPF高級API 瞭解解析度無關性概念 瞭解WPF體繫結構 瞭解WPF 4.5 WPF概述 ​ 歡迎使用 Windows Presentation Foundation (WPF) 桌面指南,這是一個與解析度無關的 UI 框架,使用基於矢 ...
  • 在日常開發中,並不是所有的功能都是用戶可見的,還在一些背後默默支持的程式,這些程式通常以服務的形式出現,統稱為輔助角色服務。今天以一個簡單的小例子,簡述基於.NET開發輔助角色服務的相關內容,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 第3章:佈局 本章目標 理解佈局的原則 理解佈局的過程 理解佈局的容器 掌握各類佈局容器的運用 理解 WPF 中的佈局 WPF 佈局原則 ​ WPF 視窗只能包含單個元素。為在WPF 視窗中放置多個元素並創建更貼近實用的用戶男面,需要在視窗上放置一個容器,然後在這個容器中添加其他元素。造成這一限制的 ...
  • 前言 在平時項目開發中,定時任務調度是一項重要的功能,廣泛應用於後臺作業、計劃任務和自動化腳本等模塊。 FreeScheduler 是一款輕量級且功能強大的定時任務調度庫,它支持臨時的延時任務和重覆迴圈任務(可持久化),能夠按秒、每天/每周/每月固定時間或自定義間隔執行(CRON 表達式)。 此外 ...
  • 目錄Blazor 組件基礎路由導航參數組件參數路由參數生命周期事件狀態更改組件事件 Blazor 組件 基礎 新建一個項目命名為 MyComponents ,項目模板的交互類型選 Auto ,其它保持預設選項: 客戶端組件 (Auto/WebAssembly): 最終解決方案裡面會有兩個項目:伺服器 ...
  • 先看一下效果吧: isChecked = false 的時候的效果 isChecked = true 的時候的效果 然後我們來實現一下這個效果吧 第一步:創建一個空的wpf項目; 第二步:在項目裡面添加一個checkbox <Grid> <CheckBox HorizontalAlignment=" ...
  • 在編寫上位機軟體時,需要經常處理命令拼接與其他設備進行通信,通常對不同的命令封裝成不同的方法,擴展稍許麻煩。 本次擬以特性方式實現,以兼顧維護性與擴展性。 思想: 一種命令對應一個類,其類中的各個屬性對應各個命令段,通過特性的方式,實現其在這包數據命令中的位置、大端或小端及其轉換為對應的目標類型; ...