fix bug with annotation result gradient stops

add tensorrt engine
This commit is contained in:
Alex Bezdieniezhnykh
2025-04-02 00:29:21 +03:00
parent e0c88bd8fb
commit b21f8e320f
36 changed files with 544 additions and 206 deletions
+5 -16
View File
@@ -8,6 +8,7 @@
xmlns:controls1="clr-namespace:Azaion.Common.Controls;assembly=Azaion.Common"
xmlns:controls2="clr-namespace:Azaion.Annotator.Controls;assembly=Azaion.Common"
mc:Ignorable="d"
xmlns:local="clr-namespace:Azaion.Annotator"
Title="Azaion Annotator" Height="800" Width="1100"
WindowState="Maximized"
>
@@ -49,6 +50,8 @@
</Trigger>
</Style.Triggers>
</Style>
<local:GradientStyleSelector x:Key="GradientStyleSelector"/>
</Window.Resources>
<Grid Name="GlobalGrid"
@@ -232,7 +235,6 @@
Grid.Row="1"
Grid.RowSpan="4"
Background="Black"
RowBackground="#252525"
Foreground="White"
RowHeaderWidth="0"
Padding="2 0 0 0"
@@ -241,7 +243,8 @@
CellStyle="{DynamicResource DataGridCellStyle1}"
IsReadOnly="True"
CanUserResizeRows="False"
CanUserResizeColumns="False">
CanUserResizeColumns="False"
RowStyleSelector="{StaticResource GradientStyleSelector}">
<DataGrid.Columns>
<DataGridTextColumn
Width="60"
@@ -264,20 +267,6 @@
<Setter Property="Background" Value="#252525"></Setter>
</Style>
</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>
</DataGrid.Columns>
</DataGrid>
+47 -2
View File
@@ -328,7 +328,11 @@ public partial class Annotator
var existingResult = _formState.AnnotationResults.FirstOrDefault(x => x.Annotation.Time == time);
if (existingResult != null)
{
_logger.LogInformation($"remove annotation {existingResult.TimeStr} {existingResult.ClassName}!");
_formState.AnnotationResults.Remove(existingResult);
}
var dict = _formState.AnnotationResults
.Select((x, i) => new { x.Annotation.Time, Index = i })
@@ -339,7 +343,8 @@ public partial class Annotator
.Select(x => x.Value + 1)
.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()
@@ -565,6 +570,7 @@ public partial class Annotator
await _mediator.Publish(new AnnotatorControlEvent(PlaybackControlEnum.Play), ct);
}
}
AddAnnotation(annotation);
if (FollowAI)
@@ -574,7 +580,7 @@ public partial class Annotator
$"{_appConfig.AnnotationConfig.DetectionClassesDict[det.ClassNumber].Name}: " +
$"xy=({det.CenterX:F2},{det.CenterY:F2}), " +
$"size=({det.Width:F2}, {det.Height:F2}), " +
$"prob: {det.Probability*100:F0}%"));
$"conf: {det.Confidence*100:F0}%"));
Dispatcher.Invoke(() =>
{
@@ -618,3 +624,42 @@ public partial class Annotator
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;
}
}
+19 -11
View File
@@ -38,16 +38,19 @@ public partial class MapMatcher : UserControl
SatelliteMap.Position = new PointLatLng(48.295985271707664, 37.14477539062501);
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.Items[gpsFilesIndex] as MediaFileInfo;
var ann = _annotations.GetValueOrDefault(Path.GetFileNameWithoutExtension(media.Name));
GpsImageEditor.Background = new ImageBrush
{
var media = (GpsFiles.SelectedItem as MediaFileInfo)!;
var ann = _annotations.GetValueOrDefault(Path.GetFileNameWithoutExtension(media.Name));
GpsImageEditor.Background = new ImageBrush
{
ImageSource = await Path.Combine(_currentDir, ann.Name).OpenImage()
};
SatelliteMap.Position = new PointLatLng(ann.Lat, ann.Lon);
ImageSource = await Path.Combine(_currentDir, ann.Name).OpenImage()
};
if (ann.Lat != 0 && ann.Lon != 0)
SatelliteMap.Position = new PointLatLng(ann.Lat, ann.Lon);
}
private void GpsFilesContextOpening(object sender, ContextMenuEventArgs e)
@@ -104,8 +107,11 @@ public partial class MapMatcher : UserControl
_allMediaFiles = mediaFiles;
GpsFiles.ItemsSource = new ObservableCollection<MediaFileInfo>(_allMediaFiles);
var annotations = SetFromCsv(mediaFiles);
Cursor = Cursors.Wait;
await Task.Delay(TimeSpan.FromSeconds(10));
SetMarkers(annotations);
Cursor = Cursors.Arrow;
await OpenGpsLocation(0);
}
private Dictionary<string, Annotation> SetFromCsv(List<MediaFileInfo> mediaFiles)
@@ -117,7 +123,9 @@ public partial class MapMatcher : UserControl
}).ToDictionary(x => Path.GetFileNameWithoutExtension(x.OriginalMediaName));
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)
{
var csvRes = csvDict.GetValueOrDefault(ann.Key);
@@ -137,7 +145,7 @@ public partial class MapMatcher : UserControl
var firstAnnotation = annotations.FirstOrDefault();
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 circle = new CircleVisual(marker, System.Windows.Media.Brushes.Blue)
@@ -147,6 +155,6 @@ public partial class MapMatcher : UserControl
marker.Shape = circle;
SatelliteMap.Markers.Add(marker);
}
SatelliteMap.ZoomAndCenterMarkers(null);
}
}
+1 -1
View File
@@ -90,5 +90,5 @@ public class Constants
#endregion
public const string CSV_PATH = "D:\\matches.csv";
public const string CSV_PATH = "matches.csv";
}
+4 -4
View File
@@ -54,7 +54,7 @@ public class CanvasEditor : Canvas
_verticalLine.Fill = value.ColorBrush;
_horizontalLine.Stroke = value.ColorBrush;
_horizontalLine.Fill = value.ColorBrush;
_classNameHint.Text = value.Name;
_classNameHint.Text = value.ShortName;
_newAnnotationRect.Stroke = value.ColorBrush;
_newAnnotationRect.Fill = value.ColorBrush;
@@ -84,7 +84,7 @@ public class CanvasEditor : Canvas
};
_classNameHint = new TextBlock
{
Text = CurrentAnnClass?.Name ?? "asd",
Text = CurrentAnnClass?.ShortName ?? "",
Foreground = new SolidColorBrush(Colors.Black),
Cursor = Cursors.Arrow,
FontSize = 16,
@@ -313,14 +313,14 @@ public class CanvasEditor : Canvas
foreach (var detection in detections)
{
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);
}
}
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,
Height = canvasLabel.Height
+1 -1
View File
@@ -68,7 +68,7 @@
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Width="*" Header="Назва" Binding="{Binding Path=Name}" CanUserSort="False">
<DataGridTextColumn Width="*" Header="Назва" Binding="{Binding Path=ShortName}" CanUserSort="False">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#252525"/>
+7 -26
View File
@@ -1,52 +1,33 @@
using System.Windows.Media;
using Azaion.Common.Database;
using Azaion.Common.Extensions;
using Newtonsoft.Json;
namespace Azaion.Common.DTO;
public class AnnotationResult
{
public Annotation Annotation { get; set; }
public List<(Color Color, double Confidence)> Colors { get; private set; }
public string ImagePath { get; set; }
public string TimeStr { 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)
{
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}";
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
? string.Join(", ", detectionClasses.Select(x => allDetectionClasses[x].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,
Name = cls.Name,
Color = cls.Color,
ShortName = cls.ShortName,
PhotoMode = mode
}))
+2 -4
View File
@@ -1,5 +1,4 @@
using System.Windows.Media;
using Azaion.Common.Extensions;
using Newtonsoft.Json;
namespace Azaion.Common.DTO;
@@ -11,6 +10,8 @@ public class DetectionClass
public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!;
public Color Color { get; set; }
[JsonIgnore]
public string UIName
{
@@ -31,9 +32,6 @@ public class DetectionClass
[JsonIgnore]
public PhotoMode PhotoMode { get; set; }
[JsonIgnore]
public Color Color => Id.ToColor();
[JsonIgnore] //For UI
public int ClassNumber => Id + 1;
+8 -8
View File
@@ -26,22 +26,22 @@ public class CanvasLabel : Label
public double Y { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double? Probability { get; }
public double? Confidence { get; }
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;
Y = y;
Width = width;
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 ch = canvasSize.Height;
@@ -75,7 +75,7 @@ public class CanvasLabel : Label
Width = label.Width * realWidth;
Height = label.Height * ch;
}
Probability = probability;
Confidence = confidence;
}
}
@@ -189,12 +189,12 @@ public class YoloLabel : Label
public class Detection : YoloLabel
{
[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
public Detection(){}
public Detection(string annotationName, YoloLabel label, double? probability = null)
public Detection(string annotationName, YoloLabel label, double confidence = 1)
{
AnnotationName = annotationName;
ClassNumber = label.ClassNumber;
@@ -202,6 +202,6 @@ public class Detection : YoloLabel
CenterY = label.CenterY;
Height = label.Height;
Width = label.Width;
Probability = probability;
Confidence = confidence;
}
}
+5 -18
View File
@@ -4,25 +4,12 @@ namespace Azaion.Common.Extensions;
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;
var hex = index == -1
? "#40DDDDDD"
: $"#40{ColorValues[index]}";
var color =(Color)ColorConverter.ConvertFromString(hex);
color.A = (byte)(MIN_ALPHA + (int)Math.Round(confidence * (MAX_ALPHA - MIN_ALPHA)));
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 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();
process.StartInfo = new ProcessStartInfo
{
FileName = ClientPath
FileName = ClientPath,
//Arguments = $"-e {credentials.Email} -p {credentials.Password} -f {apiConfig.ResourcesFolder}",
//RedirectStandardOutput = true,
//RedirectStandardError = true,
@@ -14,9 +14,11 @@ public interface IHardwareService
public class HardwareService : IHardwareService
{
private const string WIN32_GET_HARDWARE_COMMAND =
"wmic OS get TotalVisibleMemorySize /Value && " +
"wmic CPU get Name /Value && " +
"wmic path Win32_VideoController get Name /Value";
"powershell -Command \"" +
"Get-CimInstance -ClassName Win32_Processor | Select-Object -ExpandProperty Name | Write-Output; " +
"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 =
"/bin/bash -c \"free -g | grep Mem: | awk '{print $2}' && " +
+15 -11
View File
@@ -77,11 +77,11 @@ public partial class DatasetExplorer
await DeleteAnnotations();
break;
case Key.Enter:
await EditAnnotation();
await EditAnnotation(ThumbnailsView.SelectedIndex);
break;
}
};
ThumbnailsView.MouseDoubleClick += async (_, _) => await EditAnnotation();
ThumbnailsView.MouseDoubleClick += async (_, _) => await EditAnnotation(ThumbnailsView.SelectedIndex);
ThumbnailsView.SelectionChanged += (_, _) =>
{
@@ -152,7 +152,7 @@ public partial class DatasetExplorer
.Select(gr => new
{
gr.Key,
_annotationConfig.DetectionClassesDict[gr.Key].Name,
_annotationConfig.DetectionClassesDict[gr.Key].ShortName,
_annotationConfig.DetectionClassesDict[gr.Key].Color,
ClassCount = gr.Value.Count
})
@@ -175,7 +175,7 @@ public partial class DatasetExplorer
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.LabelFontSize = 18;
}
@@ -204,16 +204,17 @@ public partial class DatasetExplorer
RefreshThumbnailsButtonItem.Visibility = Visibility.Visible;
}
private async Task EditAnnotation()
public async Task EditAnnotation(int index)
{
try
{
ThumbnailLoading = true;
if (ThumbnailsView.SelectedItem == null)
if (index == -1)
return;
CurrentAnnotation = (ThumbnailsView.SelectedItem as AnnotationThumbnail)!;
CurrentAnnotation = (ThumbnailsView.Items[index] as AnnotationThumbnail)!;
ThumbnailsView.SelectedIndex = index;
var ann = CurrentAnnotation.Annotation;
ExplorerEditor.Background = new ImageBrush
{
@@ -224,7 +225,6 @@ public partial class DatasetExplorer
var time = ann.Time;
ExplorerEditor.RemoveAllAnns();
ExplorerEditor.CreateDetections(time, ann.Detections, _annotationConfig.DetectionClasses, ExplorerEditor.RenderSize);
ThumbnailLoading = false;
}
catch (Exception e)
{
@@ -233,7 +233,11 @@ public partial class DatasetExplorer
}
finally
{
ThumbnailLoading = false;
_ = Task.Run(async () =>
{
await Task.Delay(100);
ThumbnailLoading = false;
});
}
}
@@ -260,7 +264,7 @@ public partial class DatasetExplorer
}
}
private async Task DeleteAnnotations()
public async Task DeleteAnnotations()
{
var tempSelected = ThumbnailsView.SelectedIndex;
var result = MessageBox.Show("Чи дійсно видалити аннотації?","Підтвердження видалення", MessageBoxButton.YesNo, MessageBoxImage.Question);
+19 -3
View File
@@ -1,4 +1,5 @@
using System.IO;
using System.Windows;
using System.Windows.Input;
using Azaion.Common.DTO;
using Azaion.Common.DTO.Queue;
@@ -22,7 +23,9 @@ public class DatasetExplorerEventHandler(
{ Key.Delete, PlaybackControlEnum.RemoveSelectedAnns },
{ Key.X, PlaybackControlEnum.RemoveAllAnns },
{ 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)
@@ -63,15 +66,28 @@ public class DatasetExplorerEventHandler(
var detections = datasetExplorer.ExplorerEditor.CurrentDetections
.Select(x => new Detection(a.Name, x.GetLabel(datasetExplorer.ExplorerEditor.RenderSize)))
.ToList();
var index = datasetExplorer.ThumbnailsView.SelectedIndex;
await annotationService.SaveAnnotation(a.OriginalMediaName, a.Time, detections, SourceEnum.Manual, token: cancellationToken);
datasetExplorer.SwitchTab(toEditor: false);
await datasetExplorer.EditAnnotation(index + 1);
break;
case PlaybackControlEnum.RemoveSelectedAnns:
datasetExplorer.ExplorerEditor.RemoveSelectedAnns();
if (datasetExplorer.ExplorerEditor.CurrentDetections.Any(x => x.IsSelected))
datasetExplorer.ExplorerEditor.RemoveSelectedAnns();
else
{
await datasetExplorer.DeleteAnnotations();
await datasetExplorer.EditAnnotation(datasetExplorer.ThumbnailsView.SelectedIndex);
}
break;
case PlaybackControlEnum.RemoveAllAnns:
datasetExplorer.ExplorerEditor.RemoveAllAnns();
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:
datasetExplorer.SwitchTab(toEditor: false);
break;
+1 -1
View File
@@ -72,5 +72,5 @@ In case of fbgemm.dll error (Windows specific):
<h3>Build exe</h3>
```
.\build.exe
.\build.cmd
```
+1 -1
View File
@@ -14,4 +14,4 @@ cdef class ApiClient:
cdef load_bytes(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=*)
+14 -4
View File
@@ -73,6 +73,7 @@ cdef class ApiClient:
cdef load_bytes(self, str filename, str folder=None):
folder = folder or self.credentials.folder
hardware_service = HardwareService()
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')
return data
cdef load_ai_model(self):
with open(<str>constants.AI_MODEL_FILE_BIG, 'rb') as binary_file:
encrypted_bytes_big = binary_file.read()
encrypted_bytes_small = self.load_bytes(constants.AI_MODEL_FILE_SMALL)
cdef load_ai_model(self, bint is_tensor=False):
if is_tensor:
big_file = <str> constants.AI_TENSOR_MODEL_FILE_BIG
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
key = Security.get_model_encryption_key()
+73
View File
@@ -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',
)
+5 -1
View File
@@ -1,4 +1,4 @@
pyinstaller --onefile ^
pyinstaller --name=azaion-inference ^
--collect-all pyyaml ^
--collect-all jwt ^
--collect-all requests ^
@@ -8,6 +8,9 @@ pyinstaller --onefile ^
--collect-all cryptography ^
--collect-all cv2 ^
--collect-all onnxruntime ^
--collect-all tensorrt ^
--collect-all pycuda ^
--collect-all re ^
--hidden-import constants ^
--hidden-import annotation ^
--hidden-import credentials ^
@@ -19,6 +22,7 @@ pyinstaller --onefile ^
--hidden-import hardware_service ^
--hidden-import remote_command ^
--hidden-import ai_config ^
--hidden-import inference_engine ^
--hidden-import inference ^
--hidden-import remote_command_handler ^
start.py
+7 -2
View File
@@ -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 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
+6 -2
View File
@@ -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 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):
local_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
+3
View File
@@ -5,4 +5,7 @@ cdef class HardwareInfo:
cdef class HardwareService:
cdef bint is_windows
cdef get_mac_address(self, interface=*)
@staticmethod
cdef has_nvidia_gpu()
cdef HardwareInfo get_hardware_info(self)
+13
View File
@@ -1,3 +1,4 @@
import re
import subprocess
import psutil
@@ -42,6 +43,18 @@ cdef class HardwareService:
return addr.address.replace('-', '')
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):
if self.is_windows:
os_command = (
+2 -1
View File
@@ -2,10 +2,11 @@ from remote_command cimport RemoteCommand
from annotation cimport Annotation, Detection
from ai_config cimport AIRecognitionConfig
from api_client cimport ApiClient
from inference_engine cimport InferenceEngine
cdef class Inference:
cdef ApiClient api_client
cdef object session
cdef InferenceEngine engine
cdef object on_annotation
cdef Annotation _previous_annotation
cdef AIRecognitionConfig ai_config
+50 -42
View File
@@ -1,40 +1,40 @@
import json
import mimetypes
import subprocess
import cv2
import numpy as np
import onnxruntime as onnx
cimport constants
from remote_command cimport RemoteCommand
from annotation cimport Detection, Annotation
from ai_config cimport AIRecognitionConfig
from inference_engine cimport OnnxEngine, TensorRTEngine
from hardware_service cimport HardwareService
cdef class Inference:
def __init__(self, api_client, on_annotation):
self.api_client = api_client
self.on_annotation = on_annotation
self.stop_signal = False
self.session = None
self.model_input = None
self.model_width = 0
self.model_height = 0
self.engine = None
self.class_names = None
def init_ai(self):
model_bytes = self.api_client.load_ai_model()
self.session = onnx.InferenceSession(
model_bytes, providers=["CUDAExecutionProvider", "CPUExecutionProvider"]
)
model_inputs = self.session.get_inputs()
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"])
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()
self.engine = OnnxEngine(model_bytes, batch_size=4)
self.model_height, self.model_width = self.engine.get_input_shape()
self.class_names = self.engine.get_class_names()
cdef preprocess(self, frames):
blobs = [cv2.dnn.blobFromImage(frame,
@@ -47,33 +47,37 @@ cdef class Inference:
return np.vstack(blobs)
cdef postprocess(self, output, ai_config):
print('enter postprocess')
cdef list[Detection] detections = []
cdef int ann_index
cdef float x1, y1, x2, y2, conf, cx, cy, w, h
cdef int class_id
cdef list[list[Detection]] results = []
print('start try: code')
try:
for ann_index in range(len(output[0])):
detections.clear()
for det in output[0][ann_index]:
if det[4] == 0: # if confidence is 0 then valid points are over.
break
x1 = det[0] / self.model_width
y1 = det[1] / self.model_height
x2 = det[2] / self.model_width
y2 = det[3] / self.model_height
conf = round(det[4], 2)
class_id = int(det[5])
for ann_index in range(len(output[0])):
detections.clear()
for det in output[0][ann_index]:
if det[4] == 0: # if confidence is 0 then valid points are over.
break
x1 = det[0] / self.model_width
y1 = det[1] / self.model_height
x2 = det[2] / self.model_width
y2 = det[3] / self.model_height
conf = round(det[4], 2)
class_id = int(det[5])
x = (x1 + x2) / 2
y = (y1 + y2) / 2
w = x2 - x1
h = y2 - y1
if conf >= ai_config.probability_threshold:
detections.append(Detection(x, y, w, h, class_id, conf))
filtered_detections = self.remove_overlapping_detections(detections)
results.append(filtered_detections)
return results
x = (x1 + x2) / 2
y = (y1 + y2) / 2
w = x2 - x1
h = y2 - y1
if conf >= ai_config.probability_threshold:
detections.append(Detection(x, y, w, h, class_id, conf))
filtered_detections = self.remove_overlapping_detections(detections)
results.append(filtered_detections)
return results
except Exception as e:
raise RuntimeError(f"Failed to postprocess: {str(e)}")
cdef remove_overlapping_detections(self, list[Detection] detections):
cdef Detection det1, det2
@@ -121,8 +125,7 @@ cdef class Inference:
raise Exception('ai recognition config is empty')
self.stop_signal = False
if self.session is None:
self.init_ai()
self.init_ai()
print(ai_config.paths)
for m in ai_config.paths:
@@ -160,7 +163,9 @@ cdef class Inference:
if len(batch_frames) == ai_config.model_batch_size:
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)
for i in range(len(list_detections)):
detections = list_detections[i]
@@ -189,7 +194,9 @@ cdef class Inference:
timestamps.append(0)
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)
for i in range(len(list_detections)):
detections = list_detections[i]
@@ -199,6 +206,7 @@ cdef class Inference:
print(annotation.to_str(self.class_names))
self.on_annotation(cmd, annotation)
cdef stop(self):
self.stop_signal = True
+29
View File
@@ -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
+140
View File
@@ -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)}")
+3 -1
View File
@@ -9,4 +9,6 @@ msgpack
pyjwt
zmq
requests
pyyaml
pyyaml
pycuda
tensorrt
+1
View File
@@ -14,6 +14,7 @@ extensions = [
Extension('user', ['user.pyx']),
Extension('api_client', ['api_client.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('main', ['main.pyx']),
]
+4 -4
View File
@@ -32,8 +32,8 @@
<ItemGroup>
<ProjectReference Include="..\Azaion.Common\Azaion.Common.csproj" />
<ProjectReference Include="..\dummy\Azaion.Annotator\Azaion.Annotator.csproj" />
<ProjectReference Include="..\dummy\Azaion.Dataset\Azaion.Dataset.csproj" />
<ProjectReference Include="..\Azaion.Annotator\Azaion.Annotator.csproj" />
<ProjectReference Include="..\Azaion.Dataset\Azaion.Dataset.csproj" />
</ItemGroup>
<ItemGroup>
@@ -61,8 +61,8 @@
<Target Name="PostBuild" AfterTargets="Build">
<MakeDir Directories="$(TargetDir)dummy" />
<Move SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)dummy" />
<Move SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)dummy" />
<Copy SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)dummy" />
<Copy SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)dummy" />
<Exec Command="upload.cmd $(ConfigurationName) stage" />
</Target>
+2 -2
View File
@@ -74,7 +74,7 @@
BorderBrush="DimGray"
BorderThickness="0,0,0,1"
HorizontalAlignment="Left"
Text=""
Text="admin@azaion.com"
/>
<TextBlock Text="Пароль"
Grid.Row="2"
@@ -89,7 +89,7 @@
Width="300"
BorderThickness="0,0,0,1"
HorizontalAlignment="Left"
Password=""/>
Password="Az@1on1000Odm$n"/>
</Grid>
<Button x:Name="LoginBtn"
Content="Вхід"
+19 -16
View File
@@ -8,7 +8,8 @@
},
"GpsDeniedClientConfig": {
"ZeroMqHost": "127.0.0.1",
"ZeroMqPort": 5227,
"ZeroMqPort": 5555,
"ZeroMqReceiverPort": 5556,
"RetryCount": 25,
"TimeoutSeconds": 5
},
@@ -21,20 +22,22 @@
},
"AnnotationConfig": {
"DetectionClasses": [
{ "Id": 0, "Name": "Броньована техніка", "ShortName": "Броня" },
{ "Id": 1, "Name": "Вантажівка", "ShortName": "Вантаж." },
{ "Id": 2, "Name": "Машина легкова", "ShortName": "Машина" },
{ "Id": 3, "Name": "Артилерія", "ShortName": "Арта" },
{ "Id": 4, "Name": "Тінь від техніки", "ShortName": "Тінь" },
{ "Id": 5, "Name": "Окопи", "ShortName": "Окопи" },
{ "Id": 6, "Name": "Військовий", "ShortName": "Військов" },
{ "Id": 7, "Name": "Накати", "ShortName": "Накати" },
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк.захист" },
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" },
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" },
{ "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" },
{ "Id": 12, "Name": "Маскування сіткою", "ShortName": "Сітка" },
{ "Id": 13, "Name": "Маскування гілками", "ShortName": "Гілки" }
{ "Id": 0, "Name": "ArmorVehicle", "ShortName": "Броня", "Color": "#FF0000" },
{ "Id": 1, "Name": "Truck", "ShortName": "Вантаж.", "Color": "#00FF00" },
{ "Id": 2, "Name": "Vehicle", "ShortName": "Машина", "Color": "#0000FF" },
{ "Id": 3, "Name": "Atillery", "ShortName": "Арта", "Color": "#FFFF00" },
{ "Id": 4, "Name": "Shadow", "ShortName": "Тінь", "Color": "#FF00FF" },
{ "Id": 5, "Name": "Trenches", "ShortName": "Окопи", "Color": "#00FFFF" },
{ "Id": 6, "Name": "MilitaryMan", "ShortName": "Військов", "Color": "#188021" },
{ "Id": 7, "Name": "TyreTracks", "ShortName": "Накати", "Color": "#800000" },
{ "Id": 8, "Name": "AdditArmoredTank", "ShortName": "Танк.захист", "Color": "#008000" },
{ "Id": 9, "Name": "Smoke", "ShortName": "Дим", "Color": "#000080" },
{ "Id": 10, "Name": "Plane", "ShortName": "Літак", "Color": "#000080" },
{ "Id": 11, "Name": "Moto", "ShortName": "Мото", "Color": "#808000" },
{ "Id": 12, "Name": "CamouflageNnet", "ShortName": "Сітка", "Color": "#800080" },
{ "Id": 13, "Name": "CamouflageBranches", "ShortName": "Гілки", "Color": "#008080" },
{ "Id": 14, "Name": "Roof", "ShortName": "Дах", "Color": "#0050A0" },
{ "Id": 15, "Name": "Building", "ShortName": "Будівля", "Color": "#008080" }
],
"LastSelectedExplorerClass": null,
"VideoFormats": [ ".mp4", ".mov", ".avi" ],
@@ -52,7 +55,7 @@
"TrackingProbabilityIncrease": 15.0,
"TrackingIntersectionThreshold": 0.8,
"ModelBatchSize": 2
"ModelBatchSize": 4
},
"ThumbnailConfig": { "Size": "240,135", "Border": 10 },
"MapConfig":
+17 -16
View File
@@ -3,8 +3,7 @@
"ZeroMqHost": "127.0.0.1",
"ZeroMqPort": 5131,
"RetryCount": 25,
"TimeoutSeconds": 5,
"ResourcesFolder": "stage"
"TimeoutSeconds": 5
},
"GpsDeniedClientConfig": {
"ZeroMqHost": "127.0.0.1",
@@ -21,20 +20,22 @@
},
"AnnotationConfig": {
"DetectionClasses": [
{ "Id": 0, "Name": "Броньована техніка", "ShortName": "Броня" },
{ "Id": 1, "Name": "Вантажівка", "ShortName": "Вантаж." },
{ "Id": 2, "Name": "Машина легкова", "ShortName": "Машина" },
{ "Id": 3, "Name": "Артилерія", "ShortName": "Арта" },
{ "Id": 4, "Name": "Тінь від техніки", "ShortName": "Тінь" },
{ "Id": 5, "Name": "Окопи", "ShortName": "Окопи" },
{ "Id": 6, "Name": "Військовий", "ShortName": "Військов" },
{ "Id": 7, "Name": "Накати", "ShortName": "Накати" },
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк.захист" },
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" },
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" },
{ "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" },
{ "Id": 12, "Name": "Маскування сіткою", "ShortName": "Сітка" },
{ "Id": 13, "Name": "Маскування гілками", "ShortName": "Гілки" }
{ "Id": 0, "Name": "ArmorVehicle", "ShortName": "Броня", "Color": "#80FF0000" },
{ "Id": 1, "Name": "Truck", "ShortName": "Вантаж.", "Color": "#8000FF00" },
{ "Id": 2, "Name": "Vehicle", "ShortName": "Машина", "Color": "#800000FF" },
{ "Id": 3, "Name": "Atillery", "ShortName": "Арта", "Color": "#80FFFF00" },
{ "Id": 4, "Name": "Shadow", "ShortName": "Тінь", "Color": "#80FF00FF" },
{ "Id": 5, "Name": "Trenches", "ShortName": "Окопи", "Color": "#8000FFFF" },
{ "Id": 6, "Name": "MilitaryMan", "ShortName": "Військов", "Color": "#80188021" },
{ "Id": 7, "Name": "TyreTracks", "ShortName": "Накати", "Color": "#80800000" },
{ "Id": 8, "Name": "AdditArmoredTank", "ShortName": "Танк.захист", "Color": "#80008000" },
{ "Id": 9, "Name": "Smoke", "ShortName": "Дим", "Color": "#8080000080" },
{ "Id": 10, "Name": "Plane", "ShortName": "Літак", "Color": "#80000080" },
{ "Id": 11, "Name": "Moto", "ShortName": "Мото", "Color": "#80808000" },
{ "Id": 12, "Name": "CamouflageNnet", "ShortName": "Сітка", "Color": "#80800080" },
{ "Id": 13, "Name": "CamouflageBranches", "ShortName": "Гілки", "Color": "#80008080" },
{ "Id": 14, "Name": "Roof", "ShortName": "Дах", "Color": "#800050A0" },
{ "Id": 15, "Name": "Building", "ShortName": "Будівля", "Color": "#80008080" }
],
"LastSelectedExplorerClass": null,
"VideoFormats": [ ".mp4", ".mov", ".avi" ],
+10 -3
View File
@@ -21,7 +21,7 @@ move dist\Azaion.Dataset.dll dist\dummy\
echo Build Cython app
cd Azaion.Inference
.\venv\Scripts\pyinstaller --onefile ^
.\venv\Scripts\pyinstaller --name=azaion-inference ^
--collect-all jwt ^
--collect-all requests ^
--collect-all psutil ^
@@ -30,6 +30,9 @@ cd Azaion.Inference
--collect-all cryptography ^
--collect-all cv2 ^
--collect-all onnxruntime ^
--collect-all tensorrt ^
--collect-all pycuda ^
--collect-all re ^
--hidden-import constants ^
--hidden-import annotation ^
--hidden-import credentials ^
@@ -41,6 +44,7 @@ cd Azaion.Inference
--hidden-import hardware_service ^
--hidden-import remote_command ^
--hidden-import ai_config ^
--hidden-import inference_engine ^
--hidden-import inference ^
--hidden-import remote_command_handler ^
start.py
@@ -51,7 +55,9 @@ cd..
echo Download onnx model
cd build
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..
echo Copy ico
@@ -64,8 +70,9 @@ copy %cudnn-folder%\* dist\*
del dist\cudnn_adv64_9.dll
echo building installer...
iscc build\installer.iss
cd build\
echo uploading installer...
call .\cdn_manager.exe upload suite AzaionSuiteInstaller.exe ..\AzaionSuiteInstaller.exe
call cdn_manager.exe upload suite AzaionSuiteInstaller.exe ..\AzaionSuiteInstaller.exe