From b6b6751c3780682303f9fa1efb408bd8ea23c48e Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Tue, 2 Sep 2025 13:59:23 +0300 Subject: [PATCH 1/4] fix loader bug with _CACHED_HW_INFO put tile size to name and set it dynamically for AI recognition --- Azaion.Annotator/Annotator.xaml.cs | 6 ++- Azaion.Annotator/AnnotatorEventHandler.cs | 2 +- .../Extensions/RectangleFExtensions.cs | 8 ---- .../Extensions/SynchronizeInvokeExtensions.cs | 14 ------- Azaion.Common/Constants.cs | 6 +-- Azaion.Common/Controls/CanvasEditor.cs | 4 +- Azaion.Common/Database/Annotation.cs | 10 ++--- Azaion.Common/Extensions/SizeExtensions.cs | 2 +- .../Services/Inference/InferenceService.cs | 30 ++++++-------- Azaion.Common/Services/TileProcessor.cs | 14 ++----- Azaion.Inference/ai_config.pxd | 2 + Azaion.Inference/ai_config.pyx | 16 +++++--- Azaion.Inference/inference.pxd | 4 +- Azaion.Inference/inference.pyx | 41 ++++++++----------- Azaion.Inference/main_inference.pyx | 2 +- Azaion.Loader/build_loader.cmd | 4 ++ Azaion.Loader/hardware_service.pxd | 2 + Azaion.Loader/hardware_service.pyx | 6 ++- Azaion.Test/TileProcessorTest.cs | 14 +++---- 19 files changed, 83 insertions(+), 104 deletions(-) delete mode 100644 Azaion.Annotator/Extensions/RectangleFExtensions.cs delete mode 100644 Azaion.Annotator/Extensions/SynchronizeInvokeExtensions.cs diff --git a/Azaion.Annotator/Annotator.xaml.cs b/Azaion.Annotator/Annotator.xaml.cs index 9e4c0c9..afdb69c 100644 --- a/Azaion.Annotator/Annotator.xaml.cs +++ b/Azaion.Annotator/Annotator.xaml.cs @@ -504,11 +504,13 @@ public partial class Annotator if (files.Count == 0) return; - await _inferenceService.RunInference(files, DetectionCancellationSource.Token); + //TODO: Get Tile Size from UI based on height setup + var tileSize = 550; + await _inferenceService.RunInference(files, tileSize, DetectionCancellationSource.Token); LvFiles.Items.Refresh(); _isInferenceNow = false; - StatusHelp.Text = "Розпізнавання зваершено"; + StatusHelp.Text = "Розпізнавання завершено"; AIDetectBtn.IsEnabled = true; } diff --git a/Azaion.Annotator/AnnotatorEventHandler.cs b/Azaion.Annotator/AnnotatorEventHandler.cs index 5a0c4ec..2dd6e57 100644 --- a/Azaion.Annotator/AnnotatorEventHandler.cs +++ b/Azaion.Annotator/AnnotatorEventHandler.cs @@ -327,7 +327,7 @@ public class AnnotatorEventHandler( foreach (var res in results) { var time = TimeSpan.Zero; - var annotationName = $"{formState.MediaName}{Constants.SPLIT_SUFFIX}{res.Tile.Left:0000}_{res.Tile.Top:0000}!".ToTimeName(time); + var annotationName = $"{formState.MediaName}{Constants.SPLIT_SUFFIX}{res.Tile.Width}{res.Tile.Left:0000}_{res.Tile.Top:0000}!".ToTimeName(time); var tileImgPath = Path.Combine(dirConfig.Value.ImagesDirectory, $"{annotationName}{Constants.JPG_EXT}"); var bitmap = new CroppedBitmap(source, new Int32Rect((int)res.Tile.Left, (int)res.Tile.Top, (int)res.Tile.Width, (int)res.Tile.Height)); diff --git a/Azaion.Annotator/Extensions/RectangleFExtensions.cs b/Azaion.Annotator/Extensions/RectangleFExtensions.cs deleted file mode 100644 index 68e95ef..0000000 --- a/Azaion.Annotator/Extensions/RectangleFExtensions.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Drawing; - -namespace Azaion.Annotator.Extensions; - -public static class RectangleFExtensions -{ - public static double Area(this RectangleF rectangle) => rectangle.Width * rectangle.Height; -} \ No newline at end of file diff --git a/Azaion.Annotator/Extensions/SynchronizeInvokeExtensions.cs b/Azaion.Annotator/Extensions/SynchronizeInvokeExtensions.cs deleted file mode 100644 index a9937c8..0000000 --- a/Azaion.Annotator/Extensions/SynchronizeInvokeExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel; - -namespace Azaion.Annotator; - -public static class SynchronizeInvokeExtensions -{ - public static void InvokeEx(this T t, Action action) where T : ISynchronizeInvoke - { - if (t.InvokeRequired) - t.Invoke(action, [t]); - else - action(t); - } -} \ No newline at end of file diff --git a/Azaion.Common/Constants.cs b/Azaion.Common/Constants.cs index fe26b29..1f71d25 100644 --- a/Azaion.Common/Constants.cs +++ b/Azaion.Common/Constants.cs @@ -15,9 +15,9 @@ public static class Constants public const string LOADER_CONFIG_PATH = "loaderconfig.json"; public const string DEFAULT_API_URL = "https://api.azaion.com"; public const string AZAION_SUITE_EXE = "Azaion.Suite.exe"; - - public const int AI_TILE_SIZE = 1280; - + + public const int AI_TILE_SIZE_DEFAULT = 1280; + #region ExternalClientsConfig private const string DEFAULT_ZMQ_LOADER_HOST = "127.0.0.1"; diff --git a/Azaion.Common/Controls/CanvasEditor.cs b/Azaion.Common/Controls/CanvasEditor.cs index 2a2f11b..3a50017 100644 --- a/Azaion.Common/Controls/CanvasEditor.cs +++ b/Azaion.Common/Controls/CanvasEditor.cs @@ -482,8 +482,8 @@ public class CanvasEditor : Canvas canvasLabel = new CanvasLabel(detection, RenderSize, mediaSize, detection.Confidence); else { - canvasLabel = new CanvasLabel(detection, new Size(Constants.AI_TILE_SIZE, Constants.AI_TILE_SIZE), null, detection.Confidence) - .ReframeFromSmall(annotation.SplitTile!); + canvasLabel = new CanvasLabel(detection, annotation.SplitTile!.Size, null, detection.Confidence) + .ReframeFromSmall(annotation.SplitTile); //From CurrentMediaSize to Render Size var yoloLabel = new YoloLabel(canvasLabel, mediaSize); diff --git a/Azaion.Common/Database/Annotation.cs b/Azaion.Common/Database/Annotation.cs index 9927d1c..172ab04 100644 --- a/Azaion.Common/Database/Annotation.cs +++ b/Azaion.Common/Database/Annotation.cs @@ -59,13 +59,13 @@ public class Annotation return _splitTile; var startCoordIndex = Name.IndexOf(Constants.SPLIT_SUFFIX, StringComparison.Ordinal) + Constants.SPLIT_SUFFIX.Length; - var coordsStr = Name.Substring(startCoordIndex, 9).Split('_'); + var coordsStr = Name.Substring(startCoordIndex, 14).Split('_'); _splitTile = new CanvasLabel { - Left = double.Parse(coordsStr[0]), - Top = double.Parse(coordsStr[1]), - Width = Constants.AI_TILE_SIZE, - Height = Constants.AI_TILE_SIZE + Left = double.Parse(coordsStr[1]), + Top = double.Parse(coordsStr[2]), + Width = double.Parse(coordsStr[0]), + Height = double.Parse(coordsStr[0]) }; return _splitTile; } diff --git a/Azaion.Common/Extensions/SizeExtensions.cs b/Azaion.Common/Extensions/SizeExtensions.cs index c8e62b4..8c6a260 100644 --- a/Azaion.Common/Extensions/SizeExtensions.cs +++ b/Azaion.Common/Extensions/SizeExtensions.cs @@ -6,5 +6,5 @@ public static class SizeExtensions { public static bool FitSizeForAI(this Size size) => // Allow to be up to FullHD to save as 1280*1280 - size.Width <= Constants.AI_TILE_SIZE * 1.5 && size.Height <= Constants.AI_TILE_SIZE * 1.5; + size.Width <= Constants.AI_TILE_SIZE_DEFAULT * 1.5 && size.Height <= Constants.AI_TILE_SIZE_DEFAULT * 1.5; } \ No newline at end of file diff --git a/Azaion.Common/Services/Inference/InferenceService.cs b/Azaion.Common/Services/Inference/InferenceService.cs index d94ae4d..7a816b1 100644 --- a/Azaion.Common/Services/Inference/InferenceService.cs +++ b/Azaion.Common/Services/Inference/InferenceService.cs @@ -7,50 +7,44 @@ namespace Azaion.Common.Services.Inference; public interface IInferenceService { - Task RunInference(List mediaPaths, CancellationToken ct = default); + Task RunInference(List mediaPaths, int tileSize, CancellationToken ct = default); CancellationTokenSource InferenceCancelTokenSource { get; set; } void StopInference(); } // SHOULD BE ONLY ONE INSTANCE OF InferenceService. Do not add ANY NotificationHandler to it! // _inferenceCancelTokenSource should be created only once. -public class InferenceService : IInferenceService +public class InferenceService( + IInferenceClient client, + IAzaionApi azaionApi, + IOptions aiConfigOptions) : IInferenceService { - private readonly IInferenceClient _client; - private readonly IAzaionApi _azaionApi; - private readonly IOptions _aiConfigOptions; public CancellationTokenSource InferenceCancelTokenSource { get; set; } = new(); public CancellationTokenSource CheckAIAvailabilityTokenSource { get; set; } = new(); - public InferenceService(IInferenceClient client, IAzaionApi azaionApi, IOptions aiConfigOptions) - { - _client = client; - _azaionApi = azaionApi; - _aiConfigOptions = aiConfigOptions; - } - public async Task CheckAIAvailabilityStatus() { CheckAIAvailabilityTokenSource = new CancellationTokenSource(); while (!CheckAIAvailabilityTokenSource.IsCancellationRequested) { - _client.Send(RemoteCommand.Create(CommandType.AIAvailabilityCheck)); + client.Send(RemoteCommand.Create(CommandType.AIAvailabilityCheck)); await Task.Delay(10000, CheckAIAvailabilityTokenSource.Token); } } - public async Task RunInference(List mediaPaths, CancellationToken ct = default) + public async Task RunInference(List mediaPaths, int tileSize, CancellationToken ct = default) { InferenceCancelTokenSource = new CancellationTokenSource(); - _client.Send(RemoteCommand.Create(CommandType.Login, _azaionApi.Credentials)); + client.Send(RemoteCommand.Create(CommandType.Login, azaionApi.Credentials)); - var aiConfig = _aiConfigOptions.Value; + var aiConfig = aiConfigOptions.Value; aiConfig.Paths = mediaPaths; - _client.Send(RemoteCommand.Create(CommandType.Inference, aiConfig)); + aiConfig.TileSize = tileSize; + client.Send(RemoteCommand.Create(CommandType.Inference, aiConfig)); using var combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ct, InferenceCancelTokenSource.Token); await combinedTokenSource.Token.AsTask(); } - public void StopInference() => _client.Stop(); + public void StopInference() => client.Stop(); } \ No newline at end of file diff --git a/Azaion.Common/Services/TileProcessor.cs b/Azaion.Common/Services/TileProcessor.cs index 71084ec..bd23383 100644 --- a/Azaion.Common/Services/TileProcessor.cs +++ b/Azaion.Common/Services/TileProcessor.cs @@ -4,16 +4,10 @@ using Azaion.Common.DTO; namespace Azaion.Common.Services; -public class TileResult +public class TileResult(CanvasLabel tile, List detections) { - public CanvasLabel Tile { get; set; } - public List Detections { get; set; } - - public TileResult(CanvasLabel tile, List detections) - { - Tile = tile; - Detections = detections; - } + public CanvasLabel Tile { get; set; } = tile; + public List Detections { get; set; } = detections; } public static class TileProcessor @@ -41,7 +35,7 @@ public static class TileProcessor private static TileResult GetDetectionsInTile(Size originalSize, CanvasLabel startDet, List allDetections) { var tile = new CanvasLabel(startDet.Left, startDet.Right, startDet.Top, startDet.Bottom); - var maxSize = new List { startDet.Width + BORDER, startDet.Height + BORDER, Constants.AI_TILE_SIZE }.Max(); + var maxSize = new List { startDet.Width + BORDER, startDet.Height + BORDER, Constants.AI_TILE_SIZE_DEFAULT }.Max(); var selectedDetections = new List{startDet}; foreach (var det in allDetections) diff --git a/Azaion.Inference/ai_config.pxd b/Azaion.Inference/ai_config.pxd index 90ebae8..de1e8ea 100644 --- a/Azaion.Inference/ai_config.pxd +++ b/Azaion.Inference/ai_config.pxd @@ -1,4 +1,5 @@ cdef class AIRecognitionConfig: + cdef public double frame_recognition_seconds cdef public int frame_period_recognition cdef public double probability_threshold @@ -8,6 +9,7 @@ cdef class AIRecognitionConfig: cdef public double tracking_intersection_threshold cdef public int big_image_tile_overlap_percent + cdef public int tile_size cdef public bytes file_data cdef public list[str] paths diff --git a/Azaion.Inference/ai_config.pyx b/Azaion.Inference/ai_config.pyx index acbdf8b..58a1198 100644 --- a/Azaion.Inference/ai_config.pyx +++ b/Azaion.Inference/ai_config.pyx @@ -9,11 +9,13 @@ cdef class AIRecognitionConfig: tracking_distance_confidence, tracking_probability_increase, tracking_intersection_threshold, - big_image_tile_overlap_percent, file_data, paths, - model_batch_size + model_batch_size, + + big_image_tile_overlap_percent, + tile_size ): self.frame_period_recognition = frame_period_recognition self.frame_recognition_seconds = frame_recognition_seconds @@ -22,12 +24,14 @@ cdef class AIRecognitionConfig: self.tracking_distance_confidence = tracking_distance_confidence self.tracking_probability_increase = tracking_probability_increase self.tracking_intersection_threshold = tracking_intersection_threshold - self.big_image_tile_overlap_percent = big_image_tile_overlap_percent self.file_data = file_data self.paths = paths self.model_batch_size = model_batch_size + self.big_image_tile_overlap_percent = big_image_tile_overlap_percent + self.tile_size = tile_size + def __str__(self): return (f'frame_seconds : {self.frame_recognition_seconds}, distance_confidence : {self.tracking_distance_confidence}, ' f'probability_increase : {self.tracking_probability_increase}, ' @@ -48,9 +52,11 @@ cdef class AIRecognitionConfig: unpacked.get("t_dc", 0.0), unpacked.get("t_pi", 0.0), unpacked.get("t_it", 0.0), - unpacked.get("ov_p", 20), unpacked.get("d", b''), unpacked.get("p", []), - unpacked.get("m_bs") + unpacked.get("m_bs"), + + unpacked.get("ov_p", 20), + unpacked.get("tile_size", 550), ) \ No newline at end of file diff --git a/Azaion.Inference/inference.pxd b/Azaion.Inference/inference.pxd index c540595..6cea5a4 100644 --- a/Azaion.Inference/inference.pxd +++ b/Azaion.Inference/inference.pxd @@ -18,8 +18,6 @@ cdef class Inference: cdef str model_input cdef int model_width cdef int model_height - cdef int tile_width - cdef int tile_height cdef bytes get_onnx_engine_bytes(self) cdef init_ai(self) @@ -30,7 +28,7 @@ cdef class Inference: cdef _process_video(self, RemoteCommand cmd, AIRecognitionConfig ai_config, str video_name) cdef _process_images(self, RemoteCommand cmd, AIRecognitionConfig ai_config, list[str] image_paths) cdef _process_images_inner(self, RemoteCommand cmd, AIRecognitionConfig ai_config, list frame_data) - cdef split_to_tiles(self, frame, path, overlap_percent) + cdef split_to_tiles(self, frame, path, tile_size, overlap_percent) cdef stop(self) cdef preprocess(self, frames) diff --git a/Azaion.Inference/inference.pyx b/Azaion.Inference/inference.pyx index 1bdd3f5..3ca2836 100644 --- a/Azaion.Inference/inference.pyx +++ b/Azaion.Inference/inference.pyx @@ -58,8 +58,6 @@ cdef class Inference: self.model_input = None self.model_width = 0 self.model_height = 0 - self.tile_width = 0 - self.tile_height = 0 self.engine = None self.is_building_engine = False self.ai_availability_status = AIAvailabilityStatus() @@ -107,15 +105,11 @@ cdef class Inference: self.is_building_engine = False self.model_height, self.model_width = self.engine.get_input_shape() - #todo: temporarily, send it from the client - self.tile_width = 550 - self.tile_height = 550 except Exception as e: self.ai_availability_status.set_status(AIAvailabilityEnum.ERROR, str(e)) self.is_building_engine = False - cdef preprocess(self, frames): blobs = [cv2.dnn.blobFromImage(frame, scalefactor=1.0 / 255.0, @@ -277,7 +271,7 @@ cdef class Inference: if img_h <= 1.5 * self.model_height and img_w <= 1.5 * self.model_width: frame_data.append((frame, original_media_name, f'{original_media_name}_000000')) else: - res = self.split_to_tiles(frame, path, ai_config.big_image_tile_overlap_percent) + res = self.split_to_tiles(frame, path, ai_config.tile_size, ai_config.big_image_tile_overlap_percent) frame_data.extend(res) if len(frame_data) > self.engine.get_batch_size(): for chunk in self.split_list_extend(frame_data, self.engine.get_batch_size()): @@ -287,31 +281,31 @@ cdef class Inference: self._process_images_inner(cmd, ai_config, chunk) - cdef split_to_tiles(self, frame, path, overlap_percent): + cdef split_to_tiles(self, frame, path, tile_size, overlap_percent): constants_inf.log(f'splitting image {path} to tiles...') img_h, img_w, _ = frame.shape - stride_w = int(self.tile_width * (1 - overlap_percent / 100)) - stride_h = int(self.tile_height * (1 - overlap_percent / 100)) + stride_w = int(tile_size * (1 - overlap_percent / 100)) + stride_h = int(tile_size * (1 - overlap_percent / 100)) results = [] original_media_name = Path( path).stem.replace(" ", "") for y in range(0, img_h, stride_h): for x in range(0, img_w, stride_w): - x_end = min(x + self.tile_width, img_w) - y_end = min(y + self.tile_height, img_h) + x_end = min(x + tile_size, img_w) + y_end = min(y + tile_size, img_h) # correct x,y for the close-to-border tiles - if x_end - x < self.tile_width: - if img_w - (x - stride_w) <= self.tile_width: + if x_end - x < tile_size: + if img_w - (x - stride_w) <= tile_size: continue # the previous tile already covered the last gap - x = img_w - self.tile_width - if y_end - y < self.tile_height: - if img_h - (y - stride_h) <= self.tile_height: + x = img_w - tile_size + if y_end - y < tile_size: + if img_h - (y - stride_h) <= tile_size: continue # the previous tile already covered the last gap - y = img_h - self.tile_height + y = img_h - tile_size tile = frame[y:y_end, x:x_end] - name = f'{original_media_name}{constants_inf.SPLIT_SUFFIX}{x:04d}_{y:04d}!_000000' + name = f'{original_media_name}{constants_inf.SPLIT_SUFFIX}{tile_size:04d}{x:04d}_{y:04d}!_000000' results.append((tile, original_media_name, name)) return results @@ -337,14 +331,15 @@ cdef class Inference: cdef remove_tiled_duplicates(self, Annotation annotation): right = annotation.name.rindex('!') left = annotation.name.index(constants_inf.SPLIT_SUFFIX) + len(constants_inf.SPLIT_SUFFIX) - x_str, y_str = annotation.name[left:right].split('_') + tile_size_str, x_str, y_str = annotation.name[left:right].split('_') + tile_size = int(tile_size_str) x = int(x_str) y = int(y_str) for det in annotation.detections: - x1 = det.x * self.tile_width - y1 = det.y * self.tile_height - det_abs = Detection(x + x1, y + y1, det.w * self.tile_width, det.h * self.tile_height, det.cls, det.confidence) + x1 = det.x * tile_size + y1 = det.y * tile_size + det_abs = Detection(x + x1, y + y1, det.w * tile_size, det.h * tile_size, det.cls, det.confidence) detections = self._tile_detections.setdefault(annotation.original_media_name, []) if det_abs in detections: annotation.detections.remove(det) diff --git a/Azaion.Inference/main_inference.pyx b/Azaion.Inference/main_inference.pyx index 6d27280..fea5ddd 100644 --- a/Azaion.Inference/main_inference.pyx +++ b/Azaion.Inference/main_inference.pyx @@ -37,7 +37,7 @@ cdef class CommandProcessor: continue except Exception as e: traceback.print_exc() - constants_inf.log('EXIT!') + constants_inf.log('EXIT!') cdef on_command(self, RemoteCommand command): try: diff --git a/Azaion.Loader/build_loader.cmd b/Azaion.Loader/build_loader.cmd index 935b2e4..ab73d0d 100644 --- a/Azaion.Loader/build_loader.cmd +++ b/Azaion.Loader/build_loader.cmd @@ -19,6 +19,10 @@ venv\Scripts\pip install -r requirements.txt venv\Scripts\pip install --upgrade pyinstaller pyinstaller-hooks-contrib venv\Scripts\python setup.py build_ext --inplace +if %errorlevel% neq 0 ( + echo "Error building cython extension" + exit /b %errorlevel% +) echo install azaion-loader venv\Scripts\pyinstaller --name=azaion-loader ^ diff --git a/Azaion.Loader/hardware_service.pxd b/Azaion.Loader/hardware_service.pxd index 9cf2ffe..bede58a 100644 --- a/Azaion.Loader/hardware_service.pxd +++ b/Azaion.Loader/hardware_service.pxd @@ -1,3 +1,5 @@ +cdef str _CACHED_HW_INFO + cdef class HardwareService: @staticmethod diff --git a/Azaion.Loader/hardware_service.pyx b/Azaion.Loader/hardware_service.pyx index ccc6641..a37e99a 100644 --- a/Azaion.Loader/hardware_service.pyx +++ b/Azaion.Loader/hardware_service.pyx @@ -1,13 +1,17 @@ import os import subprocess cimport constants + +cdef str _CACHED_HW_INFO = None + cdef class HardwareService: - cdef str _CACHED_HW_INFO = None @staticmethod cdef str get_hardware_info(): global _CACHED_HW_INFO + if _CACHED_HW_INFO is not None: + constants.log("Using cached hardware info") return _CACHED_HW_INFO if os.name == 'nt': # windows diff --git a/Azaion.Test/TileProcessorTest.cs b/Azaion.Test/TileProcessorTest.cs index 3c7b98e..d31c2c8 100644 --- a/Azaion.Test/TileProcessorTest.cs +++ b/Azaion.Test/TileProcessorTest.cs @@ -57,7 +57,7 @@ namespace Azaion.Annotator.Test; var detections = new List { new(100, 150, 100, 150), - new(2000, 2050, 2000, 2050) // More than Constants.AI_TILE_SIZE away + new(2000, 2050, 2000, 2050) // More than Constants.AI_TILE_SIZE_DEFAULT away }; // Act @@ -139,11 +139,11 @@ namespace Azaion.Annotator.Test; { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); - // Combined width is 1270. 1270 + BORDER (10) is not > Constants.AI_TILE_SIZE (1280), so they fit. + // Combined width is 1270. 1270 + BORDER (10) is not > Constants.AI_TILE_SIZE_DEFAULT (1280), so they fit. var detections = new List { new(0, 50, 0, 50), - new(Constants.AI_TILE_SIZE - TileProcessor.BORDER - 50, Constants.AI_TILE_SIZE - TileProcessor.BORDER, 0, 50) + new(Constants.AI_TILE_SIZE_DEFAULT - TileProcessor.BORDER - 50, Constants.AI_TILE_SIZE_DEFAULT - TileProcessor.BORDER, 0, 50) }; // Act @@ -159,11 +159,11 @@ namespace Azaion.Annotator.Test; { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); - // Combined width is 1271. 1271 + BORDER (10) is > Constants.AI_TILE_SIZE (1280), so they don't fit. + // Combined width is 1271. 1271 + BORDER (10) is > Constants.AI_TILE_SIZE_DEFAULT (1280), so they don't fit. var detections = new List { new(0, 50, 1000, 1050), // Top-most - new(Constants.AI_TILE_SIZE - TileProcessor.BORDER - 49, Constants.AI_TILE_SIZE - TileProcessor.BORDER + 1, 0, 50) + new(Constants.AI_TILE_SIZE_DEFAULT - TileProcessor.BORDER - 49, Constants.AI_TILE_SIZE_DEFAULT - TileProcessor.BORDER + 1, 0, 50) }; // Act @@ -224,7 +224,7 @@ namespace Azaion.Annotator.Test; { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); - var largeDetection = new CanvasLabel(100, 100 + Constants.AI_TILE_SIZE + 100, 100, 200); + var largeDetection = new CanvasLabel(100, 100 + Constants.AI_TILE_SIZE_DEFAULT + 100, 100, 200); var detections = new List { largeDetection }; // Act @@ -245,7 +245,7 @@ namespace Azaion.Annotator.Test; { // Arrange var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE); - var largeTallDetection = new CanvasLabel(100, 150, 100, 100 + Constants.AI_TILE_SIZE + 200); + var largeTallDetection = new CanvasLabel(100, 150, 100, 100 + Constants.AI_TILE_SIZE_DEFAULT + 200); var smallDetectionNearby = new CanvasLabel(largeTallDetection.Right + 15, largeTallDetection.Right + 35, 700, 720); var detections = new List { largeTallDetection, smallDetectionNearby }; From 5ef81fab22341c0eee34927a50a264c940929da9 Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Tue, 2 Sep 2025 14:00:47 +0300 Subject: [PATCH 2/4] fix loader bug with _CACHED_HW_INFO put tile size to name and set it dynamically for AI recognition --- Azaion.Common/DTO/Config/AIRecognitionConfig.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Azaion.Common/DTO/Config/AIRecognitionConfig.cs b/Azaion.Common/DTO/Config/AIRecognitionConfig.cs index c3eff14..0b14fb9 100644 --- a/Azaion.Common/DTO/Config/AIRecognitionConfig.cs +++ b/Azaion.Common/DTO/Config/AIRecognitionConfig.cs @@ -12,9 +12,11 @@ public class AIRecognitionConfig [Key("t_dc")] public double TrackingDistanceConfidence { get; set; } [Key("t_pi")] public double TrackingProbabilityIncrease { get; set; } [Key("t_it")] public double TrackingIntersectionThreshold { get; set; } - [Key("ov_p")] public double BigImageTileOverlapPercent { get; set; } [Key("d")] public byte[] Data { get; set; } = null!; [Key("p")] public List Paths { get; set; } = null!; - [Key("m_bs")] public int ModelBatchSize { get; set; } = 2; + [Key("m_bs")] public int ModelBatchSize { get; set; } = 4; + + [Key("ov_p")] public double BigImageTileOverlapPercent { get; set; } + [Key("tile_size")] public int TileSize { get; set; } } \ No newline at end of file From d396677451f0f2cac3a6d09c7cb9955ea0c82a50 Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Tue, 2 Sep 2025 17:01:15 +0300 Subject: [PATCH 3/4] fix build for the new file --- Azaion.Inference/azaion-inference.spec | 2 +- Azaion.Inference/build_inference.cmd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Azaion.Inference/azaion-inference.spec b/Azaion.Inference/azaion-inference.spec index b2ed95d..84c6969 100644 --- a/Azaion.Inference/azaion-inference.spec +++ b/Azaion.Inference/azaion-inference.spec @@ -4,7 +4,7 @@ from PyInstaller.utils.hooks import collect_all datas = [('venv\\Lib\\site-packages\\cv2', 'cv2')] binaries = [] -hiddenimports = ['constants_inf', 'file_data', 'remote_command_inf', 'remote_command_handler_inf', 'annotation', 'loader_client', 'ai_config', 'tensorrt_engine', 'onnx_engine', 'inference_engine', 'inference'] +hiddenimports = ['constants_inf', 'ai_availability_status', 'file_data', 'remote_command_inf', 'remote_command_handler_inf', 'annotation', 'loader_client', 'ai_config', 'tensorrt_engine', 'onnx_engine', 'inference_engine', 'inference'] hiddenimports += collect_submodules('cv2') tmp_ret = collect_all('psutil') datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] diff --git a/Azaion.Inference/build_inference.cmd b/Azaion.Inference/build_inference.cmd index dc99d3e..36ec97f 100644 --- a/Azaion.Inference/build_inference.cmd +++ b/Azaion.Inference/build_inference.cmd @@ -50,7 +50,7 @@ start.py robocopy "dist\azaion-inference\_internal" "..\dist-azaion\_internal" "ai_config.cp312-win_amd64.pyd" "annotation.cp312-win_amd64.pyd" robocopy "dist\azaion-inference\_internal" "..\dist-azaion\_internal" "constants_inf.cp312-win_amd64.pyd" "file_data.cp312-win_amd64.pyd" -robocopy "dist\azaion-inference\_internal" "..\dist-azaion\_internal" "ai_availability_status.pyd" +robocopy "dist\azaion-inference\_internal" "..\dist-azaion\_internal" "ai_availability_status.cp312-win_amd64.pyd" robocopy "dist\azaion-inference\_internal" "..\dist-azaion\_internal" "remote_command_inf.cp312-win_amd64.pyd" "remote_command_handler_inf.cp312-win_amd64.pyd" robocopy "dist\azaion-inference\_internal" "..\dist-azaion\_internal" "inference.cp312-win_amd64.py=d" "inference_engine.cp312-win_amd64.pyd" robocopy "dist\azaion-inference\_internal" "..\dist-azaion\_internal" "loader_client.cp312-win_amd64.pyd" "tensorrt_engine.cp312-win_amd64.pyd" From b2b2efe120bc5e3e03af68697de9c96b79ac7863 Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Tue, 2 Sep 2025 19:32:40 +0300 Subject: [PATCH 4/4] make version check more resilient to api installer availability --- Azaion.LoaderUI/Login.xaml.cs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Azaion.LoaderUI/Login.xaml.cs b/Azaion.LoaderUI/Login.xaml.cs index 80436e4..fd5352d 100644 --- a/Azaion.LoaderUI/Login.xaml.cs +++ b/Azaion.LoaderUI/Login.xaml.cs @@ -48,7 +48,7 @@ public partial class Login }; if (string.IsNullOrWhiteSpace(creds.Email) || string.IsNullOrWhiteSpace(creds.Password)) return; - + try { SetControlsStatus(isLoading: true); @@ -56,8 +56,8 @@ public partial class Login Validate(creds); TbStatus.Foreground = Brushes.Black; - var installerVersion = await GetInstallerVer(); var localVersion = Constants.GetLocalVersion(); + var installerVersion = await GetInstallerVer() ?? localVersion; var credsEncrypted = Security.Encrypt(creds); if (installerVersion > localVersion) @@ -159,18 +159,28 @@ public partial class Login throw; } } - - private async Task GetInstallerVer() + + private async Task GetInstallerVer() { TbStatus.Text = "Checking for the newer version..."; var installerDir = string.IsNullOrWhiteSpace(_dirConfig?.SuiteInstallerDirectory) ? ConstantsLoader.SUITE_FOLDER : _dirConfig.SuiteInstallerDirectory; var installerName = await _azaionApi.GetLastInstallerName(installerDir); - var match = Regex.Match(installerName, @"\d+(\.\d+)+"); - if (!match.Success) - throw new Exception($"Can't find version in {installerName}"); - return new Version(match.Value); + try + { + var match = Regex.Match(installerName, @"\d+(\.\d+)+"); + if (!match.Success) + throw new Exception($"Can't find version in {installerName}"); + return new Version(match.Value); + } + catch (Exception e) + { + TbStatus.Text = $"Exception during the check version {e.Message}"; + _logger.LogError(e, e.Message); + await Task.Delay(1500); + return null; + } } private void CloseClick(object sender, RoutedEventArgs e) => Close();