C#封裝YOLOv4演算法進行目標檢測

叮咚z發表於2001-01-01

C#封裝YOLOv4演算法進行目標檢測

概述

官網:https://pjreddie.com/darknet/
Darknet:【Github】
C#封裝程式碼:【Github】

YOLO: 是實現實時物體檢測的系統,Darknet是基於YOLO的框架
採用C#語言對 YOLOv4 目標檢測演算法封裝,將模型在實際應用系統中落地,實現模型線上遠端呼叫。

環境準備

本章只講解如何對YOLOv4封裝進行詳解,具體環境安裝過程不做介紹
檢視你的GPU計算能力是否支援 >= 3.0:【點選檢視】

Windows執行要求

我所使用的環境

  • 系統版本:Windows 10 專業版
  • 顯示卡:GTX 1050 Ti
  • CMake版本:3.18.2
  • CUDA版本:10.1
  • OpenCV版本:4.4.0
  • cuDNN版本:10.1
  • MSVC 2017/2019: Visual Studio 2019

程式程式碼準備

原始碼下載

下載地址:【Darknet】

使用Git

git clone https://github.com/AlexeyAB/darknet
cd darknet

程式碼結構

將YOLOv4編譯為DLL

詳細教程:【點選檢視】,這個教程描述的很詳細。

進入 darknet\build\darknet 目錄,開啟解決方案 yolo_cpp_dll.sln

設定Windows SDK版本和平臺工具集為當前系統安裝版本

設定Release和x64

然後執行以下操作:Build-> Build yolo_cpp_dll

已完成生成專案“yolo_cpp_dll.vcxproj”的操作。
========== 生成: 成功 1 個,失敗 0 個,最新 0 個,跳過 0 個 ==========

在打包DLL的過程中可能遇到如下問題

C1041
無法開啟程式資料庫“D:\程式碼管理\C\darknet\build\darknet\x64\DLL_Release\vc142.pdb”;如果要將多個 CL.EXE 寫入同一個 .PDB 檔案,請使用 /FS	yolo_cpp_dll	C:\Users\administrator\AppData\Local\Temp\tmpxft_00005db0_00000000-6_dropout_layer_kernels.compute_75.cudafe1.cpp	1	
MSB3721 
命令“"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\bin\nvcc.exe" -gencode=arch=compute_30,code=\"sm_30,compute_30\" -gencode=arch=compute_75,code=\"sm_75,compute_75\" --use-local-env -ccbin "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\bin\HostX86\x64" -x cu  -IC:\opencv\build\include -IC:\opencv_3.0\opencv\build\include -I..\..\include -I..\..\3rdparty\stb\include -I..\..\3rdparty\pthreads\include -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include" -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include" -I\include -I\include -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include"     --keep-dir x64\Release -maxrregcount=0  --machine 64 --compile -cudart static     -DCUDNN_HALF -DCUDNN -DGPU -DLIB_EXPORTS -D_TIMESPEC_DEFINED -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -DWIN32 -DNDEBUG -D_CONSOLE -D_LIB -D_WINDLL -D_MBCS -Xcompiler "/EHsc /W3 /nologo /O2 /Fdx64\DLL_Release\vc142.pdb  /Zi  /MD " -o x64\DLL_Release\dropout_layer_kernels.cu.obj "D:\darknet\src\dropout_layer_kernels.cu"”已退出,返回程式碼為 2。	yolo_cpp_dll	C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\BuildCustomizations\CUDA 10.1.targets	757	

解決方法

在VS 2019 工具》選項》專案和解決方案》生成並執行 中最大並行專案生成數設為 1

在VS 2019 專案-》屬性-》配置屬性-》常規 將Windows SDK版本設定為系統當前版本即可

封裝YOLOv4編譯後的DLL

  • 1、進入 darknet\build\darknet\x64 目錄,將 pthreadGC2.dllpthreadVC2.dll 拷貝到專案 Dll 資料夾
  • 2、將編譯後的YOLOv4 DLL檔案拷貝到專案 Dll 資料夾
  • 3、進入 darknet\build\darknet\x64\cfg 目錄,將 yolov4.cfg 拷貝到專案 Cfg 資料夾
  • 4、進入 darknet\build\darknet\x64\data 目錄,將 coco.names 拷貝到專案 Data 資料夾
  • 5、下載 yolov4.weights 權重檔案 拷貝到 Weights 資料夾,檔案245 MB 【點選下載】

專案檔案

程式碼下載:【Github】

  • YoloWrapper - YOLOv4封裝專案
    • Cfg - 配置資料夾
    • Data - label資料夾
    • Dll - YOLOv4 編譯後的DLL資料夾
    • Weights - YOLOv4 權重資料夾
    • BboxContainer.cs
    • BoundingBox.cs
    • YoloWrapper.cs - 封裝主檔案,呼叫 YOLOv4 的動態連結庫
  • YoloWrapperConsole - 呼叫封裝DLL控制檯程式
    • Program.cs - 控制檯主程式,呼叫 YOLOv4 封裝檔案

程式碼

YOLOv4封裝專案

YoloWrapper.cs - 封裝主檔案,呼叫 YOLOv4 的動態連結庫

using System;
using System.Runtime.InteropServices;

