mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 11:26:31 +00:00
fix bug with annotation result gradient stops
add tensorrt engine
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
xmlns:controls1="clr-namespace:Azaion.Common.Controls;assembly=Azaion.Common"
|
xmlns:controls1="clr-namespace:Azaion.Common.Controls;assembly=Azaion.Common"
|
||||||
xmlns:controls2="clr-namespace:Azaion.Annotator.Controls;assembly=Azaion.Common"
|
xmlns:controls2="clr-namespace:Azaion.Annotator.Controls;assembly=Azaion.Common"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
|
xmlns:local="clr-namespace:Azaion.Annotator"
|
||||||
Title="Azaion Annotator" Height="800" Width="1100"
|
Title="Azaion Annotator" Height="800" Width="1100"
|
||||||
WindowState="Maximized"
|
WindowState="Maximized"
|
||||||
>
|
>
|
||||||
@@ -49,6 +50,8 @@
|
|||||||
</Trigger>
|
</Trigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<local:GradientStyleSelector x:Key="GradientStyleSelector"/>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
|
||||||
<Grid Name="GlobalGrid"
|
<Grid Name="GlobalGrid"
|
||||||
@@ -232,7 +235,6 @@
|
|||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.RowSpan="4"
|
Grid.RowSpan="4"
|
||||||
Background="Black"
|
Background="Black"
|
||||||
RowBackground="#252525"
|
|
||||||
Foreground="White"
|
Foreground="White"
|
||||||
RowHeaderWidth="0"
|
RowHeaderWidth="0"
|
||||||
Padding="2 0 0 0"
|
Padding="2 0 0 0"
|
||||||
@@ -241,7 +243,8 @@
|
|||||||
CellStyle="{DynamicResource DataGridCellStyle1}"
|
CellStyle="{DynamicResource DataGridCellStyle1}"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
CanUserResizeRows="False"
|
CanUserResizeRows="False"
|
||||||
CanUserResizeColumns="False">
|
CanUserResizeColumns="False"
|
||||||
|
RowStyleSelector="{StaticResource GradientStyleSelector}">
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Width="60"
|
Width="60"
|
||||||
@@ -264,20 +267,6 @@
|
|||||||
<Setter Property="Background" Value="#252525"></Setter>
|
<Setter Property="Background" Value="#252525"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
</DataGridTextColumn.HeaderStyle>
|
</DataGridTextColumn.HeaderStyle>
|
||||||
<DataGridTextColumn.CellStyle>
|
|
||||||
<Style TargetType="DataGridCell">
|
|
||||||
<Setter Property="Background">
|
|
||||||
<Setter.Value>
|
|
||||||
<LinearGradientBrush StartPoint="0 0 " EndPoint="1 0">
|
|
||||||
<GradientStop Offset="0.3" Color="{Binding Path=ClassColor0}" />
|
|
||||||
<GradientStop Offset="0.5" Color="{Binding Path=ClassColor1}" />
|
|
||||||
<GradientStop Offset="0.8" Color="{Binding Path=ClassColor2}" />
|
|
||||||
<GradientStop Offset="0.99" Color="{Binding Path=ClassColor3}" />
|
|
||||||
</LinearGradientBrush>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
</DataGridTextColumn.CellStyle>
|
|
||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
|||||||
@@ -328,7 +328,11 @@ public partial class Annotator
|
|||||||
|
|
||||||
var existingResult = _formState.AnnotationResults.FirstOrDefault(x => x.Annotation.Time == time);
|
var existingResult = _formState.AnnotationResults.FirstOrDefault(x => x.Annotation.Time == time);
|
||||||
if (existingResult != null)
|
if (existingResult != null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"remove annotation {existingResult.TimeStr} {existingResult.ClassName}!");
|
||||||
_formState.AnnotationResults.Remove(existingResult);
|
_formState.AnnotationResults.Remove(existingResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var dict = _formState.AnnotationResults
|
var dict = _formState.AnnotationResults
|
||||||
.Select((x, i) => new { x.Annotation.Time, Index = i })
|
.Select((x, i) => new { x.Annotation.Time, Index = i })
|
||||||
@@ -339,7 +343,8 @@ public partial class Annotator
|
|||||||
.Select(x => x.Value + 1)
|
.Select(x => x.Value + 1)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
_formState.AnnotationResults.Insert(index, new AnnotationResult(_appConfig.AnnotationConfig.DetectionClassesDict, annotation));
|
var annRes = new AnnotationResult(_appConfig.AnnotationConfig.DetectionClassesDict, annotation);
|
||||||
|
_formState.AnnotationResults.Insert(index, annRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ReloadFiles()
|
private async Task ReloadFiles()
|
||||||
@@ -565,6 +570,7 @@ public partial class Annotator
|
|||||||
await _mediator.Publish(new AnnotatorControlEvent(PlaybackControlEnum.Play), ct);
|
await _mediator.Publish(new AnnotatorControlEvent(PlaybackControlEnum.Play), ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddAnnotation(annotation);
|
AddAnnotation(annotation);
|
||||||
|
|
||||||
if (FollowAI)
|
if (FollowAI)
|
||||||
@@ -574,7 +580,7 @@ public partial class Annotator
|
|||||||
$"{_appConfig.AnnotationConfig.DetectionClassesDict[det.ClassNumber].Name}: " +
|
$"{_appConfig.AnnotationConfig.DetectionClassesDict[det.ClassNumber].Name}: " +
|
||||||
$"xy=({det.CenterX:F2},{det.CenterY:F2}), " +
|
$"xy=({det.CenterX:F2},{det.CenterY:F2}), " +
|
||||||
$"size=({det.Width:F2}, {det.Height:F2}), " +
|
$"size=({det.Width:F2}, {det.Height:F2}), " +
|
||||||
$"prob: {det.Probability*100:F0}%"));
|
$"conf: {det.Confidence*100:F0}%"));
|
||||||
|
|
||||||
Dispatcher.Invoke(() =>
|
Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
@@ -618,3 +624,42 @@ public partial class Annotator
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class GradientStyleSelector : StyleSelector
|
||||||
|
{
|
||||||
|
public override Style? SelectStyle(object item, DependencyObject container)
|
||||||
|
{
|
||||||
|
if (container is not DataGridRow row || row.DataContext is not AnnotationResult result)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var style = new Style(typeof(DataGridRow));
|
||||||
|
var brush = new LinearGradientBrush
|
||||||
|
{
|
||||||
|
StartPoint = new Point(0, 0),
|
||||||
|
EndPoint = new Point(1, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
var gradients = new List<GradientStop>();
|
||||||
|
if (result.Colors.Count != 0)
|
||||||
|
{
|
||||||
|
var color = (Color)ColorConverter.ConvertFromString("#40DDDDDD");
|
||||||
|
gradients = [new GradientStop(color, 0.99)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var increment = 1.0 / result.Colors.Count;
|
||||||
|
var currentStop = increment;
|
||||||
|
foreach (var c in result.Colors)
|
||||||
|
{
|
||||||
|
var resultColor = c.Color.ToConfidenceColor(c.Confidence);
|
||||||
|
brush.GradientStops.Add(new GradientStop(resultColor, currentStop));
|
||||||
|
currentStop += increment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var gradientStop in gradients)
|
||||||
|
brush.GradientStops.Add(gradientStop);
|
||||||
|
|
||||||
|
style.Setters.Add(new Setter(DataGridRow.BackgroundProperty, brush));
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,16 +38,19 @@ public partial class MapMatcher : UserControl
|
|||||||
SatelliteMap.Position = new PointLatLng(48.295985271707664, 37.14477539062501);
|
SatelliteMap.Position = new PointLatLng(48.295985271707664, 37.14477539062501);
|
||||||
SatelliteMap.MultiTouchEnabled = true;
|
SatelliteMap.MultiTouchEnabled = true;
|
||||||
|
|
||||||
GpsFiles.MouseDoubleClick += async (sender, args) =>
|
GpsFiles.MouseDoubleClick += async (sender, args) => { await OpenGpsLocation(GpsFiles.SelectedIndex); };
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OpenGpsLocation(int gpsFilesIndex)
|
||||||
{
|
{
|
||||||
var media = (GpsFiles.SelectedItem as MediaFileInfo)!;
|
var media = GpsFiles.Items[gpsFilesIndex] as MediaFileInfo;
|
||||||
var ann = _annotations.GetValueOrDefault(Path.GetFileNameWithoutExtension(media.Name));
|
var ann = _annotations.GetValueOrDefault(Path.GetFileNameWithoutExtension(media.Name));
|
||||||
GpsImageEditor.Background = new ImageBrush
|
GpsImageEditor.Background = new ImageBrush
|
||||||
{
|
{
|
||||||
ImageSource = await Path.Combine(_currentDir, ann.Name).OpenImage()
|
ImageSource = await Path.Combine(_currentDir, ann.Name).OpenImage()
|
||||||
};
|
};
|
||||||
|
if (ann.Lat != 0 && ann.Lon != 0)
|
||||||
SatelliteMap.Position = new PointLatLng(ann.Lat, ann.Lon);
|
SatelliteMap.Position = new PointLatLng(ann.Lat, ann.Lon);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GpsFilesContextOpening(object sender, ContextMenuEventArgs e)
|
private void GpsFilesContextOpening(object sender, ContextMenuEventArgs e)
|
||||||
@@ -104,8 +107,11 @@ public partial class MapMatcher : UserControl
|
|||||||
_allMediaFiles = mediaFiles;
|
_allMediaFiles = mediaFiles;
|
||||||
GpsFiles.ItemsSource = new ObservableCollection<MediaFileInfo>(_allMediaFiles);
|
GpsFiles.ItemsSource = new ObservableCollection<MediaFileInfo>(_allMediaFiles);
|
||||||
var annotations = SetFromCsv(mediaFiles);
|
var annotations = SetFromCsv(mediaFiles);
|
||||||
|
Cursor = Cursors.Wait;
|
||||||
await Task.Delay(TimeSpan.FromSeconds(10));
|
await Task.Delay(TimeSpan.FromSeconds(10));
|
||||||
SetMarkers(annotations);
|
SetMarkers(annotations);
|
||||||
|
Cursor = Cursors.Arrow;
|
||||||
|
await OpenGpsLocation(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<string, Annotation> SetFromCsv(List<MediaFileInfo> mediaFiles)
|
private Dictionary<string, Annotation> SetFromCsv(List<MediaFileInfo> mediaFiles)
|
||||||
@@ -117,7 +123,9 @@ public partial class MapMatcher : UserControl
|
|||||||
}).ToDictionary(x => Path.GetFileNameWithoutExtension(x.OriginalMediaName));
|
}).ToDictionary(x => Path.GetFileNameWithoutExtension(x.OriginalMediaName));
|
||||||
|
|
||||||
var csvResults = GpsCsvResult.ReadFromCsv(Constants.CSV_PATH);
|
var csvResults = GpsCsvResult.ReadFromCsv(Constants.CSV_PATH);
|
||||||
var csvDict = csvResults.ToDictionary(x => x.Image);
|
var csvDict = csvResults
|
||||||
|
.Where(x => x.MatchType == "stitched")
|
||||||
|
.ToDictionary(x => x.Image);
|
||||||
foreach (var ann in _annotations)
|
foreach (var ann in _annotations)
|
||||||
{
|
{
|
||||||
var csvRes = csvDict.GetValueOrDefault(ann.Key);
|
var csvRes = csvDict.GetValueOrDefault(ann.Key);
|
||||||
@@ -137,7 +145,7 @@ public partial class MapMatcher : UserControl
|
|||||||
|
|
||||||
var firstAnnotation = annotations.FirstOrDefault();
|
var firstAnnotation = annotations.FirstOrDefault();
|
||||||
SatelliteMap.Position = new PointLatLng(firstAnnotation.Value.Lat, firstAnnotation.Value.Lon);
|
SatelliteMap.Position = new PointLatLng(firstAnnotation.Value.Lat, firstAnnotation.Value.Lon);
|
||||||
foreach (var ann in annotations)
|
foreach (var ann in annotations.Where(x => x.Value.Lat != 0 && x.Value.Lon != 0))
|
||||||
{
|
{
|
||||||
var marker = new GMapMarker(new PointLatLng(ann.Value.Lat, ann.Value.Lon));
|
var marker = new GMapMarker(new PointLatLng(ann.Value.Lat, ann.Value.Lon));
|
||||||
var circle = new CircleVisual(marker, System.Windows.Media.Brushes.Blue)
|
var circle = new CircleVisual(marker, System.Windows.Media.Brushes.Blue)
|
||||||
@@ -147,6 +155,6 @@ public partial class MapMatcher : UserControl
|
|||||||
marker.Shape = circle;
|
marker.Shape = circle;
|
||||||
SatelliteMap.Markers.Add(marker);
|
SatelliteMap.Markers.Add(marker);
|
||||||
}
|
}
|
||||||
|
SatelliteMap.ZoomAndCenterMarkers(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,5 +90,5 @@ public class Constants
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public const string CSV_PATH = "D:\\matches.csv";
|
public const string CSV_PATH = "matches.csv";
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ public class CanvasEditor : Canvas
|
|||||||
_verticalLine.Fill = value.ColorBrush;
|
_verticalLine.Fill = value.ColorBrush;
|
||||||
_horizontalLine.Stroke = value.ColorBrush;
|
_horizontalLine.Stroke = value.ColorBrush;
|
||||||
_horizontalLine.Fill = value.ColorBrush;
|
_horizontalLine.Fill = value.ColorBrush;
|
||||||
_classNameHint.Text = value.Name;
|
_classNameHint.Text = value.ShortName;
|
||||||
|
|
||||||
_newAnnotationRect.Stroke = value.ColorBrush;
|
_newAnnotationRect.Stroke = value.ColorBrush;
|
||||||
_newAnnotationRect.Fill = value.ColorBrush;
|
_newAnnotationRect.Fill = value.ColorBrush;
|
||||||
@@ -84,7 +84,7 @@ public class CanvasEditor : Canvas
|
|||||||
};
|
};
|
||||||
_classNameHint = new TextBlock
|
_classNameHint = new TextBlock
|
||||||
{
|
{
|
||||||
Text = CurrentAnnClass?.Name ?? "asd",
|
Text = CurrentAnnClass?.ShortName ?? "",
|
||||||
Foreground = new SolidColorBrush(Colors.Black),
|
Foreground = new SolidColorBrush(Colors.Black),
|
||||||
Cursor = Cursors.Arrow,
|
Cursor = Cursors.Arrow,
|
||||||
FontSize = 16,
|
FontSize = 16,
|
||||||
@@ -313,14 +313,14 @@ public class CanvasEditor : Canvas
|
|||||||
foreach (var detection in detections)
|
foreach (var detection in detections)
|
||||||
{
|
{
|
||||||
var annClass = DetectionClass.FromYoloId(detection.ClassNumber, detectionClasses);
|
var annClass = DetectionClass.FromYoloId(detection.ClassNumber, detectionClasses);
|
||||||
var canvasLabel = new CanvasLabel(detection, RenderSize, videoSize, detection.Probability);
|
var canvasLabel = new CanvasLabel(detection, RenderSize, videoSize, detection.Confidence);
|
||||||
CreateDetectionControl(annClass, time, canvasLabel);
|
CreateDetectionControl(annClass, time, canvasLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateDetectionControl(DetectionClass annClass, TimeSpan time, CanvasLabel canvasLabel)
|
private void CreateDetectionControl(DetectionClass annClass, TimeSpan time, CanvasLabel canvasLabel)
|
||||||
{
|
{
|
||||||
var detectionControl = new DetectionControl(annClass, time, AnnotationResizeStart, canvasLabel.Probability)
|
var detectionControl = new DetectionControl(annClass, time, AnnotationResizeStart, canvasLabel.Confidence)
|
||||||
{
|
{
|
||||||
Width = canvasLabel.Width,
|
Width = canvasLabel.Width,
|
||||||
Height = canvasLabel.Height
|
Height = canvasLabel.Height
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</DataGridTemplateColumn.CellTemplate>
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
</DataGridTemplateColumn>
|
</DataGridTemplateColumn>
|
||||||
<DataGridTextColumn Width="*" Header="Назва" Binding="{Binding Path=Name}" CanUserSort="False">
|
<DataGridTextColumn Width="*" Header="Назва" Binding="{Binding Path=ShortName}" CanUserSort="False">
|
||||||
<DataGridTextColumn.HeaderStyle>
|
<DataGridTextColumn.HeaderStyle>
|
||||||
<Style TargetType="DataGridColumnHeader">
|
<Style TargetType="DataGridColumnHeader">
|
||||||
<Setter Property="Background" Value="#252525"/>
|
<Setter Property="Background" Value="#252525"/>
|
||||||
|
|||||||
@@ -1,52 +1,33 @@
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Azaion.Common.Database;
|
using Azaion.Common.Database;
|
||||||
using Azaion.Common.Extensions;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Azaion.Common.DTO;
|
namespace Azaion.Common.DTO;
|
||||||
|
|
||||||
public class AnnotationResult
|
public class AnnotationResult
|
||||||
{
|
{
|
||||||
public Annotation Annotation { get; set; }
|
public Annotation Annotation { get; set; }
|
||||||
|
public List<(Color Color, double Confidence)> Colors { get; private set; }
|
||||||
|
|
||||||
public string ImagePath { get; set; }
|
public string ImagePath { get; set; }
|
||||||
public string TimeStr { get; set; }
|
public string TimeStr { get; set; }
|
||||||
|
|
||||||
public string ClassName { get; set; }
|
public string ClassName { get; set; }
|
||||||
|
|
||||||
public Color ClassColor0 { get; set; }
|
|
||||||
public Color ClassColor1 { get; set; }
|
|
||||||
public Color ClassColor2 { get; set; }
|
|
||||||
public Color ClassColor3 { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public AnnotationResult(Dictionary<int, DetectionClass> allDetectionClasses, Annotation annotation)
|
public AnnotationResult(Dictionary<int, DetectionClass> allDetectionClasses, Annotation annotation)
|
||||||
{
|
{
|
||||||
|
|
||||||
Annotation = annotation;
|
Annotation = annotation;
|
||||||
var detections = annotation.Detections.ToList();
|
|
||||||
|
|
||||||
Color GetAnnotationClass(List<int> detectionClasses, int colorNumber)
|
|
||||||
{
|
|
||||||
if (detections.Count == 0)
|
|
||||||
return (-1).ToColor();
|
|
||||||
|
|
||||||
return colorNumber >= detectionClasses.Count
|
|
||||||
? allDetectionClasses[detectionClasses.LastOrDefault()].Color
|
|
||||||
: allDetectionClasses[detectionClasses[colorNumber]].Color;
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeStr = $"{annotation.Time:h\\:mm\\:ss}";
|
TimeStr = $"{annotation.Time:h\\:mm\\:ss}";
|
||||||
ImagePath = annotation.ImagePath;
|
ImagePath = annotation.ImagePath;
|
||||||
|
|
||||||
var detectionClasses = detections.Select(x => x.ClassNumber).Distinct().ToList();
|
var detectionClasses = annotation.Detections.Select(x => x.ClassNumber).Distinct().ToList();
|
||||||
|
|
||||||
|
Colors = annotation.Detections
|
||||||
|
.Select(d => (allDetectionClasses[d.ClassNumber].Color, d.Confidence))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
ClassName = detectionClasses.Count > 1
|
ClassName = detectionClasses.Count > 1
|
||||||
? string.Join(", ", detectionClasses.Select(x => allDetectionClasses[x].UIName))
|
? string.Join(", ", detectionClasses.Select(x => allDetectionClasses[x].UIName))
|
||||||
: allDetectionClasses[detectionClasses.FirstOrDefault()].UIName;
|
: allDetectionClasses[detectionClasses.FirstOrDefault()].UIName;
|
||||||
|
|
||||||
ClassColor0 = GetAnnotationClass(detectionClasses, 0);
|
|
||||||
ClassColor1 = GetAnnotationClass(detectionClasses, 1);
|
|
||||||
ClassColor2 = GetAnnotationClass(detectionClasses, 2);
|
|
||||||
ClassColor3 = GetAnnotationClass(detectionClasses, 3);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,7 @@ public class AnnotationConfig
|
|||||||
{
|
{
|
||||||
Id = cls.Id,
|
Id = cls.Id,
|
||||||
Name = cls.Name,
|
Name = cls.Name,
|
||||||
|
Color = cls.Color,
|
||||||
ShortName = cls.ShortName,
|
ShortName = cls.ShortName,
|
||||||
PhotoMode = mode
|
PhotoMode = mode
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Azaion.Common.Extensions;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Azaion.Common.DTO;
|
namespace Azaion.Common.DTO;
|
||||||
@@ -11,6 +10,8 @@ public class DetectionClass
|
|||||||
public string Name { get; set; } = null!;
|
public string Name { get; set; } = null!;
|
||||||
public string ShortName { get; set; } = null!;
|
public string ShortName { get; set; } = null!;
|
||||||
|
|
||||||
|
public Color Color { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string UIName
|
public string UIName
|
||||||
{
|
{
|
||||||
@@ -31,9 +32,6 @@ public class DetectionClass
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public PhotoMode PhotoMode { get; set; }
|
public PhotoMode PhotoMode { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public Color Color => Id.ToColor();
|
|
||||||
|
|
||||||
[JsonIgnore] //For UI
|
[JsonIgnore] //For UI
|
||||||
public int ClassNumber => Id + 1;
|
public int ClassNumber => Id + 1;
|
||||||
|
|
||||||
|
|||||||
@@ -26,22 +26,22 @@ public class CanvasLabel : Label
|
|||||||
public double Y { get; set; }
|
public double Y { get; set; }
|
||||||
public double Width { get; set; }
|
public double Width { get; set; }
|
||||||
public double Height { get; set; }
|
public double Height { get; set; }
|
||||||
public double? Probability { get; }
|
public double? Confidence { get; }
|
||||||
|
|
||||||
public CanvasLabel()
|
public CanvasLabel()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public CanvasLabel(int classNumber, double x, double y, double width, double height, double? probability = null) : base(classNumber)
|
public CanvasLabel(int classNumber, double x, double y, double width, double height, double? confidence = null) : base(classNumber)
|
||||||
{
|
{
|
||||||
X = x;
|
X = x;
|
||||||
Y = y;
|
Y = y;
|
||||||
Width = width;
|
Width = width;
|
||||||
Height = height;
|
Height = height;
|
||||||
Probability = probability;
|
Confidence = confidence;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CanvasLabel(YoloLabel label, Size canvasSize, Size? videoSize = null, double? probability = null)
|
public CanvasLabel(YoloLabel label, Size canvasSize, Size? videoSize = null, double confidence = 1)
|
||||||
{
|
{
|
||||||
var cw = canvasSize.Width;
|
var cw = canvasSize.Width;
|
||||||
var ch = canvasSize.Height;
|
var ch = canvasSize.Height;
|
||||||
@@ -75,7 +75,7 @@ public class CanvasLabel : Label
|
|||||||
Width = label.Width * realWidth;
|
Width = label.Width * realWidth;
|
||||||
Height = label.Height * ch;
|
Height = label.Height * ch;
|
||||||
}
|
}
|
||||||
Probability = probability;
|
Confidence = confidence;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,12 +189,12 @@ public class YoloLabel : Label
|
|||||||
public class Detection : YoloLabel
|
public class Detection : YoloLabel
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "an")][Key("an")] public string AnnotationName { get; set; } = null!;
|
[JsonProperty(PropertyName = "an")][Key("an")] public string AnnotationName { get; set; } = null!;
|
||||||
[JsonProperty(PropertyName = "p")][Key("p")] public double? Probability { get; set; }
|
[JsonProperty(PropertyName = "p")][Key("p")] public double Confidence { get; set; }
|
||||||
|
|
||||||
//For db & serialization
|
//For db & serialization
|
||||||
public Detection(){}
|
public Detection(){}
|
||||||
|
|
||||||
public Detection(string annotationName, YoloLabel label, double? probability = null)
|
public Detection(string annotationName, YoloLabel label, double confidence = 1)
|
||||||
{
|
{
|
||||||
AnnotationName = annotationName;
|
AnnotationName = annotationName;
|
||||||
ClassNumber = label.ClassNumber;
|
ClassNumber = label.ClassNumber;
|
||||||
@@ -202,6 +202,6 @@ public class Detection : YoloLabel
|
|||||||
CenterY = label.CenterY;
|
CenterY = label.CenterY;
|
||||||
Height = label.Height;
|
Height = label.Height;
|
||||||
Width = label.Width;
|
Width = label.Width;
|
||||||
Probability = probability;
|
Confidence = confidence;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,25 +4,12 @@ namespace Azaion.Common.Extensions;
|
|||||||
|
|
||||||
public static class ColorExtensions
|
public static class ColorExtensions
|
||||||
{
|
{
|
||||||
public static Color ToColor(this int id)
|
private const int MIN_ALPHA = 20;
|
||||||
|
private const int MAX_ALPHA = 100;
|
||||||
|
|
||||||
|
public static Color ToConfidenceColor(this Color color, double confidence )
|
||||||
{
|
{
|
||||||
var index = id % ColorValues.Length;
|
color.A = (byte)(MIN_ALPHA + (int)Math.Round(confidence * (MAX_ALPHA - MIN_ALPHA)));
|
||||||
var hex = index == -1
|
|
||||||
? "#40DDDDDD"
|
|
||||||
: $"#40{ColorValues[index]}";
|
|
||||||
var color =(Color)ColorConverter.ConvertFromString(hex);
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly string[] ColorValues =
|
|
||||||
[
|
|
||||||
"FF0000", "00FF00", "0000FF", "FFFF00", "FF00FF", "00FFFF", "000000",
|
|
||||||
"800000", "008000", "000080", "808000", "800080", "008080", "808080",
|
|
||||||
"C00000", "00C000", "0000C0", "C0C000", "C000C0", "00C0C0", "C0C0C0",
|
|
||||||
"400000", "004000", "000040", "404000", "400040", "004040", "404040",
|
|
||||||
"200000", "002000", "000020", "202000", "200020", "002020", "202020",
|
|
||||||
"600000", "006000", "000060", "606000", "600060", "006060", "606060",
|
|
||||||
"A00000", "00A000", "0000A0", "A0A000", "A000A0", "00A0A0", "A0A0A0",
|
|
||||||
"E00000", "00E000", "0000E0", "E0E000", "E000E0", "00E0E0", "E0E0E0"
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
@@ -13,4 +13,7 @@ public class InferenceClientConfig : ExternalClientConfig
|
|||||||
public string ResourcesFolder { get; set; } = "";
|
public string ResourcesFolder { get; set; } = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GpsDeniedClientConfig : ExternalClientConfig;
|
public class GpsDeniedClientConfig : ExternalClientConfig
|
||||||
|
{
|
||||||
|
public int ZeroMqReceiverPort { get; set; }
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ public abstract class BaseZeroMqExternalClient : IExternalClient
|
|||||||
using var process = new Process();
|
using var process = new Process();
|
||||||
process.StartInfo = new ProcessStartInfo
|
process.StartInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = ClientPath
|
FileName = ClientPath,
|
||||||
//Arguments = $"-e {credentials.Email} -p {credentials.Password} -f {apiConfig.ResourcesFolder}",
|
//Arguments = $"-e {credentials.Email} -p {credentials.Password} -f {apiConfig.ResourcesFolder}",
|
||||||
//RedirectStandardOutput = true,
|
//RedirectStandardOutput = true,
|
||||||
//RedirectStandardError = true,
|
//RedirectStandardError = true,
|
||||||
|
|||||||
@@ -14,9 +14,11 @@ public interface IHardwareService
|
|||||||
public class HardwareService : IHardwareService
|
public class HardwareService : IHardwareService
|
||||||
{
|
{
|
||||||
private const string WIN32_GET_HARDWARE_COMMAND =
|
private const string WIN32_GET_HARDWARE_COMMAND =
|
||||||
"wmic OS get TotalVisibleMemorySize /Value && " +
|
"powershell -Command \"" +
|
||||||
"wmic CPU get Name /Value && " +
|
"Get-CimInstance -ClassName Win32_Processor | Select-Object -ExpandProperty Name | Write-Output; " +
|
||||||
"wmic path Win32_VideoController get Name /Value";
|
"Get-CimInstance -ClassName Win32_VideoController | Select-Object -ExpandProperty Name | Write-Output; " +
|
||||||
|
"Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -ExpandProperty TotalVisibleMemorySize | Write-Output" +
|
||||||
|
"\"";
|
||||||
|
|
||||||
private const string UNIX_GET_HARDWARE_COMMAND =
|
private const string UNIX_GET_HARDWARE_COMMAND =
|
||||||
"/bin/bash -c \"free -g | grep Mem: | awk '{print $2}' && " +
|
"/bin/bash -c \"free -g | grep Mem: | awk '{print $2}' && " +
|
||||||
|
|||||||
@@ -77,11 +77,11 @@ public partial class DatasetExplorer
|
|||||||
await DeleteAnnotations();
|
await DeleteAnnotations();
|
||||||
break;
|
break;
|
||||||
case Key.Enter:
|
case Key.Enter:
|
||||||
await EditAnnotation();
|
await EditAnnotation(ThumbnailsView.SelectedIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ThumbnailsView.MouseDoubleClick += async (_, _) => await EditAnnotation();
|
ThumbnailsView.MouseDoubleClick += async (_, _) => await EditAnnotation(ThumbnailsView.SelectedIndex);
|
||||||
|
|
||||||
ThumbnailsView.SelectionChanged += (_, _) =>
|
ThumbnailsView.SelectionChanged += (_, _) =>
|
||||||
{
|
{
|
||||||
@@ -152,7 +152,7 @@ public partial class DatasetExplorer
|
|||||||
.Select(gr => new
|
.Select(gr => new
|
||||||
{
|
{
|
||||||
gr.Key,
|
gr.Key,
|
||||||
_annotationConfig.DetectionClassesDict[gr.Key].Name,
|
_annotationConfig.DetectionClassesDict[gr.Key].ShortName,
|
||||||
_annotationConfig.DetectionClassesDict[gr.Key].Color,
|
_annotationConfig.DetectionClassesDict[gr.Key].Color,
|
||||||
ClassCount = gr.Value.Count
|
ClassCount = gr.Value.Count
|
||||||
})
|
})
|
||||||
@@ -175,7 +175,7 @@ public partial class DatasetExplorer
|
|||||||
|
|
||||||
foreach (var x in data)
|
foreach (var x in data)
|
||||||
{
|
{
|
||||||
var label = ClassDistribution.Plot.Add.Text(x.Name, 50, -1.5 * x.Key + 1.1);
|
var label = ClassDistribution.Plot.Add.Text(x.ShortName, 50, -1.5 * x.Key + 1.1);
|
||||||
label.LabelFontColor = foregroundColor;
|
label.LabelFontColor = foregroundColor;
|
||||||
label.LabelFontSize = 18;
|
label.LabelFontSize = 18;
|
||||||
}
|
}
|
||||||
@@ -204,16 +204,17 @@ public partial class DatasetExplorer
|
|||||||
RefreshThumbnailsButtonItem.Visibility = Visibility.Visible;
|
RefreshThumbnailsButtonItem.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EditAnnotation()
|
public async Task EditAnnotation(int index)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ThumbnailLoading = true;
|
ThumbnailLoading = true;
|
||||||
|
if (index == -1)
|
||||||
if (ThumbnailsView.SelectedItem == null)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CurrentAnnotation = (ThumbnailsView.SelectedItem as AnnotationThumbnail)!;
|
CurrentAnnotation = (ThumbnailsView.Items[index] as AnnotationThumbnail)!;
|
||||||
|
ThumbnailsView.SelectedIndex = index;
|
||||||
|
|
||||||
var ann = CurrentAnnotation.Annotation;
|
var ann = CurrentAnnotation.Annotation;
|
||||||
ExplorerEditor.Background = new ImageBrush
|
ExplorerEditor.Background = new ImageBrush
|
||||||
{
|
{
|
||||||
@@ -224,7 +225,6 @@ public partial class DatasetExplorer
|
|||||||
var time = ann.Time;
|
var time = ann.Time;
|
||||||
ExplorerEditor.RemoveAllAnns();
|
ExplorerEditor.RemoveAllAnns();
|
||||||
ExplorerEditor.CreateDetections(time, ann.Detections, _annotationConfig.DetectionClasses, ExplorerEditor.RenderSize);
|
ExplorerEditor.CreateDetections(time, ann.Detections, _annotationConfig.DetectionClasses, ExplorerEditor.RenderSize);
|
||||||
ThumbnailLoading = false;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -233,7 +233,11 @@ public partial class DatasetExplorer
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(100);
|
||||||
ThumbnailLoading = false;
|
ThumbnailLoading = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -260,7 +264,7 @@ public partial class DatasetExplorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteAnnotations()
|
public async Task DeleteAnnotations()
|
||||||
{
|
{
|
||||||
var tempSelected = ThumbnailsView.SelectedIndex;
|
var tempSelected = ThumbnailsView.SelectedIndex;
|
||||||
var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Azaion.Common.DTO;
|
using Azaion.Common.DTO;
|
||||||
using Azaion.Common.DTO.Queue;
|
using Azaion.Common.DTO.Queue;
|
||||||
@@ -22,7 +23,9 @@ public class DatasetExplorerEventHandler(
|
|||||||
{ Key.Delete, PlaybackControlEnum.RemoveSelectedAnns },
|
{ Key.Delete, PlaybackControlEnum.RemoveSelectedAnns },
|
||||||
{ Key.X, PlaybackControlEnum.RemoveAllAnns },
|
{ Key.X, PlaybackControlEnum.RemoveAllAnns },
|
||||||
{ Key.Escape, PlaybackControlEnum.Close },
|
{ Key.Escape, PlaybackControlEnum.Close },
|
||||||
{ Key.V, PlaybackControlEnum.ValidateAnnotations}
|
{ Key.Down, PlaybackControlEnum.Next },
|
||||||
|
{ Key.Up, PlaybackControlEnum.Previous },
|
||||||
|
{ Key.V, PlaybackControlEnum.ValidateAnnotations},
|
||||||
};
|
};
|
||||||
|
|
||||||
public async Task Handle(DatasetExplorerControlEvent notification, CancellationToken cancellationToken)
|
public async Task Handle(DatasetExplorerControlEvent notification, CancellationToken cancellationToken)
|
||||||
@@ -63,15 +66,28 @@ public class DatasetExplorerEventHandler(
|
|||||||
var detections = datasetExplorer.ExplorerEditor.CurrentDetections
|
var detections = datasetExplorer.ExplorerEditor.CurrentDetections
|
||||||
.Select(x => new Detection(a.Name, x.GetLabel(datasetExplorer.ExplorerEditor.RenderSize)))
|
.Select(x => new Detection(a.Name, x.GetLabel(datasetExplorer.ExplorerEditor.RenderSize)))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
var index = datasetExplorer.ThumbnailsView.SelectedIndex;
|
||||||
await annotationService.SaveAnnotation(a.OriginalMediaName, a.Time, detections, SourceEnum.Manual, token: cancellationToken);
|
await annotationService.SaveAnnotation(a.OriginalMediaName, a.Time, detections, SourceEnum.Manual, token: cancellationToken);
|
||||||
datasetExplorer.SwitchTab(toEditor: false);
|
await datasetExplorer.EditAnnotation(index + 1);
|
||||||
break;
|
break;
|
||||||
case PlaybackControlEnum.RemoveSelectedAnns:
|
case PlaybackControlEnum.RemoveSelectedAnns:
|
||||||
|
if (datasetExplorer.ExplorerEditor.CurrentDetections.Any(x => x.IsSelected))
|
||||||
datasetExplorer.ExplorerEditor.RemoveSelectedAnns();
|
datasetExplorer.ExplorerEditor.RemoveSelectedAnns();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await datasetExplorer.DeleteAnnotations();
|
||||||
|
await datasetExplorer.EditAnnotation(datasetExplorer.ThumbnailsView.SelectedIndex);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PlaybackControlEnum.RemoveAllAnns:
|
case PlaybackControlEnum.RemoveAllAnns:
|
||||||
datasetExplorer.ExplorerEditor.RemoveAllAnns();
|
datasetExplorer.ExplorerEditor.RemoveAllAnns();
|
||||||
break;
|
break;
|
||||||
|
case PlaybackControlEnum.Next:
|
||||||
|
await datasetExplorer.EditAnnotation(datasetExplorer.ThumbnailsView.SelectedIndex + 1);
|
||||||
|
break;
|
||||||
|
case PlaybackControlEnum.Previous:
|
||||||
|
await datasetExplorer.EditAnnotation(datasetExplorer.ThumbnailsView.SelectedIndex - 1);
|
||||||
|
break;
|
||||||
case PlaybackControlEnum.Close:
|
case PlaybackControlEnum.Close:
|
||||||
datasetExplorer.SwitchTab(toEditor: false);
|
datasetExplorer.SwitchTab(toEditor: false);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -72,5 +72,5 @@ In case of fbgemm.dll error (Windows specific):
|
|||||||
|
|
||||||
<h3>Build exe</h3>
|
<h3>Build exe</h3>
|
||||||
```
|
```
|
||||||
.\build.exe
|
.\build.cmd
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ cdef class ApiClient:
|
|||||||
|
|
||||||
cdef load_bytes(self, str filename, str folder=*)
|
cdef load_bytes(self, str filename, str folder=*)
|
||||||
cdef upload_file(self, str filename, str folder=*)
|
cdef upload_file(self, str filename, str folder=*)
|
||||||
cdef load_ai_model(self)
|
cdef load_ai_model(self, bint is_tensor=*)
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ cdef class ApiClient:
|
|||||||
|
|
||||||
cdef load_bytes(self, str filename, str folder=None):
|
cdef load_bytes(self, str filename, str folder=None):
|
||||||
folder = folder or self.credentials.folder
|
folder = folder or self.credentials.folder
|
||||||
|
|
||||||
hardware_service = HardwareService()
|
hardware_service = HardwareService()
|
||||||
cdef HardwareInfo hardware = hardware_service.get_hardware_info()
|
cdef HardwareInfo hardware = hardware_service.get_hardware_info()
|
||||||
|
|
||||||
@@ -110,11 +111,20 @@ cdef class ApiClient:
|
|||||||
constants.log(<str>f'Downloaded file: {filename}, {len(data)} bytes')
|
constants.log(<str>f'Downloaded file: {filename}, {len(data)} bytes')
|
||||||
return data
|
return data
|
||||||
|
|
||||||
cdef load_ai_model(self):
|
cdef load_ai_model(self, bint is_tensor=False):
|
||||||
with open(<str>constants.AI_MODEL_FILE_BIG, 'rb') as binary_file:
|
if is_tensor:
|
||||||
encrypted_bytes_big = binary_file.read()
|
big_file = <str> constants.AI_TENSOR_MODEL_FILE_BIG
|
||||||
encrypted_bytes_small = self.load_bytes(constants.AI_MODEL_FILE_SMALL)
|
small_file = <str> constants.AI_TENSOR_MODEL_FILE_SMALL
|
||||||
|
else:
|
||||||
|
big_file = <str>constants.AI_ONNX_MODEL_FILE_BIG
|
||||||
|
small_file = <str> constants.AI_ONNX_MODEL_FILE_SMALL
|
||||||
|
|
||||||
|
with open(big_file, 'rb') as binary_file:
|
||||||
|
encrypted_bytes_big = binary_file.read()
|
||||||
|
print('read encrypted big file')
|
||||||
|
print(f'small file: {small_file}')
|
||||||
|
encrypted_bytes_small = self.load_bytes(small_file)
|
||||||
|
print('read encrypted small file')
|
||||||
encrypted_model_bytes = encrypted_bytes_small + encrypted_bytes_big
|
encrypted_model_bytes = encrypted_bytes_small + encrypted_bytes_big
|
||||||
key = Security.get_model_encryption_key()
|
key = Security.get_model_encryption_key()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
from PyInstaller.utils.hooks import collect_all
|
||||||
|
|
||||||
|
datas = []
|
||||||
|
binaries = []
|
||||||
|
hiddenimports = ['constants', 'annotation', 'credentials', 'file_data', 'user', 'security', 'secure_model', 'api_client', 'hardware_service', 'remote_command', 'ai_config', 'inference_engine', 'inference', 'remote_command_handler']
|
||||||
|
tmp_ret = collect_all('pyyaml')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('jwt')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('requests')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('psutil')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('msgpack')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('zmq')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('cryptography')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('cv2')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('onnxruntime')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('tensorrt')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('pycuda')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
tmp_ret = collect_all('re')
|
||||||
|
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||||
|
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
['start.py'],
|
||||||
|
pathex=[],
|
||||||
|
binaries=binaries,
|
||||||
|
datas=datas,
|
||||||
|
hiddenimports=hiddenimports,
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=[],
|
||||||
|
noarchive=False,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
pyz = PYZ(a.pure)
|
||||||
|
|
||||||
|
exe = EXE(
|
||||||
|
pyz,
|
||||||
|
a.scripts,
|
||||||
|
[],
|
||||||
|
exclude_binaries=True,
|
||||||
|
name='azaion-inference',
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
console=True,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
)
|
||||||
|
coll = COLLECT(
|
||||||
|
exe,
|
||||||
|
a.binaries,
|
||||||
|
a.datas,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
name='azaion-inference',
|
||||||
|
)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
pyinstaller --onefile ^
|
pyinstaller --name=azaion-inference ^
|
||||||
--collect-all pyyaml ^
|
--collect-all pyyaml ^
|
||||||
--collect-all jwt ^
|
--collect-all jwt ^
|
||||||
--collect-all requests ^
|
--collect-all requests ^
|
||||||
@@ -8,6 +8,9 @@ pyinstaller --onefile ^
|
|||||||
--collect-all cryptography ^
|
--collect-all cryptography ^
|
||||||
--collect-all cv2 ^
|
--collect-all cv2 ^
|
||||||
--collect-all onnxruntime ^
|
--collect-all onnxruntime ^
|
||||||
|
--collect-all tensorrt ^
|
||||||
|
--collect-all pycuda ^
|
||||||
|
--collect-all re ^
|
||||||
--hidden-import constants ^
|
--hidden-import constants ^
|
||||||
--hidden-import annotation ^
|
--hidden-import annotation ^
|
||||||
--hidden-import credentials ^
|
--hidden-import credentials ^
|
||||||
@@ -19,6 +22,7 @@ pyinstaller --onefile ^
|
|||||||
--hidden-import hardware_service ^
|
--hidden-import hardware_service ^
|
||||||
--hidden-import remote_command ^
|
--hidden-import remote_command ^
|
||||||
--hidden-import ai_config ^
|
--hidden-import ai_config ^
|
||||||
|
--hidden-import inference_engine ^
|
||||||
--hidden-import inference ^
|
--hidden-import inference ^
|
||||||
--hidden-import remote_command_handler ^
|
--hidden-import remote_command_handler ^
|
||||||
start.py
|
start.py
|
||||||
@@ -6,8 +6,13 @@ cdef str ANNOTATIONS_QUEUE # Name of the annotations queue in rabbit
|
|||||||
|
|
||||||
cdef str API_URL # Base URL for the external API
|
cdef str API_URL # Base URL for the external API
|
||||||
cdef str QUEUE_CONFIG_FILENAME # queue config filename to load from api
|
cdef str QUEUE_CONFIG_FILENAME # queue config filename to load from api
|
||||||
cdef str AI_MODEL_FILE_BIG # AI Model file (BIG part)
|
|
||||||
cdef str AI_MODEL_FILE_SMALL # AI Model file (small part)
|
cdef str AI_ONNX_MODEL_FILE_BIG
|
||||||
|
cdef str AI_ONNX_MODEL_FILE_SMALL
|
||||||
|
|
||||||
|
cdef str AI_TENSOR_MODEL_FILE_BIG
|
||||||
|
cdef str AI_TENSOR_MODEL_FILE_SMALL
|
||||||
|
|
||||||
|
|
||||||
cdef bytes DONE_SIGNAL
|
cdef bytes DONE_SIGNAL
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,12 @@ cdef str ANNOTATIONS_QUEUE = "azaion-annotations"
|
|||||||
|
|
||||||
cdef str API_URL = "https://api.azaion.com" # Base URL for the external API
|
cdef str API_URL = "https://api.azaion.com" # Base URL for the external API
|
||||||
cdef str QUEUE_CONFIG_FILENAME = "secured-config.json"
|
cdef str QUEUE_CONFIG_FILENAME = "secured-config.json"
|
||||||
cdef str AI_MODEL_FILE_BIG = "azaion.onnx.big"
|
|
||||||
cdef str AI_MODEL_FILE_SMALL = "azaion.onnx.small"
|
cdef str AI_ONNX_MODEL_FILE_BIG = "azaion.onnx.big"
|
||||||
|
cdef str AI_ONNX_MODEL_FILE_SMALL = "azaion.onnx.small"
|
||||||
|
|
||||||
|
cdef str AI_TENSOR_MODEL_FILE_BIG = "azaion.engine.big"
|
||||||
|
cdef str AI_TENSOR_MODEL_FILE_SMALL = "azaion.engine.small"
|
||||||
|
|
||||||
cdef log(str log_message, bytes client_id=None):
|
cdef log(str log_message, bytes client_id=None):
|
||||||
local_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
|
local_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
|
||||||
|
|||||||
@@ -5,4 +5,7 @@ cdef class HardwareInfo:
|
|||||||
cdef class HardwareService:
|
cdef class HardwareService:
|
||||||
cdef bint is_windows
|
cdef bint is_windows
|
||||||
cdef get_mac_address(self, interface=*)
|
cdef get_mac_address(self, interface=*)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
cdef has_nvidia_gpu()
|
||||||
cdef HardwareInfo get_hardware_info(self)
|
cdef HardwareInfo get_hardware_info(self)
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
@@ -42,6 +43,18 @@ cdef class HardwareService:
|
|||||||
return addr.address.replace('-', '')
|
return addr.address.replace('-', '')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
cdef has_nvidia_gpu():
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(['nvidia-smi']).decode()
|
||||||
|
match = re.search(r'CUDA Version:\s*([\d.]+)', output)
|
||||||
|
if match:
|
||||||
|
return float(match.group(1)) > 11
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
return False
|
||||||
|
|
||||||
cdef HardwareInfo get_hardware_info(self):
|
cdef HardwareInfo get_hardware_info(self):
|
||||||
if self.is_windows:
|
if self.is_windows:
|
||||||
os_command = (
|
os_command = (
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ from remote_command cimport RemoteCommand
|
|||||||
from annotation cimport Annotation, Detection
|
from annotation cimport Annotation, Detection
|
||||||
from ai_config cimport AIRecognitionConfig
|
from ai_config cimport AIRecognitionConfig
|
||||||
from api_client cimport ApiClient
|
from api_client cimport ApiClient
|
||||||
|
from inference_engine cimport InferenceEngine
|
||||||
|
|
||||||
cdef class Inference:
|
cdef class Inference:
|
||||||
cdef ApiClient api_client
|
cdef ApiClient api_client
|
||||||
cdef object session
|
cdef InferenceEngine engine
|
||||||
cdef object on_annotation
|
cdef object on_annotation
|
||||||
cdef Annotation _previous_annotation
|
cdef Annotation _previous_annotation
|
||||||
cdef AIRecognitionConfig ai_config
|
cdef AIRecognitionConfig ai_config
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
import json
|
import json
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
import subprocess
|
||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import onnxruntime as onnx
|
|
||||||
|
|
||||||
cimport constants
|
|
||||||
from remote_command cimport RemoteCommand
|
from remote_command cimport RemoteCommand
|
||||||
from annotation cimport Detection, Annotation
|
from annotation cimport Detection, Annotation
|
||||||
from ai_config cimport AIRecognitionConfig
|
from ai_config cimport AIRecognitionConfig
|
||||||
|
from inference_engine cimport OnnxEngine, TensorRTEngine
|
||||||
|
from hardware_service cimport HardwareService
|
||||||
|
|
||||||
cdef class Inference:
|
cdef class Inference:
|
||||||
def __init__(self, api_client, on_annotation):
|
def __init__(self, api_client, on_annotation):
|
||||||
self.api_client = api_client
|
self.api_client = api_client
|
||||||
self.on_annotation = on_annotation
|
self.on_annotation = on_annotation
|
||||||
self.stop_signal = False
|
self.stop_signal = False
|
||||||
self.session = None
|
|
||||||
self.model_input = None
|
self.model_input = None
|
||||||
self.model_width = 0
|
self.model_width = 0
|
||||||
self.model_height = 0
|
self.model_height = 0
|
||||||
|
self.engine = None
|
||||||
self.class_names = None
|
self.class_names = None
|
||||||
|
|
||||||
def init_ai(self):
|
def init_ai(self):
|
||||||
|
if self.engine is not None:
|
||||||
|
return
|
||||||
|
|
||||||
|
is_nvidia = HardwareService.has_nvidia_gpu()
|
||||||
|
if is_nvidia:
|
||||||
|
model_bytes = self.api_client.load_ai_model(is_tensor=True)
|
||||||
|
self.engine = TensorRTEngine(model_bytes, batch_size=4)
|
||||||
|
else:
|
||||||
model_bytes = self.api_client.load_ai_model()
|
model_bytes = self.api_client.load_ai_model()
|
||||||
self.session = onnx.InferenceSession(
|
self.engine = OnnxEngine(model_bytes, batch_size=4)
|
||||||
model_bytes, providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
|
|
||||||
)
|
self.model_height, self.model_width = self.engine.get_input_shape()
|
||||||
model_inputs = self.session.get_inputs()
|
self.class_names = self.engine.get_class_names()
|
||||||
self.model_input = model_inputs[0].name
|
|
||||||
input_shape = model_inputs[0].shape
|
|
||||||
self.model_width = input_shape[2]
|
|
||||||
self.model_height = input_shape[3]
|
|
||||||
print(f'AI detection model input: {self.model_input} ({self.model_width}, {self.model_height})')
|
|
||||||
model_meta = self.session.get_modelmeta()
|
|
||||||
print("Metadata:", model_meta.custom_metadata_map)
|
|
||||||
self.class_names = eval(model_meta.custom_metadata_map["names"])
|
|
||||||
|
|
||||||
cdef preprocess(self, frames):
|
cdef preprocess(self, frames):
|
||||||
blobs = [cv2.dnn.blobFromImage(frame,
|
blobs = [cv2.dnn.blobFromImage(frame,
|
||||||
@@ -47,12 +47,14 @@ cdef class Inference:
|
|||||||
return np.vstack(blobs)
|
return np.vstack(blobs)
|
||||||
|
|
||||||
cdef postprocess(self, output, ai_config):
|
cdef postprocess(self, output, ai_config):
|
||||||
|
print('enter postprocess')
|
||||||
cdef list[Detection] detections = []
|
cdef list[Detection] detections = []
|
||||||
cdef int ann_index
|
cdef int ann_index
|
||||||
cdef float x1, y1, x2, y2, conf, cx, cy, w, h
|
cdef float x1, y1, x2, y2, conf, cx, cy, w, h
|
||||||
cdef int class_id
|
cdef int class_id
|
||||||
cdef list[list[Detection]] results = []
|
cdef list[list[Detection]] results = []
|
||||||
|
print('start try: code')
|
||||||
|
try:
|
||||||
for ann_index in range(len(output[0])):
|
for ann_index in range(len(output[0])):
|
||||||
detections.clear()
|
detections.clear()
|
||||||
for det in output[0][ann_index]:
|
for det in output[0][ann_index]:
|
||||||
@@ -74,6 +76,8 @@ cdef class Inference:
|
|||||||
filtered_detections = self.remove_overlapping_detections(detections)
|
filtered_detections = self.remove_overlapping_detections(detections)
|
||||||
results.append(filtered_detections)
|
results.append(filtered_detections)
|
||||||
return results
|
return results
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"Failed to postprocess: {str(e)}")
|
||||||
|
|
||||||
cdef remove_overlapping_detections(self, list[Detection] detections):
|
cdef remove_overlapping_detections(self, list[Detection] detections):
|
||||||
cdef Detection det1, det2
|
cdef Detection det1, det2
|
||||||
@@ -121,7 +125,6 @@ cdef class Inference:
|
|||||||
raise Exception('ai recognition config is empty')
|
raise Exception('ai recognition config is empty')
|
||||||
|
|
||||||
self.stop_signal = False
|
self.stop_signal = False
|
||||||
if self.session is None:
|
|
||||||
self.init_ai()
|
self.init_ai()
|
||||||
|
|
||||||
print(ai_config.paths)
|
print(ai_config.paths)
|
||||||
@@ -160,7 +163,9 @@ cdef class Inference:
|
|||||||
|
|
||||||
if len(batch_frames) == ai_config.model_batch_size:
|
if len(batch_frames) == ai_config.model_batch_size:
|
||||||
input_blob = self.preprocess(batch_frames)
|
input_blob = self.preprocess(batch_frames)
|
||||||
outputs = self.session.run(None, {self.model_input: input_blob})
|
|
||||||
|
outputs = self.engine.run(input_blob)
|
||||||
|
|
||||||
list_detections = self.postprocess(outputs, ai_config)
|
list_detections = self.postprocess(outputs, ai_config)
|
||||||
for i in range(len(list_detections)):
|
for i in range(len(list_detections)):
|
||||||
detections = list_detections[i]
|
detections = list_detections[i]
|
||||||
@@ -189,7 +194,9 @@ cdef class Inference:
|
|||||||
timestamps.append(0)
|
timestamps.append(0)
|
||||||
|
|
||||||
input_blob = self.preprocess(frames)
|
input_blob = self.preprocess(frames)
|
||||||
outputs = self.session.run(None, {self.model_input: input_blob})
|
|
||||||
|
outputs = self.engine.run(input_blob)
|
||||||
|
|
||||||
list_detections = self.postprocess(outputs, ai_config)
|
list_detections = self.postprocess(outputs, ai_config)
|
||||||
for i in range(len(list_detections)):
|
for i in range(len(list_detections)):
|
||||||
detections = list_detections[i]
|
detections = list_detections[i]
|
||||||
@@ -199,6 +206,7 @@ cdef class Inference:
|
|||||||
print(annotation.to_str(self.class_names))
|
print(annotation.to_str(self.class_names))
|
||||||
self.on_annotation(cmd, annotation)
|
self.on_annotation(cmd, annotation)
|
||||||
|
|
||||||
|
|
||||||
cdef stop(self):
|
cdef stop(self):
|
||||||
self.stop_signal = True
|
self.stop_signal = True
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
from typing import List, Tuple
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
cdef class InferenceEngine:
|
||||||
|
cdef public int batch_size
|
||||||
|
cdef tuple get_input_shape(self)
|
||||||
|
cdef int get_batch_size(self)
|
||||||
|
cdef get_class_names(self)
|
||||||
|
cpdef run(self, input_data)
|
||||||
|
|
||||||
|
cdef class OnnxEngine(InferenceEngine):
|
||||||
|
cdef object session
|
||||||
|
cdef list model_inputs
|
||||||
|
cdef str input_name
|
||||||
|
cdef object input_shape
|
||||||
|
cdef object class_names
|
||||||
|
|
||||||
|
cdef class TensorRTEngine(InferenceEngine):
|
||||||
|
cdef object stream
|
||||||
|
cdef object context
|
||||||
|
cdef str input_name
|
||||||
|
cdef str output_name
|
||||||
|
cdef object d_input
|
||||||
|
cdef object d_output
|
||||||
|
cdef object input_shape
|
||||||
|
cdef object output_shape
|
||||||
|
cdef object h_output
|
||||||
|
cdef object class_names
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import json
|
||||||
|
import struct
|
||||||
|
from typing import List, Tuple
|
||||||
|
import numpy as np
|
||||||
|
import onnxruntime as onnx
|
||||||
|
import tensorrt as trt
|
||||||
|
import pycuda.driver as cuda
|
||||||
|
import pycuda.autoinit # required for automatically initialize CUDA, do not remove.
|
||||||
|
|
||||||
|
|
||||||
|
cdef class InferenceEngine:
|
||||||
|
def __init__(self, model_bytes: bytes, batch_size: int = 1, **kwargs):
|
||||||
|
self.batch_size = batch_size
|
||||||
|
|
||||||
|
cdef tuple get_input_shape(self):
|
||||||
|
raise NotImplementedError("Subclass must implement get_input_shape")
|
||||||
|
|
||||||
|
cdef int get_batch_size(self):
|
||||||
|
return self.batch_size
|
||||||
|
|
||||||
|
cpdef run(self, input_data):
|
||||||
|
raise NotImplementedError("Subclass must implement run")
|
||||||
|
|
||||||
|
cdef get_class_names(self):
|
||||||
|
raise NotImplementedError("Subclass must implement get_class_names")
|
||||||
|
|
||||||
|
|
||||||
|
cdef class OnnxEngine(InferenceEngine):
|
||||||
|
def __init__(self, model_bytes: bytes, batch_size: int = 1, **kwargs):
|
||||||
|
super().__init__(model_bytes, batch_size)
|
||||||
|
self.batch_size = batch_size
|
||||||
|
self.session = onnx.InferenceSession(model_bytes, providers=["CUDAExecutionProvider", "CPUExecutionProvider"])
|
||||||
|
self.model_inputs = self.session.get_inputs()
|
||||||
|
self.input_name = self.model_inputs[0].name
|
||||||
|
self.input_shape = self.model_inputs[0].shape
|
||||||
|
if self.input_shape[0] != -1:
|
||||||
|
self.batch_size = self.input_shape[0]
|
||||||
|
print(f'AI detection model input: {self.model_inputs} {self.input_shape}')
|
||||||
|
model_meta = self.session.get_modelmeta()
|
||||||
|
print("Metadata:", model_meta.custom_metadata_map)
|
||||||
|
self.class_names = eval(model_meta.custom_metadata_map["names"])
|
||||||
|
|
||||||
|
cdef tuple get_input_shape(self):
|
||||||
|
shape = self.input_shape
|
||||||
|
return shape[2], shape[3]
|
||||||
|
|
||||||
|
cdef int get_batch_size(self):
|
||||||
|
return self.batch_size
|
||||||
|
|
||||||
|
cdef get_class_names(self):
|
||||||
|
return self.class_names
|
||||||
|
|
||||||
|
cpdef run(self, input_data):
|
||||||
|
return self.session.run(None, {self.input_name: input_data})
|
||||||
|
|
||||||
|
|
||||||
|
cdef class TensorRTEngine(InferenceEngine):
|
||||||
|
def __init__(self, model_bytes: bytes, batch_size: int = 4, **kwargs):
|
||||||
|
super().__init__(model_bytes, batch_size)
|
||||||
|
self.batch_size = batch_size
|
||||||
|
print('Enter init TensorRT')
|
||||||
|
try:
|
||||||
|
logger = trt.Logger(trt.Logger.WARNING)
|
||||||
|
|
||||||
|
metadata_len = struct.unpack("<I", model_bytes[:4])[0]
|
||||||
|
try:
|
||||||
|
metadata = json.loads(model_bytes[4:4 + metadata_len])
|
||||||
|
print(f"Model metadata: {json.dumps(metadata, indent=2)}")
|
||||||
|
string_dict = metadata['names']
|
||||||
|
self.class_names = {int(k): v for k, v in string_dict.items()}
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
print(f"Failed to parse metadata")
|
||||||
|
return
|
||||||
|
engine_data = model_bytes[4 + metadata_len:]
|
||||||
|
|
||||||
|
|
||||||
|
runtime = trt.Runtime(logger)
|
||||||
|
engine = runtime.deserialize_cuda_engine(engine_data)
|
||||||
|
|
||||||
|
if engine is None:
|
||||||
|
raise RuntimeError(f"Failed to load TensorRT engine from bytes")
|
||||||
|
|
||||||
|
self.context = engine.create_execution_context()
|
||||||
|
# input
|
||||||
|
self.input_name = engine.get_tensor_name(0)
|
||||||
|
engine_input_shape = engine.get_tensor_shape(self.input_name)
|
||||||
|
if engine_input_shape[0] != -1:
|
||||||
|
self.batch_size = engine_input_shape[0]
|
||||||
|
|
||||||
|
self.input_shape = [
|
||||||
|
self.batch_size,
|
||||||
|
engine_input_shape[1], # Channels (usually fixed at 3 for RGB)
|
||||||
|
1280 if engine_input_shape[2] == -1 else engine_input_shape[2], # Height
|
||||||
|
1280 if engine_input_shape[3] == -1 else engine_input_shape[3] # Width
|
||||||
|
]
|
||||||
|
self.context.set_input_shape(self.input_name, self.input_shape)
|
||||||
|
input_size = trt.volume(self.input_shape) * np.dtype(np.float32).itemsize
|
||||||
|
self.d_input = cuda.mem_alloc(input_size)
|
||||||
|
|
||||||
|
# output
|
||||||
|
self.output_name = engine.get_tensor_name(1)
|
||||||
|
engine_output_shape = tuple(engine.get_tensor_shape(self.output_name))
|
||||||
|
self.output_shape = [
|
||||||
|
batch_size if self.input_shape[0] == -1 else self.input_shape[0],
|
||||||
|
300 if engine_output_shape[1] == -1 else engine_output_shape[1], # max detections number
|
||||||
|
6 if engine_output_shape[2] == -1 else engine_output_shape[2] # x1 y1 x2 y2 conf cls
|
||||||
|
]
|
||||||
|
self.h_output = cuda.pagelocked_empty(tuple(self.output_shape), dtype=np.float32)
|
||||||
|
self.d_output = cuda.mem_alloc(self.h_output.nbytes)
|
||||||
|
|
||||||
|
self.stream = cuda.Stream()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"Failed to initialize TensorRT engine: {str(e)}")
|
||||||
|
|
||||||
|
cdef tuple get_input_shape(self):
|
||||||
|
return self.input_shape[2], self.input_shape[3]
|
||||||
|
|
||||||
|
cdef int get_batch_size(self):
|
||||||
|
return self.batch_size
|
||||||
|
|
||||||
|
cdef get_class_names(self):
|
||||||
|
return self.class_names
|
||||||
|
|
||||||
|
cpdef run(self, input_data):
|
||||||
|
try:
|
||||||
|
cuda.memcpy_htod_async(self.d_input, input_data, self.stream)
|
||||||
|
self.context.set_tensor_address(self.input_name, int(self.d_input)) # input buffer
|
||||||
|
self.context.set_tensor_address(self.output_name, int(self.d_output)) # output buffer
|
||||||
|
|
||||||
|
self.context.execute_async_v3(stream_handle=self.stream.handle)
|
||||||
|
self.stream.synchronize()
|
||||||
|
|
||||||
|
# Fix: Remove the stream parameter from memcpy_dtoh
|
||||||
|
cuda.memcpy_dtoh(self.h_output, self.d_output)
|
||||||
|
output = self.h_output.reshape(self.output_shape)
|
||||||
|
return [output]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(f"Failed to run TensorRT inference: {str(e)}")
|
||||||
@@ -10,3 +10,5 @@ pyjwt
|
|||||||
zmq
|
zmq
|
||||||
requests
|
requests
|
||||||
pyyaml
|
pyyaml
|
||||||
|
pycuda
|
||||||
|
tensorrt
|
||||||
@@ -14,6 +14,7 @@ extensions = [
|
|||||||
Extension('user', ['user.pyx']),
|
Extension('user', ['user.pyx']),
|
||||||
Extension('api_client', ['api_client.pyx']),
|
Extension('api_client', ['api_client.pyx']),
|
||||||
Extension('ai_config', ['ai_config.pyx']),
|
Extension('ai_config', ['ai_config.pyx']),
|
||||||
|
Extension('inference_engine', ['inference_engine.pyx'], include_dirs=[np.get_include()]),
|
||||||
Extension('inference', ['inference.pyx'], include_dirs=[np.get_include()]),
|
Extension('inference', ['inference.pyx'], include_dirs=[np.get_include()]),
|
||||||
Extension('main', ['main.pyx']),
|
Extension('main', ['main.pyx']),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Azaion.Common\Azaion.Common.csproj" />
|
<ProjectReference Include="..\Azaion.Common\Azaion.Common.csproj" />
|
||||||
<ProjectReference Include="..\dummy\Azaion.Annotator\Azaion.Annotator.csproj" />
|
<ProjectReference Include="..\Azaion.Annotator\Azaion.Annotator.csproj" />
|
||||||
<ProjectReference Include="..\dummy\Azaion.Dataset\Azaion.Dataset.csproj" />
|
<ProjectReference Include="..\Azaion.Dataset\Azaion.Dataset.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -61,8 +61,8 @@
|
|||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="Build">
|
<Target Name="PostBuild" AfterTargets="Build">
|
||||||
<MakeDir Directories="$(TargetDir)dummy" />
|
<MakeDir Directories="$(TargetDir)dummy" />
|
||||||
<Move SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)dummy" />
|
<Copy SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)dummy" />
|
||||||
<Move SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)dummy" />
|
<Copy SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)dummy" />
|
||||||
<Exec Command="upload.cmd $(ConfigurationName) stage" />
|
<Exec Command="upload.cmd $(ConfigurationName) stage" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
BorderBrush="DimGray"
|
BorderBrush="DimGray"
|
||||||
BorderThickness="0,0,0,1"
|
BorderThickness="0,0,0,1"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Text=""
|
Text="admin@azaion.com"
|
||||||
/>
|
/>
|
||||||
<TextBlock Text="Пароль"
|
<TextBlock Text="Пароль"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
Width="300"
|
Width="300"
|
||||||
BorderThickness="0,0,0,1"
|
BorderThickness="0,0,0,1"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Password=""/>
|
Password="Az@1on1000Odm$n"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Button x:Name="LoginBtn"
|
<Button x:Name="LoginBtn"
|
||||||
Content="Вхід"
|
Content="Вхід"
|
||||||
|
|||||||
+19
-16
@@ -8,7 +8,8 @@
|
|||||||
},
|
},
|
||||||
"GpsDeniedClientConfig": {
|
"GpsDeniedClientConfig": {
|
||||||
"ZeroMqHost": "127.0.0.1",
|
"ZeroMqHost": "127.0.0.1",
|
||||||
"ZeroMqPort": 5227,
|
"ZeroMqPort": 5555,
|
||||||
|
"ZeroMqReceiverPort": 5556,
|
||||||
"RetryCount": 25,
|
"RetryCount": 25,
|
||||||
"TimeoutSeconds": 5
|
"TimeoutSeconds": 5
|
||||||
},
|
},
|
||||||
@@ -21,20 +22,22 @@
|
|||||||
},
|
},
|
||||||
"AnnotationConfig": {
|
"AnnotationConfig": {
|
||||||
"DetectionClasses": [
|
"DetectionClasses": [
|
||||||
{ "Id": 0, "Name": "Броньована техніка", "ShortName": "Броня" },
|
{ "Id": 0, "Name": "ArmorVehicle", "ShortName": "Броня", "Color": "#FF0000" },
|
||||||
{ "Id": 1, "Name": "Вантажівка", "ShortName": "Вантаж." },
|
{ "Id": 1, "Name": "Truck", "ShortName": "Вантаж.", "Color": "#00FF00" },
|
||||||
{ "Id": 2, "Name": "Машина легкова", "ShortName": "Машина" },
|
{ "Id": 2, "Name": "Vehicle", "ShortName": "Машина", "Color": "#0000FF" },
|
||||||
{ "Id": 3, "Name": "Артилерія", "ShortName": "Арта" },
|
{ "Id": 3, "Name": "Atillery", "ShortName": "Арта", "Color": "#FFFF00" },
|
||||||
{ "Id": 4, "Name": "Тінь від техніки", "ShortName": "Тінь" },
|
{ "Id": 4, "Name": "Shadow", "ShortName": "Тінь", "Color": "#FF00FF" },
|
||||||
{ "Id": 5, "Name": "Окопи", "ShortName": "Окопи" },
|
{ "Id": 5, "Name": "Trenches", "ShortName": "Окопи", "Color": "#00FFFF" },
|
||||||
{ "Id": 6, "Name": "Військовий", "ShortName": "Військов" },
|
{ "Id": 6, "Name": "MilitaryMan", "ShortName": "Військов", "Color": "#188021" },
|
||||||
{ "Id": 7, "Name": "Накати", "ShortName": "Накати" },
|
{ "Id": 7, "Name": "TyreTracks", "ShortName": "Накати", "Color": "#800000" },
|
||||||
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк.захист" },
|
{ "Id": 8, "Name": "AdditArmoredTank", "ShortName": "Танк.захист", "Color": "#008000" },
|
||||||
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" },
|
{ "Id": 9, "Name": "Smoke", "ShortName": "Дим", "Color": "#000080" },
|
||||||
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" },
|
{ "Id": 10, "Name": "Plane", "ShortName": "Літак", "Color": "#000080" },
|
||||||
{ "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" },
|
{ "Id": 11, "Name": "Moto", "ShortName": "Мото", "Color": "#808000" },
|
||||||
{ "Id": 12, "Name": "Маскування сіткою", "ShortName": "Сітка" },
|
{ "Id": 12, "Name": "CamouflageNnet", "ShortName": "Сітка", "Color": "#800080" },
|
||||||
{ "Id": 13, "Name": "Маскування гілками", "ShortName": "Гілки" }
|
{ "Id": 13, "Name": "CamouflageBranches", "ShortName": "Гілки", "Color": "#008080" },
|
||||||
|
{ "Id": 14, "Name": "Roof", "ShortName": "Дах", "Color": "#0050A0" },
|
||||||
|
{ "Id": 15, "Name": "Building", "ShortName": "Будівля", "Color": "#008080" }
|
||||||
],
|
],
|
||||||
"LastSelectedExplorerClass": null,
|
"LastSelectedExplorerClass": null,
|
||||||
"VideoFormats": [ ".mp4", ".mov", ".avi" ],
|
"VideoFormats": [ ".mp4", ".mov", ".avi" ],
|
||||||
@@ -52,7 +55,7 @@
|
|||||||
"TrackingProbabilityIncrease": 15.0,
|
"TrackingProbabilityIncrease": 15.0,
|
||||||
"TrackingIntersectionThreshold": 0.8,
|
"TrackingIntersectionThreshold": 0.8,
|
||||||
|
|
||||||
"ModelBatchSize": 2
|
"ModelBatchSize": 4
|
||||||
},
|
},
|
||||||
"ThumbnailConfig": { "Size": "240,135", "Border": 10 },
|
"ThumbnailConfig": { "Size": "240,135", "Border": 10 },
|
||||||
"MapConfig":
|
"MapConfig":
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
"ZeroMqHost": "127.0.0.1",
|
"ZeroMqHost": "127.0.0.1",
|
||||||
"ZeroMqPort": 5131,
|
"ZeroMqPort": 5131,
|
||||||
"RetryCount": 25,
|
"RetryCount": 25,
|
||||||
"TimeoutSeconds": 5,
|
"TimeoutSeconds": 5
|
||||||
"ResourcesFolder": "stage"
|
|
||||||
},
|
},
|
||||||
"GpsDeniedClientConfig": {
|
"GpsDeniedClientConfig": {
|
||||||
"ZeroMqHost": "127.0.0.1",
|
"ZeroMqHost": "127.0.0.1",
|
||||||
@@ -21,20 +20,22 @@
|
|||||||
},
|
},
|
||||||
"AnnotationConfig": {
|
"AnnotationConfig": {
|
||||||
"DetectionClasses": [
|
"DetectionClasses": [
|
||||||
{ "Id": 0, "Name": "Броньована техніка", "ShortName": "Броня" },
|
{ "Id": 0, "Name": "ArmorVehicle", "ShortName": "Броня", "Color": "#80FF0000" },
|
||||||
{ "Id": 1, "Name": "Вантажівка", "ShortName": "Вантаж." },
|
{ "Id": 1, "Name": "Truck", "ShortName": "Вантаж.", "Color": "#8000FF00" },
|
||||||
{ "Id": 2, "Name": "Машина легкова", "ShortName": "Машина" },
|
{ "Id": 2, "Name": "Vehicle", "ShortName": "Машина", "Color": "#800000FF" },
|
||||||
{ "Id": 3, "Name": "Артилерія", "ShortName": "Арта" },
|
{ "Id": 3, "Name": "Atillery", "ShortName": "Арта", "Color": "#80FFFF00" },
|
||||||
{ "Id": 4, "Name": "Тінь від техніки", "ShortName": "Тінь" },
|
{ "Id": 4, "Name": "Shadow", "ShortName": "Тінь", "Color": "#80FF00FF" },
|
||||||
{ "Id": 5, "Name": "Окопи", "ShortName": "Окопи" },
|
{ "Id": 5, "Name": "Trenches", "ShortName": "Окопи", "Color": "#8000FFFF" },
|
||||||
{ "Id": 6, "Name": "Військовий", "ShortName": "Військов" },
|
{ "Id": 6, "Name": "MilitaryMan", "ShortName": "Військов", "Color": "#80188021" },
|
||||||
{ "Id": 7, "Name": "Накати", "ShortName": "Накати" },
|
{ "Id": 7, "Name": "TyreTracks", "ShortName": "Накати", "Color": "#80800000" },
|
||||||
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк.захист" },
|
{ "Id": 8, "Name": "AdditArmoredTank", "ShortName": "Танк.захист", "Color": "#80008000" },
|
||||||
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" },
|
{ "Id": 9, "Name": "Smoke", "ShortName": "Дим", "Color": "#8080000080" },
|
||||||
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" },
|
{ "Id": 10, "Name": "Plane", "ShortName": "Літак", "Color": "#80000080" },
|
||||||
{ "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" },
|
{ "Id": 11, "Name": "Moto", "ShortName": "Мото", "Color": "#80808000" },
|
||||||
{ "Id": 12, "Name": "Маскування сіткою", "ShortName": "Сітка" },
|
{ "Id": 12, "Name": "CamouflageNnet", "ShortName": "Сітка", "Color": "#80800080" },
|
||||||
{ "Id": 13, "Name": "Маскування гілками", "ShortName": "Гілки" }
|
{ "Id": 13, "Name": "CamouflageBranches", "ShortName": "Гілки", "Color": "#80008080" },
|
||||||
|
{ "Id": 14, "Name": "Roof", "ShortName": "Дах", "Color": "#800050A0" },
|
||||||
|
{ "Id": 15, "Name": "Building", "ShortName": "Будівля", "Color": "#80008080" }
|
||||||
],
|
],
|
||||||
"LastSelectedExplorerClass": null,
|
"LastSelectedExplorerClass": null,
|
||||||
"VideoFormats": [ ".mp4", ".mov", ".avi" ],
|
"VideoFormats": [ ".mp4", ".mov", ".avi" ],
|
||||||
|
|||||||
+10
-3
@@ -21,7 +21,7 @@ move dist\Azaion.Dataset.dll dist\dummy\
|
|||||||
|
|
||||||
echo Build Cython app
|
echo Build Cython app
|
||||||
cd Azaion.Inference
|
cd Azaion.Inference
|
||||||
.\venv\Scripts\pyinstaller --onefile ^
|
.\venv\Scripts\pyinstaller --name=azaion-inference ^
|
||||||
--collect-all jwt ^
|
--collect-all jwt ^
|
||||||
--collect-all requests ^
|
--collect-all requests ^
|
||||||
--collect-all psutil ^
|
--collect-all psutil ^
|
||||||
@@ -30,6 +30,9 @@ cd Azaion.Inference
|
|||||||
--collect-all cryptography ^
|
--collect-all cryptography ^
|
||||||
--collect-all cv2 ^
|
--collect-all cv2 ^
|
||||||
--collect-all onnxruntime ^
|
--collect-all onnxruntime ^
|
||||||
|
--collect-all tensorrt ^
|
||||||
|
--collect-all pycuda ^
|
||||||
|
--collect-all re ^
|
||||||
--hidden-import constants ^
|
--hidden-import constants ^
|
||||||
--hidden-import annotation ^
|
--hidden-import annotation ^
|
||||||
--hidden-import credentials ^
|
--hidden-import credentials ^
|
||||||
@@ -41,6 +44,7 @@ cd Azaion.Inference
|
|||||||
--hidden-import hardware_service ^
|
--hidden-import hardware_service ^
|
||||||
--hidden-import remote_command ^
|
--hidden-import remote_command ^
|
||||||
--hidden-import ai_config ^
|
--hidden-import ai_config ^
|
||||||
|
--hidden-import inference_engine ^
|
||||||
--hidden-import inference ^
|
--hidden-import inference ^
|
||||||
--hidden-import remote_command_handler ^
|
--hidden-import remote_command_handler ^
|
||||||
start.py
|
start.py
|
||||||
@@ -51,7 +55,9 @@ cd..
|
|||||||
echo Download onnx model
|
echo Download onnx model
|
||||||
cd build
|
cd build
|
||||||
call cdn_manager.exe download models azaion.onnx.big
|
call cdn_manager.exe download models azaion.onnx.big
|
||||||
move azaion.onnx.big ..\dist\
|
call cdn_manager.exe download models azaion.engine.big
|
||||||
|
|
||||||
|
move azaion.* ..\dist\
|
||||||
cd..
|
cd..
|
||||||
|
|
||||||
echo Copy ico
|
echo Copy ico
|
||||||
@@ -64,8 +70,9 @@ copy %cudnn-folder%\* dist\*
|
|||||||
del dist\cudnn_adv64_9.dll
|
del dist\cudnn_adv64_9.dll
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
echo building installer...
|
echo building installer...
|
||||||
iscc build\installer.iss
|
iscc build\installer.iss
|
||||||
cd build\
|
cd build\
|
||||||
echo uploading installer...
|
echo uploading installer...
|
||||||
call .\cdn_manager.exe upload suite AzaionSuiteInstaller.exe ..\AzaionSuiteInstaller.exe
|
call cdn_manager.exe upload suite AzaionSuiteInstaller.exe ..\AzaionSuiteInstaller.exe
|
||||||
Reference in New Issue
Block a user