最美塑型师 發表於 2020-9-12 16:28:00

C#封装YOLOv4算法进行目标检测

<h1 id="c封装yolov4算法进行目标检测">C#封装YOLOv4算法进行目标检测</h1>
<h2 id="概述">概述</h2>
<p>官网:https://pjreddie.com/darknet/<br>
Darknet:【Github】<br>
C#封装代码:【Github】</p>
<p>YOLO: 是实现实时物体检测的系统,Darknet是基于YOLO的框架<br>
采用C#语言对 YOLOv4 目标检测算法封装,将模型在实际应用系统中落地,实现模型在线远程调用。</p>
<h2 id="环境准备">环境准备</h2>
<p>本章只讲解如何对YOLOv4封装进行详解,具体环境安装过程不做介绍<br>
查看你的GPU计算能力是否支持 &gt;= 3.0:【点击查看】</p>
<p>Windows运行要求</p>
<ul>
<li>CMake &gt;= 3.12: 【点击下载】</li>
<li>CUDA &gt;= 10.0: 【点击下载】</li>
<li>OpenCV &gt;= 2.4: 【点击下载】</li>
<li>cuDNN &gt;= 7.0: 【点击下载】</li>
<li>Visual Studio 2017/2019: 【点击下载】</li>
</ul>
<p>我所使用的环境</p>
<ul>
<li>系统版本:Windows 10 专业版</li>
<li>显卡:GTX 1050 Ti</li>
<li>CMake版本:3.18.2</li>
<li>CUDA版本:10.1</li>
<li>OpenCV版本:4.4.0</li>
<li>cuDNN版本:10.1</li>
<li>MSVC 2017/2019: Visual Studio 2019</li>
</ul>
<h2 id="程序代码准备">程序代码准备</h2>
<h3 id="源代码下载">源代码下载</h3>
<p>下载地址:【Darknet】</p>
<p>使用Git</p>
<pre><code class="language-PowerShell">git clone https://github.com/AlexeyAB/darknet
cd darknet
</code></pre>
<h3 id="代码结构">代码结构</h3>
<p><img src="https://img2020.cnblogs.com/blog/1213796/202009/1213796-20200912162337600-205036889.png" alt="" loading="lazy"></p>
<h2 id="将yolov4编译为dll">将YOLOv4编译为DLL</h2>
<p>详细教程:【点击查看】,这个教程描述的很详细。</p>
<p>进入 <code>darknet\build\darknet</code> 目录,打开解决方案 yolo_cpp_dll.sln</p>
<p><img src="https://img2020.cnblogs.com/blog/1213796/202009/1213796-20200912162412259-1736088086.png" alt="" loading="lazy"></p>
<p>设置Windows SDK版本和平台工具集为当前系统安装版本</p>
<p><img src="https://img2020.cnblogs.com/blog/1213796/202009/1213796-20200912162437978-1521070799.png" alt="" loading="lazy"></p>
<p>设置Release和x64</p>
<p><img src="https://img2020.cnblogs.com/blog/1213796/202009/1213796-20200912162452922-1740888450.png" alt="" loading="lazy"></p>
<p>然后执行以下操作:Build-&gt; Build yolo_cpp_dll</p>
<pre><code class="language-PowerShell">已完成生成项目“yolo_cpp_dll.vcxproj”的操作。
========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========
</code></pre>
<h3 id="在打包dll的过程中可能遇到如下问题">在打包DLL的过程中可能遇到如下问题</h3>
<pre><code class="language-PowerShell">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       
</code></pre>
<pre><code class="language-PowerShell">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       
</code></pre>
<h3 id="解决方法">解决方法</h3>
<p>在VS 2019 <code>工具》选项》项目和解决方案》生成并运行</code> 中最大并行项目生成数设为 <code>1</code></p>
<p><img src="https://img2020.cnblogs.com/blog/1213796/202009/1213796-20200912162511449-606383563.png" alt="" loading="lazy"></p>
<p>在VS 2019 <code>项目-》属性-》配置属性-》常规</code> 将Windows SDK版本设置为系统当前版本即可</p>
<p><img src="https://img2020.cnblogs.com/blog/1213796/202009/1213796-20200912162528724-615678812.png" alt="" loading="lazy"></p>
<h2 id="封装yolov4编译后的dll">封装YOLOv4编译后的DLL</h2>
<ul>
<li>1、进入 <code>darknet\build\darknet\x64</code> 目录,将 <code>pthreadGC2.dll</code> 和 <code>pthreadVC2.dll</code> 拷贝到项目 <code>Dll</code> 文件夹</li>
<li>2、将编译后的YOLOv4 DLL文件拷贝到项目 <code>Dll</code> 文件夹</li>
<li>3、进入 <code>darknet\build\darknet\x64\cfg</code> 目录,将 <code>yolov4.cfg</code> 拷贝到项目 <code>Cfg</code> 文件夹</li>
<li>4、进入 <code>darknet\build\darknet\x64\data</code> 目录,将 <code>coco.names</code> 拷贝到项目 <code>Data</code> 文件夹</li>
<li>5、下载 yolov4.weights 权重文件 拷贝到 <code>Weights</code> 文件夹,文件245 MB 【点击下载】</li>
</ul>
<h3 id="项目文件">项目文件</h3>
<p>代码下载:【Github】</p>
<ul>
<li><code>YoloWrapper</code> - YOLOv4封装项目
<ul>
<li><code>Cfg</code> - 配置文件夹</li>
<li><code>Data</code> - label文件夹</li>
<li><code>Dll</code> - YOLOv4 编译后的DLL文件夹</li>
<li><code>Weights</code> - YOLOv4 权重文件夹</li>
<li><code>BboxContainer.cs</code></li>
<li><code>BoundingBox.cs</code></li>
<li><code>YoloWrapper.cs</code> - 封装主文件,调用 YOLOv4 的动态链接库</li>
</ul>
</li>
<li><code>YoloWrapperConsole</code> - 调用封装DLL控制台程序
<ul>
<li><code>Program.cs</code> - 控制台主程序,调用 YOLOv4 封装文件</li>
</ul>
</li>
</ul>
<p><img src="https://img2020.cnblogs.com/blog/1213796/202009/1213796-20200912162548001-1116761599.png" alt="" loading="lazy"></p>
<h3 id="代码">代码</h3>
<h4 id="yolov4封装项目">YOLOv4封装项目</h4>
<p><code>YoloWrapper.cs</code> - 封装主文件,调用 YOLOv4 的动态链接库</p>
<pre><code class="language-C#">using System;
using System.Runtime.InteropServices;

