Skip to content

Commit c58a967

Browse files
committed
ImageTensor GetPixel/SetPixel support
1 parent fb4b212 commit c58a967

File tree

7 files changed

+94
-29
lines changed

7 files changed

+94
-29
lines changed

TensorStack.Common/Extensions/Extensions.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,5 +167,27 @@ public static async Task SafeCancelAsync(this CancellationTokenSource cancellati
167167
}
168168
catch { }
169169
}
170+
171+
172+
/// <summary>
173+
/// Normalizes to float.
174+
/// </summary>
175+
/// <param name="value">The value.</param>
176+
/// <returns>System.Single.</returns>
177+
public static float NormalizeToFloat(this byte value)
178+
{
179+
return (value / 255.0f) * 2.0f - 1.0f;
180+
}
181+
182+
183+
/// <summary>
184+
/// Denormalizes to byte.
185+
/// </summary>
186+
/// <param name="value">The value.</param>
187+
/// <returns>System.Byte.</returns>
188+
public static byte DenormalizeToByte(this float value)
189+
{
190+
return (byte)Math.Round(Math.Clamp((value / 2.0 + 0.5) * 255.0, 0.0, 255.0));
191+
}
170192
}
171193
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace TensorStack.Common.Image
2+
{
3+
public readonly struct ImagePixel
4+
{
5+
public readonly float R;
6+
public readonly float G;
7+
public readonly float B;
8+
public readonly float A;
9+
10+
public ImagePixel(float r, float g, float b, float a)
11+
{
12+
R = r;
13+
G = g;
14+
B = b;
15+
A = a;
16+
}
17+
}
18+
}

TensorStack.Common/Tensor/ImageTensor.cs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) TensorStack. All rights reserved.
22
// Licensed under the Apache 2.0 License.
33
using System;
4+
using TensorStack.Common.Image;
45

56
namespace TensorStack.Common.Tensor
67
{
@@ -16,7 +17,7 @@ public class ImageTensor : Tensor<float>
1617
/// </summary>
1718
/// <param name="tensor">The tensor.</param>
1819
public ImageTensor(Tensor<float> tensor)
19-
: base(ProcessChannels(tensor), [1, 4, ..tensor.Dimensions[^2..]])
20+
: base(ProcessChannels(tensor), [1, 4, .. tensor.Dimensions[^2..]])
2021
{
2122
ThrowIfInvalid();
2223
}
@@ -175,6 +176,55 @@ public ImageTensor CloneAs()
175176
return Clone().AsImageTensor();
176177
}
177178

179+
180+
/// <summary>
181+
/// Gets the RGBA pixel from ImageTensor
182+
/// </summary>
183+
/// <param name="imageTensor">The image tensor.</param>
184+
/// <param name="x">The x.</param>
185+
/// <param name="y">The y.</param>
186+
/// <returns>ImagePixel.</returns>
187+
/// <exception cref="System.ArgumentOutOfRangeException">Pixel ({x},{y}) out of range ({imageTensor.Width}x{imageTensor.Height}).</exception>
188+
public ImagePixel GetPixel(int x, int y)
189+
{
190+
if (x >= Width || y >= Height)
191+
throw new ArgumentOutOfRangeException($"Pixel ({x},{y}) out of range ({Width}x{Height}).");
192+
193+
var pixelIndex = y * Width + x;
194+
var span = Memory.Span;
195+
var stride = Height * Width;
196+
return new ImagePixel(
197+
span[0 * stride + pixelIndex],
198+
span[1 * stride + pixelIndex],
199+
span[2 * stride + pixelIndex],
200+
span[3 * stride + pixelIndex]
201+
);
202+
}
203+
204+
205+
/// <summary>
206+
/// Sets the RGBA pixel for ImageTensor
207+
/// </summary>
208+
/// <param name="imageTensor">The image tensor.</param>
209+
/// <param name="x">The x.</param>
210+
/// <param name="y">The y.</param>
211+
/// <param name="color">The color.</param>
212+
/// <exception cref="System.ArgumentOutOfRangeException">Pixel ({x},{y}) out of range ({imageTensor.Width}x{imageTensor.Height}).</exception>
213+
public void SetPixel(int x, int y, ImagePixel color)
214+
{
215+
if (x >= Width || y >= Height)
216+
throw new ArgumentOutOfRangeException($"Pixel ({x},{y}) out of range ({Width}x{Height}).");
217+
218+
int pixelIndex = y * Width + x;
219+
var span = Memory.Span;
220+
int stride = Height * Width;
221+
span[0 * stride + pixelIndex] = color.R;
222+
span[1 * stride + pixelIndex] = color.G;
223+
span[2 * stride + pixelIndex] = color.B;
224+
span[3 * stride + pixelIndex] = color.A;
225+
}
226+
227+
178228
/// <summary>
179229
/// Throws if Dimensions are invalid.
180230
/// </summary>

TensorStack.Image.Bitmap/Extensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Drawing;
44
using System.Drawing.Imaging;
55
using System.Threading.Tasks;
6+
using TensorStack.Common;
67
using TensorStack.Common.Tensor;
78

89
namespace TensorStack.Image

TensorStack.Image.BitmapImage/Extensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Windows;
66
using System.Windows.Media;
77
using System.Windows.Media.Imaging;
8+
using TensorStack.Common;
89
using TensorStack.Common.Tensor;
910

1011
namespace TensorStack.Image

TensorStack.Image.ImageSharp/Extensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using SixLabors.ImageSharp;
44
using SixLabors.ImageSharp.PixelFormats;
55
using System.Threading.Tasks;
6+
using TensorStack.Common;
67
using TensorStack.Common.Tensor;
78

89
namespace TensorStack.Image

TensorStack.Image/Extensions.cs

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

0 commit comments

Comments
 (0)