diff --git a/src/Microsoft.ML.Data/StaticPipe/PipelineColumn.cs b/src/Microsoft.ML.Data/StaticPipe/PipelineColumn.cs
index bf097b9571..91e68c4c30 100644
--- a/src/Microsoft.ML.Data/StaticPipe/PipelineColumn.cs
+++ b/src/Microsoft.ML.Data/StaticPipe/PipelineColumn.cs
@@ -34,7 +34,7 @@ private protected PipelineColumn(Reconciler reconciler, PipelineColumn[] depende
///
/// For representing a non-key, non-vector .
///
- ///
+ /// The scalar item type.
public abstract class Scalar : PipelineColumn
{
protected Scalar(Reconciler reconciler, params PipelineColumn[] dependencies)
@@ -142,4 +142,19 @@ protected VarKey(Reconciler reconciler, params PipelineColumn[] dependencies)
public override string ToString() => $"{nameof(VarKey)}<{typeof(T).Name}>";
}
+
+ ///
+ /// For representing a custom .
+ ///
+ /// The custom item type.
+ public abstract class Custom: PipelineColumn
+ {
+ protected Custom(Reconciler reconciler, params PipelineColumn[] dependencies)
+ : base(reconciler, dependencies)
+ {
+ }
+
+ public override string ToString() => $"{nameof(Custom)}<{typeof(T).Name}>";
+ }
+
}
diff --git a/src/Microsoft.ML.Data/StaticPipe/StaticPipeInternalUtils.cs b/src/Microsoft.ML.Data/StaticPipe/StaticPipeInternalUtils.cs
index 9b0040f3b3..4b61e90957 100644
--- a/src/Microsoft.ML.Data/StaticPipe/StaticPipeInternalUtils.cs
+++ b/src/Microsoft.ML.Data/StaticPipe/StaticPipeInternalUtils.cs
@@ -59,6 +59,7 @@ private sealed class AVarVector : VarVector { public AVarVector(Rec rec) :
private sealed class AKey : Key { public AKey(Rec rec) : base(rec, null) { } }
private sealed class AKey : Key { public AKey(Rec rec) : base(rec, null) { } }
private sealed class AVarKey : VarKey { public AVarKey(Rec rec) : base(rec, null) { } }
+ private sealed class ACustom : Custom { public ACustom(Rec rec) : base(rec, null) { } }
private static PipelineColumn MakeScalar(Rec rec) => new AScalar(rec);
private static PipelineColumn MakeVector(Rec rec) => new AVector(rec);
@@ -67,6 +68,7 @@ private sealed class AVarKey : VarKey { public AVarKey(Rec rec) : base(rec
private static PipelineColumn MakeKey(Rec rec) => new AKey(rec);
private static Key MakeKey(Rec rec) => new AKey(rec);
private static PipelineColumn MakeVarKey(Rec rec) => new AVarKey(rec);
+ private static PipelineColumn MakeCustom(Rec rec) => new ACustom(rec);
private static MethodInfo[] _valueTupleCreateMethod = InitValueTupleCreateMethods();
@@ -121,6 +123,8 @@ public static object MakeAnalysisInstanceCore(Rec rec)
}
if (genT == typeof(VarKey<>))
return Utils.MarshalInvoke(MakeVector, genP[0], rec);
+ if (genT== typeof(Custom<>))
+ return Utils.MarshalInvoke(MakeCustom, genP[0], rec);
}
throw Contracts.Except($"Type {t} is a {nameof(PipelineColumn)} yet does not appear to be directly one of " +
$"the official types. This is commonly due to a mistake by the component author and can be addressed by " +
diff --git a/src/Microsoft.ML.Data/StaticPipe/StaticSchemaShape.cs b/src/Microsoft.ML.Data/StaticPipe/StaticSchemaShape.cs
index df981d25bb..82ae82141f 100644
--- a/src/Microsoft.ML.Data/StaticPipe/StaticSchemaShape.cs
+++ b/src/Microsoft.ML.Data/StaticPipe/StaticSchemaShape.cs
@@ -195,7 +195,7 @@ private static bool IsStandard(IExceptionContext ectx, Type t)
}
var gt = t.IsGenericType ? t.GetGenericTypeDefinition() : t;
if (gt != typeof(Scalar<>) && gt != typeof(Key<>) && gt != typeof(Key<,>) && gt != typeof(VarKey<>) &&
- gt != typeof(Vector<>) && gt != typeof(VarVector<>) && gt != typeof(NormVector<>))
+ gt != typeof(Vector<>) && gt != typeof(VarVector<>) && gt != typeof(NormVector<>) && gt != typeof(Custom<>))
{
throw ectx.ExceptParam(nameof(t),
$"Type {t} was not one of the standard subclasses of {nameof(PipelineColumn)}");
diff --git a/src/Microsoft.ML.ImageAnalytics/ImageGrayscaleTransform.cs b/src/Microsoft.ML.ImageAnalytics/ImageGrayscaleTransform.cs
index f7dd526505..7a2fd6ba43 100644
--- a/src/Microsoft.ML.ImageAnalytics/ImageGrayscaleTransform.cs
+++ b/src/Microsoft.ML.ImageAnalytics/ImageGrayscaleTransform.cs
@@ -240,12 +240,12 @@ private interface IColInput
PipelineColumn Input { get; }
}
- internal sealed class OutPipelineColumn : Scalar, IColInput
+ internal sealed class OutPipelineColumn : Custom, IColInput
{
public PipelineColumn Input { get; }
- public OutPipelineColumn(Scalar input)
- : base(Reconciler.Inst, input)
+ public OutPipelineColumn(Custom input)
+ : base(Reconciler.Inst, input)
{
Contracts.AssertValue(input);
Contracts.Assert(typeof(T) == typeof(Bitmap) || typeof(T) == typeof(UnknownSizeBitmap));
@@ -257,8 +257,8 @@ public OutPipelineColumn(Scalar input)
/// Reconciler to an for the .
///
/// Because we want to use the same reconciler for
- ///
- ///
+ ///
+ ///
private sealed class Reconciler : EstimatorReconciler
{
public static Reconciler Inst = new Reconciler();
diff --git a/src/Microsoft.ML.ImageAnalytics/ImageLoaderTransform.cs b/src/Microsoft.ML.ImageAnalytics/ImageLoaderTransform.cs
index e0ad15bbd5..253bd523d2 100644
--- a/src/Microsoft.ML.ImageAnalytics/ImageLoaderTransform.cs
+++ b/src/Microsoft.ML.ImageAnalytics/ImageLoaderTransform.cs
@@ -242,7 +242,7 @@ public override SchemaShape GetOutputSchema(SchemaShape inputSchema)
return new SchemaShape(result.Values);
}
- internal sealed class OutPipelineColumn : Scalar
+ internal sealed class OutPipelineColumn : Custom
{
private readonly Scalar _input;
diff --git a/src/Microsoft.ML.ImageAnalytics/ImagePixelExtractorTransform.cs b/src/Microsoft.ML.ImageAnalytics/ImagePixelExtractorTransform.cs
index 0a70dee243..c526222501 100644
--- a/src/Microsoft.ML.ImageAnalytics/ImagePixelExtractorTransform.cs
+++ b/src/Microsoft.ML.ImageAnalytics/ImagePixelExtractorTransform.cs
@@ -669,18 +669,18 @@ public override SchemaShape GetOutputSchema(SchemaShape inputSchema)
private interface IColInput
{
- Scalar Input { get; }
+ Custom Input { get; }
ImagePixelExtractorTransform.ColumnInfo MakeColumnInfo(string input, string output);
}
internal sealed class OutPipelineColumn : Vector, IColInput
{
- public Scalar Input { get; }
+ public Custom Input { get; }
private static readonly ImagePixelExtractorTransform.Arguments _defaultArgs = new ImagePixelExtractorTransform.Arguments();
private readonly ImagePixelExtractorTransform.Column _colParam;
- public OutPipelineColumn(Scalar input, ImagePixelExtractorTransform.Column col)
+ public OutPipelineColumn(Custom input, ImagePixelExtractorTransform.Column col)
: base(Reconciler.Inst, input)
{
Contracts.AssertValue(input);
@@ -705,8 +705,8 @@ public ImagePixelExtractorTransform.ColumnInfo MakeColumnInfo(string input, stri
/// Reconciler to an for the .
///
/// Because we want to use the same reconciler for
- ///
- ///
+ ///
+ ///
private sealed class Reconciler : EstimatorReconciler
{
///
diff --git a/src/Microsoft.ML.ImageAnalytics/ImageResizerTransform.cs b/src/Microsoft.ML.ImageAnalytics/ImageResizerTransform.cs
index 4db5d9ac01..83d5c97736 100644
--- a/src/Microsoft.ML.ImageAnalytics/ImageResizerTransform.cs
+++ b/src/Microsoft.ML.ImageAnalytics/ImageResizerTransform.cs
@@ -461,7 +461,7 @@ public override SchemaShape GetOutputSchema(SchemaShape inputSchema)
return new SchemaShape(result.Values);
}
- internal sealed class OutPipelineColumn : Scalar
+ internal sealed class OutPipelineColumn : Custom
{
private readonly PipelineColumn _input;
private readonly int _width;
@@ -487,8 +487,8 @@ private ImageResizerTransform.ColumnInfo MakeColumnInfo(string input, string out
///
/// Reconciler to an for the .
///
- ///
- ///
+ ///
+ ///
private sealed class Reconciler : EstimatorReconciler
{
public static Reconciler Inst = new Reconciler();
diff --git a/src/Microsoft.ML.ImageAnalytics/ImageStaticPipe.cs b/src/Microsoft.ML.ImageAnalytics/ImageStaticPipe.cs
index 829aca3179..daf94f2bc0 100644
--- a/src/Microsoft.ML.ImageAnalytics/ImageStaticPipe.cs
+++ b/src/Microsoft.ML.ImageAnalytics/ImageStaticPipe.cs
@@ -29,7 +29,7 @@ public static class ImageStaticPipe
/// safe for users to simply always make their input paths absolute.
/// The loaded images
///
- public static Scalar LoadAsImage(this Scalar path, string relativeTo = null)
+ public static Custom LoadAsImage(this Scalar path, string relativeTo = null)
{
Contracts.CheckValue(path, nameof(path));
Contracts.CheckValueOrNull(relativeTo);
@@ -42,7 +42,7 @@ public static Scalar LoadAsImage(this Scalar path, st
/// The image to convert
/// The grayscale images
///
- public static Scalar AsGrayscale(this Scalar input)
+ public static Custom AsGrayscale(this Custom input)
{
Contracts.CheckValue(input, nameof(input));
return new ImageGrayscaleEstimator.OutPipelineColumn(input);
@@ -54,7 +54,7 @@ public static Scalar AsGrayscale(this ScalarThe image to convert
/// The grayscale images
///
- public static Scalar AsGrayscale(this Scalar input)
+ public static Custom AsGrayscale(this Custom input)
{
Contracts.CheckValue(input, nameof(input));
return new ImageGrayscaleEstimator.OutPipelineColumn(input);
@@ -70,7 +70,7 @@ public static Scalar AsGrayscale(this Scalar input)
/// If cropping is necessary, at what position will the image be fixed?
/// The now uniformly sized images
///
- public static Scalar Resize(this Scalar input, int width, int height,
+ public static Custom Resize(this Custom input, int width, int height,
ImageResizerTransform.ResizingKind resizing = ImageResizerTransform.ResizingKind.IsoCrop,
ImageResizerTransform.Anchor cropAnchor = ImageResizerTransform.Anchor.Center)
{
@@ -93,7 +93,7 @@ public static Scalar Resize(this Scalar input, int wi
/// If cropping is necessary, at what
/// The resized images
///
- public static Scalar Resize(this Scalar input, int width, int height,
+ public static Custom Resize(this Custom input, int width, int height,
ImageResizerTransform.ResizingKind resizing = ImageResizerTransform.ResizingKind.IsoCrop,
ImageResizerTransform.Anchor cropAnchor = ImageResizerTransform.Anchor.Center)
{
@@ -121,7 +121,7 @@ public static Scalar Resize(this Scalar input, int width, int he
/// Add this amount to the pixel values, before scaling
/// The vectorized image
///
- public static Vector ExtractPixels(this Scalar input, bool useAlpha = false, bool useRed = true,
+ public static Vector ExtractPixels(this Custom input, bool useAlpha = false, bool useRed = true,
bool useGreen = true, bool useBlue = true, bool interleaveArgb = false, float scale = 1.0f, float offset = 0.0f)
{
var colParams = new ImagePixelExtractorTransform.Column
@@ -151,7 +151,7 @@ public static Vector ExtractPixels(this Scalar input, bool useAlp
/// Whether the pixel values should be interleaved, as opposed to being separated by channel
/// The vectorized image
///
- public static Vector ExtractPixelsAsBytes(this Scalar input, bool useAlpha = false, bool useRed = true,
+ public static Vector ExtractPixelsAsBytes(this Custom input, bool useAlpha = false, bool useRed = true,
bool useGreen = true, bool useBlue = true, bool interleaveArgb = false)
{
var colParams = new ImagePixelExtractorTransform.Column
diff --git a/test/Microsoft.ML.StaticPipelineTesting/ImageAnalyticsTests.cs b/test/Microsoft.ML.StaticPipelineTesting/ImageAnalyticsTests.cs
index ad29dbfde5..ea6fee04d3 100644
--- a/test/Microsoft.ML.StaticPipelineTesting/ImageAnalyticsTests.cs
+++ b/test/Microsoft.ML.StaticPipelineTesting/ImageAnalyticsTests.cs
@@ -35,6 +35,11 @@ public void SimpleImageSmokeTest()
Assert.Equal(3, vecType.GetDim(0));
Assert.Equal(8, vecType.GetDim(1));
Assert.Equal(10, vecType.GetDim(2));
+
+ var readAsImage = TextLoader.CreateReader(env,
+ ctx => ctx.LoadText(0).LoadAsImage());
+ var est = readAsImage.MakeNewEstimator().Append(r => r.AsGrayscale().Resize(10, 8).ExtractPixels());
+ var pipe= readAsImage.Append(est);
}
}
}