namespace YoloWrapper
{

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

      
      private static extern int InitializeYolo(string configurationFilename, string weightsFilename, int gpu);

      
      private static extern int DetectImage(string filename, ref BboxContainer container);

      
      private static extern int DetectImage(IntPtr pArray, int nSize, ref BboxContainer container);

      
      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) * 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;
      }

    }

}

</code></pre>
<p><code>BboxContainer.cs</code></p>
<pre><code class="language-C#">using System.Runtime.InteropServices;

namespace YoloWrapper
{
   
    public struct BboxContainer
    {
      
      public BoundingBox[] candidates;
    }
}
</code></pre>
<p><code>BoundingBox.cs</code></p>
<pre><code class="language-C#">using System;
using System.Runtime.InteropServices;

namespace YoloWrapper
{
   
    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;
    }
}
</code></pre>
<h4 id="调用封装dll控制台程序">调用封装DLL控制台程序</h4>
<p><code>BoundingBox.cs</code></p>
<pre><code class="language-C#">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&lt;int, string&gt; _namesDic = new Dictionary&lt;int, string&gt;();

      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 &lt; lines.Length; i++)
                _namesDic.Add(i, lines);
      }


      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 =&gt; o.h &gt; 0 || o.w &gt; 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);
      }
    }
}
</code></pre>
<h3 id="测试返回结果">测试返回结果</h3>
<table>
<thead>
<tr>
<th>Type</th>
<th>Confidence</th>
<th>X</th>
<th>Y</th>
<th>Width</th>
<th>Height</th>
</tr>
</thead>
<tbody>
<tr>
<td>mouse</td>
<td>0.25446844</td>
<td>1206</td>
<td>633</td>
<td>78</td>
<td>30</td>
</tr>
<tr>
<td>laptop</td>
<td>0.5488589</td>
<td>907</td>
<td>451</td>
<td>126</td>
<td>148</td>
</tr>
<tr>
<td>laptop</td>
<td>0.51734066</td>
<td>688</td>
<td>455</td>
<td>53</td>
<td>37</td>
</tr>
<tr>
<td>laptop</td>
<td>0.48207012</td>
<td>980</td>
<td>423</td>
<td>113</td>
<td>99</td>
</tr>
<tr>
<td>person</td>
<td>0.58085686</td>
<td>429</td>
<td>293</td>
<td>241</td>
<td>469</td>
</tr>
<tr>
<td>bottle</td>
<td>0.22032459</td>
<td>796</td>
<td>481</td>
<td>43</td>
<td>48</td>
</tr>
<tr>
<td>bottle</td>
<td>0.24873751</td>
<td>659</td>
<td>491</td>
<td>32</td>
<td>53</td>
</tr>
<tr>
<td>cup</td>
<td>0.5715177</td>
<td>868</td>
<td>453</td>
<td>55</td>
<td>70</td>
</tr>
<tr>
<td>bottle</td>
<td>0.29916075</td>
<td>1264</td>
<td>459</td>
<td>31</td>
<td>89</td>
</tr>
<tr>
<td>cup</td>
<td>0.2782725</td>
<td>685</td>
<td>503</td>
<td>35</td>
<td>40</td>
</tr>
<tr>
<td>cup</td>
<td>0.28154427</td>
<td>740</td>
<td>539</td>
<td>78</td>
<td>44</td>
</tr>
<tr>
<td>person</td>
<td>0.94347733</td>
<td>81</td>
<td>199</td>
<td>541</td>
<td>880</td>
</tr>
<tr>
<td>person</td>
<td>0.9496539</td>
<td>1187</td>
<td>368</td>
<td>233</td>
<td>155</td>
</tr>
<tr>
<td>chair</td>
<td>0.22458112</td>
<td>624</td>
<td>442</td>
<td>45</td>
<td>48</td>
</tr>
<tr>
<td>person</td>
<td>0.97528315</td>
<td>655</td>
<td>389</td>
<td>86</td>
<td>100</td>
</tr>
<tr>
<td>bottle</td>
<td>0.9407686</td>
<td>1331</td>
<td>436</td>
<td>33</td>
<td>107</td>
</tr>
<tr>
<td>bottle</td>
<td>0.9561032</td>
<td>1293</td>
<td>434</td>
<td>37</td>
<td>113</td>
</tr>
<tr>
<td>chair</td>
<td>0.4784215</td>
<td>1</td>
<td>347</td>
<td>386</td>
<td>730</td>
</tr>
<tr>
<td>cup</td>
<td>0.8945817</td>
<td>822</td>
<td>586</td>
<td>112</td>
<td>69</td>
</tr>
<tr>
<td>cup</td>
<td>0.6422996</td>
<td>1265</td>
<td>472</td>
<td>31</td>
<td>72</td>
</tr>
<tr>
<td>laptop</td>
<td>0.9833646</td>
<td>802</td>
<td>700</td>
<td>639</td>
<td>216</td>
</tr>
<tr>
<td>cup</td>
<td>0.9216428</td>
<td>828</td>
<td>521</td>
<td>115</td>
<td>71</td>
</tr>
<tr>
<td>chair</td>
<td>0.88087356</td>
<td>1124</td>
<td>416</td>
<td>111</td>
<td>70</td>
</tr>
<tr>
<td>diningtable</td>
<td>0.3222557</td>
<td>531</td>
<td>585</td>
<td>951</td>
<td>472</td>
</tr>
</tbody>
</table>
<h4 id="控制台">控制台</h4>
<p><img src="https://img2020.cnblogs.com/blog/1213796/202009/1213796-20200912162613352-723399143.png" alt="" loading="lazy"></p><br><br>
来源:https://www.cnblogs.com/zypblog/p/13656366.html
頁: [1]
查看完整版本: C#封装YOLOv4算法进行目标检测