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
+96 -39
View File
@@ -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<DetectionClass> 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();
+1 -1
View File
@@ -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;