Skip to content
This repository was archived by the owner on Nov 27, 2024. It is now read-only.

Commit 9c8dd6d

Browse files
committed
Move common InputImage to OnnxStack.Core, Tidy Upscale implementation
1 parent 8abd309 commit 9c8dd6d

File tree

17 files changed

+216
-133
lines changed

17 files changed

+216
-133
lines changed

OnnxStack.Console/Examples/StableDiffusionGif.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using OnnxStack.StableDiffusion;
1+
using OnnxStack.Core.Image;
2+
using OnnxStack.StableDiffusion;
23
using OnnxStack.StableDiffusion.Common;
34
using OnnxStack.StableDiffusion.Config;
45
using OnnxStack.StableDiffusion.Enums;

OnnxStack.Console/Examples/UpscaleExample.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using OnnxStack.ImageUpscaler.Services;
1+
using OnnxStack.Core.Image;
2+
using OnnxStack.ImageUpscaler.Services;
23
using SixLabors.ImageSharp;
34
using SixLabors.ImageSharp.PixelFormats;
45

@@ -42,7 +43,7 @@ public async Task RunAsync()
4243
var inputImage = await Image.LoadAsync<Rgba32>(imageFile);
4344

4445
OutputHelpers.WriteConsole("Upscaling Image...", ConsoleColor.Cyan);
45-
var result = await _imageUpscaleService.GenerateAsync(modelSet, inputImage);
46+
var result = await _imageUpscaleService.GenerateAsImageAsync(modelSet, new InputImage(inputImage));
4647
await result.SaveAsPngAsync(Path.Combine(_outputDirectory, "Result.png"));
4748
OutputHelpers.WriteConsole("Upscaling Complete.", ConsoleColor.Cyan);
4849
}

OnnxStack.StableDiffusion/Models/InputImage.cs renamed to OnnxStack.Core/Image/InputImage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System.IO;
55
using System.Text.Json.Serialization;
66

7-
namespace OnnxStack.StableDiffusion.Models
7+
namespace OnnxStack.Core.Image
88
{
99
public class InputImage
1010
{

OnnxStack.Core/OnnxStack.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
<PackageReference Include="Microsoft.ML" Version="2.0.1" />
4242
<PackageReference Include="Microsoft.ML.OnnxRuntime.Extensions" Version="0.9.0" />
4343
<PackageReference Include="Microsoft.ML.OnnxRuntime.Managed" Version="1.16.2" />
44+
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.0" />
4445
</ItemGroup>
4546

4647
<ItemGroup>

OnnxStack.ImageUpscaler/Extensions/ImageExtensions.cs

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,89 @@
11
using Microsoft.ML.OnnxRuntime;
22
using Microsoft.ML.OnnxRuntime.Tensors;
33
using OnnxStack.Core;
4+
using OnnxStack.Core.Image;
5+
using OnnxStack.ImageUpscaler.Models;
46
using SixLabors.ImageSharp;
57
using SixLabors.ImageSharp.PixelFormats;
68
using System;
9+
using System.Collections.Generic;
710

811
namespace OnnxStack.ImageUpscaler.Extensions
912
{
1013
internal static class ImageExtensions
1114
{
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+
}
1287

1388
/// <summary>
1489
/// Converts to DenseTensor.
@@ -20,7 +95,7 @@ public static DenseTensor<float> ToDenseTensor(this Image<Rgba32> image, ReadOnl
2095
{
2196
using (image)
2297
{
23-
return ProcessPixels(image, dimensions);
98+
return NormalizeToZeroToOne(image, dimensions);
2499
}
25100
}
26101

@@ -51,23 +126,24 @@ public static Image<Rgba32> ToImage(this DenseTensor<float> imageTensor)
51126
for (var x = 0; x < width; x++)
52127
{
53128
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)
57132
);
58133
}
59134
}
60135
return result;
61136
}
62137

63138

