C#调用YOLOv3算法dll动态链接库
前段时间在搞一个软件,目标是实现细胞计数的功能,当时我细胞计数的算法用到的是YOLOv3目标检测算法,所以就涉及到怎么实现模型落地的问题。当时有个同学在帮老师做项目,他比较懂,我于是向他寻求帮助,但是…可能涉及到了商业机密吧,于是我就自己研究。
我看了很多博客,感觉讲的也不是很到位,或者说没有给出一些干货,今天我来给大家带点干货,当然我是用**C#**调用的YOLOv3动态链接库,如果有需要的小伙伴就拿去吧。
yolov3编译成动态库
大家按照这个链接去GitHub下载YOLOv3的源码:https://github.com/AlexeyAB/darknet?tdsourcetag=s_pcqq_aiomsg.我是按照这个教程做的:https://zhuanlan.zhihu.com/p/97605980,这个教程还是很详细的,我就不讲了。
C#调用YOLOv3动态链接库
我已经将软件打包到GitHub上了:https://github.com/NameZth/AICounter-master.git,由于YOLOv3的权重文件和配置文件太大就没有上传,所以需要小伙伴自己训练一下模型. 当然我也是参考别人做的:https://github.com/RaminAbbaszadi/YoloWrapper-WPF,下面是文件的分布:
在***DeepLearningWrapper***这个文件中调用的YOLOv3的动态链接库:
using System;
using System.IO;
using System.Text;
using System.Linq;
using DeepLearning.Base;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace DeepLearning
{
public class DeepLearningWrapper : IDisposable
{
#region Const
public const int MAX_OBJECTS_NUMBER = 1000;
private const string DEEP_LEARNING_LIBRARY_DLL_CPU_VERSION = @"\x64\yolo_cpp_dll.dll";
private const string DEEP_LEARNING_LIBRARY_DLL_GPU_VERSION = @"\x64\yolo_cpp_gpu.dll";
#endregion
#region Fields
private static Dictionary<int, string> m_ObjectType = new Dictionary<int, string>();
private static NetConfigaration m_NetConf;
#endregion
#region Initilizing
public DeepLearningWrapper()
{
}
#endregion
#region DllImport Cpu
[DllImport(DEEP_LEARNING_LIBRARY_DLL_CPU_VERSION, EntryPoint = "init")]
public static extern int InitializeNetInCpu(string configrationFilenamr, string weightFileanme, int gpu);
[DllImport(DEEP_LEARNING_LIBRARY_DLL_CPU_VERSION, EntryPoint = "detect_image")]
internal static extern int DetectImageInCpu(string filename, ref BoundingBoxContainer container);
[DllImport(DEEP_LEARNING_LIBRARY_DLL_CPU_VERSION, EntryPoint = "detect_mat")]
internal static extern int DetectImageInCpu(IntPtr pArray, int nSize, ref BoundingBoxContainer container);
[DllImport(DEEP_LEARNING_LIBRARY_DLL_CPU_VERSION, EntryPoint = "dispose")]
internal static extern int DisposeNetInCpu();
#endregion
#region DllImport Gpu
[DllImport(DEEP_LEARNING_LIBRARY_DLL_GPU_VERSION, EntryPoint = "init")]
internal static extern int InitializeNetInGpu(string configurationFilename, string weightsFilename, int gpu);
[DllImport(DEEP_LEARNING_LIBRARY_DLL_GPU_VERSION, EntryPoint = "detect_image")]
internal static extern int DetectImageInGpu(string filename, ref BoundingBoxContainer container);
[DllImport(DEEP_LEARNING_LIBRARY_DLL_GPU_VERSION, EntryPoint = "detect_mat")]
internal static extern int DetectImageInGpu(IntPtr pArray, int nSize, ref BoundingBoxContainer container);
[DllImport(DEEP_LEARNING_LIBRARY_DLL_GPU_VERSION, EntryPoint = "dispose")]
internal static extern int DisposeNetInGpu();
[DllImport(DEEP_LEARNING_LIBRARY_DLL_GPU_VERSION, EntryPoint = "get_device_count")]
internal static extern int GetDeviceCount();
[DllImport(DEEP_LEARNING_LIBRARY_DLL_GPU_VERSION, EntryPoint = "get_device_name")]
internal static extern int GetDeviceName(int gpu, StringBuilder deviceName);
#endregion
#region Dispose
public void Dispose()
{
switch (DetectionHardware)
{
case DetectionHardwares.CPU:
DisposeNetInCpu();
break;
case DetectionHardwares.GPU:
DisposeNetInGpu();
break;
}
}
#endregion
#region Wrapper
public void InitilizeDeepLearningNetwork(int gpu = 0)
{
if (m_NetConf == null)
m_NetConf = new NetConfigaration();
HardwareReport = new HardwareReports();
DetectionHardware = DetectionHardwares.CPU;
if (HardwareReport.IsCudaExists && HardwareReport.IsCudnnExists)
DetectionHardware = DetectionHardwares.GPU;
switch (DetectionHardware)
{
case DetectionHardwares.CPU:
InitializeNetInCpu(m_NetConf.ConfigFile, m_NetConf.Weightfile, 0);
break;
case DetectionHardwares.GPU:
var deviceCount = GetDeviceCount();
if (gpu > (deviceCount - 1))
throw new IndexOutOfRangeException("Graphic device index is out of range");
var deviceName = new StringBuilder();
GetDeviceName(gpu, deviceName);
HardwareReport.GraphicDeviceName = deviceName.ToString();
InitializeNetInGpu(m_NetConf.ConfigFile, m_NetConf.Weightfile, gpu);
break;
default:
break;
}
var lines = File.ReadAllLines(m_NetConf.NamesFile);
for (var i = 0; i < lines.Length; i++)
m_ObjectType.Add(i, lines[i]);
}
public IEnumerable<DetectedItemInfo> Detect(string imageFilePath)
{
if (!File.Exists(imageFilePath))
throw new FileNotFoundException("Cannot find the file", imageFilePath);
var container = new BoundingBoxContainer();
var count = 0;
switch (DetectionHardware)
{
case DetectionHardwares.CPU:
count = DetectImageInCpu(imageFilePath, ref container);
break;
case DetectionHardwares.GPU:
count = DetectImageInGpu(imageFilePath, ref container);
break;
}
return Convert(container);
}
public IEnumerable<DetectedItemInfo> Detect(byte[] imageData)
{
var container = new BoundingBoxContainer();
var size = Marshal.SizeOf(imageData[0]) * imageData.Length;
var pnt = Marshal.AllocHGlobal(size);
try
{
// Copy the array to unmanaged memory.
Marshal.Copy(imageData, 0, pnt, imageData.Length);
var count = 0;
switch (DetectionHardware)
{
case DetectionHardwares.CPU:
count = DetectImageInCpu(pnt, imageData.Length, ref container);
break;
case DetectionHardwares.GPU:
count = DetectImageInGpu(pnt, imageData.Length, ref container);
break;
}
}
catch (Exception exception)
{
return null;
}
finally
{
// Free the unmanaged memory.
Marshal.FreeHGlobal(pnt);
}
return Convert(container);
}
#endregion
#region Utilities
private IEnumerable<DetectedItemInfo> Convert(BoundingBoxContainer container)
{
var netItems = new List<DetectedItemInfo>();
foreach (var item in container.candidates.Where(o => o.height > 0 || o.width > 0))
{
var objectType = m_ObjectType[(int)item.obj_id];
var netItem = new DetectedItemInfo() { X = (int)item.leftTopX, Y = (int)item.leftTopY, Height = (int)item.height, Width = (int)item.width, Confidence = item.prob, Type = objectType };
netItems.Add(netItem);
}
return netItems;
}
#endregion
#region Properties
public DetectionHardwares DetectionHardware = DetectionHardwares.Unknown;
public HardwareReports HardwareReport { get; private set; }
#endregion
}
}
然后就是在其他软件中类的定义:
***BoundingBox***文件:
using System;
namespace DeepLearning
{
internal struct BoundingBox
{
#region Fields
internal UInt32 leftTopX, leftTopY, width, height;
internal float prob;
internal UInt32 obj_id;
internal UInt32 track_id;
internal UInt32 frames_counter;
#endregion
}
}
***BoundingBoxContainer***文件:
using System.Runtime.InteropServices;
namespace DeepLearning
{
[StructLayout(LayoutKind.Sequential)]
internal struct BoundingBoxContainer
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DeepLearningWrapper.MAX_OBJECTS_NUMBER)]
internal BoundingBox[] candidates;
}
}
***DetectedItemInfo***文件:
namespace DeepLearning
{
public class DetectedItemInfo
{
#region Properties
public string Type { get; set; }
public double Confidence { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
#endregion
#region Utilities
public bool Compare(DetectedItemInfo newItem)
{
bool result = false;
if (newItem != null)
{
if (newItem.Type == this.Type && newItem.Confidence == this.Confidence &&
newItem.X == this.X && newItem.Y == this.Y && newItem.Width == this.Width &&
newItem.Height == this.Height)
{
result = true;
}
}
return result;
}
#endregion
}
}
HardwareReports文件:
using System;
using System.IO;
namespace DeepLearning
{
public class HardwareReports
{
#region Initilizing
public HardwareReports()
{
Init();
}
private void Init()
{
if (File.Exists(@"x64\cudnn64_7.dll"))
IsCudnnExists = true;
var envirormentVariables = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine);
if (envirormentVariables.Contains("CUDA_PATH"))
IsCudaExists = true;
}
#endregion
#region Properties
public bool IsCudaExists { get; set; }
public bool IsCudnnExists { get; set; }
public string GraphicDeviceName { get; set; }
#endregion
}
}
NetConfigaration文件:
namespace DeepLearning
{
public class NetConfigaration
{
#region Const
private const string CONFIG_FILE_PATH = @"Assets\Aalskidhytd.cfg";
private const string WEIGHT_FILE_PATH = @"Assets\Aalskidhytd.weights";
private const string NAMES_FILE_PATH = @"Assets\Aalskidhytd.names";
#endregion
#region Initilizing
public NetConfigaration()
{
Init();
}
private void Init()
{
ConfigFile = CONFIG_FILE_PATH;
Weightfile = WEIGHT_FILE_PATH;
NamesFile = NAMES_FILE_PATH;
}
#endregion
#region Properties
public string ConfigFile { get; set; }
public string Weightfile { get; set; }
public string NamesFile { get; set; }
#endregion
}
}
软件界面展示(检测的精度不是很高):