clamp detections to media borders - create, move, resize

fix inference start
fix config
fix resize rectangles show
This commit is contained in:
Oleksandr Bezdieniezhnykh
2025-08-14 04:22:55 +03:00
parent 4780e8c61c
commit 61c93e9c88
4 changed files with 102 additions and 45 deletions
+92 -35
View File
@@ -7,7 +7,6 @@ using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
using Azaion.Common.Database; using Azaion.Common.Database;
using Azaion.Common.DTO; using Azaion.Common.DTO;
using Azaion.Common.Events;
using MediatR; using MediatR;
using Color = System.Windows.Media.Color; using Color = System.Windows.Media.Color;
using Image = System.Windows.Controls.Image; using Image = System.Windows.Controls.Image;
@@ -40,6 +39,7 @@ public class CanvasEditor : Canvas
private readonly TimeSpan _viewThreshold = TimeSpan.FromMilliseconds(400); private readonly TimeSpan _viewThreshold = TimeSpan.FromMilliseconds(400);
public Image BackgroundImage { get; set; } = new() { Stretch = Stretch.Uniform }; public Image BackgroundImage { get; set; } = new() { Stretch = Stretch.Uniform };
private RectangleF? _clampedRect;
public static readonly DependencyProperty GetTimeFuncProp = public static readonly DependencyProperty GetTimeFuncProp =
DependencyProperty.Register( DependencyProperty.Register(
@@ -129,6 +129,7 @@ public class CanvasEditor : Canvas
{ {
SetZoom(); SetZoom();
BackgroundImage.Source = source; BackgroundImage.Source = source;
UpdateClampedRect();
} }
private void SetZoom(Matrix? matrix = null) private void SetZoom(Matrix? matrix = null)
@@ -190,7 +191,7 @@ public class CanvasEditor : Canvas
private void CanvasMouseMove(object sender, MouseEventArgs e) private void CanvasMouseMove(object sender, MouseEventArgs e)
{ {
var pos = e.GetPosition(this); var pos = GetClampedPosition(e);
_horizontalLine.Y1 = _horizontalLine.Y2 = pos.Y; _horizontalLine.Y1 = _horizontalLine.Y2 = pos.Y;
_verticalLine.X1 = _verticalLine.X2 = pos.X; _verticalLine.X1 = _verticalLine.X2 = pos.X;
SetLeft(_classNameHint, pos.X + 10); SetLeft(_classNameHint, pos.X + 10);
@@ -199,24 +200,36 @@ public class CanvasEditor : Canvas
switch (SelectionState) switch (SelectionState)
{ {
case SelectionState.NewAnnCreating: case SelectionState.NewAnnCreating:
NewAnnotationCreatingMove(sender, e); NewAnnotationCreatingMove(pos);
break; break;
case SelectionState.AnnResizing: case SelectionState.AnnResizing:
AnnotationResizeMove(sender, e); AnnotationResizeMove(pos);
break; break;
case SelectionState.AnnMoving: case SelectionState.AnnMoving:
AnnotationPositionMove(sender, e); AnnotationPositionMove(pos);
e.Handled = true;
break; break;
case SelectionState.PanZoomMoving: case SelectionState.PanZoomMoving:
PanZoomMove(sender, e); PanZoomMove(pos);
break; break;
} }
} }
private void PanZoomMove(object sender, MouseEventArgs e) private Point GetClampedPosition(MouseEventArgs e)
{ {
var currentPoint = e.GetPosition(this); var pos = e.GetPosition(this);
var delta = currentPoint - _panStartPoint; 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; var matrix = _matrixTransform.Matrix;
matrix.Translate(delta.X, delta.Y); matrix.Translate(delta.X, delta.Y);
@@ -229,7 +242,7 @@ public class CanvasEditor : Canvas
(sender as UIElement)?.ReleaseMouseCapture(); (sender as UIElement)?.ReleaseMouseCapture();
if (SelectionState == SelectionState.NewAnnCreating) if (SelectionState == SelectionState.NewAnnCreating)
{ {
var endPos = e.GetPosition(this); var endPos = GetClampedPosition(e);
_newAnnotationRect.Width = 0; _newAnnotationRect.Width = 0;
_newAnnotationRect.Height = 0; _newAnnotationRect.Height = 0;
var width = Math.Abs(endPos.X - _newAnnotationStartPos.X); 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); var origin = lb.TranslatePoint(new Point(0, 0), this);
lb.Children[0].Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); lb.Children[0].Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
var size = lb.Children[0].DesiredSize; 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) foreach (var c in CurrentDetections)
{ {
if (c == detectionControl) if (c == detectionControl)
continue; continue;
var detRect = new RectangleF((float)GetLeft(c), (float)GetTop(c), (float)c.Width, (float)c.Height); 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(); // var intersect = detections[i].ToRectangle();
@@ -287,6 +300,42 @@ public class CanvasEditor : Canvas
_verticalLine.Y2 = e.NewSize.Height; _verticalLine.Y2 = e.NewSize.Height;
BackgroundImage.Width = e.NewSize.Width; BackgroundImage.Width = e.NewSize.Width;
BackgroundImage.Height = e.NewSize.Height; 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 #region Annotation Resizing & Moving
@@ -300,17 +349,15 @@ public class CanvasEditor : Canvas
e.Handled = true; e.Handled = true;
} }
private void AnnotationResizeMove(object sender, MouseEventArgs e) private void AnnotationResizeMove(Point point)
{ {
if (SelectionState != SelectionState.AnnResizing) if (SelectionState != SelectionState.AnnResizing)
return; return;
var currentPos = e.GetPosition(this);
var x = GetLeft(_curAnn); var x = GetLeft(_curAnn);
var y = GetTop(_curAnn); var y = GetTop(_curAnn);
var offsetX = currentPos.X - _lastPos.X; var offsetX = point.X - _lastPos.X;
var offsetY = currentPos.Y - _lastPos.Y; var offsetY = point.Y - _lastPos.Y;
switch (_curRec.HorizontalAlignment, _curRec.VerticalAlignment) switch (_curRec.HorizontalAlignment, _curRec.VerticalAlignment)
{ {
case (HorizontalAlignment.Left, VerticalAlignment.Top): case (HorizontalAlignment.Left, VerticalAlignment.Top):
@@ -350,7 +397,7 @@ public class CanvasEditor : Canvas
_curAnn.Height = Math.Max(MIN_SIZE, _curAnn.Height + offsetY); _curAnn.Height = Math.Max(MIN_SIZE, _curAnn.Height + offsetY);
break; break;
} }
_lastPos = currentPos; _lastPos = point;
} }
private void AnnotationPositionStart(object sender, MouseEventArgs e) private void AnnotationPositionStart(object sender, MouseEventArgs e)
@@ -367,19 +414,26 @@ public class CanvasEditor : Canvas
e.Handled = true; e.Handled = true;
} }
private void AnnotationPositionMove(object sender, MouseEventArgs e) private void AnnotationPositionMove(Point point)
{ {
if (SelectionState != SelectionState.AnnMoving) if (SelectionState != SelectionState.AnnMoving)
return; return;
var currentPos = e.GetPosition(this); var offsetX = point.X - _lastPos.X;
var offsetX = currentPos.X - _lastPos.X; var offsetY = point.Y - _lastPos.Y;
var offsetY = currentPos.Y - _lastPos.Y;
SetLeft(_curAnn, GetLeft(_curAnn) + offsetX); var nextLeft = GetLeft(_curAnn) + offsetX;
SetTop(_curAnn, GetTop(_curAnn) + offsetY); var nextTop = GetTop(_curAnn) + offsetY;
_lastPos = currentPos;
e.Handled = true; 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 #endregion
@@ -391,26 +445,29 @@ public class CanvasEditor : Canvas
_newAnnotationStartPos = e.GetPosition(this); _newAnnotationStartPos = e.GetPosition(this);
SetLeft(_newAnnotationRect, _newAnnotationStartPos.X); SetLeft(_newAnnotationRect, _newAnnotationStartPos.X);
SetTop(_newAnnotationRect, _newAnnotationStartPos.Y); SetTop(_newAnnotationRect, _newAnnotationStartPos.Y);
_newAnnotationRect.MouseMove += NewAnnotationCreatingMove; _newAnnotationRect.MouseMove += (sender, e) =>
{
var currentPos = e.GetPosition(this);
NewAnnotationCreatingMove(currentPos);
};
SelectionState = SelectionState.NewAnnCreating; SelectionState = SelectionState.NewAnnCreating;
} }
private void NewAnnotationCreatingMove(object sender, MouseEventArgs e) private void NewAnnotationCreatingMove(Point point)
{ {
if (SelectionState != SelectionState.NewAnnCreating) if (SelectionState != SelectionState.NewAnnCreating)
return; return;
var currentPos = e.GetPosition(this); var diff = point - _newAnnotationStartPos;
var diff = currentPos - _newAnnotationStartPos;
_newAnnotationRect.Height = Math.Abs(diff.Y); _newAnnotationRect.Height = Math.Abs(diff.Y);
_newAnnotationRect.Width = Math.Abs(diff.X); _newAnnotationRect.Width = Math.Abs(diff.X);
if (diff.X < 0) if (diff.X < 0)
SetLeft(_newAnnotationRect, currentPos.X); SetLeft(_newAnnotationRect, point.X);
if (diff.Y < 0) if (diff.Y < 0)
SetTop(_newAnnotationRect, currentPos.Y); SetTop(_newAnnotationRect, point.Y);
} }
public void CreateDetections(Annotation annotation, List<DetectionClass> detectionClasses, Size mediaSize) public void CreateDetections(Annotation annotation, List<DetectionClass> detectionClasses, Size mediaSize)
@@ -432,7 +489,9 @@ public class CanvasEditor : Canvas
canvasLabel = new CanvasLabel(yoloLabel, RenderSize, mediaSize, canvasLabel.Confidence); canvasLabel = new CanvasLabel(yoloLabel, RenderSize, mediaSize, canvasLabel.Confidence);
} }
CreateDetectionControl(detectionClass, annotation.Time, canvasLabel); var control = CreateDetectionControl(detectionClass, annotation.Time, canvasLabel);
control.UpdateLayout();
CheckLabelBoundaries(control);
} }
} }
@@ -482,8 +541,6 @@ public class CanvasEditor : Canvas
RemoveAnnotations(expiredAnns); RemoveAnnotations(expiredAnns);
} }
public void ResetBackground() => Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0));
public void ZoomTo(Point point) public void ZoomTo(Point point)
{ {
SetZoom(); SetZoom();
+1 -1
View File
@@ -127,9 +127,9 @@ public class DetectionControl : Border
VerticalAlignment = VerticalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch,
Children = { _selectionFrame } Children = { _selectionFrame }
}; };
_grid.Children.Add(DetectionLabelContainer);
foreach (var rect in _resizedRectangles) foreach (var rect in _resizedRectangles)
_grid.Children.Add(rect); _grid.Children.Add(rect);
_grid.Children.Add(DetectionLabelContainer);
Child = _grid; Child = _grid;
Cursor = Cursors.SizeAll; Cursor = Cursors.SizeAll;
+1 -1
View File
@@ -49,7 +49,7 @@ public class InferenceClient : IInferenceClient
Arguments = $"-p {_inferenceClientConfig.ZeroMqPort} -lp {_loaderClientConfig.ZeroMqPort} -a {_inferenceClientConfig.ApiUrl}", Arguments = $"-p {_inferenceClientConfig.ZeroMqPort} -lp {_loaderClientConfig.ZeroMqPort} -a {_inferenceClientConfig.ApiUrl}",
CreateNoWindow = true CreateNoWindow = true
}; };
//process.Start(); process.Start();
} }
catch (Exception e) catch (Exception e)
{ {
+4 -4
View File
@@ -17,10 +17,10 @@
"DirectoriesConfig": { "DirectoriesConfig": {
"ApiResourcesDirectory": "stage", "ApiResourcesDirectory": "stage",
"VideosDirectory": "E:\\Azaion6", "VideosDirectory": "E:\\Azaion6",
"LabelsDirectory": "E:\\labels_test", "LabelsDirectory": "E:\\labels",
"ImagesDirectory": "E:\\images_test", "ImagesDirectory": "E:\\images",
"ResultsDirectory": "E:\\results_test", "ResultsDirectory": "E:\\results",
"ThumbnailsDirectory": "E:\\thumbnails_test", "ThumbnailsDirectory": "E:\\thumbnails",
"GpsSatDirectory": "satellitesDir", "GpsSatDirectory": "satellitesDir",
"GpsRouteDirectory": "routeDir" "GpsRouteDirectory": "routeDir"
}, },