some code cleanup (#403)
* some code cleanup separating model from UI code and and add some needed error handling and fps status. Also try and make project file more compatible with various win sdk install versions * fix typo. * fix CR feedback.
This commit is contained in:
Родитель
c0bfe7272e
Коммит
7c956de214
|
@ -2,6 +2,7 @@
|
|||
x:Class="YOLOv4ObjectDetection.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:YOLOv4ObjectDetection">
|
||||
xmlns:local="using:YOLOv4ObjectDetection"
|
||||
RequestedTheme="Dark">
|
||||
|
||||
</Application>
|
||||
|
|
|
@ -9,10 +9,22 @@
|
|||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid>
|
||||
<Button x:Name="button_go" Content="Go" Margin="78,74,0,0" VerticalAlignment="Top" Click="button_go_Click"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CaptureElement x:Name="WebCam" Stretch="Fill" VerticalAlignment="Center" HorizontalAlignment="Left" Width="416" Height="416"/>
|
||||
</StackPanel>
|
||||
<Canvas x:Name="OverlayCanvas" VerticalAlignment="Center" HorizontalAlignment="Left" Width="416" Height="416"/>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<AppBar Grid.Row="0" IsOpen="True" IsSticky="True">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<AppBarButton Icon="Play" x:Name="button_go" Label="Go" Click="button_go_Click" ToolTipService.ToolTip="Start detecting objects in the video." />
|
||||
</StackPanel>
|
||||
</AppBar>
|
||||
<Grid Grid.Row="1">
|
||||
<CaptureElement x:Name="WebCam" Grid.Row="1" Stretch="Fill" VerticalAlignment="Center" HorizontalAlignment="Center" Width="416" Height="416"/>
|
||||
<Canvas x:Name="OverlayCanvas" VerticalAlignment="Center" HorizontalAlignment="Center" Width="416" Height="416"/>
|
||||
</Grid>
|
||||
<Grid Grid.Row="2" Background="{ThemeResource ProgressBarBackgroundThemeBrush}">
|
||||
<TextBlock x:Name="textblock_status" Margin="5"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -29,116 +29,39 @@ namespace YOLOv4ObjectDetection
|
|||
public sealed partial class MainPage : Page
|
||||
{
|
||||
private MediaCapture _media_capture;
|
||||
private LearningModel _model;
|
||||
private LearningModelSession _session;
|
||||
private LearningModelBinding _binding;
|
||||
|
||||
private Model _model;
|
||||
private DispatcherTimer _timer;
|
||||
private readonly SolidColorBrush _fill_brush = new SolidColorBrush(Colors.Transparent);
|
||||
private readonly SolidColorBrush _line_brush = new SolidColorBrush(Colors.DarkGreen);
|
||||
private readonly double _line_thickness = 2.0;
|
||||
|
||||
private readonly string[] _labels =
|
||||
{
|
||||
"person",
|
||||
"bicycle",
|
||||
"car",
|
||||
"motorbike",
|
||||
"aeroplane",
|
||||
"bus",
|
||||
"train",
|
||||
"truck",
|
||||
"boat",
|
||||
"traffic light",
|
||||
"fire hydrant",
|
||||
"stop sign",
|
||||
"parking meter",
|
||||
"bench",
|
||||
"bird",
|
||||
"cat",
|
||||
"dog",
|
||||
"horse",
|
||||
"sheep",
|
||||
"cow",
|
||||
"elephant",
|
||||
"bear",
|
||||
"zebra",
|
||||
"giraffe",
|
||||
"backpack",
|
||||
"umbrella",
|
||||
"handbag",
|
||||
"tie",
|
||||
"suitcase",
|
||||
"frisbee",
|
||||
"skis",
|
||||
"snowboard",
|
||||
"sports ball",
|
||||
"kite",
|
||||
"baseball bat",
|
||||
"baseball glove",
|
||||
"skateboard",
|
||||
"surfboard",
|
||||
"tennis racket",
|
||||
"bottle",
|
||||
"wine glass",
|
||||
"cup",
|
||||
"fork",
|
||||
"knife",
|
||||
"spoon",
|
||||
"bowl",
|
||||
"banana",
|
||||
"apple",
|
||||
"sandwich",
|
||||
"orange",
|
||||
"broccoli",
|
||||
"carrot",
|
||||
"hot dog",
|
||||
"pizza",
|
||||
"donut",
|
||||
"cake",
|
||||
"chair",
|
||||
"sofa",
|
||||
"pottedplant",
|
||||
"bed",
|
||||
"diningtable",
|
||||
"toilet",
|
||||
"tvmonitor",
|
||||
"laptop",
|
||||
"mouse",
|
||||
"remote",
|
||||
"keyboard",
|
||||
"cell phone",
|
||||
"microwave",
|
||||
"oven",
|
||||
"toaster",
|
||||
"sink",
|
||||
"refrigerator",
|
||||
"book",
|
||||
"clock",
|
||||
"vase",
|
||||
"scissors",
|
||||
"teddy bear",
|
||||
"hair drier",
|
||||
"toothbrush"
|
||||
};
|
||||
|
||||
internal struct DetectionResult
|
||||
{
|
||||
public string label;
|
||||
public List<float> bbox;
|
||||
public double prob;
|
||||
}
|
||||
|
||||
class Comparer : IComparer<DetectionResult>
|
||||
{
|
||||
public int Compare(DetectionResult x, DetectionResult y)
|
||||
{
|
||||
return y.prob.CompareTo(x.prob);
|
||||
}
|
||||
}
|
||||
|
||||
public MainPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.InitializeComponent();
|
||||
button_go.IsEnabled = false;
|
||||
this.Loaded += OnPageLoaded;
|
||||
}
|
||||
|
||||
private void OnPageLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_ = InitModelAsync();
|
||||
_ = InitCameraAsync();
|
||||
}
|
||||
|
||||
private async Task InitModelAsync()
|
||||
{
|
||||
ShowStatus("Loading yolo.onnx model...");
|
||||
try
|
||||
{
|
||||
_model = new Model();
|
||||
await _model.InitModelAsync();
|
||||
ShowStatus("ready");
|
||||
button_go.IsEnabled = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowStatus(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InitCameraAsync()
|
||||
|
@ -165,20 +88,44 @@ namespace YOLOv4ObjectDetection
|
|||
await _media_capture.StartPreviewAsync();
|
||||
WebCam.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
ProcessFrame();
|
||||
}
|
||||
|
||||
private bool processing;
|
||||
private Stopwatch watch;
|
||||
private int count;
|
||||
|
||||
private async Task ProcessFrame()
|
||||
{
|
||||
var frame = new VideoFrame(Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8, (int)WebCam.Width, (int)WebCam.Height);
|
||||
await _media_capture.GetPreviewFrameAsync(frame);
|
||||
if (processing)
|
||||
{
|
||||
// if we can't keep up to 30 fps, then ignore this tick.
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (watch == null)
|
||||
{
|
||||
watch = new Stopwatch();
|
||||
watch.Start();
|
||||
}
|
||||
|
||||
var results = await EvaluateFrame(frame);
|
||||
|
||||
await DrawBoxes(results.ToArray(), frame);
|
||||
|
||||
ProcessFrame();
|
||||
processing = true;
|
||||
var frame = new VideoFrame(Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8, (int)WebCam.Width, (int)WebCam.Height);
|
||||
await _media_capture.GetPreviewFrameAsync(frame);
|
||||
var results = await _model.EvaluateFrame(frame);
|
||||
await DrawBoxes(results, frame);
|
||||
count++;
|
||||
if (watch.ElapsedMilliseconds > 1000)
|
||||
{
|
||||
ShowStatus(string.Format("{0} fps", count));
|
||||
count = 0;
|
||||
watch.Restart();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
processing = false;
|
||||
}
|
||||
}
|
||||
|
||||
private float Sigmoid(float val)
|
||||
|
@ -187,119 +134,16 @@ namespace YOLOv4ObjectDetection
|
|||
return x / (1.0f + x);
|
||||
}
|
||||
|
||||
// Compute Intersection over Union(IOU)
|
||||
private float ComputeIOU(DetectionResult DRa, DetectionResult DRb)
|
||||
{
|
||||
float ay1 = DRa.bbox[0];
|
||||
float ax1 = DRa.bbox[1];
|
||||
float ay2 = DRa.bbox[2];
|
||||
float ax2 = DRa.bbox[3];
|
||||
float by1 = DRb.bbox[0];
|
||||
float bx1 = DRb.bbox[1];
|
||||
float by2 = DRb.bbox[2];
|
||||
float bx2 = DRb.bbox[3];
|
||||
|
||||
Debug.Assert(ay1 < ay2);
|
||||
Debug.Assert(ax1 < ax2);
|
||||
Debug.Assert(by1 < by2);
|
||||
Debug.Assert(bx1 < bx2);
|
||||
|
||||
// determine the coordinates of the intersection rectangle
|
||||
float x_left = Math.Max(ax1, bx1);
|
||||
float y_top = Math.Max(ay1, by1);
|
||||
float x_right = Math.Min(ax2, bx2);
|
||||
float y_bottom = Math.Min(ay2, by2);
|
||||
|
||||
if (x_right < x_left || y_bottom < y_top)
|
||||
return 0;
|
||||
float intersection_area = (x_right - x_left) * (y_bottom - y_top);
|
||||
float bb1_area = (ax2 - ax1) * (ay2 - ay1);
|
||||
float bb2_area = (bx2 - bx1) * (by2 - by1);
|
||||
float iou = intersection_area / (bb1_area + bb2_area - intersection_area);
|
||||
|
||||
Debug.Assert(iou >= 0 && iou <= 1);
|
||||
return iou;
|
||||
}
|
||||
|
||||
// Non-maximum Suppression(NMS), a technique which filters the proposals
|
||||
// based on Intersection over Union(IOU)
|
||||
private List<DetectionResult> NMS(IReadOnlyList<DetectionResult> detections,
|
||||
float IOU_threshold = 0.45f,
|
||||
float score_threshold=0.3f)
|
||||
{
|
||||
List<DetectionResult> final_detections = new List<DetectionResult>();
|
||||
for (int i = 0; i < detections.Count; i++)
|
||||
{
|
||||
int j = 0;
|
||||
for (j = 0; j < final_detections.Count; j++)
|
||||
{
|
||||
if (ComputeIOU(final_detections[j], detections[i]) > IOU_threshold)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j==final_detections.Count)
|
||||
{
|
||||
final_detections.Add(detections[i]);
|
||||
}
|
||||
}
|
||||
return final_detections;
|
||||
}
|
||||
|
||||
// parse the result from WinML evaluation results to self defined object struct
|
||||
private List<DetectionResult> ParseResult(float[] results)
|
||||
{
|
||||
int c_values = 84;
|
||||
int c_boxes = results.Length / c_values;
|
||||
float confidence_threshold = 0.5f;
|
||||
List<DetectionResult> detections = new List<DetectionResult>();
|
||||
this.OverlayCanvas.Children.Clear();
|
||||
for (int i_box = 0; i_box < c_boxes; i_box++)
|
||||
{
|
||||
float max_prob = 0.0f;
|
||||
int label_index = -1;
|
||||
for (int j_confidence = 4; j_confidence < c_values; j_confidence++)
|
||||
{
|
||||
int index = i_box * c_values + j_confidence;
|
||||
if (results[index] > max_prob)
|
||||
{
|
||||
max_prob = results[index];
|
||||
label_index = j_confidence - 4;
|
||||
}
|
||||
}
|
||||
if (max_prob > confidence_threshold)
|
||||
{
|
||||
List<float> bbox = new List<float>();
|
||||
bbox.Add(results[i_box * c_values + 0]);
|
||||
bbox.Add(results[i_box * c_values + 1]);
|
||||
bbox.Add(results[i_box * c_values + 2]);
|
||||
bbox.Add(results[i_box * c_values + 3]);
|
||||
|
||||
detections.Add(new DetectionResult()
|
||||
{
|
||||
label = _labels[label_index],
|
||||
bbox = bbox,
|
||||
prob = max_prob
|
||||
});
|
||||
}
|
||||
}
|
||||
return detections;
|
||||
}
|
||||
|
||||
// draw bounding boxes on the output frame based on evaluation result
|
||||
private async Task DrawBoxes(float[] results, VideoFrame frame)
|
||||
private async Task DrawBoxes(List<Model.DetectionResult> detections, VideoFrame frame)
|
||||
{
|
||||
List<DetectionResult> detections = ParseResult(results);
|
||||
Comparer cp = new Comparer();
|
||||
detections.Sort(cp);
|
||||
IReadOnlyList<DetectionResult> final_detetions = NMS(detections);
|
||||
|
||||
for (int i=0; i < final_detetions.Count; ++i)
|
||||
this.OverlayCanvas.Children.Clear();
|
||||
for (int i=0; i < detections.Count; ++i)
|
||||
{
|
||||
int top = (int)(final_detetions[i].bbox[0] * WebCam.Height);
|
||||
int left = (int)(final_detetions[i].bbox[1] * WebCam.Width);
|
||||
int bottom = (int)(final_detetions[i].bbox[2] * WebCam.Height);
|
||||
int right = (int)(final_detetions[i].bbox[3] * WebCam.Width);
|
||||
int top = (int)(detections[i].bbox[0] * WebCam.Height);
|
||||
int left = (int)(detections[i].bbox[1] * WebCam.Width);
|
||||
int bottom = (int)(detections[i].bbox[2] * WebCam.Height);
|
||||
int right = (int)(detections[i].bbox[3] * WebCam.Width);
|
||||
|
||||
var brush = new ImageBrush();
|
||||
var bitmap_source = new SoftwareBitmapSource();
|
||||
|
@ -331,46 +175,44 @@ namespace YOLOv4ObjectDetection
|
|||
textBlock.Foreground = foregroundColorBrush;
|
||||
textBlock.FontSize = 18;
|
||||
|
||||
textBlock.Text = final_detetions[i].label;
|
||||
textBlock.Text = detections[i].label;
|
||||
// Hide
|
||||
textBlock.Visibility = Visibility.Collapsed;
|
||||
border.Background = backgroundColorBrush;
|
||||
border.Child = textBlock;
|
||||
|
||||
Canvas.SetLeft(border, final_detetions[i].bbox[1] * 416 + 2);
|
||||
Canvas.SetTop(border, final_detetions[i].bbox[0] * 416 + 2);
|
||||
Canvas.SetLeft(border, detections[i].bbox[1] * 416 + 2);
|
||||
Canvas.SetTop(border, detections[i].bbox[0] * 416 + 2);
|
||||
textBlock.Visibility = Visibility.Visible;
|
||||
// Add to canvas
|
||||
this.OverlayCanvas.Children.Add(border);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<float>> EvaluateFrame(VideoFrame frame)
|
||||
{
|
||||
_binding.Clear();
|
||||
_binding.Bind("input_1:0", frame);
|
||||
var results = await _session.EvaluateAsync(_binding, "");
|
||||
|
||||
TensorFloat result = results.Outputs["Identity:0"] as TensorFloat;
|
||||
var shape = result.Shape;
|
||||
var data = result.GetAsVectorView();
|
||||
|
||||
return data.ToList<float>();
|
||||
}
|
||||
|
||||
private void button_go_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
InitModelAsync();
|
||||
InitCameraAsync();
|
||||
if (_timer == null)
|
||||
{
|
||||
// now start processing frames, no need to do more than 30 per second!
|
||||
_timer = new DispatcherTimer()
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(30)
|
||||
};
|
||||
_timer.Tick += OnTimerTick;
|
||||
_timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InitModelAsync()
|
||||
void ShowStatus(string text)
|
||||
{
|
||||
var model_file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets//Yolo.onnx"));
|
||||
_model = await LearningModel.LoadFromStorageFileAsync(model_file);
|
||||
var device = new LearningModelDevice(LearningModelDeviceKind.Cpu);
|
||||
_session = new LearningModelSession(_model, device);
|
||||
_binding = new LearningModelBinding(_session);
|
||||
textblock_status.Text = text;
|
||||
}
|
||||
|
||||
|
||||
private void OnTimerTick(object sender, object e)
|
||||
{
|
||||
// don't wait for this async task to finish
|
||||
_ = ProcessFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.AI.MachineLearning;
|
||||
using Windows.Media;
|
||||
using Windows.Storage;
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace YOLOv4ObjectDetection
|
||||
{
|
||||
class Model
|
||||
{
|
||||
private LearningModel _model;
|
||||
private LearningModelSession _session;
|
||||
private LearningModelBinding _binding;
|
||||
|
||||
private readonly string[] _labels =
|
||||
{
|
||||
"person",
|
||||
"bicycle",
|
||||
"car",
|
||||
"motorbike",
|
||||
"aeroplane",
|
||||
"bus",
|
||||
"train",
|
||||
"truck",
|
||||
"boat",
|
||||
"traffic light",
|
||||
"fire hydrant",
|
||||
"stop sign",
|
||||
"parking meter",
|
||||
"bench",
|
||||
"bird",
|
||||
"cat",
|
||||
"dog",
|
||||
"horse",
|
||||
"sheep",
|
||||
"cow",
|
||||
"elephant",
|
||||
"bear",
|
||||
"zebra",
|
||||
"giraffe",
|
||||
"backpack",
|
||||
"umbrella",
|
||||
"handbag",
|
||||
"tie",
|
||||
"suitcase",
|
||||
"frisbee",
|
||||
"skis",
|
||||
"snowboard",
|
||||
"sports ball",
|
||||
"kite",
|
||||
"baseball bat",
|
||||
"baseball glove",
|
||||
"skateboard",
|
||||
"surfboard",
|
||||
"tennis racket",
|
||||
"bottle",
|
||||
"wine glass",
|
||||
"cup",
|
||||
"fork",
|
||||
"knife",
|
||||
"spoon",
|
||||
"bowl",
|
||||
"banana",
|
||||
"apple",
|
||||
"sandwich",
|
||||
"orange",
|
||||
"broccoli",
|
||||
"carrot",
|
||||
"hot dog",
|
||||
"pizza",
|
||||
"donut",
|
||||
"cake",
|
||||
"chair",
|
||||
"sofa",
|
||||
"pottedplant",
|
||||
"bed",
|
||||
"diningtable",
|
||||
"toilet",
|
||||
"tvmonitor",
|
||||
"laptop",
|
||||
"mouse",
|
||||
"remote",
|
||||
"keyboard",
|
||||
"cell phone",
|
||||
"microwave",
|
||||
"oven",
|
||||
"toaster",
|
||||
"sink",
|
||||
"refrigerator",
|
||||
"book",
|
||||
"clock",
|
||||
"vase",
|
||||
"scissors",
|
||||
"teddy bear",
|
||||
"hair drier",
|
||||
"toothbrush"
|
||||
};
|
||||
|
||||
internal struct DetectionResult
|
||||
{
|
||||
public string label;
|
||||
public List<float> bbox;
|
||||
public double prob;
|
||||
}
|
||||
|
||||
class Comparer : IComparer<DetectionResult>
|
||||
{
|
||||
public int Compare(DetectionResult x, DetectionResult y)
|
||||
{
|
||||
return y.prob.CompareTo(x.prob);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal async Task InitModelAsync()
|
||||
{
|
||||
var model_file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets//Yolo.onnx"));
|
||||
_model = await LearningModel.LoadFromStorageFileAsync(model_file);
|
||||
var device = new LearningModelDevice(LearningModelDeviceKind.Cpu);
|
||||
_session = new LearningModelSession(_model, device);
|
||||
_binding = new LearningModelBinding(_session);
|
||||
}
|
||||
|
||||
|
||||
internal async Task<List<DetectionResult>> EvaluateFrame(VideoFrame frame)
|
||||
{
|
||||
_binding.Clear();
|
||||
_binding.Bind("input_1:0", frame);
|
||||
var results = await _session.EvaluateAsync(_binding, "");
|
||||
|
||||
TensorFloat result = results.Outputs["Identity:0"] as TensorFloat;
|
||||
var shape = result.Shape;
|
||||
var data = result.GetAsVectorView();
|
||||
var detections = ParseResult(data.ToList<float>().ToArray());
|
||||
|
||||
Comparer cp = new Comparer();
|
||||
detections.Sort(cp);
|
||||
return NMS(detections);
|
||||
}
|
||||
|
||||
|
||||
// parse the result from WinML evaluation results to self defined object struct
|
||||
private List<DetectionResult> ParseResult(float[] results)
|
||||
{
|
||||
int c_values = 84;
|
||||
int c_boxes = results.Length / c_values;
|
||||
float confidence_threshold = 0.5f;
|
||||
List<DetectionResult> detections = new List<DetectionResult>();
|
||||
for (int i_box = 0; i_box < c_boxes; i_box++)
|
||||
{
|
||||
float max_prob = 0.0f;
|
||||
int label_index = -1;
|
||||
for (int j_confidence = 4; j_confidence < c_values; j_confidence++)
|
||||
{
|
||||
int index = i_box * c_values + j_confidence;
|
||||
if (results[index] > max_prob)
|
||||
{
|
||||
max_prob = results[index];
|
||||
label_index = j_confidence - 4;
|
||||
}
|
||||
}
|
||||
if (max_prob > confidence_threshold)
|
||||
{
|
||||
List<float> bbox = new List<float>();
|
||||
bbox.Add(results[i_box * c_values + 0]);
|
||||
bbox.Add(results[i_box * c_values + 1]);
|
||||
bbox.Add(results[i_box * c_values + 2]);
|
||||
bbox.Add(results[i_box * c_values + 3]);
|
||||
|
||||
detections.Add(new DetectionResult()
|
||||
{
|
||||
label = _labels[label_index],
|
||||
bbox = bbox,
|
||||
prob = max_prob
|
||||
});
|
||||
}
|
||||
}
|
||||
return detections;
|
||||
}
|
||||
|
||||
// Non-maximum Suppression(NMS), a technique which filters the proposals
|
||||
// based on Intersection over Union(IOU)
|
||||
private List<DetectionResult> NMS(IReadOnlyList<DetectionResult> detections,
|
||||
float IOU_threshold = 0.45f,
|
||||
float score_threshold = 0.3f)
|
||||
{
|
||||
List<DetectionResult> final_detections = new List<DetectionResult>();
|
||||
for (int i = 0; i < detections.Count; i++)
|
||||
{
|
||||
int j = 0;
|
||||
for (j = 0; j < final_detections.Count; j++)
|
||||
{
|
||||
if (ComputeIOU(final_detections[j], detections[i]) > IOU_threshold)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == final_detections.Count)
|
||||
{
|
||||
final_detections.Add(detections[i]);
|
||||
}
|
||||
}
|
||||
return final_detections;
|
||||
}
|
||||
|
||||
// Compute Intersection over Union(IOU)
|
||||
private float ComputeIOU(DetectionResult DRa, DetectionResult DRb)
|
||||
{
|
||||
float ay1 = DRa.bbox[0];
|
||||
float ax1 = DRa.bbox[1];
|
||||
float ay2 = DRa.bbox[2];
|
||||
float ax2 = DRa.bbox[3];
|
||||
float by1 = DRb.bbox[0];
|
||||
float bx1 = DRb.bbox[1];
|
||||
float by2 = DRb.bbox[2];
|
||||
float bx2 = DRb.bbox[3];
|
||||
|
||||
Debug.Assert(ay1 < ay2);
|
||||
Debug.Assert(ax1 < ax2);
|
||||
Debug.Assert(by1 < by2);
|
||||
Debug.Assert(bx1 < bx2);
|
||||
|
||||
// determine the coordinates of the intersection rectangle
|
||||
float x_left = Math.Max(ax1, bx1);
|
||||
float y_top = Math.Max(ay1, by1);
|
||||
float x_right = Math.Min(ax2, bx2);
|
||||
float y_bottom = Math.Min(ay2, by2);
|
||||
|
||||
if (x_right < x_left || y_bottom < y_top)
|
||||
return 0;
|
||||
float intersection_area = (x_right - x_left) * (y_bottom - y_top);
|
||||
float bb1_area = (ax2 - ax1) * (ay2 - ay1);
|
||||
float bb2_area = (bx2 - bx1) * (by2 - by1);
|
||||
float iou = intersection_area / (bb1_area + bb2_area - intersection_area);
|
||||
|
||||
Debug.Assert(iou >= 0 && iou <= 1);
|
||||
return iou;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
<AssemblyName>YOLOv4ObjectDetection</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">$(WindowsSDKVersion.Trim('\\'))</TargetPlatformVersion>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
|
@ -122,6 +123,7 @@
|
|||
<Compile Include="MainPage.xaml.cs">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Model.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче