From 61c93e9c88a82d717b751856957f6adfa83caf0a Mon Sep 17 00:00:00 2001 From: Oleksandr Bezdieniezhnykh Date: Thu, 14 Aug 2025 04:22:55 +0300 Subject: [PATCH] clamp detections to media borders - create, move, resize fix inference start fix config fix resize rectangles show --- Azaion.Common/Controls/CanvasEditor.cs | 135 +++++++++++++++------ Azaion.Common/Controls/DetectionControl.cs | 2 +- Azaion.Common/Services/InferenceClient.cs | 2 +- Azaion.Suite/config.json | 8 +- 4 files changed, 102 insertions(+), 45 deletions(-) diff --git a/Azaion.Common/Controls/CanvasEditor.cs b/Azaion.Common/Controls/CanvasEditor.cs index ff4969e..7e99166 100644 --- a/Azaion.Common/Controls/CanvasEditor.cs +++ b/Azaion.Common/Controls/CanvasEditor.cs @@ -7,7 +7,6 @@ using System.Windows.Media.Imaging; using System.Windows.Shapes; using Azaion.Common.Database; using Azaion.Common.DTO; -using Azaion.Common.Events; using MediatR; using Color = System.Windows.Media.Color; using Image = System.Windows.Controls.Image; @@ -40,7 +39,8 @@ public class CanvasEditor : Canvas private readonly TimeSpan _viewThreshold = TimeSpan.FromMilliseconds(400); public Image BackgroundImage { get; set; } = new() { Stretch = Stretch.Uniform }; - + private RectangleF? _clampedRect; + public static readonly DependencyProperty GetTimeFuncProp = DependencyProperty.Register( nameof(GetTimeFunc), @@ -129,6 +129,7 @@ public class CanvasEditor : Canvas { SetZoom(); BackgroundImage.Source = source; + UpdateClampedRect(); } private void SetZoom(Matrix? matrix = null) @@ -190,7 +191,7 @@ public class CanvasEditor : Canvas private void CanvasMouseMove(object sender, MouseEventArgs e) { - var pos = e.GetPosition(this); + var pos = GetClampedPosition(e); _horizontalLine.Y1 = _horizontalLine.Y2 = pos.Y; _verticalLine.X1 = _verticalLine.X2 = pos.X; SetLeft(_classNameHint, pos.X + 10); @@ -199,24 +200,36 @@ public class CanvasEditor : Canvas switch (SelectionState) { case SelectionState.NewAnnCreating: - NewAnnotationCreatingMove(sender, e); + NewAnnotationCreatingMove(pos); break; case SelectionState.AnnResizing: - AnnotationResizeMove(sender, e); + AnnotationResizeMove(pos); break; case SelectionState.AnnMoving: - AnnotationPositionMove(sender, e); + AnnotationPositionMove(pos); + e.Handled = true; break; case SelectionState.PanZoomMoving: - PanZoomMove(sender, e); + PanZoomMove(pos); break; } } - private void PanZoomMove(object sender, MouseEventArgs e) + private Point GetClampedPosition(MouseEventArgs e) { - var currentPoint = e.GetPosition(this); - var delta = currentPoint - _panStartPoint; + var pos = e.GetPosition(this); + return !_clampedRect.HasValue + ? pos + : new Point + ( + Math.Clamp(pos.X, _clampedRect.Value.X, _clampedRect.Value.Right), + Math.Clamp(pos.Y, _clampedRect.Value.Y, _clampedRect.Value.Bottom) + ); + } + + private void PanZoomMove(Point point) + { + var delta = point - _panStartPoint; var matrix = _matrixTransform.Matrix; matrix.Translate(delta.X, delta.Y); @@ -229,7 +242,7 @@ public class CanvasEditor : Canvas (sender as UIElement)?.ReleaseMouseCapture(); if (SelectionState == SelectionState.NewAnnCreating) { - var endPos = e.GetPosition(this); + var endPos = GetClampedPosition(e); _newAnnotationRect.Width = 0; _newAnnotationRect.Height = 0; var width = Math.Abs(endPos.X - _newAnnotationStartPos.X); @@ -262,14 +275,14 @@ public class CanvasEditor : Canvas var origin = lb.TranslatePoint(new Point(0, 0), this); lb.Children[0].Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); var size = lb.Children[0].DesiredSize; - var lbRect = new RectangleF((float)origin.X, (float)origin.Y, (float)size.Width, (float)size.Height); + var controlLabel = new RectangleF((float)origin.X, (float)origin.Y, (float)size.Width, (float)size.Height); foreach (var c in CurrentDetections) { if (c == detectionControl) continue; var detRect = new RectangleF((float)GetLeft(c), (float)GetTop(c), (float)c.Width, (float)c.Height); - detRect.Intersect(lbRect); + detRect.Intersect(controlLabel); // var intersect = detections[i].ToRectangle(); @@ -287,8 +300,44 @@ public class CanvasEditor : Canvas _verticalLine.Y2 = e.NewSize.Height; BackgroundImage.Width = e.NewSize.Width; BackgroundImage.Height = e.NewSize.Height; + UpdateClampedRect(); } - + + private void UpdateClampedRect() + { + if (BackgroundImage.Source is not BitmapSource imageSource) + { + _clampedRect = null; + return; + } + + var imgWidth = imageSource.PixelWidth; + var imgHeight = imageSource.PixelHeight; + var canvasWidth = ActualWidth; + var canvasHeight = ActualHeight; + + var imgRatio = imgWidth / (double)imgHeight; + var canvasRatio = canvasWidth / canvasHeight; + + double renderedWidth; + double renderedHeight; + + if (imgRatio > canvasRatio) + { + renderedWidth = canvasWidth; + renderedHeight = canvasWidth / imgRatio; + } + else + { + renderedHeight = canvasHeight; + renderedWidth = canvasHeight * imgRatio; + } + var xOffset = (canvasWidth - renderedWidth) / 2; + var yOffset = (canvasHeight - renderedHeight) / 2; + + _clampedRect = new RectangleF((float)xOffset, (float)yOffset, (float)renderedWidth, (float)renderedHeight); + } + #region Annotation Resizing & Moving private void AnnotationResizeStart(object sender, MouseEventArgs e) @@ -300,17 +349,15 @@ public class CanvasEditor : Canvas e.Handled = true; } - private void AnnotationResizeMove(object sender, MouseEventArgs e) + private void AnnotationResizeMove(Point point) { if (SelectionState != SelectionState.AnnResizing) return; - var currentPos = e.GetPosition(this); - var x = GetLeft(_curAnn); var y = GetTop(_curAnn); - var offsetX = currentPos.X - _lastPos.X; - var offsetY = currentPos.Y - _lastPos.Y; + var offsetX = point.X - _lastPos.X; + var offsetY = point.Y - _lastPos.Y; switch (_curRec.HorizontalAlignment, _curRec.VerticalAlignment) { case (HorizontalAlignment.Left, VerticalAlignment.Top): @@ -350,7 +397,7 @@ public class CanvasEditor : Canvas _curAnn.Height = Math.Max(MIN_SIZE, _curAnn.Height + offsetY); break; } - _lastPos = currentPos; + _lastPos = point; } private void AnnotationPositionStart(object sender, MouseEventArgs e) @@ -367,19 +414,26 @@ public class CanvasEditor : Canvas e.Handled = true; } - private void AnnotationPositionMove(object sender, MouseEventArgs e) + private void AnnotationPositionMove(Point point) { if (SelectionState != SelectionState.AnnMoving) return; - var currentPos = e.GetPosition(this); - var offsetX = currentPos.X - _lastPos.X; - var offsetY = currentPos.Y - _lastPos.Y; - - SetLeft(_curAnn, GetLeft(_curAnn) + offsetX); - SetTop(_curAnn, GetTop(_curAnn) + offsetY); - _lastPos = currentPos; - e.Handled = true; + var offsetX = point.X - _lastPos.X; + var offsetY = point.Y - _lastPos.Y; + + var nextLeft = GetLeft(_curAnn) + offsetX; + var nextTop = GetTop(_curAnn) + offsetY; + + if (_clampedRect.HasValue) + { + nextLeft = Math.Clamp(nextLeft, _clampedRect.Value.X, _clampedRect.Value.Right - _curAnn.Width); + nextTop = Math.Clamp(nextTop, _clampedRect.Value.Y, _clampedRect.Value.Bottom - _curAnn.Height); + } + + SetLeft(_curAnn, nextLeft); + SetTop(_curAnn, nextTop); + _lastPos = point; } #endregion @@ -391,26 +445,29 @@ public class CanvasEditor : Canvas _newAnnotationStartPos = e.GetPosition(this); SetLeft(_newAnnotationRect, _newAnnotationStartPos.X); SetTop(_newAnnotationRect, _newAnnotationStartPos.Y); - _newAnnotationRect.MouseMove += NewAnnotationCreatingMove; + _newAnnotationRect.MouseMove += (sender, e) => + { + var currentPos = e.GetPosition(this); + NewAnnotationCreatingMove(currentPos); + }; SelectionState = SelectionState.NewAnnCreating; } - private void NewAnnotationCreatingMove(object sender, MouseEventArgs e) + private void NewAnnotationCreatingMove(Point point) { if (SelectionState != SelectionState.NewAnnCreating) return; - var currentPos = e.GetPosition(this); - var diff = currentPos - _newAnnotationStartPos; + var diff = point - _newAnnotationStartPos; _newAnnotationRect.Height = Math.Abs(diff.Y); _newAnnotationRect.Width = Math.Abs(diff.X); if (diff.X < 0) - SetLeft(_newAnnotationRect, currentPos.X); + SetLeft(_newAnnotationRect, point.X); if (diff.Y < 0) - SetTop(_newAnnotationRect, currentPos.Y); + SetTop(_newAnnotationRect, point.Y); } public void CreateDetections(Annotation annotation, List detectionClasses, Size mediaSize) @@ -432,7 +489,9 @@ public class CanvasEditor : Canvas canvasLabel = new CanvasLabel(yoloLabel, RenderSize, mediaSize, canvasLabel.Confidence); } - CreateDetectionControl(detectionClass, annotation.Time, canvasLabel); + var control = CreateDetectionControl(detectionClass, annotation.Time, canvasLabel); + control.UpdateLayout(); + CheckLabelBoundaries(control); } } @@ -481,9 +540,7 @@ public class CanvasEditor : Canvas .ToList(); RemoveAnnotations(expiredAnns); } - - public void ResetBackground() => Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)); - + public void ZoomTo(Point point) { SetZoom(); diff --git a/Azaion.Common/Controls/DetectionControl.cs b/Azaion.Common/Controls/DetectionControl.cs index e3bf6a1..bee6a8b 100644 --- a/Azaion.Common/Controls/DetectionControl.cs +++ b/Azaion.Common/Controls/DetectionControl.cs @@ -127,9 +127,9 @@ public class DetectionControl : Border VerticalAlignment = VerticalAlignment.Stretch, Children = { _selectionFrame } }; + _grid.Children.Add(DetectionLabelContainer); foreach (var rect in _resizedRectangles) _grid.Children.Add(rect); - _grid.Children.Add(DetectionLabelContainer); Child = _grid; Cursor = Cursors.SizeAll; diff --git a/Azaion.Common/Services/InferenceClient.cs b/Azaion.Common/Services/InferenceClient.cs index 714311f..7e59620 100644 --- a/Azaion.Common/Services/InferenceClient.cs +++ b/Azaion.Common/Services/InferenceClient.cs @@ -49,7 +49,7 @@ public class InferenceClient : IInferenceClient Arguments = $"-p {_inferenceClientConfig.ZeroMqPort} -lp {_loaderClientConfig.ZeroMqPort} -a {_inferenceClientConfig.ApiUrl}", CreateNoWindow = true }; - //process.Start(); + process.Start(); } catch (Exception e) { diff --git a/Azaion.Suite/config.json b/Azaion.Suite/config.json index c5595a5..748dbb9 100644 --- a/Azaion.Suite/config.json +++ b/Azaion.Suite/config.json @@ -17,10 +17,10 @@ "DirectoriesConfig": { "ApiResourcesDirectory": "stage", "VideosDirectory": "E:\\Azaion6", - "LabelsDirectory": "E:\\labels_test", - "ImagesDirectory": "E:\\images_test", - "ResultsDirectory": "E:\\results_test", - "ThumbnailsDirectory": "E:\\thumbnails_test", + "LabelsDirectory": "E:\\labels", + "ImagesDirectory": "E:\\images", + "ResultsDirectory": "E:\\results", + "ThumbnailsDirectory": "E:\\thumbnails", "GpsSatDirectory": "satellitesDir", "GpsRouteDirectory": "routeDir" },