Skip to content

Commit af9f7ca

Browse files
committed
v1.0.7 Updated OpenCVForUnity version to 2.6.5. Refactor the code. Add onnx model generation scripts for YOLOv9, YOLOv10, YOLOv11 and YOLOv12.
1 parent b0db46a commit af9f7ca

39 files changed

+4750
-412
lines changed
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Assets/YOLOv8WithOpenCVForUnityExample/Scripts/YOLOv8WithOpenCVForUnity/YOLOv8ClassPredictor.cs

+31-37
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212

1313
namespace YOLOv8WithOpenCVForUnity
1414
{
15-
16-
public class YOLOv8ClassPredictor
15+
/// <summary>
16+
/// Referring to https://github.com/ultralytics/ultralytics/
17+
/// </summary>
18+
public class YOLOv8ClassPredictor : IDisposable
1719
{
1820
Size input_size;
1921
int backend;
@@ -38,7 +40,7 @@ public YOLOv8ClassPredictor(string modelFilepath, string classesFilepath, Size i
3840

3941
if (!string.IsNullOrEmpty(classesFilepath))
4042
{
41-
classNames = readClassNames(classesFilepath);
43+
classNames = ReadClassNames(classesFilepath);
4244
}
4345

4446
input_size = new Size(inputSize.width > 0 ? inputSize.width : 224, inputSize.height > 0 ? inputSize.height : 224);
@@ -71,7 +73,7 @@ public YOLOv8ClassPredictor(string modelFilepath, string classesFilepath, Size i
7173
palette.Add(new Scalar(255, 55, 199, 255));
7274
}
7375

74-
protected virtual Mat preprocess(Mat image)
76+
protected virtual Mat PreProcess(Mat image)
7577
{
7678
// https://github.com/ultralytics/ultralytics/blob/d74a5a9499acf1afd13d970645e5b1cfcadf4a8f/ultralytics/data/augment.py#L1059
7779

@@ -96,7 +98,7 @@ protected virtual Mat preprocess(Mat image)
9698
return blob;// [1, 3, h, w]
9799
}
98100

99-
public virtual Mat infer(Mat image)
101+
public virtual Mat Infer(Mat image)
100102
{
101103
// cheack
102104
if (image.channels() != 3)
@@ -106,7 +108,7 @@ public virtual Mat infer(Mat image)
106108
}
107109

108110
// Preprocess
109-
Mat input_blob = preprocess(image);
111+
Mat input_blob = PreProcess(image);
110112

111113
// Forward
112114
classification_net.setInput(input_blob);
@@ -115,7 +117,7 @@ public virtual Mat infer(Mat image)
115117
classification_net.forward(output_blob, classification_net.getUnconnectedOutLayersNames());
116118

117119
// Postprocess
118-
Mat results = postprocess(output_blob, image.size());
120+
Mat results = PostProcess(output_blob, image.size());
119121

120122
input_blob.Dispose();
121123
for (int i = 0; i < output_blob.Count; i++)
@@ -126,7 +128,7 @@ public virtual Mat infer(Mat image)
126128
return results;// [1, num_classes]
127129
}
128130

129-
protected virtual Mat postprocess(List<Mat> output_blob, Size original_shape)
131+
protected virtual Mat PostProcess(List<Mat> output_blob, Size original_shape)
130132
{
131133
Mat output_blob_0 = output_blob[0];
132134

@@ -135,21 +137,7 @@ protected virtual Mat postprocess(List<Mat> output_blob, Size original_shape)
135137
return results;// [1, num_classes]
136138
}
137139

138-
protected virtual Mat softmax(Mat src)
139-
{
140-
Mat dst = src.clone();
141-
142-
Core.MinMaxLocResult result = Core.minMaxLoc(src);
143-
Scalar max = new Scalar(result.maxVal);
144-
Core.subtract(src, max, dst);
145-
Core.exp(dst, dst);
146-
Scalar sum = Core.sumElems(dst);
147-
Core.divide(dst, sum, dst);
148-
149-
return dst;
150-
}
151-
152-
public virtual void visualize(Mat image, Mat results, bool print_results = false, bool isRGB = false)
140+
public virtual void Visualize(Mat image, Mat results, bool print_results = false, bool isRGB = false)
153141
{
154142
if (image.IsDisposed)
155143
return;
@@ -162,9 +150,9 @@ public virtual void visualize(Mat image, Mat results, bool print_results = false
162150
if (print_results)
163151
sb = new StringBuilder(64);
164152

165-
ClassificationData bmData = getBestMatchData(results);
153+
ClassificationData bmData = GetBestMatchData(results);
166154
int classId = (int)bmData.cls;
167-
string label = getClassLabel(bmData.cls) + ", " + bmData.conf.ToString("F2");
155+
string label = GetClassLabel(bmData.cls) + ", " + bmData.conf.ToString("F2");
168156

169157
Scalar c = palette[classId % palette.Count];
170158
Scalar color = isRGB ? c : new Scalar(c.val[2], c.val[1], c.val[0], c.val[3]);
@@ -183,14 +171,14 @@ public virtual void visualize(Mat image, Mat results, bool print_results = false
183171
// Print results
184172
if (print_results)
185173
{
186-
sb.AppendLine("Best match: " + getClassLabel(bmData.cls) + ", " + bmData.ToString());
174+
sb.AppendLine("Best match: " + GetClassLabel(bmData.cls) + ", " + bmData.ToString());
187175
}
188176

189177
if (print_results)
190178
Debug.Log(sb.ToString());
191179
}
192180

193-
public virtual void dispose()
181+
public virtual void Dispose()
194182
{
195183
if (classification_net != null)
196184
classification_net.Dispose();
@@ -206,7 +194,7 @@ public virtual void dispose()
206194
getDataMat = null;
207195
}
208196

209-
protected virtual List<string> readClassNames(string filename)
197+
protected virtual List<string> ReadClassNames(string filename)
210198
{
211199
List<string> classNames = new List<string>();
212200

@@ -235,14 +223,18 @@ protected virtual List<string> readClassNames(string filename)
235223
return classNames;
236224
}
237225

238-
[StructLayout(LayoutKind.Sequential)]
226+
[Serializable]
227+
[StructLayout(LayoutKind.Sequential, Pack = 1)]
239228
public readonly struct ClassificationData
240229
{
241230
public readonly float cls;
242231
public readonly float conf;
243232

244-
// sizeof(ClassificationData)
245-
public const int Size = 2 * sizeof(float);
233+
// Count of elements
234+
public const int ELEMENT_COUNT = 2;
235+
236+
// sizeof(DetectionData)
237+
public const int DATA_SIZE = ELEMENT_COUNT * sizeof(float);
246238

247239
public ClassificationData(int cls, float conf)
248240
{
@@ -252,11 +244,13 @@ public ClassificationData(int cls, float conf)
252244

253245
public override string ToString()
254246
{
255-
return "cls:" + cls.ToString() + " conf:" + conf.ToString();
247+
StringBuilder sb = new StringBuilder(64);
248+
sb.AppendFormat("conf:{0} cls:{1}", conf, cls);
249+
return sb.ToString();
256250
}
257251
};
258252

259-
public virtual ClassificationData[] getData(Mat results)
253+
public virtual ClassificationData[] GetData(Mat results)
260254
{
261255
if (results.empty())
262256
return new ClassificationData[0];
@@ -279,20 +273,20 @@ public virtual ClassificationData[] getData(Mat results)
279273
return dst;
280274
}
281275

282-
public virtual ClassificationData[] getSortedData(Mat results, int topK = 5)
276+
public virtual ClassificationData[] GetSortedData(Mat results, int topK = 5)
283277
{
284278
if (results.empty())
285279
return new ClassificationData[0];
286280

287281
int num = results.cols();
288282

289283
if (topK < 1 || topK > num) topK = num;
290-
var sortedData = getData(results).OrderByDescending(x => x.conf).Take(topK).ToArray();
284+
var sortedData = GetData(results).OrderByDescending(x => x.conf).Take(topK).ToArray();
291285

292286
return sortedData;
293287
}
294288

295-
public virtual ClassificationData getBestMatchData(Mat results)
289+
public virtual ClassificationData GetBestMatchData(Mat results)
296290
{
297291
if (results.empty())
298292
return new ClassificationData();
@@ -302,7 +296,7 @@ public virtual ClassificationData getBestMatchData(Mat results)
302296
return new ClassificationData((int)minmax.maxLoc.x, (float)minmax.maxVal);
303297
}
304298

305-
public virtual string getClassLabel(float id)
299+
public virtual string GetClassLabel(float id)
306300
{
307301
int classId = (int)id;
308302
string className = string.Empty;

Assets/YOLOv8WithOpenCVForUnityExample/Scripts/YOLOv8WithOpenCVForUnity/YOLOv8ObjectDetector.cs

+29-20
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313

1414
namespace YOLOv8WithOpenCVForUnity
1515
{
16-
17-
public class YOLOv8ObjectDetector
16+
/// <summary>
17+
/// Referring to https://github.com/ultralytics/ultralytics/
18+
/// https://github.com/ultralytics/ultralytics/tree/main/examples/YOLOv8-OpenCV-ONNX-Python
19+
/// </summary>
20+
public class YOLOv8ObjectDetector : IDisposable
1821
{
1922
Size input_size;
2023
float conf_threshold;
@@ -53,7 +56,7 @@ public YOLOv8ObjectDetector(string modelFilepath, string classesFilepath, Size i
5356

5457
if (!string.IsNullOrEmpty(classesFilepath))
5558
{
56-
classNames = readClassNames(classesFilepath);
59+
classNames = ReadClassNames(classesFilepath);
5760
num_classes = classNames.Count;
5861
}
5962

@@ -90,7 +93,7 @@ public YOLOv8ObjectDetector(string modelFilepath, string classesFilepath, Size i
9093
palette.Add(new Scalar(255, 55, 199, 255));
9194
}
9295

93-
protected virtual Mat preprocess(Mat image)
96+
protected virtual Mat PreProcess(Mat image)
9497
{
9598
// https://github.com/ultralytics/ultralytics/blob/d74a5a9499acf1afd13d970645e5b1cfcadf4a8f/ultralytics/data/augment.py#L645
9699

@@ -116,7 +119,7 @@ protected virtual Mat preprocess(Mat image)
116119
return blob;// [1, 3, h, w]
117120
}
118121

119-
public virtual Mat infer(Mat image)
122+
public virtual Mat Infer(Mat image)
120123
{
121124
// cheack
122125
if (image.channels() != 3)
@@ -126,7 +129,7 @@ public virtual Mat infer(Mat image)
126129
}
127130

128131
// Preprocess
129-
Mat input_blob = preprocess(image);
132+
Mat input_blob = PreProcess(image);
130133

131134
// Forward
132135
object_detection_net.setInput(input_blob);
@@ -135,7 +138,7 @@ public virtual Mat infer(Mat image)
135138
object_detection_net.forward(output_blob, object_detection_net.getUnconnectedOutLayersNames());
136139

137140
// Postprocess
138-
Mat results = postprocess(output_blob[0], image.size());
141+
Mat results = PostProcess(output_blob[0], image.size());
139142

140143
// scale_boxes
141144
float ratio = Mathf.Max((float)image.cols() / (float)input_size.width, (float)image.rows() / (float)input_size.height);
@@ -166,7 +169,7 @@ public virtual Mat infer(Mat image)
166169
return results;// [n, 6] (xyxy, conf, cls)
167170
}
168171

169-
protected virtual Mat postprocess(Mat output_blob, Size original_shape)
172+
protected virtual Mat PostProcess(Mat output_blob, Size original_shape)
170173
{
171174
Mat output_blob_0 = output_blob;
172175

@@ -301,15 +304,15 @@ protected virtual Mat postprocess(Mat output_blob, Size original_shape)
301304

302305
}
303306

304-
public virtual void visualize(Mat image, Mat results, bool print_results = false, bool isRGB = false)
307+
public virtual void Visualize(Mat image, Mat results, bool print_results = false, bool isRGB = false)
305308
{
306309
if (image.IsDisposed)
307310
return;
308311

309312
if (results.empty() || results.cols() < 6)
310313
return;
311314

312-
DetectionData[] data = getData(results);
315+
DetectionData[] data = GetData(results);
313316

314317
foreach (var d in data.Reverse())
315318
{
@@ -325,7 +328,7 @@ public virtual void visualize(Mat image, Mat results, bool print_results = false
325328

326329
Imgproc.rectangle(image, new Point(left, top), new Point(right, bottom), color, 2);
327330

328-
string label = $"{getClassLabel(classId)}, {conf:F2}";
331+
string label = $"{GetClassLabel(classId)}, {conf:F2}";
329332

330333
int[] baseLine = new int[1];
331334
Size labelSize = Imgproc.getTextSize(label, Imgproc.FONT_HERSHEY_SIMPLEX, 0.5, 1, baseLine);
@@ -344,7 +347,7 @@ public virtual void visualize(Mat image, Mat results, bool print_results = false
344347
for (int i = 0; i < data.Length; ++i)
345348
{
346349
var d = data[i];
347-
string label = getClassLabel(d.cls);
350+
string label = GetClassLabel(d.cls);
348351

349352
sb.AppendFormat("-----------object {0}-----------", i + 1);
350353
sb.AppendLine();
@@ -360,7 +363,7 @@ public virtual void visualize(Mat image, Mat results, bool print_results = false
360363
}
361364
}
362365

363-
public virtual void dispose()
366+
public virtual void Dispose()
364367
{
365368
if (object_detection_net != null)
366369
object_detection_net.Dispose();
@@ -399,7 +402,7 @@ public virtual void dispose()
399402
class_ids = null;
400403
}
401404

402-
protected virtual List<string> readClassNames(string filename)
405+
protected virtual List<string> ReadClassNames(string filename)
403406
{
404407
List<string> classNames = new List<string>();
405408

@@ -428,7 +431,8 @@ protected virtual List<string> readClassNames(string filename)
428431
return classNames;
429432
}
430433

431-
[StructLayout(LayoutKind.Sequential)]
434+
[Serializable]
435+
[StructLayout(LayoutKind.Sequential, Pack = 1)]
432436
public readonly struct DetectionData
433437
{
434438
public readonly float x1;
@@ -438,8 +442,11 @@ public readonly struct DetectionData
438442
public readonly float conf;
439443
public readonly float cls;
440444

441-
// sizeof(ClassificationData)
442-
public const int Size = 6 * sizeof(float);
445+
// Count of elements
446+
public const int ELEMENT_COUNT = 6;
447+
448+
// sizeof(DetectionData)
449+
public const int DATA_SIZE = ELEMENT_COUNT * sizeof(float);
443450

444451
public DetectionData(int x1, int y1, int x2, int y2, float conf, int cls)
445452
{
@@ -453,11 +460,13 @@ public DetectionData(int x1, int y1, int x2, int y2, float conf, int cls)
453460

454461
public override string ToString()
455462
{
456-
return "x1:" + x1.ToString() + " y1:" + y1.ToString() + "x2:" + x2.ToString() + " y2:" + y2.ToString() + " conf:" + conf.ToString() + " cls:" + cls.ToString();
463+
StringBuilder sb = new StringBuilder(128);
464+
sb.AppendFormat("x1:{0} y1:{1} x2:{2} y2:{3} conf:{4} cls:{5}", x1, y1, x2, y2, conf, cls);
465+
return sb.ToString();
457466
}
458467
};
459468

460-
public virtual DetectionData[] getData(Mat results)
469+
public virtual DetectionData[] GetData(Mat results)
461470
{
462471
if (results.empty())
463472
return new DetectionData[0];
@@ -468,7 +477,7 @@ public virtual DetectionData[] getData(Mat results)
468477
return dst;
469478
}
470479

471-
public virtual string getClassLabel(float id)
480+
public virtual string GetClassLabel(float id)
472481
{
473482
int classId = (int)id;
474483
string className = string.Empty;

0 commit comments

Comments
 (0)