1
1
using Microsoft . ML . OnnxRuntime ;
2
2
using Microsoft . ML . OnnxRuntime . Tensors ;
3
3
using OnnxStack . Core ;
4
+ using OnnxStack . Core . Image ;
5
+ using OnnxStack . ImageUpscaler . Models ;
4
6
using SixLabors . ImageSharp ;
5
7
using SixLabors . ImageSharp . PixelFormats ;
6
8
using System ;
9
+ using System . Collections . Generic ;
7
10
8
11
namespace OnnxStack . ImageUpscaler . Extensions
9
12
{
10
13
internal static class ImageExtensions
11
14
{
15
+ /// <summary>
16
+ /// Generates the image tiles.
17
+ /// </summary>
18
+ /// <param name="imageSource">The image source.</param>
19
+ /// <param name="sampleSize">Maximum size of the tile.</param>
20
+ /// <param name="scaleFactor">The scale factor.</param>
21
+ /// <returns></returns>
22
+ public static List < ImageTile > GenerateTiles ( this Image < Rgba32 > imageSource , int sampleSize , int scaleFactor )
23
+ {
24
+ var tiles = new List < ImageTile > ( ) ;
25
+ var tileSizeX = Math . Min ( sampleSize , imageSource . Width ) ;
26
+ var tileSizeY = Math . Min ( sampleSize , imageSource . Height ) ;
27
+ var columns = ( int ) Math . Ceiling ( ( double ) imageSource . Width / tileSizeX ) ;
28
+ var rows = ( int ) Math . Ceiling ( ( double ) imageSource . Height / tileSizeY ) ;
29
+ var tileWidth = imageSource . Width / columns ;
30
+ var tileHeight = imageSource . Height / rows ;
31
+
32
+ for ( int y = 0 ; y < rows ; y ++ )
33
+ {
34
+ for ( int x = 0 ; x < columns ; x ++ )
35
+ {
36
+ var tileRect = new Rectangle ( x * tileWidth , y * tileHeight , tileWidth , tileHeight ) ;
37
+ var tileDest = new Rectangle ( tileRect . X * scaleFactor , tileRect . Y * scaleFactor , tileWidth * scaleFactor , tileHeight * scaleFactor ) ;
38
+ var tileImage = ExtractTile ( imageSource , tileRect ) ;
39
+ tiles . Add ( new ImageTile ( tileImage , tileDest ) ) ;
40
+ }
41
+ }
42
+ return tiles ;
43
+ }
44
+
45
+
46
+ /// <summary>
47
+ /// Extracts an image tile from a source image.
48
+ /// </summary>
49
+ /// <param name="sourceImage">The source image.</param>
50
+ /// <param name="sourceArea">The source area.</param>
51
+ /// <returns></returns>
52
+ public static Image < Rgba32 > ExtractTile ( this Image < Rgba32 > sourceImage , Rectangle sourceArea )
53
+ {
54
+ var height = sourceArea . Height ;
55
+ var targetImage = new Image < Rgba32 > ( sourceArea . Width , sourceArea . Height ) ;
56
+ sourceImage . ProcessPixelRows ( targetImage , ( sourceAccessor , targetAccessor ) =>
57
+ {
58
+ for ( int i = 0 ; i < height ; i ++ )
59
+ {
60
+ var sourceRow = sourceAccessor . GetRowSpan ( sourceArea . Y + i ) ;
61
+ var targetRow = targetAccessor . GetRowSpan ( i ) ;
62
+ sourceRow . Slice ( sourceArea . X , sourceArea . Width ) . CopyTo ( targetRow ) ;
63
+ }
64
+ } ) ;
65
+ return targetImage ;
66
+ }
67
+
68
+
69
+ /// <summary>
70
+ /// Converts to InputImage to an Image<Rgba32>
71
+ /// </summary>
72
+ /// <param name="inputImage">The input image.</param>
73
+ /// <returns></returns>
74
+ public static Image < Rgba32 > ToImage ( this InputImage inputImage )
75
+ {
76
+ if ( ! string . IsNullOrEmpty ( inputImage . ImageBase64 ) )
77
+ return Image . Load < Rgba32 > ( Convert . FromBase64String ( inputImage . ImageBase64 . Split ( ',' ) [ 1 ] ) ) ;
78
+ if ( inputImage . ImageBytes != null )
79
+ return Image . Load < Rgba32 > ( inputImage . ImageBytes ) ;
80
+ if ( inputImage . ImageStream != null )
81
+ return Image . Load < Rgba32 > ( inputImage . ImageStream ) ;
82
+ if ( inputImage . ImageTensor != null )
83
+ return inputImage . ImageTensor . ToImage ( ) ;
84
+
85
+ return inputImage . Image ;
86
+ }
12
87
13
88
/// <summary>
14
89
/// Converts to DenseTensor.
@@ -20,7 +95,7 @@ public static DenseTensor<float> ToDenseTensor(this Image<Rgba32> image, ReadOnl
20
95
{
21
96
using ( image )
22
97
{
23
- return ProcessPixels ( image , dimensions ) ;
98
+ return NormalizeToZeroToOne ( image , dimensions ) ;
24
99
}
25
100
}
26
101
@@ -51,23 +126,24 @@ public static Image<Rgba32> ToImage(this DenseTensor<float> imageTensor)
51
126
for ( var x = 0 ; x < width ; x ++ )
52
127
{
53
128
result [ x , y ] = new Rgba32 (
54
- CalculateByte ( imageTensor , 0 , y , x ) ,
55
- CalculateByte ( imageTensor , 1 , y , x ) ,
56
- CalculateByte ( imageTensor , 2 , y , x )
129
+ DenormalizeZeroToOneToByte ( imageTensor , 0 , y , x ) ,
130
+ DenormalizeZeroToOneToByte ( imageTensor , 1 , y , x ) ,
131
+ DenormalizeZeroToOneToByte ( imageTensor , 2 , y , x )
57
132
) ;
58
133
}
59
134
}
60
135
return result ;
61
136
}
62
137
63
138
139
+
64
140
/// <summary>
65
- /// Processes the pixels.
141
+ /// Normalizes the pixels from 0-255 to 0-1
66
142
/// </summary>
67
143
/// <param name="image">The image.</param>
68
144
/// <param name="dimensions">The dimensions.</param>
69
145
/// <returns></returns>
70
- private static DenseTensor < float > ProcessPixels ( Image < Rgba32 > image , ReadOnlySpan < int > dimensions )
146
+ private static DenseTensor < float > NormalizeToZeroToOne ( Image < Rgba32 > image , ReadOnlySpan < int > dimensions )
71
147
{
72
148
var width = dimensions [ 3 ] ;
73
149
var height = dimensions [ 2 ] ;
@@ -90,15 +166,16 @@ private static DenseTensor<float> ProcessPixels(Image<Rgba32> image, ReadOnlySpa
90
166
}
91
167
92
168
169
+
93
170
/// <summary>
94
- /// Calculates the byte.
171
+ /// Denormalizes the pixels from 0-1 to 0-255
95
172
/// </summary>
96
173
/// <param name="imageTensor">The image tensor.</param>
97
174
/// <param name="index">The index.</param>
98
175
/// <param name="y">The y.</param>
99
176
/// <param name="x">The x.</param>
100
177
/// <returns></returns>
101
- private static byte CalculateByte ( Tensor < float > imageTensor , int index , int y , int x )
178
+ private static byte DenormalizeZeroToOneToByte ( DenseTensor < float > imageTensor , int index , int y , int x )
102
179
{
103
180
return ( byte ) Math . Round ( Math . Clamp ( imageTensor [ 0 , index , y , x ] , 0 , 1 ) * 255 ) ;
104
181
}
0 commit comments