diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 31a0bedb..b696517f 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,10 +7,16 @@ - Fixed return type of LengthSquared for integer-based vectors. Now returns an integer instead of double. - Added missing readonly modifiers for structs - Renamed CIeLuvf to CieLuvf +- Cleanup of `PixImage` and `PixVolume`: + - Deprecated `Array` in favor of `Data` + - Deprecated `PixImage.IntStride` in favor of `Stride` and `StrideL` + - `PixVolume` implements `IPixImage3d` + - Added `PixVolume.BytesPerChannel` + - Added `PixVolume.ToCanonicalDenseLayout` + - Removed obsolete loading API - Removed obsolete API: - [Color] obsolete conversion functions - [Color] `Parse()` overload with IFormatProvider parameter - - [PixImage] obsolete loading API - `Async.AwaitTask` (already in FSharp.Core) - `Caching.cacheFunction` - `IDictionary.GetValueOrDefault` diff --git a/src/Aardvark.Base.Tensors.CSharp/PixImage/PixImage.cs b/src/Aardvark.Base.Tensors.CSharp/PixImage/PixImage.cs index f28568e5..46bab405 100644 --- a/src/Aardvark.Base.Tensors.CSharp/PixImage/PixImage.cs +++ b/src/Aardvark.Base.Tensors.CSharp/PixImage/PixImage.cs @@ -6,7 +6,6 @@ using System.Reflection; using System.Text; using System.Threading; -using System.Drawing; namespace Aardvark.Base { @@ -179,7 +178,7 @@ public static List GetLoaders() { lock (s_loaders) { - var list = s_loaders.ToList(); + var list = s_loaders.ToList(); list.Sort((x, y) => y.Value - x.Value); return list.Map(x => x.Key); } @@ -299,17 +298,47 @@ public PixImage(Col.Format format) #region Properties - public PixImageInfo Info { get { return new PixImageInfo(PixFormat, Size); } } + public abstract Array Data { get; } + + public abstract PixFormat PixFormat { get; } + + public abstract VolumeInfo VolumeInfo { get; } + + public abstract int BytesPerChannel { get; } + + public PixImageInfo Info => new PixImageInfo(PixFormat, Size); /// /// Size.X * Size.Y. /// - public int NumberOfPixels { get { return Size.X * Size.Y; } } + public int NumberOfPixels => Size.X * Size.Y; /// /// Width/height. /// - public double AspectRatio { get { return Size.X / (double)Size.Y; } } + public double AspectRatio => Size.X / (double)Size.Y; + + public V2i Size => (V2i)VolumeInfo.Size.XY; + + public V2l SizeL => VolumeInfo.Size.XY; + + public int ChannelCount => (int)VolumeInfo.Size.Z; + + public long ChannelCountL => VolumeInfo.Size.Z; + + public int Stride => BytesPerChannel * (int)VolumeInfo.DY; + + public long StrideL => BytesPerChannel * VolumeInfo.DY; + + #region Obsolete + + [Obsolete("Use Data instead.")] + public Array Array => Data; + + [Obsolete("Use Stride instead.")] + public int IntStride => Stride; + + #endregion #endregion @@ -650,7 +679,7 @@ public void SaveAsJpeg(string filename, int quality = PixJpegSaveParams.DefaultQ /// The loader to use, or null if no specific loader is to be used. /// if the image could not be saved. public void SaveAsPng(string filename, int compressionLevel = PixPngSaveParams.DefaultCompressionLevel, - bool normalizeFilename = true, IPixLoader loader = null) + bool normalizeFilename = true, IPixLoader loader = null) => Save(filename, new PixPngSaveParams(compressionLevel), normalizeFilename, loader); #endregion @@ -809,6 +838,8 @@ public static PixImageInfo GetInfoFromStream(Stream stream, IPixLoader loader = public PixImage ToPixImage() => AsPixImage() ?? new PixImage(this); + public abstract PixImage ToPixImage(Col.Format format); + public PixImage ToPixImage(Col.Format format) { if (this is PixImage castImage && castImage.Format == format && castImage.ChannelCount == format.ChannelCount()) @@ -816,60 +847,34 @@ public PixImage ToPixImage(Col.Format format) return new PixImage(format, this); } - #endregion - - #region Abstract Methods - - public abstract PixFormat PixFormat { get; } - - public abstract VolumeInfo VolumeInfo { get; } - - public abstract V2i Size { get; } - public abstract V2l SizeL { get; } - - public abstract int ChannelCount { get; } - public abstract long ChannelCountL { get; } + public abstract PixImage ToCanonicalDenseLayout(); - public abstract Array Array { get; } + #endregion - public abstract int IntStride { get; } + #region Copy public abstract void CopyChannelTo(long channelIndex, Matrix target); public abstract void CopyVolumeTo(Volume target); - public abstract PixImage ToPixImage(Col.Format format); - public abstract PixImage CopyToPixImage(); public abstract PixImage CopyToPixImageWithCanonicalDenseLayout(); - public abstract PixImage ToCanonicalDenseLayout(); - - public abstract Array Data { get; } - - public abstract T Visit(IPixImageVisitor visitor); #endregion - #region Image Manipulation (abstract) + #region Image Manipulation public abstract PixImage Transformed(ImageTrafo trafo); - public abstract PixImage RemappedPixImage( - Matrix xMap, Matrix yMap, - ImageInterpolation ip = ImageInterpolation.Cubic); + public abstract PixImage RemappedPixImage(Matrix xMap, Matrix yMap, ImageInterpolation ip = ImageInterpolation.Cubic); - public abstract PixImage ResizedPixImage( - V2i size, ImageInterpolation ip = ImageInterpolation.Cubic); + public abstract PixImage ResizedPixImage(V2i size, ImageInterpolation ip = ImageInterpolation.Cubic); - public abstract PixImage RotatedPixImage( - double angleInRadiansCCW, bool resize = true, - ImageInterpolation ip = ImageInterpolation.Cubic); + public abstract PixImage RotatedPixImage(double angleInRadiansCCW, bool resize = true, ImageInterpolation ip = ImageInterpolation.Cubic); - public abstract PixImage ScaledPixImage( - V2d scaleFactor, - ImageInterpolation ip = ImageInterpolation.Cubic); + public abstract PixImage ScaledPixImage(V2d scaleFactor, ImageInterpolation ip = ImageInterpolation.Cubic); #endregion @@ -915,6 +920,12 @@ public static void ExpandPixels(PixImage bitImage, PixImage pixImage #endregion + #region IPixImageVisitor + + public abstract T Visit(IPixImageVisitor visitor); + + #endregion + #region IPix public Tr Op(IPixOp op) { return op.PixImage(this); } @@ -927,7 +938,7 @@ public static void ExpandPixels(PixImage bitImage, PixImage pixImage /// is specified as type parameter. /// [Serializable] - public partial class PixImage : PixImage //, IPixImage2d + public partial class PixImage : PixImage { public Volume Volume; @@ -1148,46 +1159,6 @@ public PixImage(Col.Format format, PixImage pixImage) Format = format; } - public PixImage CopyToImageLayout() - { - if (Volume.HasImageLayout()) - return new PixImage(Format, Volume.CopyToImage()); - return new PixImage(this); - } - - public PixImage Copy() => new PixImage(Format, Volume.CopyToImageWindow()); - - public override PixImage CopyToPixImage() => Copy(); - - public override PixImage CopyToPixImageWithCanonicalDenseLayout() => CopyToImageLayout(); - - public override PixImage ToCanonicalDenseLayout() => ToImageLayout(); - - /// - /// Copy function for color conversions. - /// - /// - /// - /// - public PixImage Copy(Func fun) => Copy(fun, Format); - - /// - /// Copy function for color conversions. Note that the - /// new color format must have the same number of channels - /// as the old one, and the result of the supplied conversion - /// function is reinterpreted as a color in the new format. - /// - /// - /// - /// - /// - public PixImage Copy(Func fun, Col.Format format) - { - var mat = GetMatrix().MapWindow(fun); - var vol = new Volume(mat.Data, Volume.Info); - return new PixImage(format, vol); - } - #endregion #region Constructors from File / Stream @@ -1273,15 +1244,13 @@ public static PixImage Create(Col.Format format, params Matrix[] c #region Properties - public override VolumeInfo VolumeInfo => Volume.Info; - - public override V2i Size => (V2i)Volume.Info.Size.XY; + public override Array Data => Volume.Data; - public override V2l SizeL => Volume.Info.Size.XY; + public override PixFormat PixFormat => new PixFormat(typeof(T), Format); - public override int ChannelCount => (int)Volume.Info.Size.Z; + public override VolumeInfo VolumeInfo => Volume.Info; - public override long ChannelCountL => Volume.Info.Size.Z; + public override int BytesPerChannel => typeof(T).GetCLRSize(); /// /// Returns the channels of the image in canonical order: red, green, @@ -1303,12 +1272,6 @@ public IEnumerable> Channels /// public Matrix[] ChannelArray => Channels.ToArray(); - public int BytesPerChannel => System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)); - - public override Array Array => Volume.Data; - - public override int IntStride => BytesPerChannel * (int)Volume.DY; - /// /// Returns the matrix representation of the volume if there is only /// one channel. Fails if there are multiple channels. @@ -1571,10 +1534,75 @@ public void SetResized( #region Conversions - public PixImage ToImageLayout() => !Volume.HasImageLayout() ? new PixImage(Format, this) : this; + public override PixImage ToPixImage(Col.Format format) + { + if (Format == format && ChannelCount == format.ChannelCount()) + return this; + return new PixImage(format, this); + } public PixImage ToFormat(Col.Format format) => Format == format ? this : new PixImage(format, this); + public PixImage ToImageLayout() => !Volume.HasImageLayout() ? new PixImage(Format, this) : this; + + public override PixImage ToCanonicalDenseLayout() => ToImageLayout(); + + #endregion + + #region Copy + + public override void CopyChannelTo(long channelIndex, Matrix target) + { + var subMatrix = GetChannel(channelIndex); + target.Set(subMatrix); + } + + public override void CopyVolumeTo(Volume target) + { + if (Volume is Volume source) + target.Set(source); + else + target.Set(Volume.AsVolume()); + } + + public PixImage CopyToImageLayout() + { + if (Volume.HasImageLayout()) + return new PixImage(Format, Volume.CopyToImage()); + return new PixImage(this); + } + + public PixImage Copy() => new PixImage(Format, Volume.CopyToImageWindow()); + + public override PixImage CopyToPixImage() => Copy(); + + public override PixImage CopyToPixImageWithCanonicalDenseLayout() => CopyToImageLayout(); + + /// + /// Copy function for color conversions. + /// + /// + /// + /// + public PixImage Copy(Func fun) => Copy(fun, Format); + + /// + /// Copy function for color conversions. Note that the + /// new color format must have the same number of channels + /// as the old one, and the result of the supplied conversion + /// function is reinterpreted as a color in the new format. + /// + /// + /// + /// + /// + public PixImage Copy(Func fun, Col.Format format) + { + var mat = GetMatrix().MapWindow(fun); + var vol = new Volume(mat.Data, Volume.Info); + return new PixImage(format, vol); + } + #endregion #region Obtaining Matrices @@ -1625,32 +1653,7 @@ public Matrix GetChannelInFormatOrder(long formatChannelIndex) #endregion - #region Concrete Implementation Of Abstract Functions - - public override PixFormat PixFormat => new PixFormat(typeof(T), Format); - - public override void CopyChannelTo(long channelIndex, Matrix target) - { - var subMatrix = GetChannel(channelIndex); - target.Set(subMatrix); - } - - public override void CopyVolumeTo(Volume target) - { - if (Volume is Volume source) - target.Set(source); - else - target.Set(Volume.AsVolume()); - } - - public override PixImage ToPixImage(Col.Format format) - { - if (Format == format && ChannelCount == format.ChannelCount()) - return this; - return new PixImage(format, this); - } - - public override Array Data => Volume.HasImageLayout() ? Volume.Data : throw new ArgumentException(nameof(Volume)); + #region IPixImageVisitor public override TResult Visit(IPixImageVisitor visitor) => visitor.Visit(this); diff --git a/src/Aardvark.Base.Tensors.CSharp/PixImage/PixVolume.cs b/src/Aardvark.Base.Tensors.CSharp/PixImage/PixVolume.cs index 0e968926..48bc00c1 100644 --- a/src/Aardvark.Base.Tensors.CSharp/PixImage/PixVolume.cs +++ b/src/Aardvark.Base.Tensors.CSharp/PixImage/PixVolume.cs @@ -1,12 +1,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Text; -//#if !__MonoCS__ && !__ANDROID__ -//using System.Windows.Media; -//using System.Windows.Media.Imaging; -//#endif namespace Aardvark.Base { @@ -15,7 +9,7 @@ public interface IPixVolumeVisitor T Visit(PixVolume volume); } - public abstract class PixVolume : IPix + public abstract class PixVolume : IPix, IPixImage3d { public Col.Format Format; @@ -34,7 +28,30 @@ public PixVolume(Col.Format format) #region Properties - public PixVolumeInfo Info { get { return new PixVolumeInfo(PixFormat, Size); } } + public abstract Array Data { get; } + + public abstract PixFormat PixFormat { get; } + + public abstract Tensor4Info Tensor4Info { get; } + + public abstract int BytesPerChannel { get; } + + public PixVolumeInfo Info => new PixVolumeInfo(PixFormat, Size); + + public V3i Size => (V3i)Tensor4Info.Size.XYZ; + + public V3l SizeL => Tensor4Info.Size.XYZ; + + public int ChannelCount => (int)Tensor4Info.Size.W; + + public long ChannelCountL => Tensor4Info.Size.W; + + #region Obsolete + + [Obsolete("Use Data instead.")] + public Array Array => Data; + + #endregion #endregion @@ -72,6 +89,8 @@ private static void ToGray(PixVolume src, object dst, Func toGr public PixVolume ToPixVolume() => AsPixVolume() ?? new PixVolume(this); + public abstract PixVolume ToPixVolume(Col.Format format); + public PixVolume ToPixVolume(Col.Format format) { if (this is PixVolume castVolume && castVolume.Format == format && castVolume.ChannelCount == format.ChannelCount()) @@ -79,32 +98,24 @@ public PixVolume ToPixVolume(Col.Format format) return new PixVolume(format, this); } - #endregion - - #region Abstract Methods - - public abstract PixFormat PixFormat { get; } - - public abstract Tensor4Info Tensor4Info { get; } - - public abstract V3i Size { get; } - - public abstract V3l SizeL { get; } + public abstract PixVolume ToCanonicalDenseLayout(); - public abstract int ChannelCount { get; } + #endregion - public abstract Array Array { get; } + #region Copy public abstract void CopyChannelTo(long channelIndex, Volume target); public abstract void CopyTensor4To(Tensor4 target); - public abstract PixVolume ToPixVolume(Col.Format format); - public abstract PixVolume CopyToPixVolume(); public abstract PixVolume CopyToPixVolumeWithCanonicalDenseLayout(); + #endregion + + #region IPixVolumeVisitor + public abstract TResult Visit(IPixVolumeVisitor visitor); #endregion @@ -116,7 +127,7 @@ public PixVolume ToPixVolume(Col.Format format) #endregion } - public class PixVolume : PixVolume, IPixImage3d + public class PixVolume : PixVolume { public Tensor4 Tensor4; @@ -259,76 +270,17 @@ public PixVolume(Col.Format format, PixVolume pixVolume) Format = format; } - public PixVolume CopyToImageLayout() - { - if (Tensor4.HasImageLayout()) - return new PixVolume(Format, Tensor4.CopyToImage()); - return new PixVolume(this); - } - - public PixVolume Copy() - { - return new PixVolume(Format, Tensor4.CopyToImageWindow()); - } - - public override PixVolume CopyToPixVolume() - { - return Copy(); - } - - public override PixVolume CopyToPixVolumeWithCanonicalDenseLayout() - { - return CopyToImageLayout(); - } - - /// - /// Copy function for color conversions. - /// - /// - /// - /// - public PixImage Copy(Func fun) - { - return Copy(fun, Format); - } - - /// - /// Copy function for color conversions. Note that the - /// new color format must have the same number of channels - /// as the old one, and the result of the supplied conversion - /// function is reinterpreted as a color in the new format. - /// - /// - /// - /// - /// - public PixImage Copy(Func fun, Col.Format format) - { - var mat = GetVolume().MapWindow(fun); - var vol = new Volume(mat.Data, Volume.Info); - return new PixImage(format, vol); - } - #endregion #region Properties - public override Tensor4Info Tensor4Info => Tensor4.Info; + public override Array Data => Tensor4.Data; - public override V3i Size - { - get { return (V3i)Tensor4.Info.Size.XYZ; } - } + public override PixFormat PixFormat => new PixFormat(typeof(T), Format); - public override V3l SizeL - { - get { return Tensor4.Info.Size.XYZ; } - } + public override Tensor4Info Tensor4Info => Tensor4.Info; - public override int ChannelCount - { - get { return (int)Tensor4.Info.Size.W; } - } + public override int BytesPerChannel => typeof(T).GetCLRSize(); /// /// Returns the channels of the image in canonical order: red, green, @@ -348,44 +300,88 @@ public IEnumerable> Channels /// Returns the array containing the cahnnels in canonical order: red, /// green, blue, (alpha). /// - public Volume[] ChannelArray + public Volume[] ChannelArray => Channels.ToArray(); + + /// + /// Returns the volume representation of the tensor4 if there is only + /// one channel. Fails if there are multiple channels. + /// + public Volume Volume => Tensor4.AsVolumeWindow(); + + #endregion + + #region Conversions + + public override PixVolume ToPixVolume(Col.Format format) { - get { return Channels.ToArray(); } + if (Format == format && ChannelCount == format.ChannelCount()) + return this; + return new PixVolume(format, this); } - public int BytesPerChannel + public PixVolume ToFormat(Col.Format format) => Format == format ? this : new PixVolume(format, this); + + public PixVolume ToImageLayout() => !Tensor4.HasImageLayout() ? new PixVolume(Format, this) : this; + + public override PixVolume ToCanonicalDenseLayout() => ToImageLayout(); + + #endregion + + #region Copy + + public override void CopyChannelTo(long channelIndex, Volume target) { - get { return System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)); } + var subMatrix = GetChannel(channelIndex); + target.Set(subMatrix); } - public override Array Array + public override void CopyTensor4To(Tensor4 target) { - get { return Tensor4.Data; } + if (Tensor4 is Tensor4 source) + target.Set(source); + else + target.Set(Tensor4.AsTensor4()); } - /// - /// Returns the volume representation of the tensor4 if there is only - /// one channel. Fails if there are multiple channels. - /// - public Volume Volume + public PixVolume CopyToImageLayout() { - get { return Tensor4.AsVolumeWindow(); } + if (Tensor4.HasImageLayout()) + return new PixVolume(Format, Tensor4.CopyToImage()); + return new PixVolume(this); } - #endregion + public PixVolume Copy() => new PixVolume(Format, Tensor4.CopyToImageWindow()); - #region Conversions + public override PixVolume CopyToPixVolume() => Copy(); - public PixVolume ToImageLayout() + public override PixVolume CopyToPixVolumeWithCanonicalDenseLayout() => CopyToImageLayout(); + + /// + /// Copy function for color conversions. + /// + /// + /// + /// + public PixImage Copy(Func fun) { - if (!Tensor4.HasImageLayout()) - return new PixVolume(Format, this); - else return this; + return Copy(fun, Format); } - public PixVolume ToFormat(Col.Format format) + /// + /// Copy function for color conversions. Note that the + /// new color format must have the same number of channels + /// as the old one, and the result of the supplied conversion + /// function is reinterpreted as a color in the new format. + /// + /// + /// + /// + /// + public PixImage Copy(Func fun, Col.Format format) { - return Format == format ? this : new PixVolume(format, this); + var mat = GetVolume().MapWindow(fun); + var vol = new Volume(mat.Data, Volume.Info); + return new PixImage(format, vol); } #endregion @@ -450,33 +446,7 @@ public Volume GetVolume() #endregion - #region Concrete Implementation Of Abstract Functions - - public override PixFormat PixFormat - { - get { return new PixFormat(typeof(T), Format); } - } - - public override void CopyChannelTo(long channelIndex, Volume target) - { - var subMatrix = GetChannel(channelIndex); - target.Set(subMatrix); - } - - public override void CopyTensor4To(Tensor4 target) - { - if (Tensor4 is Tensor4 source) - target.Set(source); - else - target.Set(Tensor4.AsTensor4()); - } - - public override PixVolume ToPixVolume(Col.Format format) - { - if (Format == format && ChannelCount == format.ChannelCount()) - return this; - return new PixVolume(format, this); - } + #region IPixVolumeVisitor public override TResult Visit(IPixVolumeVisitor visitor) { @@ -484,14 +454,5 @@ public override TResult Visit(IPixVolumeVisitor visitor) } #endregion - - #region IPixImage3d Members - - public Array Data - { - get { return Tensor4.Data; } - } - - #endregion } }