fix switcher between modes in DatasetExplorer.xaml

This commit is contained in:
Alex Bezdieniezhnykh
2025-03-02 21:32:31 +02:00
parent 227d01ba5e
commit d93da15528
15 changed files with 141 additions and 55 deletions
+2 -2
View File
@@ -49,8 +49,8 @@ public partial class Annotator
public bool FollowAI = false; public bool FollowAI = false;
public bool IsInferenceNow = false; public bool IsInferenceNow = false;
private readonly TimeSpan _thresholdBefore = TimeSpan.FromMilliseconds(100); private readonly TimeSpan _thresholdBefore = TimeSpan.FromMilliseconds(50);
private readonly TimeSpan _thresholdAfter = TimeSpan.FromMilliseconds(300); private readonly TimeSpan _thresholdAfter = TimeSpan.FromMilliseconds(150);
private static readonly Guid SaveConfigTaskId = Guid.NewGuid(); private static readonly Guid SaveConfigTaskId = Guid.NewGuid();
public ObservableCollection<MediaFileInfo> AllMediaFiles { get; set; } = new(); public ObservableCollection<MediaFileInfo> AllMediaFiles { get; set; } = new();
+86 -10
View File
@@ -82,26 +82,102 @@
Grid.Row="1" Grid.Row="1"
Orientation="Horizontal" Orientation="Horizontal"
HorizontalAlignment="Center" HorizontalAlignment="Center"
Margin="0,5,0,5"> Margin="0,2,0,2">
<RadioButton x:Name="NormalModeRadioButton" <RadioButton x:Name="NormalModeRadioButton"
Tag="0" Tag="0"
Content="Звичайний"
GroupName="Mode" GroupName="Mode"
Checked="ModeRadioButton_Checked" Checked="ModeRadioButton_Checked"
IsChecked="True" IsChecked="{Binding IsChecked}"
Style="{StaticResource ButtonRadioButtonStyle}"/> Style="{StaticResource ButtonRadioButtonStyle}">
<StackPanel Orientation="Horizontal">
<Image Height="16" Width="16">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V640 H640 V0 H0 Z">
<GeometryDrawing Brush="LightGray" Geometry="m256,105.5c-83.9,0-152.2,68.3-152.2,152.2 0,83.9 68.3,152.2 152.2,152.2 83.9,0 152.2-68.3
152.2-152.2 0-84-68.3-152.2-152.2-152.2zm0,263.5c-61.4,0-111.4-50-111.4-111.4 0-61.4 50-111.4 111.4-111.4 61.4,0 111.4,50 111.4,111.4
0,61.4-50,111.4-111.4,111.4z" />
<GeometryDrawing Brush="LightGray" Geometry="m256,74.8c11.3,0 20.4-9.1 20.4-20.4v-23c0-11.3-9.1-20.4-20.4-20.4-11.3,0-20.4,9.1-20.4,20.4v23c2.84217e-14,11.3 9.1,20.4 20.4,20.4z" />
<GeometryDrawing Brush="LightGray" Geometry="m256,437.2c-11.3,0-20.4,9.1-20.4,20.4v22.9c0,11.3 9.1,20.4 20.4,20.4 11.3,0 20.4-9.1 20.4-20.4v-22.9c0-11.2-9.1-20.4-20.4-20.4z" />
<GeometryDrawing Brush="LightGray" Geometry="m480.6,235.6h-23c-11.3,0-20.4,9.1-20.4,20.4 0,11.3 9.1,20.4 20.4,20.4h23c11.3,0 20.4-9.1 20.4-20.4 0-11.3-9.1-20.4-20.4-20.4z" />
<GeometryDrawing Brush="LightGray" Geometry="m54.4,235.6h-23c-11.3,0-20.4,9.1-20.4,20.4 0,11.3 9.1,20.4 20.4,20.4h22.9c11.3,0 20.4-9.1 20.4-20.4 0.1-11.3-9.1-20.4-20.3-20.4z" />
<GeometryDrawing Brush="LightGray" Geometry="M400.4,82.8L384.1,99c-8,8-8,20.9,0,28.9s20.9,8,28.9,0l16.2-16.2c8-8,8-20.9,0-28.9S408.3,74.8,400.4,82.8z" />
<GeometryDrawing Brush="LightGray" Geometry="m99,384.1l-16.2,16.2c-8,8-8,20.9 0,28.9 8,8 20.9,8 28.9,0l16.2-16.2c8-8 8-20.9 0-28.9s-20.9-7.9-28.9,0z" />
<GeometryDrawing Brush="LightGray" Geometry="m413,384.1c-8-8-20.9-8-28.9,0-8,8-8,20.9 0,28.9l16.2,16.2c8,8 20.9,8 28.9,0 8-8 8-20.9 0-28.9l-16.2-16.2z" />
<GeometryDrawing Brush="LightGray" Geometry="m99,127.9c8,8 20.9,8 28.9,0 8-8 8-20.9 0-28.9l-16.2-16.2c-8-8-20.9-8-28.9,0-8,8-8,20.9 0,28.9l16.2,16.2z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock Text="Норма"
Padding="7"
/>
</StackPanel>
</RadioButton>
<RadioButton x:Name="EveningModeRadioButton" <RadioButton x:Name="EveningModeRadioButton"
Tag="20" Tag="20"
Content="Зима"
GroupName="Mode" GroupName="Mode"
Checked="ModeRadioButton_Checked" Margin="10,0,0,0" Checked="ModeRadioButton_Checked" Margin="3,0,0,0"
Style="{StaticResource ButtonRadioButtonStyle}"/> Style="{StaticResource ButtonRadioButtonStyle}">
<StackPanel Orientation="Horizontal">
<Image Height="16" Width="16">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V640 H640 V0 H0 Z">
<GeometryDrawing Brush="LightGray" Geometry="m444.8,256l50.2-50.2c8-8 8-20.9 0-28.9-8-8-20.9-8-28.9,0l-58.7,58.7h-85c-1.3-4.2-3-8.3-5-12.1l60.1-60.1h83c11.3,
0 20.4-9.1 20.4-20.4 0-11.3-9.1-20.4-20.4-20.4h-71v-71c0-11.3-9.1-20.4-20.4-20.4s-20.4,9.1-20.4,20.4v83l-60.1,60.1c-3.8-2-7.9-3.7-12.1-5v-85l58.7-58.7c8-8 8-20.9
0-28.9-8-8-20.9-8-28.9,0l-50.3,50.1-50.2-50.2c-8-8-20.9-8-28.9,0-8,8-8,20.9 0,28.9l58.7,58.7v85c-4.2,1.3-8.3,
3-12.1,5l-60.1-60.1v-83c0-11.3-9.1-20.4-20.4-20.4-11.3,0-20.4,9.1-20.4,20.4v71h-71c-11.3,0-20.4,9.1-20.4,20.4 0,11.3 9.1,20.4 20.4,
20.4h83l60.1,60.1c-2,3.8-3.7,7.9-5,12.1h-85l-58.7-58.7c-8-8-20.9-8-28.9,0-8,8-8,20.9 0,28.9l50.1,50.3-50.2,50.2c-8,8-8,20.9 0,28.9
8,8 20.9,8 28.9,0l58.7-58.7h85c1.3,4.2 3,8.3 5,12.1l-60.1,60.1h-83c-11.3,0-20.4,9.1-20.4,20.4 0,11.3 9.1,20.4 20.4,20.4h71v71c0,11.3
9.1,20.4 20.4,20.4 11.3,0 20.4-9.1 20.4-20.4v-83l60.1-60.1c3.8,2 7.9,3.7 12.1,5v85l-58.7,58.7c-8,8-8,20.9 0,28.9 8,8 20.9,8 28.9,0l50.2-50.2
50.2,50.2c8,8 20.9,8 28.9,0 8-8 8-20.9 0-28.9l-58.7-58.7v-85c4.2-1.3 8.3-3 12.1-5l60.1,60.1v83c0,11.3 9.1,20.4 20.4,20.4s20.4-9.1 20.4-20.4v-71h71c11.3,0
20.4-9.1 20.4-20.4 0-11.3-9.1-20.4-20.4-20.4h-83l-60.1-60.1c2-3.8 3.7-7.9 5-12.1h85l58.7,58.7c8,8 20.9,8 28.9,0 8-8 8-20.9
0-28.9l-50-50.2zm-217.3,0c0-15.7 12.8-28.5 28.5-28.5s28.5,12.8 28.5,28.5-12.8,28.5-28.5,28.5-28.5-12.8-28.5-28.5z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock Text="Зима"
Padding="7"
/>
</StackPanel>
</RadioButton>
<RadioButton x:Name="NightModeRadioButton" <RadioButton x:Name="NightModeRadioButton"
Tag="40" Tag="40"
Content="Ніч"
GroupName="Mode" GroupName="Mode"
Checked="ModeRadioButton_Checked" Margin="10,0,0,0" Checked="ModeRadioButton_Checked" Margin="3,0,0,0"
Style="{StaticResource ButtonRadioButtonStyle}"/> Style="{StaticResource ButtonRadioButtonStyle}"
>
<StackPanel Orientation="Horizontal">
<Image Height="16" Width="16">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V640 H640 V0 H0 Z">
<GeometryDrawing Brush="LightGray" Geometry="m500,113.1c-2.4-7.5-8.9-13-16.8-14.1l-55.2-7.9-24.6-48.9c-3.5-7-10.7-11.4-18.5-11.4-7.8,0-15,4.4-18.5,11.4l-24.6,
48.9-55.2,7.9c-7.8,1.1-14.3,6.6-16.8,14.1-2.4,7.5-0.3,15.8 5.4,21.3l39.7,37.9-9.4,53.4c-1.4,7.7 1.8,15.6 8.1,20.2 6.3,4.7 14.7,5.3 21.7,1.7l49.5-25.5
49.5,25.5c3,1.5 6.2,2.3 9.5,2.3 4.3,0 8.6-1.4 12.2-4 6.3-4.6 9.5-12.5 8.1-20.2l-9.4-53.4 39.7-37.9c5.9-5.5 8-13.8 5.6-21.3zm-81.6,36.9c-5,4.8-7.3,
11.7-6.1,18.5l4.1,23.3-22-11.3c-5.9-3-13-3-18.9,0l-22,11.3 4.1-23.3c1.2-6.8-1.1-13.7-6.1-18.5l-16.9-16.2 23.8-3.4c6.7-1 12.5-5.1 15.5-11.2l11-21.9
11,21.9c3,6 8.8,10.2 15.5,11.2l23.8,3.4-16.8,16.2z" />
<GeometryDrawing Brush="LightGray" Geometry="m442,361c-14.9,3.4-30.3,5.1-45.7,5.1-113.8,0-206.4-92.6-206.4-206.3 0-41.8 12.4-82 35.9-116.3
4.8-7 4.8-16.3 0-23.4-4.8-7.1-13.4-10.5-21.8-8.6-54,12.2-103,42.7-138,86-35.4,43.8-55,99.2-55,155.7 0,66.2 25.8,128.4 72.6,175.2 46.8,46.8
109.1,72.6 175.3,72.6 81.9,0 158.4-40.4 204.8-108.1 4.8-7 4.8-16.3 0-23.4-4.8-7-13.4-10.4-21.7-8.5zm-183.1,98.5c-113.8,0-206.4-92.6-206.4-206.3
0-78.2 45.3-149.1 112.8-183.8-11.2,28.6-17,59.1-17, 90.4 0,66.2 25.8,128.4 72.6,175.2 46.7,46.7 108.8,72.5 174.9,72.6-37.3,33.1-85.8,51.9-136.9,51.9z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
<TextBlock Text="Ніч"
Padding="7"
/>
</StackPanel>
</RadioButton>
</StackPanel> </StackPanel>
</Grid> </Grid>
</UserControl> </UserControl>
@@ -13,6 +13,7 @@ public class DetectionClassChangedEventArgs(DetectionClass detectionClass, int c
public partial class DetectionClasses public partial class DetectionClasses
{ {
public event EventHandler<DetectionClassChangedEventArgs>? DetectionClassChanged; public event EventHandler<DetectionClassChangedEventArgs>? DetectionClassChanged;
public bool IsChecked = true;
public DetectionClasses() public DetectionClasses()
{ {
+1 -1
View File
@@ -26,7 +26,7 @@ public class DetectionControl : Border
{ {
_grid.Background = value.ColorBrush; _grid.Background = value.ColorBrush;
_probabilityLabel.Background = value.ColorBrush; _probabilityLabel.Background = value.ColorBrush;
_classNameLabel.Text = value.Name; _classNameLabel.Text = value.UIName;
_detectionClass = value; _detectionClass = value;
} }
} }
+1 -1
View File
@@ -37,7 +37,7 @@ public class DetectionClass
public int ClassNumber => Id + 1; public int ClassNumber => Id + 1;
[JsonIgnore] [JsonIgnore]
public int YoloId => (int)PhotoMode + Id; public int YoloId => Id == -1 ? Id : (int)PhotoMode + Id;
[JsonIgnore] [JsonIgnore]
public SolidColorBrush ColorBrush => new(Color); public SolidColorBrush ColorBrush => new(Color);
@@ -28,7 +28,7 @@ public class PythonResourceLoader : IResourceLoader, IAuthProvider
public PythonResourceLoader(PythonConfig config) public PythonResourceLoader(PythonConfig config)
{ {
//StartPython(); StartPython();
_dealer.Options.Identity = Encoding.UTF8.GetBytes(_clientId.ToString("N")); _dealer.Options.Identity = Encoding.UTF8.GetBytes(_clientId.ToString("N"));
_dealer.Connect($"tcp://{config.ZeroMqHost}:{config.ZeroMqPort}"); _dealer.Connect($"tcp://{config.ZeroMqHost}:{config.ZeroMqPort}");
} }
+1 -1
View File
@@ -57,7 +57,7 @@
<RowDefinition Height="32"></RowDefinition> <RowDefinition Height="32"></RowDefinition>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="200" /> <ColumnDefinition Width="250" />
<ColumnDefinition Width="4"/> <ColumnDefinition Width="4"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
+8 -6
View File
@@ -22,7 +22,7 @@ public partial class DatasetExplorer
private readonly AnnotationConfig _annotationConfig; private readonly AnnotationConfig _annotationConfig;
private readonly DirectoriesConfig _directoriesConfig; private readonly DirectoriesConfig _directoriesConfig;
private readonly Dictionary<int, List<Annotation>> _annotationsDict; private readonly Dictionary<int, Dictionary<string, Annotation>> _annotationsDict;
private readonly CancellationTokenSource _cts = new(); private readonly CancellationTokenSource _cts = new();
public List<DetectionClass> AllDetectionClasses { get; set; } public List<DetectionClass> AllDetectionClasses { get; set; }
@@ -61,7 +61,7 @@ public partial class DatasetExplorer
var photoModes = Enum.GetValues(typeof(PhotoMode)).Cast<PhotoMode>().ToList(); var photoModes = Enum.GetValues(typeof(PhotoMode)).Cast<PhotoMode>().ToList();
_annotationsDict = _annotationConfig.DetectionClasses.SelectMany(cls => photoModes.Select(mode => (int)mode + cls.Id)) _annotationsDict = _annotationConfig.DetectionClasses.SelectMany(cls => photoModes.Select(mode => (int)mode + cls.Id))
.ToDictionary(x => x, _ => new List<Annotation>()); .ToDictionary(x => x, _ => new Dictionary<string, Annotation>());
_annotationsDict.Add(-1, []); _annotationsDict.Add(-1, []);
AnnotationsClasses = annotationConfig.Value.DetectionClasses; AnnotationsClasses = annotationConfig.Value.DetectionClasses;
@@ -141,8 +141,8 @@ public partial class DatasetExplorer
public void AddAnnotationToDict(Annotation annotation) public void AddAnnotationToDict(Annotation annotation)
{ {
foreach (var c in annotation.Classes) foreach (var c in annotation.Classes)
_annotationsDict[c].Add(annotation); _annotationsDict[c][annotation.Name] = annotation;
_annotationsDict[-1].Add(annotation); _annotationsDict[-1][annotation.Name] = annotation;
} }
private async Task LoadClassDistribution() private async Task LoadClassDistribution()
@@ -277,9 +277,11 @@ public partial class DatasetExplorer
private async Task ReloadThumbnails() private async Task ReloadThumbnails()
{ {
SelectedAnnotations.Clear(); SelectedAnnotations.Clear();
foreach (var ann in _annotationsDict[ExplorerEditor.CurrentAnnClass.Id]) SelectedAnnotationDict.Clear();
var annotations = _annotationsDict[ExplorerEditor.CurrentAnnClass.YoloId];
foreach (var ann in annotations.OrderByDescending(x => x.Value.CreatedDate))
{ {
var annThumb = new AnnotationThumbnail(ann); var annThumb = new AnnotationThumbnail(ann.Value);
SelectedAnnotations.Add(annThumb); SelectedAnnotations.Add(annThumb);
SelectedAnnotationDict.Add(annThumb.Annotation.Name, annThumb); SelectedAnnotationDict.Add(annThumb.Annotation.Name, annThumb);
} }
@@ -92,12 +92,15 @@ public class DatasetExplorerEventHandler(
//TODO: For editing existing need to handle updates //TODO: For editing existing need to handle updates
datasetExplorer.AddAnnotationToDict(annotation); datasetExplorer.AddAnnotationToDict(annotation);
if (annotation.Classes.Contains(selectedClass)) if (annotation.Classes.Contains(selectedClass) || selectedClass == -1)
{ {
var annThumb = new AnnotationThumbnail(annotation); var annThumb = new AnnotationThumbnail(annotation);
datasetExplorer.SelectedAnnotations.Add(annThumb); if (!datasetExplorer.SelectedAnnotationDict.ContainsKey(annThumb.Annotation.Name))
{
datasetExplorer.SelectedAnnotations.Insert(0, annThumb);
datasetExplorer.SelectedAnnotationDict.Add(annThumb.Annotation.Name, annThumb); datasetExplorer.SelectedAnnotationDict.Add(annThumb.Annotation.Name, annThumb);
} }
}
await Task.CompletedTask; await Task.CompletedTask;
} }
+1
View File
@@ -119,3 +119,4 @@ cdef class ApiClient:
key = Security.get_model_encryption_key() key = Security.get_model_encryption_key()
model_bytes = Security.decrypt_to(encrypted_model_bytes, key) model_bytes = Security.decrypt_to(encrypted_model_bytes, key)
return model_bytes
+4 -4
View File
@@ -18,13 +18,13 @@ cdef class Inference:
cdef bint is_video(self, str filepath) cdef bint is_video(self, str filepath)
cdef run_inference(self, RemoteCommand cmd) cdef run_inference(self, RemoteCommand cmd)
cdef _process_video(self, RemoteCommand cmd, str video_name) cdef _process_video(self, RemoteCommand cmd, AIRecognitionConfig ai_config, str video_name)
cdef _process_images(self, RemoteCommand cmd, list[str] image_paths) cdef _process_images(self, RemoteCommand cmd, AIRecognitionConfig ai_config, list[str] image_paths)
cdef stop(self) cdef stop(self)
cdef preprocess(self, frames) cdef preprocess(self, frames)
cdef remove_overlapping_detections(self, list[Detection] detections) cdef remove_overlapping_detections(self, list[Detection] detections)
cdef postprocess(self, output) cdef postprocess(self, output, ai_config)
cdef split_list_extend(self, lst, chunk_size) cdef split_list_extend(self, lst, chunk_size)
cdef bint is_valid_annotation(self, Annotation annotation) cdef bint is_valid_annotation(self, Annotation annotation, AIRecognitionConfig ai_config)
+23 -19
View File
@@ -20,7 +20,6 @@ cdef class Inference:
self.model_width = 0 self.model_width = 0
self.model_height = 0 self.model_height = 0
self.class_names = None self.class_names = None
self.ai_config = AIRecognitionConfig(4, 2, 0.25, 0.15, 15, 0.8, b'', [])
def init_ai(self): def init_ai(self):
model_bytes = self.api_client.load_ai_model() model_bytes = self.api_client.load_ai_model()
@@ -47,7 +46,7 @@ cdef class Inference:
for frame in frames] for frame in frames]
return np.vstack(blobs) return np.vstack(blobs)
cdef postprocess(self, output): cdef postprocess(self, output, ai_config):
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
@@ -70,6 +69,7 @@ cdef class Inference:
y = (y1 + y2) / 2 y = (y1 + y2) / 2
w = x2 - x1 w = x2 - x1
h = y2 - y1 h = y2 - y1
if conf >= ai_config.probability_threshold:
detections.append(Detection(x, y, w, h, class_id, conf)) detections.append(Detection(x, y, w, h, class_id, conf))
filtered_detections = self.remove_overlapping_detections(detections) filtered_detections = self.remove_overlapping_detections(detections)
results.append(filtered_detections) results.append(filtered_detections)
@@ -116,30 +116,32 @@ cdef class Inference:
cdef run_inference(self, RemoteCommand cmd): cdef run_inference(self, RemoteCommand cmd):
cdef list[str] videos = [] cdef list[str] videos = []
cdef list[str] images = [] cdef list[str] images = []
cdef AIRecognitionConfig ai_config = AIRecognitionConfig.from_msgpack(cmd.data)
if ai_config is None:
raise Exception('ai recognition config is empty')
self.ai_config = AIRecognitionConfig.from_msgpack(cmd.data)
self.stop_signal = False self.stop_signal = False
if self.session is None: if self.session is None:
self.init_ai() self.init_ai()
for m in self.ai_config.paths: print(ai_config.paths)
for m in ai_config.paths:
if self.is_video(m): if self.is_video(m):
videos.append(m) videos.append(m)
else: else:
images.append(m) images.append(m)
# images first, it's faster # images first, it's faster
if len(images) > 0: if len(images) > 0:
for chunk in self.split_list_extend(images, constants.MODEL_BATCH_SIZE): for chunk in self.split_list_extend(images, constants.MODEL_BATCH_SIZE):
print(f'run inference on {" ".join(chunk)}...') print(f'run inference on {" ".join(chunk)}...')
self._process_images(cmd, chunk) self._process_images(cmd, ai_config, chunk)
if len(videos) > 0: if len(videos) > 0:
for v in videos: for v in videos:
print(f'run inference on {v}...') print(f'run inference on {v}...')
self._process_video(cmd, v) self._process_video(cmd, ai_config, v)
cdef _process_video(self, RemoteCommand cmd, str video_name): cdef _process_video(self, RemoteCommand cmd, AIRecognitionConfig ai_config, str video_name):
cdef int frame_count = 0 cdef int frame_count = 0
cdef list batch_frames = [] cdef list batch_frames = []
cdef list[int] batch_timestamps = [] cdef list[int] batch_timestamps = []
@@ -152,30 +154,32 @@ cdef class Inference:
break break
frame_count += 1 frame_count += 1
if frame_count % self.ai_config.frame_period_recognition == 0: if frame_count % ai_config.frame_period_recognition == 0:
batch_frames.append(frame) batch_frames.append(frame)
batch_timestamps.append(int(v_input.get(cv2.CAP_PROP_POS_MSEC))) batch_timestamps.append(int(v_input.get(cv2.CAP_PROP_POS_MSEC)))
if len(batch_frames) == constants.MODEL_BATCH_SIZE: if len(batch_frames) == constants.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.session.run(None, {self.model_input: input_blob})
list_detections = self.postprocess(outputs) 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]
annotation = Annotation(video_name, batch_timestamps[i], detections) annotation = Annotation(video_name, batch_timestamps[i], detections)
if self.is_valid_annotation(annotation): if self.is_valid_annotation(annotation, ai_config):
_, image = cv2.imencode('.jpg', frame) _, image = cv2.imencode('.jpg', batch_frames[i])
annotation.image = image.tobytes() annotation.image = image.tobytes()
self._previous_annotation = annotation
print(annotation.to_str(self.class_names)) print(annotation.to_str(self.class_names))
self.on_annotation(cmd, annotation) self.on_annotation(cmd, annotation)
self._previous_annotation = annotation
batch_frames.clear() batch_frames.clear()
batch_timestamps.clear() batch_timestamps.clear()
v_input.release() v_input.release()
cdef _process_images(self, RemoteCommand cmd, list[str] image_paths): cdef _process_images(self, RemoteCommand cmd, AIRecognitionConfig ai_config, list[str] image_paths):
cdef list frames = [] cdef list frames = []
cdef list timestamps = [] cdef list timestamps = []
self._previous_annotation = None self._previous_annotation = None
@@ -186,7 +190,7 @@ cdef class Inference:
input_blob = self.preprocess(frames) input_blob = self.preprocess(frames)
outputs = self.session.run(None, {self.model_input: input_blob}) outputs = self.session.run(None, {self.model_input: input_blob})
list_detections = self.postprocess(outputs) 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]
annotation = Annotation(image_paths[i], timestamps[i], detections) annotation = Annotation(image_paths[i], timestamps[i], detections)
@@ -198,7 +202,7 @@ cdef class Inference:
cdef stop(self): cdef stop(self):
self.stop_signal = True self.stop_signal = True
cdef bint is_valid_annotation(self, Annotation annotation): cdef bint is_valid_annotation(self, Annotation annotation, AIRecognitionConfig ai_config):
# No detections, invalid # No detections, invalid
if not annotation.detections: if not annotation.detections:
return False return False
@@ -208,7 +212,7 @@ cdef class Inference:
return True return True
# Enough time has passed since last annotation # Enough time has passed since last annotation
if annotation.time >= self._previous_annotation.time + <long>(self.ai_config.frame_recognition_seconds * 1000): if annotation.time >= self._previous_annotation.time + <long>(ai_config.frame_recognition_seconds * 1000):
return True return True
# More objects detected than before # More objects detected than before
@@ -236,11 +240,11 @@ cdef class Inference:
closest_det = prev_det closest_det = prev_det
# Check if beyond tracking distance # Check if beyond tracking distance
if min_distance_sq > self.ai_config.tracking_distance_confidence: if min_distance_sq > ai_config.tracking_distance_confidence:
return True return True
# Check probability increase # Check probability increase
if current_det.confidence >= closest_det.confidence + self.ai_config.tracking_probability_increase: if current_det.confidence >= closest_det.confidence + ai_config.tracking_probability_increase:
return True return True
return False return False
-2
View File
@@ -4,8 +4,6 @@ from PyInstaller.utils.hooks import collect_all
datas = [] datas = []
binaries = [] binaries = []
hiddenimports = ['constants', 'annotation', 'credentials', 'file_data', 'user', 'security', 'secure_model', 'api_client', 'hardware_service', 'remote_command', 'ai_config', 'inference', 'remote_command_handler'] hiddenimports = ['constants', 'annotation', 'credentials', 'file_data', 'user', 'security', 'secure_model', 'api_client', 'hardware_service', 'remote_command', 'ai_config', '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') tmp_ret = collect_all('jwt')
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
tmp_ret = collect_all('requests') tmp_ret = collect_all('requests')
+2 -2
View File
@@ -51,8 +51,8 @@ public partial class App
private readonly List<string> _encryptedResources = private readonly List<string> _encryptedResources =
[ [
// "Azaion.Annotator", "Azaion.Annotator",
// "Azaion.Dataset" "Azaion.Dataset"
]; ];
private static PythonConfig ReadPythonConfig() private static PythonConfig ReadPythonConfig()
+3 -2
View File
@@ -1,5 +1,6 @@
@echo off @echo off
cd %~dp0..
echo Build .net app echo Build .net app
dotnet build -c Release dotnet build -c Release
@@ -46,8 +47,8 @@ move dist\start.exe ..\dist\azaion-inference.exe
copy config.yaml ..\dist copy config.yaml ..\dist
echo Download onnx model echo Download onnx model
cd build cd ..\build
call onnx_download.exe call onnx_downloader.exe
move azaion.onnx.big ..\dist\ move azaion.onnx.big ..\dist\
cd .. cd ..