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计算能力是否支持 >= 3.0:【点击查看】</p>
<p>Windows运行要求</p>
<ul>
<li>CMake >= 3.12: 【点击下载】</li>
<li>CUDA >= 10.0: 【点击下载】</li>
<li>OpenCV >= 2.4: 【点击下载】</li>
<li>cuDNN >= 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-> 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<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);
}
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);
}
}
}
</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]