Files
annotations/Azaion.Test/TileProcessorTest.cs
T
Oleksandr Bezdieniezhnykh ad782bcbaa splitting python complete
2025-08-12 14:48:56 +03:00

263 lines
9.1 KiB
C#

using System.Windows;
using Azaion.Common;
using Azaion.Common.DTO;
using Azaion.Common.Services;
using Xunit;
namespace Azaion.Annotator.Test;
public class TileProcessorTest
{
private const int IMAGE_SIZE = 5000;
[Fact]
public void Split_DetectionsNearImageCorners_ShouldCreateFourTiles()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var detections = new List<CanvasLabel>
{
new(10, 60, 10, 60), // Top-left corner
new(IMAGE_SIZE - 60, IMAGE_SIZE - 10, 10, 60), // Top-right corner
new(10, 60, IMAGE_SIZE - 60, IMAGE_SIZE - 10), // Bottom-left corner
new(IMAGE_SIZE - 60, IMAGE_SIZE - 10, IMAGE_SIZE - 60, IMAGE_SIZE - 10) // Bottom-right corner
};
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Equal(4, results.Count);
}
[Fact]
public void Split_DetectionsFarApartButFitInOneTile_ShouldCreateOneTile()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var detections = new List<CanvasLabel>
{
new(100, 150, 100, 150),
new(1200, 1250, 1200, 1250)
};
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Single(results);
Assert.Equal(2, results[0].Detections.Count);
}
[Fact]
public void Split_DetectionsTooFarApart_ShouldCreateMultipleTiles()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var detections = new List<CanvasLabel>
{
new(100, 150, 100, 150),
new(2000, 2050, 2000, 2050) // More than Constants.AI_TILE_SIZE away
};
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Equal(2, results.Count);
Assert.Contains(results, r => r.Detections.Count == 1 && r.Detections.Contains(detections[0]));
Assert.Contains(results, r => r.Detections.Count == 1 && r.Detections.Contains(detections[1]));
}
[Fact]
public void Split_ComplexScenario_ShouldCreateCorrectNumberOfTiles()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var detections = new List<CanvasLabel>
{
// Group 1 (should be tiled together)
new(100, 150, 100, 150),
new(200, 250, 200, 250),
new(500, 550, 500, 550),
// Group 2 (far from group 1, should be in a separate tile)
new(3000, 3050, 3000, 3050),
new(3100, 3150, 3100, 3150),
};
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Equal(2, results.Count);
var group1Tile = results.FirstOrDefault(r => r.Detections.Count == 3);
var group2Tile = results.FirstOrDefault(r => r.Detections.Count == 2);
Assert.NotNull(group1Tile);
Assert.NotNull(group2Tile);
Assert.Contains(detections[0], group1Tile.Detections);
Assert.Contains(detections[1], group1Tile.Detections);
Assert.Contains(detections[2], group1Tile.Detections);
Assert.Contains(detections[3], group2Tile.Detections);
Assert.Contains(detections[4], group2Tile.Detections);
}
[Fact]
public void Split_NoDetections_ShouldReturnEmptyList()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var detections = new List<CanvasLabel>();
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Empty(results);
}
[Fact]
public void Split_OneDetection_ShouldCreateOneTile()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var detections = new List<CanvasLabel> { new(100, 150, 100, 150) };
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Single(results);
Assert.Single(results[0].Detections);
Assert.Equal(detections[0], results[0].Detections[0]);
}
[Fact]
public void Split_DetectionsOnTileBoundary_ShouldFitInOneTile()
{
// 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.
var detections = new List<CanvasLabel>
{
new(0, 50, 0, 50),
new(Constants.AI_TILE_SIZE - TileProcessor.BORDER - 50, Constants.AI_TILE_SIZE - TileProcessor.BORDER, 0, 50)
};
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Single(results);
Assert.Equal(2, results[0].Detections.Count);
}
[Fact]
public void Split_DetectionsJustOverTileBoundary_ShouldCreateTwoTiles()
{
// 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.
var detections = new List<CanvasLabel>
{
new(0, 50, 1000, 1050), // Top-most
new(Constants.AI_TILE_SIZE - TileProcessor.BORDER - 49, Constants.AI_TILE_SIZE - TileProcessor.BORDER + 1, 0, 50)
};
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Equal(2, results.Count);
}
[Fact]
public void Split_ResultingTiles_ShouldBeWithinImageBoundaries()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var detections = new List<CanvasLabel>
{
new(10, 60, 10, 60), // Top-left corner
new(IMAGE_SIZE - 60, IMAGE_SIZE - 10, IMAGE_SIZE - 60, IMAGE_SIZE - 10) // Bottom-right corner
};
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Equal(2, results.Count);
foreach (var result in results)
{
var tile = result.Tile;
Assert.True(tile.Left >= 0, $"Tile Left boundary {tile.Left} is out of bounds.");
Assert.True(tile.Top >= 0, $"Tile Top boundary {tile.Top} is out of bounds.");
Assert.True(tile.Right <= originalSize.Width, $"Tile Right boundary {tile.Right} is out of bounds.");
Assert.True(tile.Bottom <= originalSize.Height, $"Tile Bottom boundary {tile.Bottom} is out of bounds.");
}
}
[Fact]
public void Split_ChainedDetections_ShouldCreateOneTile()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var detections = new List<CanvasLabel>
{
new(100, 200, 100, 200), // Detection A
new(600, 700, 600, 700), // Detection B (close to A)
new(1100, 1200, 1100, 1200) // Detection C (close to B, but far from A)
};
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Single(results);
Assert.Equal(3, results[0].Detections.Count);
}
[Fact]
public void Split_SingleDetectionLargerThanTileSize_ShouldCreateOneTile()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var largeDetection = new CanvasLabel(100, 100 + Constants.AI_TILE_SIZE + 100, 100, 200);
var detections = new List<CanvasLabel> { largeDetection };
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Single(results);
var resultTile = results[0];
Assert.Single(resultTile.Detections);
Assert.Equal(largeDetection, resultTile.Detections[0]);
// The tile should be at least as large as the detection it contains.
Assert.True(resultTile.Tile.Width >= largeDetection.Width);
Assert.True(resultTile.Tile.Height >= largeDetection.Height);
}
[Fact]
public void Split_LargeDetectionWithNearbySmallDetection_ShouldCreateOneTile()
{
// Arrange
var originalSize = new Size(IMAGE_SIZE, IMAGE_SIZE);
var largeTallDetection = new CanvasLabel(100, 150, 100, 100 + Constants.AI_TILE_SIZE + 200);
var smallDetectionNearby = new CanvasLabel(largeTallDetection.Right + 15, largeTallDetection.Right + 35, 700, 720);
var detections = new List<CanvasLabel> { largeTallDetection, smallDetectionNearby };
// Act
var results = TileProcessor.Split(originalSize, detections, CancellationToken.None);
// Assert
Assert.Single(results);
Assert.Equal(2, results[0].Detections.Count);
Assert.Contains(largeTallDetection, results[0].Detections);
Assert.Contains(smallDetectionNearby, results[0].Detections);
}
}