| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- using OpenCvSharp.Dnn;
- using OpenCvSharp;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using Sdcb.OpenVINO;
- namespace TeamAAS_VP.Core
- {
- public class DetectionResult
- {
- public int ClassId { get; }
- public string Class { get; }
- public Rect Rect { get; }
- public float Confidence { get; }
- public DetectionResult(int classId, string @class, Rect rect, float confidence)
- {
- ClassId = classId;
- Class = @class;
- Rect = rect;
- Confidence = confidence;
- }
- public static DetectionResult[] FromYolov8DetectionResult(ReadOnlySpan<float> tensorData, Shape shape, Size2f sizeRatio, string[] dicts)
- {
- // tensorData: 1x84x8400=705600xF32
- // shape: 1x84x8400, 84=(x, y, width, height)+80 class confidences, 8400=possible object count(code should for loop 8400 first)
- float[] t = Transpose(tensorData, shape[1], shape[2]);
- List<DetectionResult> detResults = new List<DetectionResult>();
- int objectCount = shape[2];
- int clsRowCount = shape[1];
- if (dicts.Length != clsRowCount - 4) throw new ArgumentException($"dicts length {dicts.Length} does not match shape cls row count{clsRowCount}.");
- for (int i = 0; i < objectCount; i++)
- {
- int startIdx = i * clsRowCount;
- ReadOnlySpan<float> rectData = t.AsSpan().Slice(startIdx, 4);
- ReadOnlySpan<float> confidenceInfo = t.AsSpan().Slice(startIdx + 4, clsRowCount - 4);
- int maxConfidenceClsId = IndexOfMax(confidenceInfo);
- float confidence = confidenceInfo[maxConfidenceClsId];
- int centerX = (int)(rectData[0] * sizeRatio.Width);
- int centerY = (int)(rectData[1] * sizeRatio.Height);
- int width = (int)(rectData[2] * sizeRatio.Width);
- int height = (int)(rectData[3] * sizeRatio.Height);
- detResults.Add(new DetectionResult(
- maxConfidenceClsId, dicts[maxConfidenceClsId],
- new Rect(centerX - width / 2, centerY - height / 2, width, height),
- confidence));
- }
- CvDnn.NMSBoxes(detResults.Select(x => x.Rect).ToList(), detResults.Select(x => x.Confidence).ToList(), scoreThreshold: 0.5f, nmsThreshold: 0.5f, out int[] indices);
- return detResults.Where((x, i) => indices.Contains(i)).ToArray();
- }
- private static int IndexOfMax(ReadOnlySpan<float> data)
- {
- if (data.Length == 0) throw new ArgumentException("The provided data span is null or empty.");
- // 初始化最大值及其索引
- int maxIndex = 0;
- float maxValue = data[0];
- // 遍历跨度查找最大值及其索引
- for (int i = 1; i < data.Length; i++)
- {
- if (data[i] > maxValue)
- {
- maxValue = data[i];
- maxIndex = i;
- }
- }
- // 返回最大值及其索引
- return maxIndex;
- }
- private static unsafe float[] Transpose(ReadOnlySpan<float> tensorData, int rows, int cols)
- {
- float[] transposedTensorData = new float[tensorData.Length];
- fixed (float* pTensorData = tensorData)
- {
- fixed (float* pTransposedData = transposedTensorData)
- {
- for (int i = 0; i < rows; i++)
- {
- for (int j = 0; j < cols; j++)
- {
- // Index in the original tensor
- int index = i * cols + j;
- // Index in the transposed tensor
- int transposedIndex = j * rows + i;
- pTransposedData[transposedIndex] = pTensorData[index];
- }
- }
- }
- }
- return transposedTensorData;
- }
- }
- }
|