namespace YoloWrapper
{

    public class YoloWrapper : IDisposable
    {
        private const string YoloLibraryName = @"\Dlls\yolo_cpp_dll.dll";

        [DllImport(YoloLibraryName, EntryPoint = "init")]
        private static extern int InitializeYolo(string configurationFilename, string weightsFilename, int gpu);

        [DllImport(YoloLibraryName, EntryPoint = "detect_image")]
        private static extern int DetectImage(string filename, ref BboxContainer container);

        [DllImport(YoloLibraryName, EntryPoint = "detect_mat")]
        private static extern int DetectImage(IntPtr pArray, int nSize, ref BboxContainer container);

        [DllImport(YoloLibraryName, EntryPoint = "dispose")]
        private static extern int DisposeYolo();

        public YoloWrapper(string configurationFilename, string weightsFilename, int gpu)
        {
            InitializeYolo(configurationFilename, weightsFilename, gpu);
        }

        public void Dispose()
        {
            DisposeYolo();
        }

        public BoundingBox[] Detect(string filename)
        {
            var container = new BboxContainer();
            var count = DetectImage(filename, ref container);

            return container.candidates;
        }

        public BoundingBox[] Detect(byte[] imageData)
        {
            var container = new BboxContainer();

            var size = Marshal.SizeOf(imageData[0]) * imageData.Length;
            var pnt = Marshal.AllocHGlobal(size);

            try
            {
                Marshal.Copy(imageData, 0, pnt, imageData.Length);
                var count = DetectImage(pnt, imageData.Length, ref container);
                if (count == -1)
                {
                    throw new NotSupportedException($"{YoloLibraryName} has no OpenCV support");
                }
            }
            catch (Exception exception)
            {
                return null;
            }
            finally
            {
                Marshal.FreeHGlobal(pnt);
            }

            return container.candidates;
        }

    }

}

BboxContainer.cs

using System.Runtime.InteropServices;

namespace YoloWrapper
{
    [StructLayout(LayoutKind.Sequential)]
    public struct BboxContainer
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)]
        public BoundingBox[] candidates;
    }
}

BoundingBox.cs

using System;
using System.Runtime.InteropServices;

namespace YoloWrapper
{
    [StructLayout(LayoutKind.Sequential)]
    public struct BoundingBox
    {
        public UInt32 x, y, w, h;
        public float prob;
        public UInt32 obj_id;
        public UInt32 track_id;
        public UInt32 frames_counter;
        public float x_3d, y_3d, z_3d;
    }
}

呼叫封裝DLL控制檯程式

BoundingBox.cs

using ConsoleTables;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using YoloWrapper;

namespace YoloWrapperConsole
{
    class Program
    {
        private const string configurationFilename = @".\Cfg\yolov4.cfg";
        private const string weightsFilename = @".\Weights\yolov4.weights";
        private const string namesFile = @".\Data\coco.names";

        private static Dictionary<int, string> _namesDic = new Dictionary<int, string>();

        private static YoloWrapper.YoloWrapper _wrapper;

        static void Main(string[] args)
        {
            Initilize();

            Console.Write("ImagePath:");
            string imagePath = Console.ReadLine();
            var bbox = _wrapper.Detect(imagePath);

            Convert(bbox);

            Console.ReadKey();
        }

        private static void Initilize()
        {
            _wrapper = new YoloWrapper.YoloWrapper(configurationFilename, weightsFilename, 0);

            var lines = File.ReadAllLines(namesFile);
            for (var i = 0; i < lines.Length; i++)
                _namesDic.Add(i, lines[i]);
        }


        private static void Convert(BoundingBox[] bbox)
        {
            Console.WriteLine("Result:");
            var table = new ConsoleTable("Type", "Confidence", "X", "Y", "Width", "Height");
            foreach (var item in bbox.Where(o => o.h > 0 || o.w > 0))
            {
                var type = _namesDic[(int)item.obj_id];
                table.AddRow(type, item.prob, item.x, item.y, item.w, item.h);
            }
            table.Write(Format.MarkDown);
        }
    }
}

測試返回結果

Type Confidence X Y Width Height
mouse 0.25446844 1206 633 78 30
laptop 0.5488589 907 451 126 148
laptop 0.51734066 688 455 53 37
laptop 0.48207012 980 423 113 99
person 0.58085686 429 293 241 469
bottle 0.22032459 796 481 43 48
bottle 0.24873751 659 491 32 53
cup 0.5715177 868 453 55 70
bottle 0.29916075 1264 459 31 89
cup 0.2782725 685 503 35 40
cup 0.28154427 740 539 78 44
person 0.94347733 81 199 541 880
person 0.9496539 1187 368 233 155
chair 0.22458112 624 442 45 48
person 0.97528315 655 389 86 100
bottle 0.9407686 1331 436 33 107
bottle 0.9561032 1293 434 37 113
chair 0.4784215 1 347 386 730
cup 0.8945817 822 586 112 69
cup 0.6422996 1265 472 31 72
laptop 0.9833646 802 700 639 216
cup 0.9216428 828 521 115 71
chair 0.88087356 1124 416 111 70
diningtable 0.3222557 531 585 951 472

控制檯

相關文章