From bd8112fc333f4192d1714a58aac111fd17025ce3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 12 Jul 2016 16:52:06 +1000 Subject: [PATCH] Experiment with multipliers. Former-commit-id: 084a071bbe2f57ed8eaa29fc48e77ebf24eb204b Former-commit-id: cf8ca002917043c93bd18c10e21c0005999ef972 Former-commit-id: a7f231eb49f32fe8b3bc9bff312fd9995e2dabbc --- GenericImage/IImageBase.cs | 9 +- GenericImage/IImageProcessor.cs | 76 ++++ GenericImage/IPixelAccessor.cs | 16 +- GenericImage/ImageBase.cs | 40 +- GenericImage/ImageProcessor.cs | 165 ++++++++ GenericImage/PackedVectors/Bgra.cs | 52 +++ GenericImage/PackedVectors/IColor.cs | 37 ++ GenericImage/ProgressEventArgs.cs | 23 + GenericImage/ResizeProcessor.cs | 393 ++++++++++++++++++ src/ImageProcessorCore/PackedVector/Bgra32.cs | 4 +- .../PackedVector/IPackedVector.cs | 22 +- 11 files changed, 804 insertions(+), 33 deletions(-) create mode 100644 GenericImage/IImageProcessor.cs create mode 100644 GenericImage/ImageProcessor.cs create mode 100644 GenericImage/PackedVectors/Bgra.cs create mode 100644 GenericImage/PackedVectors/IColor.cs create mode 100644 GenericImage/ProgressEventArgs.cs create mode 100644 GenericImage/ResizeProcessor.cs diff --git a/GenericImage/IImageBase.cs b/GenericImage/IImageBase.cs index 4e614a628d..d5dac55168 100644 --- a/GenericImage/IImageBase.cs +++ b/GenericImage/IImageBase.cs @@ -2,15 +2,16 @@ { using GenericImage.PackedVectors; - public interface IImageBase - where TPacked : IPackedVector + public interface IImageBase + where TColor : IColor + where TDepth : struct { - TPacked[] Pixels { get; } + TColor[] Pixels { get; } int Width { get; } int Height { get; } - IPixelAccessor Lock(); + IPixelAccessor Lock(); } } diff --git a/GenericImage/IImageProcessor.cs b/GenericImage/IImageProcessor.cs new file mode 100644 index 0000000000..68aecb3be8 --- /dev/null +++ b/GenericImage/IImageProcessor.cs @@ -0,0 +1,76 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace GenericImage +{ + using PackedVectors; + + /// + /// A delegate which is called as progress is made processing an image. + /// + /// The source of the event. + /// An object that contains the event data. + public delegate void ProgressEventHandler(object sender, ProgressEventArgs e); + + /// + /// Encapsulates methods to alter the pixels of an image. + /// + public interface IImageProcessor + { + /// + /// Event fires when each row of the source image has been processed. + /// + /// + /// This event may be called from threads other than the client thread, and from multiple threads simultaneously. + /// Individual row notifications may arrived out of order. + /// + event ProgressEventHandler OnProgress; + + /// + /// Applies the process to the specified portion of the specified . + /// + /// The type of pixels contained within the image. + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// + /// The method keeps the source image unchanged and returns the + /// the result of image processing filter as new image. + /// + /// + /// is null or is null. + /// + /// + /// doesnt fit the dimension of the image. + /// + void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle) + where TColor : IColor, new() where TDepth : struct; + + /// + /// Applies the process to the specified portion of the specified at the specified + /// location and with the specified size. + /// + /// The type of pixels contained within the image. + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// The target width. + /// The target height. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// + /// The method keeps the source image unchanged and returns the + /// the result of image process as new image. + /// + void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle) + where TColor : IColor, new() where TDepth : struct; + } +} diff --git a/GenericImage/IPixelAccessor.cs b/GenericImage/IPixelAccessor.cs index 7eb9b445b6..3ef5887916 100644 --- a/GenericImage/IPixelAccessor.cs +++ b/GenericImage/IPixelAccessor.cs @@ -2,14 +2,22 @@ { using System; - using GenericImage.PackedVectors; - - public interface IPixelAccessor : IDisposable + public interface IPixelAccessor : IDisposable { - IPackedVector this[int x, int y] + TColor this[int x, int y] { get; set; } + + /// + /// Gets the width. + /// + int Width { get; } + + /// + /// Gets the height. + /// + int Height { get; } } } diff --git a/GenericImage/ImageBase.cs b/GenericImage/ImageBase.cs index 9eed0dcccb..e8052d36ca 100644 --- a/GenericImage/ImageBase.cs +++ b/GenericImage/ImageBase.cs @@ -8,21 +8,21 @@ /// Encapsulates the basic properties and methods required to manipulate images /// in different pixel formats. /// - /// - /// The packed vector pixels format. - /// - public abstract class ImageBase - where TPacked : IPackedVector + /// The packed vector pixels format. + /// The bit depth of the image. byte, float, etc. + public abstract class ImageBase : IImageBase + where TColor : IColor + where TDepth : struct { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// protected ImageBase() { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The width of the image in pixels. /// The height of the image in pixels. @@ -36,19 +36,19 @@ this.Width = width; this.Height = height; - this.Pixels = new TPacked[width * height]; + this.Pixels = new TColor[width * height]; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// - /// The other to create this instance from. + /// The other to create this instance from. /// /// - /// Thrown if the given is null. + /// Thrown if the given is null. /// - protected ImageBase(ImageBase other) + protected ImageBase(ImageBase other) { // Guard.NotNull(other, nameof(other), "Other image cannot be null."); @@ -58,14 +58,14 @@ this.FrameDelay = other.FrameDelay; // Copy the pixels. - this.Pixels = new TPacked[this.Width * this.Height]; + this.Pixels = new TColor[this.Width * this.Height]; Array.Copy(other.Pixels, this.Pixels, other.Pixels.Length); } /// /// Gets the pixels as an array of the given packed pixel format. /// - public TPacked[] Pixels { get; private set; } + public TColor[] Pixels { get; private set; } /// /// Gets the width in pixels. @@ -100,6 +100,8 @@ /// public int FrameDelay { get; set; } + + /// /// Sets the pixel array of the image to the given value. /// @@ -114,7 +116,7 @@ /// /// Thrown if the length is not equal to Width * Height. /// - public void SetPixels(int width, int height, TPacked[] pixels) + public void SetPixels(int width, int height, TColor[] pixels) { if (width <= 0) { @@ -151,7 +153,7 @@ /// /// Thrown if the length is not equal to Width * Height. /// - public void ClonePixels(int width, int height, TPacked[] pixels) + public void ClonePixels(int width, int height, TColor[] pixels) { if (width <= 0) { @@ -172,7 +174,7 @@ this.Height = height; // Copy the pixels. - this.Pixels = new TPacked[pixels.Length]; + this.Pixels = new TColor[pixels.Length]; Array.Copy(pixels, this.Pixels, pixels.Length); } @@ -182,7 +184,7 @@ /// It is imperative that the accessor is correctly disposed off after use. /// /// - /// The - public abstract IPixelAccessor Lock(); + /// The + public abstract IPixelAccessor Lock(); } } diff --git a/GenericImage/ImageProcessor.cs b/GenericImage/ImageProcessor.cs new file mode 100644 index 0000000000..18f4966206 --- /dev/null +++ b/GenericImage/ImageProcessor.cs @@ -0,0 +1,165 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace GenericImage +{ + using System; + using System.Threading; + + using GenericImage.PackedVectors; + + /// + /// Allows the application of processors to images. + /// + public abstract class ImageProcessor : IImageProcessor + { + /// + public event ProgressEventHandler OnProgress; + + /// + /// The number of rows processed by a derived class. + /// + private int numRowsProcessed; + + /// + /// The total number of rows that will be processed by a derived class. + /// + private int totalRows; + + /// + public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle) + where TColor : IColor, new() where TDepth : struct + { + try + { + this.OnApply(target, source, target.Bounds, sourceRectangle); + + this.numRowsProcessed = 0; + this.totalRows = sourceRectangle.Height; + + this.Apply(target, source, target.Bounds, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom); + + this.AfterApply(target, source, target.Bounds, sourceRectangle); + } + catch (Exception ex) + { + + throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); + } + } + + /// + public void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle) where TColor : IColor, new() where TDepth : struct + { + try + { + TColor[] pixels = new TColor[width * height]; + target.SetPixels(width, height, pixels); + + // Ensure we always have bounds. + if (sourceRectangle == Rectangle.Empty) + { + sourceRectangle = source.Bounds; + } + + if (targetRectangle == Rectangle.Empty) + { + targetRectangle = target.Bounds; + } + + this.OnApply(target, source, targetRectangle, sourceRectangle); + + this.numRowsProcessed = 0; + this.totalRows = targetRectangle.Height; + + this.Apply(target, source, targetRectangle, sourceRectangle, targetRectangle.Y, targetRectangle.Bottom); + + this.AfterApply(target, source, target.Bounds, sourceRectangle); + } + catch (Exception ex) + { + throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); + } + } + + /// + /// This method is called before the process is applied to prepare the processor. + /// + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// + /// The structure that specifies the portion of the image object to draw. + /// + protected virtual void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + where TColor : IColor, new() where TDepth : struct + { + } + + /// + /// Applies the process to the specified portion of the specified at the specified location + /// and with the specified size. + /// + /// The type of pixels contained within the image. + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// The index of the row within the source image to start processing. + /// The index of the row within the source image to end processing. + /// + /// The method keeps the source image unchanged and returns the + /// the result of image process as new image. + /// + protected abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + where TColor : IColor, new() where TDepth : struct; + + /// + /// This method is called after the process is applied to prepare the processor. + /// + /// The type of pixels contained within the image. + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// + /// The structure that specifies the portion of the image object to draw. + /// + protected virtual void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + where TColor : IColor, new() where TDepth : struct + { + } + + /// + /// Must be called by derived classes after processing a single row. + /// + protected void OnRowProcessed() + { + if (this.OnProgress != null) + { + int currThreadNumRows = Interlocked.Add(ref this.numRowsProcessed, 1); + + // Multi-pass filters process multiple times more rows than totalRows, so update totalRows on the fly + if (currThreadNumRows > this.totalRows) + { + this.totalRows = currThreadNumRows; + } + + // Report progress. This may be on the client's thread, or on a Task library thread. + this.OnProgress(this, new ProgressEventArgs { RowsProcessed = currThreadNumRows, TotalRows = this.totalRows }); + } + } + } +} diff --git a/GenericImage/PackedVectors/Bgra.cs b/GenericImage/PackedVectors/Bgra.cs new file mode 100644 index 0000000000..7b82c0683a --- /dev/null +++ b/GenericImage/PackedVectors/Bgra.cs @@ -0,0 +1,52 @@ +using System; +using System.Numerics; + +namespace GenericImage.PackedVectors +{ + public struct Bgra : IColor4 + where TDepth : struct + { + public TDepth X { get; set; } + + public TDepth Y { get; set; } + + public TDepth Z { get; set; } + + public TDepth W { get; set; } + + public void Add(TColor value) where TColor : IColor + { + throw new NotImplementedException(); + } + + public void Multiply(TColor value) where TColor : IColor + { + throw new NotImplementedException(); + } + + public void Multiply(float value) where TColor : IColor + { + throw new NotImplementedException(); + } + + public void Divide(TColor value) where TColor : IColor + { + throw new NotImplementedException(); + } + + public void PackVector(Vector4 vector) + { + throw new NotImplementedException(); + } + + public Vector4 ToVector() + { + throw new NotImplementedException(); + } + + public byte[] ToBytes() + { + throw new System.NotImplementedException(); + } + } +} diff --git a/GenericImage/PackedVectors/IColor.cs b/GenericImage/PackedVectors/IColor.cs new file mode 100644 index 0000000000..52825d63a6 --- /dev/null +++ b/GenericImage/PackedVectors/IColor.cs @@ -0,0 +1,37 @@ +namespace GenericImage.PackedVectors +{ + using System.Numerics; + + public interface IColor4 : IColor + where T : struct + { + T X { get; set; } + + T Y { get; set; } + + T Z { get; set; } + + T W { get; set; } + } + + public interface IColor : IColor + where TDepth : struct + { + void Add(TColor value) where TColor : IColor; + + void Multiply(TColor value) where TColor : IColor; + + void Multiply(float value) where TColor : IColor; + + void Divide(TColor value) where TColor : IColor; + } + + public interface IColor + { + void PackVector(Vector4 vector); + + Vector4 ToVector(); + + byte[] ToBytes(); + } +} diff --git a/GenericImage/ProgressEventArgs.cs b/GenericImage/ProgressEventArgs.cs new file mode 100644 index 0000000000..5e9a1e9598 --- /dev/null +++ b/GenericImage/ProgressEventArgs.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace GenericImage +{ + /// + /// Contains event data related to the progress made processing an image. + /// + public class ProgressEventArgs : System.EventArgs + { + /// + /// Gets or sets the number of rows processed. + /// + public int RowsProcessed { get; set; } + + /// + /// Gets or sets the total number of rows. + /// + public int TotalRows { get; set; } + } +} \ No newline at end of file diff --git a/GenericImage/ResizeProcessor.cs b/GenericImage/ResizeProcessor.cs new file mode 100644 index 0000000000..9752e2960d --- /dev/null +++ b/GenericImage/ResizeProcessor.cs @@ -0,0 +1,393 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore.Processors +{ + using System; + using System.Numerics; + using System.Threading.Tasks; + + using GenericImage; + + /// + /// Provides methods that allow the resizing of images using various algorithms. + /// + public class ResizeProcessor : ImageProcessor + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The sampler to perform the resize operation. + /// + public ResizeProcessor(IResampler sampler) + { + Guard.NotNull(sampler, nameof(sampler)); + + this.Sampler = sampler; + } + + /// + /// Gets the sampler to perform the resize operation. + /// + public IResampler Sampler { get; } + + /// + /// Gets or sets the horizontal weights. + /// + protected Weights[] HorizontalWeights { get; set; } + + /// + /// Gets or sets the vertical weights. + /// + protected Weights[] VerticalWeights { get; set; } + + /// + protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + { + if (!(this.Sampler is NearestNeighborResampler)) + { + this.HorizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width); + this.VerticalWeights = this.PrecomputeWeights(targetRectangle.Height, sourceRectangle.Height); + } + } + + /// + protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + { + // Jump out, we'll deal with that later. + if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle) + { + return; + } + + int width = target.Width; + int height = target.Height; + int sourceHeight = sourceRectangle.Height; + int targetX = target.Bounds.X; + int targetY = target.Bounds.Y; + int targetRight = target.Bounds.Right; + int targetBottom = target.Bounds.Bottom; + int startX = targetRectangle.X; + int endX = targetRectangle.Right; + bool compand = this.Compand; + + if (this.Sampler is NearestNeighborResampler) + { + // Scaling factors + float widthFactor = sourceRectangle.Width / (float)targetRectangle.Width; + float heightFactor = sourceRectangle.Height / (float)targetRectangle.Height; + + using (IPixelAccessor sourcePixels = source.Lock()) + using (IPixelAccessor targetPixels = target.Lock()) + { + Parallel.For( + startY, + endY, + y => + { + if (targetY <= y && y < targetBottom) + { + // Y coordinates of source points + int originY = (int)((y - startY) * heightFactor); + + for (int x = startX; x < endX; x++) + { + if (targetX <= x && x < targetRight) + { + // X coordinates of source points + int originX = (int)((x - startX) * widthFactor); + targetPixels[x, y] = sourcePixels[originX, originY]; + } + } + + this.OnRowProcessed(); + } + }); + } + + // Break out now. + return; + } + + // Interpolate the image using the calculated weights. + // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm + // First process the columns. Since we are not using multiple threads startY and endY + // are the upper and lower bounds of the source rectangle. + Image firstPass = new Image(target.Width, source.Height); + using (IPixelAccessor sourcePixels = source.Lock()) + using (IPixelAccessor firstPassPixels = firstPass.Lock()) + using (IPixelAccessor targetPixels = target.Lock()) + { + Parallel.For( + 0, + sourceHeight, + y => + { + for (int x = startX; x < endX; x++) + { + if (x >= 0 && x < width) + { + // Ensure offsets are normalised for cropping and padding. + int offsetX = x - startX; + float sum = this.HorizontalWeights[offsetX].Sum; + Weight[] horizontalValues = this.HorizontalWeights[offsetX].Values; + + // Destination color components + //Color destination = new Color(); + + //for (int i = 0; i < sum; i++) + //{ + // Weight xw = horizontalValues[i]; + // int originX = xw.Index; + // Color sourceColor = compand + // ? Color.Expand(sourcePixels[originX, y]) + // : sourcePixels[originX, y]; + + // destination += sourceColor * xw.Value; + //} + + //if (compand) + //{ + // destination = Color.Compress(destination); + //} + + //firstPassPixels[x, y] = destination; + TColor sourceColor; + TColor destination = default(TColor); + + for (int i = 0; i < sum; i++) + { + Weight xw = horizontalValues[i]; + int originX = xw.Index; + sourceColor = sourcePixels[originX, y]; + //Color sourceColor = compand + // ? Color.Expand(sourcePixels[originX, y]) + // : sourcePixels[originX, y]; + //sourceColor.Multiply(xw.Value); + //destination.Add(sourceColor); + //destination += sourceColor * xw.Value; + + sourceColor.Multiply(xw.Value); + destination.Add(sourceColor); + } + + //if (compand) + //{ + // destination = Color.Compress(destination); + //} + //T packed = default(T); + //packed.PackVector(destination); + + firstPassPixels[x, y] = destination; + } + } + }); + + // Now process the rows. + Parallel.For( + startY, + endY, + y => + { + if (y >= 0 && y < height) + { + // Ensure offsets are normalised for cropping and padding. + int offsetY = y - startY; + float sum = this.VerticalWeights[offsetY].Sum; + Weight[] verticalValues = this.VerticalWeights[offsetY].Values; + + for (int x = 0; x < width; x++) + { + // Destination color components + TColor sourceColor; + TColor destination = default(TColor); + + for (int i = 0; i < sum; i++) + { + Weight yw = verticalValues[i]; + int originY = yw.Index; + sourceColor = firstPassPixels[x, originY]; + //Color sourceColor = compand + // ? Color.Expand(firstPassPixels[x, originY]) + // : firstPassPixels[x, originY]; + //Vector4 sourceColor = firstPassPixels[x, originY].ToVector4(); + //destination += sourceColor * yw.Value; + + sourceColor.Multiply(yw.Value); + destination.Add(sourceColor); + } + + //if (compand) + //{ + // destination = Color.Compress(destination); + //} + + //T packed = default(T); + //packed.PackVector(destination); + + targetPixels[x, y] = destination; + } + } + + this.OnRowProcessed(); + }); + + } + } + + /// + protected override void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + { + // Copy the pixels over. + if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle) + { + target.ClonePixels(target.Width, target.Height, source.Pixels); + } + } + + /// + /// Computes the weights to apply at each pixel when resizing. + /// + /// The destination section size. + /// The source section size. + /// + /// The . + /// + protected Weights[] PrecomputeWeights(int destinationSize, int sourceSize) + { + float scale = (float)destinationSize / sourceSize; + IResampler sampler = this.Sampler; + float radius = sampler.Radius; + double left; + double right; + float weight; + int index; + int sum; + + Weights[] result = new Weights[destinationSize]; + + // When shrinking, broaden the effective kernel support so that we still + // visit every source pixel. + if (scale < 1) + { + float width = radius / scale; + float filterScale = 1 / scale; + + // Make the weights slices, one source for each column or row. + for (int i = 0; i < destinationSize; i++) + { + float centre = i / scale; + left = Math.Ceiling(centre - width); + right = Math.Floor(centre + width); + + result[i] = new Weights + { + Values = new Weight[(int)(right - left + 1)] + }; + + for (double j = left; j <= right; j++) + { + weight = sampler.GetValue((float)((centre - j) / filterScale)) / filterScale; + if (j < 0) + { + index = (int)-j; + } + else if (j >= sourceSize) + { + index = (int)((sourceSize - j) + sourceSize - 1); + } + else + { + index = (int)j; + } + + sum = (int)result[i].Sum++; + result[i].Values[sum] = new Weight(index, weight); + } + } + } + else + { + // Make the weights slices, one source for each column or row. + for (int i = 0; i < destinationSize; i++) + { + float centre = i / scale; + left = Math.Ceiling(centre - radius); + right = Math.Floor(centre + radius); + result[i] = new Weights + { + Values = new Weight[(int)(right - left + 1)] + }; + + for (double j = left; j <= right; j++) + { + weight = sampler.GetValue((float)(centre - j)); + if (j < 0) + { + index = (int)-j; + } + else if (j >= sourceSize) + { + index = (int)((sourceSize - j) + sourceSize - 1); + } + else + { + index = (int)j; + } + + sum = (int)result[i].Sum++; + result[i].Values[sum] = new Weight(index, weight); + } + } + } + + return result; + } + + /// + /// Represents the weight to be added to a scaled pixel. + /// + protected struct Weight + { + /// + /// Initializes a new instance of the struct. + /// + /// The index. + /// The value. + public Weight(int index, float value) + { + this.Index = index; + this.Value = value; + } + + /// + /// Gets the pixel index. + /// + public int Index { get; } + + /// + /// Gets the result of the interpolation algorithm. + /// + public float Value { get; } + } + + /// + /// Represents a collection of weights and their sum. + /// + protected class Weights + { + /// + /// Gets or sets the values. + /// + public Weight[] Values { get; set; } + + /// + /// Gets or sets the sum. + /// + public float Sum { get; set; } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessorCore/PackedVector/Bgra32.cs b/src/ImageProcessorCore/PackedVector/Bgra32.cs index 5fdf24e17f..c1119d9c45 100644 --- a/src/ImageProcessorCore/PackedVector/Bgra32.cs +++ b/src/ImageProcessorCore/PackedVector/Bgra32.cs @@ -11,7 +11,7 @@ namespace ImageProcessorCore /// /// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 1. /// - public struct Bgra32 : IPackedVector, IEquatable + public struct Bgra32 : IPackedVector, IEquatable { /// /// Initializes a new instance of the struct. @@ -43,7 +43,7 @@ namespace ImageProcessorCore // The maths are wrong here I just wanted to test the performance to see if the // issues are caused by the Vector transform or something else. - public void Add(IPackedVector value) + public void Add(IPackedVector value) { } diff --git a/src/ImageProcessorCore/PackedVector/IPackedVector.cs b/src/ImageProcessorCore/PackedVector/IPackedVector.cs index e7533a0dd6..bf4556309b 100644 --- a/src/ImageProcessorCore/PackedVector/IPackedVector.cs +++ b/src/ImageProcessorCore/PackedVector/IPackedVector.cs @@ -22,6 +22,8 @@ namespace ImageProcessorCore /// Typically packed in least to greatest significance order. /// T PackedValue { get; set; } + + } /// @@ -29,18 +31,30 @@ namespace ImageProcessorCore /// public interface IPackedVector { - void Add(IPackedVector value); + void Add(U value); - void Subtract(IPackedVector value); + void Subtract(U value); - void Multiply(IPackedVector value); + void Multiply(U value); void Multiply(float value); - void Divide(IPackedVector value); + void Divide(U value); void Divide(float value); + //void Add(IPackedVector value); + + //void Subtract(IPackedVector value); + + //void Multiply(IPackedVector value); + + //void Multiply(float value); + + //void Divide(IPackedVector value); + + //void Divide(float value); + /// /// Sets the packed representation from a . ///