139+
64140
/// <summary>
65-
/// Processes the pixels.
141+
/// Normalizes the pixels from 0-255 to 0-1
66142
/// </summary>
67143
/// <param name="image">The image.</param>
68144
/// <param name="dimensions">The dimensions.</param>
69145
/// <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)
71147
{
72148
var width = dimensions[3];
73149
var height = dimensions[2];
@@ -90,15 +166,16 @@ private static DenseTensor<float> ProcessPixels(Image<Rgba32> image, ReadOnlySpa
90166
}
91167

92168

169+
93170
/// <summary>
94-
/// Calculates the byte.
171+
/// Denormalizes the pixels from 0-1 to 0-255
95172
/// </summary>
96173
/// <param name="imageTensor">The image tensor.</param>
97174
/// <param name="index">The index.</param>
98175
/// <param name="y">The y.</param>
99176
/// <param name="x">The x.</param>
100177
/// <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)
102179
{
103180
return (byte)Math.Round(Math.Clamp(imageTensor[0, index, y, x], 0, 1) * 255);
104181
}

OnnxStack.ImageUpscaler/OnnxStack.ImageUpscaler.csproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@
3131
</None>
3232
</ItemGroup>
3333

34-
<ItemGroup>
35-
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.2" />
36-
</ItemGroup>
37-
3834
<ItemGroup>
3935
<ProjectReference Include="..\OnnxStack.Core\OnnxStack.Core.csproj" />
4036
</ItemGroup>

OnnxStack.ImageUpscaler/Registration.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ public static void AddOnnxStackImageUpscaler(this IServiceCollection serviceColl
3838
/// <param name="serviceCollection">The service collection.</param>
3939
private static void RegisterServices(this IServiceCollection serviceCollection)
4040
{
41-
serviceCollection.AddSingleton<IImageService, ImageService>();
4241
serviceCollection.AddSingleton<IUpscaleService, UpscaleService>();
4342
}
4443

OnnxStack.ImageUpscaler/Services/IImageService.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.

OnnxStack.ImageUpscaler/Services/IUpscaleService.cs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
using OnnxStack.ImageUpscaler.Config;
1+
using Microsoft.ML.OnnxRuntime.Tensors;
2+
using OnnxStack.Core.Image;
3+
using OnnxStack.ImageUpscaler.Config;
24
using OnnxStack.StableDiffusion.Config;
35
using SixLabors.ImageSharp;
46
using SixLabors.ImageSharp.PixelFormats;
57
using System.Collections.Generic;
8+
using System.IO;
69
using System.Threading.Tasks;
710

811
namespace OnnxStack.ImageUpscaler.Services
@@ -44,6 +47,32 @@ public interface IUpscaleService
4447
/// <param name="modelOptions">The model options.</param>
4548
/// <param name="inputImage">The input image.</param>
4649
/// <returns></returns>
47-
Task<Image<Rgba32>> GenerateAsync(UpscaleModelSet modelOptions, Image<Rgba32> inputImage);
50+
Task<DenseTensor<float>> GenerateAsync(UpscaleModelSet modelOptions, InputImage inputImage);
51+
52+
/// <summary>
53+
/// Generates the upscaled image.
54+
/// </summary>
55+
/// <param name="modelOptions">The model options.</param>
56+
/// <param name="inputImage">The input image.</param>
57+
/// <returns></returns>
58+
Task<Image<Rgba32>> GenerateAsImageAsync(UpscaleModelSet modelOptions, InputImage inputImage);
59+
60+
61+
/// <summary>
62+
/// Generates the upscaled image.
63+
/// </summary>
64+
/// <param name="modelOptions">The model options.</param>
65+
/// <param name="inputImage">The input image.</param>
66+
/// <returns></returns>
67+
Task<byte[]> GenerateAsByteAsync(UpscaleModelSet modelOptions, InputImage inputImage);
68+
69+
70+
/// <summary>
71+
/// Generates the upscaled image.
72+
/// </summary>
73+
/// <param name="modelOptions">The model options.</param>
74+
/// <param name="inputImage">The input image.</param>
75+
/// <returns></returns>
76+
Task<Stream> GenerateAsStreamAsync(UpscaleModelSet modelOptions, InputImage inputImage);
4877
}
4978
}

OnnxStack.ImageUpscaler/Services/ImageService.cs

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)