|
1 | 1 | using Microsoft.ML.OnnxRuntime.Tensors; |
| 2 | +using OnnxStack.Core.Model; |
2 | 3 | using SixLabors.ImageSharp; |
3 | 4 | using SixLabors.ImageSharp.PixelFormats; |
4 | 5 | using SixLabors.ImageSharp.Processing; |
| 6 | +using System.Threading.Tasks; |
5 | 7 |
|
6 | 8 | namespace OnnxStack.Core.Image |
7 | 9 | { |
@@ -40,6 +42,104 @@ public static ResizeMode ToResizeMode(this ImageResizeMode resizeMode) |
40 | 42 | }; |
41 | 43 | } |
42 | 44 |
|
| 45 | + |
| 46 | + /// <summary> |
| 47 | + /// Splits the Tensor into 4 equal tiles. |
| 48 | + /// </summary> |
| 49 | + /// <param name="sourceTensor">The source tensor.</param> |
| 50 | + /// <returns>TODO: Optimize</returns> |
| 51 | + public static ImageTiles SplitImageTiles(this DenseTensor<float> sourceTensor, int overlap = 20) |
| 52 | + { |
| 53 | + var tileWidth = sourceTensor.Dimensions[3] / 2; |
| 54 | + var tileHeight = sourceTensor.Dimensions[2] / 2; |
| 55 | + return new ImageTiles(tileWidth, tileHeight, overlap, |
| 56 | + SplitImageTile(sourceTensor, 0, 0, tileHeight + overlap, tileWidth + overlap), |
| 57 | + SplitImageTile(sourceTensor, 0, tileWidth - overlap, tileHeight + overlap, tileWidth * 2), |
| 58 | + SplitImageTile(sourceTensor, tileHeight - overlap, 0, tileHeight * 2, tileWidth + overlap), |
| 59 | + SplitImageTile(sourceTensor, tileHeight - overlap, tileWidth - overlap, tileHeight * 2, tileWidth * 2)); |
| 60 | + } |
| 61 | + |
| 62 | + |
| 63 | + /// <summary> |
| 64 | + /// Splits a tile from the source. |
| 65 | + /// </summary> |
| 66 | + /// <param name="source">The tensor.</param> |
| 67 | + /// <param name="startRow">The start row.</param> |
| 68 | + /// <param name="startCol">The start col.</param> |
| 69 | + /// <param name="endRow">The end row.</param> |
| 70 | + /// <param name="endCol">The end col.</param> |
| 71 | + /// <returns></returns> |
| 72 | + private static DenseTensor<float> SplitImageTile(DenseTensor<float> source, int startRow, int startCol, int endRow, int endCol) |
| 73 | + { |
| 74 | + int height = endRow - startRow; |
| 75 | + int width = endCol - startCol; |
| 76 | + int channels = source.Dimensions[1]; |
| 77 | + var splitTensor = new DenseTensor<float>(new[] { 1, channels, height, width }); |
| 78 | + Parallel.For(0, channels, (c) => |
| 79 | + { |
| 80 | + Parallel.For(0, height, (i) => |
| 81 | + { |
| 82 | + Parallel.For(0, width, (j) => |
| 83 | + { |
| 84 | + splitTensor[0, c, i, j] = source[0, c, startRow + i, startCol + j]; |
| 85 | + }); |
| 86 | + }); |
| 87 | + }); |
| 88 | + return splitTensor; |
| 89 | + } |
| 90 | + |
| 91 | + |
| 92 | + /// <summary> |
| 93 | + /// Joins the tiles into a single Tensor. |
| 94 | + /// </summary> |
| 95 | + /// <param name="tiles">The tiles.</param> |
| 96 | + /// <returns>TODO: Optimize</returns> |
| 97 | + public static DenseTensor<float> JoinImageTiles(this ImageTiles tiles) |
| 98 | + { |
| 99 | + var totalWidth = tiles.Width * 2; |
| 100 | + var totalHeight = tiles.Height * 2; |
| 101 | + var channels = tiles.Tile1.Dimensions[1]; |
| 102 | + var destination = new DenseTensor<float>(new[] { 1, channels, totalHeight, totalWidth }); |
| 103 | + JoinImageTile(destination, tiles.Tile1, 0, 0, tiles.Height + tiles.Overlap, tiles.Width + tiles.Overlap); |
| 104 | + JoinImageTile(destination, tiles.Tile2, 0, tiles.Width - tiles.Overlap, tiles.Height + tiles.Overlap, totalWidth); |
| 105 | + JoinImageTile(destination, tiles.Tile3, tiles.Height - tiles.Overlap, 0, totalHeight, tiles.Width + tiles.Overlap); |
| 106 | + JoinImageTile(destination, tiles.Tile4, tiles.Height - tiles.Overlap, tiles.Width - tiles.Overlap, totalHeight, totalWidth); |
| 107 | + return destination; |
| 108 | + } |
| 109 | + |
| 110 | + |
| 111 | + /// <summary> |
| 112 | + /// Joins the tile to the destination tensor. |
| 113 | + /// </summary> |
| 114 | + /// <param name="destination">The destination.</param> |
| 115 | + /// <param name="tile">The tile.</param> |
| 116 | + /// <param name="startRow">The start row.</param> |
| 117 | + /// <param name="startCol">The start col.</param> |
| 118 | + /// <param name="endRow">The end row.</param> |
| 119 | + /// <param name="endCol">The end col.</param> |
| 120 | + private static void JoinImageTile(DenseTensor<float> destination, DenseTensor<float> tile, int startRow, int startCol, int endRow, int endCol) |
| 121 | + { |
| 122 | + int height = endRow - startRow; |
| 123 | + int width = endCol - startCol; |
| 124 | + int channels = tile.Dimensions[1]; |
| 125 | + Parallel.For(0, channels, (c) => |
| 126 | + { |
| 127 | + Parallel.For(0, height, (i) => |
| 128 | + { |
| 129 | + Parallel.For(0, width, (j) => |
| 130 | + { |
| 131 | + var value = tile[0, c, i, j]; |
| 132 | + var existing = destination[0, c, startRow + i, startCol + j]; |
| 133 | + if (existing > 0) |
| 134 | + { |
| 135 | + // Blend ovelap |
| 136 | + value = (existing + value) / 2f; |
| 137 | + } |
| 138 | + destination[0, c, startRow + i, startCol + j] = value; |
| 139 | + }); |
| 140 | + }); |
| 141 | + }); |
| 142 | + } |
43 | 143 | } |
44 | 144 |
|
45 | 145 | public enum ImageNormalizeType |
|
0 commit comments