From ff12efd767af78e28a2a1c94790dee594ee64b8f Mon Sep 17 00:00:00 2001 From: Yael Dekel Date: Wed, 12 Sep 2018 15:46:12 -0700 Subject: [PATCH] Fix bug in pixel extractor transform, and add more unit tests. --- .../ImagePixelExtractorTransform.cs | 16 +- .../VectorToImageTransform.cs | 10 +- test/Microsoft.ML.Tests/ImagesTests.cs | 579 +++++++++++++++++- 3 files changed, 589 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.ML.ImageAnalytics/ImagePixelExtractorTransform.cs b/src/Microsoft.ML.ImageAnalytics/ImagePixelExtractorTransform.cs index f8855688be..fd340c2e46 100644 --- a/src/Microsoft.ML.ImageAnalytics/ImagePixelExtractorTransform.cs +++ b/src/Microsoft.ML.ImageAnalytics/ImagePixelExtractorTransform.cs @@ -505,30 +505,30 @@ private ValueGetter> GetGetterCore(IRow input, int iinfo if (ex.Interleave) { int idst = 0; - for (int y = 0; y < h; ++y) - for (int x = 0; x < w; x++) + for (int x = 0; x < w; x++) + for (int y = 0; y < h; ++y) { - var pb = src.GetPixel(y, x); + var pb = src.GetPixel(x, y); if (vb != null) { - if (a) { vb[idst++] = (byte)0; } + if (a) { vb[idst++] = pb.A; } if (r) { vb[idst++] = pb.R; } if (g) { vb[idst++] = pb.G; } if (b) { vb[idst++] = pb.B; } } else if (!needScale) { - if (a) { vf[idst++] = 0.0f; } + if (a) { vf[idst++] = pb.A; } if (r) { vf[idst++] = pb.R; } if (g) { vf[idst++] = pb.G; } if (b) { vf[idst++] = pb.B; } } else { - if (a) { vf[idst++] = 0.0f; } + if (a) { vf[idst++] = (pb.A - offset) * scale; } if (r) { vf[idst++] = (pb.R - offset) * scale; } - if (g) { vf[idst++] = (pb.B - offset) * scale; } - if (b) { vf[idst++] = (pb.G - offset) * scale; } + if (g) { vf[idst++] = (pb.G - offset) * scale; } + if (b) { vf[idst++] = (pb.B - offset) * scale; } } } Contracts.Assert(idst == size); diff --git a/src/Microsoft.ML.ImageAnalytics/VectorToImageTransform.cs b/src/Microsoft.ML.ImageAnalytics/VectorToImageTransform.cs index b9d35a6cdc..2446b7a7b6 100644 --- a/src/Microsoft.ML.ImageAnalytics/VectorToImageTransform.cs +++ b/src/Microsoft.ML.ImageAnalytics/VectorToImageTransform.cs @@ -386,7 +386,7 @@ private ValueGetter GetterFromType(IRow input, int iinfo, ColInf float alpha = 0; if (ex.Interleave) { - if (ex.Alpha) position++; + if (ex.Alpha) alpha = Convert.ToSingle(values[position++]); if (ex.Red) red = Convert.ToSingle(values[position++]); if (ex.Green) green = Convert.ToSingle(values[position++]); if (ex.Blue) blue = Convert.ToSingle(values[position++]); @@ -405,10 +405,10 @@ private ValueGetter GetterFromType(IRow input, int iinfo, ColInf else { pixel = Color.FromArgb( - (int)((alpha - offset) * scale), - (int)((red - offset) * scale), - (int)((green - offset) * scale), - (int)((blue - offset) * scale)); + ex.Alpha ? (int)Math.Round((alpha - offset) * scale) : 0, + (int)Math.Round((red - offset) * scale), + (int)Math.Round((green - offset) * scale), + (int)Math.Round((blue - offset) * scale)); } dst.SetPixel(x, y, pixel); } diff --git a/test/Microsoft.ML.Tests/ImagesTests.cs b/test/Microsoft.ML.Tests/ImagesTests.cs index 39087b9606..37e2ccd33c 100644 --- a/test/Microsoft.ML.Tests/ImagesTests.cs +++ b/test/Microsoft.ML.Tests/ImagesTests.cs @@ -184,7 +184,7 @@ public void TestGreyscaleTransformImages() } [Fact] - public void TestBackAndForthConversion() + public void TestBackAndForthConversionWithAlphaInterleave() { using (var env = new TlcEnvironment()) { @@ -210,6 +210,9 @@ public void TestBackAndForthConversion() var pixels = ImagePixelExtractorTransform.Create(env, new ImagePixelExtractorTransform.Arguments() { + InterleaveArgb = true, + Offset = 127.5f, + Scale = 2f / 255, Column = new ImagePixelExtractorTransform.Column[1]{ new ImagePixelExtractorTransform.Column() { Source= "ImageCropped", Name = "ImagePixels", UseAlpha=true} } @@ -217,12 +220,15 @@ public void TestBackAndForthConversion() IDataView backToBitmaps = new VectorToImageTransform(env, new VectorToImageTransform.Arguments() { + InterleaveArgb = true, + Offset = -1f, + Scale = 255f / 2, Column = new VectorToImageTransform.Column[1]{ new VectorToImageTransform.Column() { Source= "ImagePixels", Name = "ImageRestored" , ImageHeight=imageHeight, ImageWidth=imageWidth, ContainsAlpha=true} } }, pixels); - var fname = nameof(TestBackAndForthConversion) + "_model.zip"; + var fname = nameof(TestBackAndForthConversionWithAlphaInterleave) + "_model.zip"; var fh = env.CreateOutputFile(fname); using (var ch = env.Start("save")) @@ -250,7 +256,574 @@ public void TestBackAndForthConversion() for (int x = 0; x < imageWidth; x++) for (int y = 0; y < imageHeight; y++) { - Assert.True(croppedBitmap.GetPixel(x, y) == restoredBitmap.GetPixel(x, y)); + var c = croppedBitmap.GetPixel(x, y); + var r = restoredBitmap.GetPixel(x, y); + Assert.True(c == r); + } + } + } + } + Done(); + } + + [Fact] + public void TestBackAndForthConversionWithoutAlphaInterleave() + { + using (var env = new TlcEnvironment()) + { + var imageHeight = 100; + var imageWidth = 130; + var dataFile = GetDataPath("images/images.tsv"); + var imageFolder = Path.GetDirectoryName(dataFile); + var data = env.CreateLoader("Text{col=ImagePath:TX:0 col=Name:TX:1}", new MultiFileSource(dataFile)); + var images = ImageLoaderTransform.Create(env, new ImageLoaderTransform.Arguments() + { + Column = new ImageLoaderTransform.Column[1] + { + new ImageLoaderTransform.Column() { Source= "ImagePath", Name="ImageReal" } + }, + ImageFolder = imageFolder + }, data); + var cropped = ImageResizerTransform.Create(env, new ImageResizerTransform.Arguments() + { + Column = new ImageResizerTransform.Column[1]{ + new ImageResizerTransform.Column() { Source = "ImageReal", Name= "ImageCropped", ImageHeight =imageHeight, ImageWidth = imageWidth, Resizing = ImageResizerTransform.ResizingKind.IsoCrop} + } + }, images); + + var pixels = ImagePixelExtractorTransform.Create(env, new ImagePixelExtractorTransform.Arguments() + { + InterleaveArgb = true, + Offset = 127.5f, + Scale = 2f / 255, + Column = new ImagePixelExtractorTransform.Column[1]{ + new ImagePixelExtractorTransform.Column() { Source= "ImageCropped", Name = "ImagePixels", UseAlpha=false} + } + }, cropped); + + IDataView backToBitmaps = new VectorToImageTransform(env, new VectorToImageTransform.Arguments() + { + InterleaveArgb = true, + Offset = -1f, + Scale = 255f / 2, + Column = new VectorToImageTransform.Column[1]{ + new VectorToImageTransform.Column() { Source= "ImagePixels", Name = "ImageRestored" , ImageHeight=imageHeight, ImageWidth=imageWidth, ContainsAlpha=false} + } + }, pixels); + + var fname = nameof(TestBackAndForthConversionWithoutAlphaInterleave) + "_model.zip"; + + var fh = env.CreateOutputFile(fname); + using (var ch = env.Start("save")) + TrainUtils.SaveModel(env, ch, fh, null, new RoleMappedData(backToBitmaps)); + + backToBitmaps = ModelFileUtils.LoadPipeline(env, fh.OpenReadStream(), new MultiFileSource(dataFile)); + DeleteOutputPath(fname); + + + backToBitmaps.Schema.TryGetColumnIndex("ImageRestored", out int bitmapColumn); + backToBitmaps.Schema.TryGetColumnIndex("ImageCropped", out int cropBitmapColumn); + using (var cursor = backToBitmaps.GetRowCursor((x) => true)) + { + var bitmapGetter = cursor.GetGetter(bitmapColumn); + Bitmap restoredBitmap = default; + + var bitmapCropGetter = cursor.GetGetter(cropBitmapColumn); + Bitmap croppedBitmap = default; + while (cursor.MoveNext()) + { + bitmapGetter(ref restoredBitmap); + Assert.NotNull(restoredBitmap); + bitmapCropGetter(ref croppedBitmap); + Assert.NotNull(croppedBitmap); + for (int x = 0; x < imageWidth; x++) + for (int y = 0; y < imageHeight; y++) + { + var c = croppedBitmap.GetPixel(x, y); + var r = restoredBitmap.GetPixel(x, y); + Assert.True(c.R == r.R && c.G == r.G && c.B == r.B); + } + } + } + } + Done(); + } + + [Fact] + public void TestBackAndForthConversionWithAlphaNoInterleave() + { + using (var env = new TlcEnvironment()) + { + var imageHeight = 100; + var imageWidth = 130; + var dataFile = GetDataPath("images/images.tsv"); + var imageFolder = Path.GetDirectoryName(dataFile); + var data = env.CreateLoader("Text{col=ImagePath:TX:0 col=Name:TX:1}", new MultiFileSource(dataFile)); + var images = ImageLoaderTransform.Create(env, new ImageLoaderTransform.Arguments() + { + Column = new ImageLoaderTransform.Column[1] + { + new ImageLoaderTransform.Column() { Source= "ImagePath", Name="ImageReal" } + }, + ImageFolder = imageFolder + }, data); + var cropped = ImageResizerTransform.Create(env, new ImageResizerTransform.Arguments() + { + Column = new ImageResizerTransform.Column[1]{ + new ImageResizerTransform.Column() { Source = "ImageReal", Name= "ImageCropped", ImageHeight =imageHeight, ImageWidth = imageWidth, Resizing = ImageResizerTransform.ResizingKind.IsoCrop} + } + }, images); + + var pixels = ImagePixelExtractorTransform.Create(env, new ImagePixelExtractorTransform.Arguments() + { + InterleaveArgb = false, + Offset = 127.5f, + Scale = 2f / 255, + Column = new ImagePixelExtractorTransform.Column[1]{ + new ImagePixelExtractorTransform.Column() { Source= "ImageCropped", Name = "ImagePixels", UseAlpha=true} + } + }, cropped); + + IDataView backToBitmaps = new VectorToImageTransform(env, new VectorToImageTransform.Arguments() + { + InterleaveArgb = false, + Offset = -1f, + Scale = 255f / 2, + Column = new VectorToImageTransform.Column[1]{ + new VectorToImageTransform.Column() { Source= "ImagePixels", Name = "ImageRestored" , ImageHeight=imageHeight, ImageWidth=imageWidth, ContainsAlpha=true} + } + }, pixels); + + var fname = nameof(TestBackAndForthConversionWithAlphaNoInterleave) + "_model.zip"; + + var fh = env.CreateOutputFile(fname); + using (var ch = env.Start("save")) + TrainUtils.SaveModel(env, ch, fh, null, new RoleMappedData(backToBitmaps)); + + backToBitmaps = ModelFileUtils.LoadPipeline(env, fh.OpenReadStream(), new MultiFileSource(dataFile)); + DeleteOutputPath(fname); + + + backToBitmaps.Schema.TryGetColumnIndex("ImageRestored", out int bitmapColumn); + backToBitmaps.Schema.TryGetColumnIndex("ImageCropped", out int cropBitmapColumn); + using (var cursor = backToBitmaps.GetRowCursor((x) => true)) + { + var bitmapGetter = cursor.GetGetter(bitmapColumn); + Bitmap restoredBitmap = default; + + var bitmapCropGetter = cursor.GetGetter(cropBitmapColumn); + Bitmap croppedBitmap = default; + while (cursor.MoveNext()) + { + bitmapGetter(ref restoredBitmap); + Assert.NotNull(restoredBitmap); + bitmapCropGetter(ref croppedBitmap); + Assert.NotNull(croppedBitmap); + for (int x = 0; x < imageWidth; x++) + for (int y = 0; y < imageHeight; y++) + { + var c = croppedBitmap.GetPixel(x, y); + var r = restoredBitmap.GetPixel(x, y); + Assert.True(c == r); + } + } + } + } + Done(); + } + + [Fact] + public void TestBackAndForthConversionWithoutAlphaNoInterleave() + { + using (var env = new TlcEnvironment()) + { + var imageHeight = 100; + var imageWidth = 130; + var dataFile = GetDataPath("images/images.tsv"); + var imageFolder = Path.GetDirectoryName(dataFile); + var data = env.CreateLoader("Text{col=ImagePath:TX:0 col=Name:TX:1}", new MultiFileSource(dataFile)); + var images = ImageLoaderTransform.Create(env, new ImageLoaderTransform.Arguments() + { + Column = new ImageLoaderTransform.Column[1] + { + new ImageLoaderTransform.Column() { Source= "ImagePath", Name="ImageReal" } + }, + ImageFolder = imageFolder + }, data); + var cropped = ImageResizerTransform.Create(env, new ImageResizerTransform.Arguments() + { + Column = new ImageResizerTransform.Column[1]{ + new ImageResizerTransform.Column() { Source = "ImageReal", Name= "ImageCropped", ImageHeight =imageHeight, ImageWidth = imageWidth, Resizing = ImageResizerTransform.ResizingKind.IsoCrop} + } + }, images); + + var pixels = ImagePixelExtractorTransform.Create(env, new ImagePixelExtractorTransform.Arguments() + { + InterleaveArgb = false, + Offset = 127.5f, + Scale = 2f / 255, + Column = new ImagePixelExtractorTransform.Column[1]{ + new ImagePixelExtractorTransform.Column() { Source= "ImageCropped", Name = "ImagePixels", UseAlpha=false} + } + }, cropped); + + IDataView backToBitmaps = new VectorToImageTransform(env, new VectorToImageTransform.Arguments() + { + InterleaveArgb = false, + Offset = -1f, + Scale = 255f / 2, + Column = new VectorToImageTransform.Column[1]{ + new VectorToImageTransform.Column() { Source= "ImagePixels", Name = "ImageRestored" , ImageHeight=imageHeight, ImageWidth=imageWidth, ContainsAlpha=false} + } + }, pixels); + + var fname = nameof(TestBackAndForthConversionWithoutAlphaNoInterleave) + "_model.zip"; + + var fh = env.CreateOutputFile(fname); + using (var ch = env.Start("save")) + TrainUtils.SaveModel(env, ch, fh, null, new RoleMappedData(backToBitmaps)); + + backToBitmaps = ModelFileUtils.LoadPipeline(env, fh.OpenReadStream(), new MultiFileSource(dataFile)); + DeleteOutputPath(fname); + + + backToBitmaps.Schema.TryGetColumnIndex("ImageRestored", out int bitmapColumn); + backToBitmaps.Schema.TryGetColumnIndex("ImageCropped", out int cropBitmapColumn); + using (var cursor = backToBitmaps.GetRowCursor((x) => true)) + { + var bitmapGetter = cursor.GetGetter(bitmapColumn); + Bitmap restoredBitmap = default; + + var bitmapCropGetter = cursor.GetGetter(cropBitmapColumn); + Bitmap croppedBitmap = default; + while (cursor.MoveNext()) + { + bitmapGetter(ref restoredBitmap); + Assert.NotNull(restoredBitmap); + bitmapCropGetter(ref croppedBitmap); + Assert.NotNull(croppedBitmap); + for (int x = 0; x < imageWidth; x++) + for (int y = 0; y < imageHeight; y++) + { + var c = croppedBitmap.GetPixel(x, y); + var r = restoredBitmap.GetPixel(x, y); + Assert.True(c.R == r.R && c.G == r.G && c.B == r.B); + } + } + } + } + Done(); + } + + [Fact] + public void TestBackAndForthConversionWithAlphaInterleaveNoOffset() + { + using (var env = new TlcEnvironment()) + { + var imageHeight = 100; + var imageWidth = 130; + var dataFile = GetDataPath("images/images.tsv"); + var imageFolder = Path.GetDirectoryName(dataFile); + var data = env.CreateLoader("Text{col=ImagePath:TX:0 col=Name:TX:1}", new MultiFileSource(dataFile)); + var images = ImageLoaderTransform.Create(env, new ImageLoaderTransform.Arguments() + { + Column = new ImageLoaderTransform.Column[1] + { + new ImageLoaderTransform.Column() { Source= "ImagePath", Name="ImageReal" } + }, + ImageFolder = imageFolder + }, data); + var cropped = ImageResizerTransform.Create(env, new ImageResizerTransform.Arguments() + { + Column = new ImageResizerTransform.Column[1]{ + new ImageResizerTransform.Column() { Source = "ImageReal", Name= "ImageCropped", ImageHeight =imageHeight, ImageWidth = imageWidth, Resizing = ImageResizerTransform.ResizingKind.IsoCrop} + } + }, images); + + var pixels = ImagePixelExtractorTransform.Create(env, new ImagePixelExtractorTransform.Arguments() + { + InterleaveArgb = true, + Column = new ImagePixelExtractorTransform.Column[1]{ + new ImagePixelExtractorTransform.Column() { Source= "ImageCropped", Name = "ImagePixels", UseAlpha=true} + } + }, cropped); + + IDataView backToBitmaps = new VectorToImageTransform(env, new VectorToImageTransform.Arguments() + { + InterleaveArgb = true, + Column = new VectorToImageTransform.Column[1]{ + new VectorToImageTransform.Column() { Source= "ImagePixels", Name = "ImageRestored" , ImageHeight=imageHeight, ImageWidth=imageWidth, ContainsAlpha=true} + } + }, pixels); + + var fname = nameof(TestBackAndForthConversionWithAlphaInterleaveNoOffset) + "_model.zip"; + + var fh = env.CreateOutputFile(fname); + using (var ch = env.Start("save")) + TrainUtils.SaveModel(env, ch, fh, null, new RoleMappedData(backToBitmaps)); + + backToBitmaps = ModelFileUtils.LoadPipeline(env, fh.OpenReadStream(), new MultiFileSource(dataFile)); + DeleteOutputPath(fname); + + + backToBitmaps.Schema.TryGetColumnIndex("ImageRestored", out int bitmapColumn); + backToBitmaps.Schema.TryGetColumnIndex("ImageCropped", out int cropBitmapColumn); + using (var cursor = backToBitmaps.GetRowCursor((x) => true)) + { + var bitmapGetter = cursor.GetGetter(bitmapColumn); + Bitmap restoredBitmap = default; + + var bitmapCropGetter = cursor.GetGetter(cropBitmapColumn); + Bitmap croppedBitmap = default; + while (cursor.MoveNext()) + { + bitmapGetter(ref restoredBitmap); + Assert.NotNull(restoredBitmap); + bitmapCropGetter(ref croppedBitmap); + Assert.NotNull(croppedBitmap); + for (int x = 0; x < imageWidth; x++) + for (int y = 0; y < imageHeight; y++) + { + var c = croppedBitmap.GetPixel(x, y); + var r = restoredBitmap.GetPixel(x, y); + Assert.True(c == r); + } + } + } + } + Done(); + } + + [Fact] + public void TestBackAndForthConversionWithoutAlphaInterleaveNoOffset() + { + using (var env = new TlcEnvironment()) + { + var imageHeight = 100; + var imageWidth = 130; + var dataFile = GetDataPath("images/images.tsv"); + var imageFolder = Path.GetDirectoryName(dataFile); + var data = env.CreateLoader("Text{col=ImagePath:TX:0 col=Name:TX:1}", new MultiFileSource(dataFile)); + var images = ImageLoaderTransform.Create(env, new ImageLoaderTransform.Arguments() + { + Column = new ImageLoaderTransform.Column[1] + { + new ImageLoaderTransform.Column() { Source= "ImagePath", Name="ImageReal" } + }, + ImageFolder = imageFolder + }, data); + var cropped = ImageResizerTransform.Create(env, new ImageResizerTransform.Arguments() + { + Column = new ImageResizerTransform.Column[1]{ + new ImageResizerTransform.Column() { Source = "ImageReal", Name= "ImageCropped", ImageHeight =imageHeight, ImageWidth = imageWidth, Resizing = ImageResizerTransform.ResizingKind.IsoCrop} + } + }, images); + + var pixels = ImagePixelExtractorTransform.Create(env, new ImagePixelExtractorTransform.Arguments() + { + InterleaveArgb = true, + Column = new ImagePixelExtractorTransform.Column[1]{ + new ImagePixelExtractorTransform.Column() { Source= "ImageCropped", Name = "ImagePixels", UseAlpha=false} + } + }, cropped); + + IDataView backToBitmaps = new VectorToImageTransform(env, new VectorToImageTransform.Arguments() + { + InterleaveArgb = true, + Column = new VectorToImageTransform.Column[1]{ + new VectorToImageTransform.Column() { Source= "ImagePixels", Name = "ImageRestored" , ImageHeight=imageHeight, ImageWidth=imageWidth, ContainsAlpha=false} + } + }, pixels); + + var fname = nameof(TestBackAndForthConversionWithoutAlphaInterleaveNoOffset) + "_model.zip"; + + var fh = env.CreateOutputFile(fname); + using (var ch = env.Start("save")) + TrainUtils.SaveModel(env, ch, fh, null, new RoleMappedData(backToBitmaps)); + + backToBitmaps = ModelFileUtils.LoadPipeline(env, fh.OpenReadStream(), new MultiFileSource(dataFile)); + DeleteOutputPath(fname); + + + backToBitmaps.Schema.TryGetColumnIndex("ImageRestored", out int bitmapColumn); + backToBitmaps.Schema.TryGetColumnIndex("ImageCropped", out int cropBitmapColumn); + using (var cursor = backToBitmaps.GetRowCursor((x) => true)) + { + var bitmapGetter = cursor.GetGetter(bitmapColumn); + Bitmap restoredBitmap = default; + + var bitmapCropGetter = cursor.GetGetter(cropBitmapColumn); + Bitmap croppedBitmap = default; + while (cursor.MoveNext()) + { + bitmapGetter(ref restoredBitmap); + Assert.NotNull(restoredBitmap); + bitmapCropGetter(ref croppedBitmap); + Assert.NotNull(croppedBitmap); + for (int x = 0; x < imageWidth; x++) + for (int y = 0; y < imageHeight; y++) + { + var c = croppedBitmap.GetPixel(x, y); + var r = restoredBitmap.GetPixel(x, y); + Assert.True(c.R == r.R && c.G == r.G && c.B == r.B); + } + } + } + } + Done(); + } + + [Fact] + public void TestBackAndForthConversionWithAlphaNoInterleaveNoOffset() + { + using (var env = new TlcEnvironment()) + { + var imageHeight = 100; + var imageWidth = 130; + var dataFile = GetDataPath("images/images.tsv"); + var imageFolder = Path.GetDirectoryName(dataFile); + var data = env.CreateLoader("Text{col=ImagePath:TX:0 col=Name:TX:1}", new MultiFileSource(dataFile)); + var images = ImageLoaderTransform.Create(env, new ImageLoaderTransform.Arguments() + { + Column = new ImageLoaderTransform.Column[1] + { + new ImageLoaderTransform.Column() { Source= "ImagePath", Name="ImageReal" } + }, + ImageFolder = imageFolder + }, data); + var cropped = ImageResizerTransform.Create(env, new ImageResizerTransform.Arguments() + { + Column = new ImageResizerTransform.Column[1]{ + new ImageResizerTransform.Column() { Source = "ImageReal", Name= "ImageCropped", ImageHeight =imageHeight, ImageWidth = imageWidth, Resizing = ImageResizerTransform.ResizingKind.IsoCrop} + } + }, images); + + var pixels = ImagePixelExtractorTransform.Create(env, new ImagePixelExtractorTransform.Arguments() + { + InterleaveArgb = false, + Column = new ImagePixelExtractorTransform.Column[1]{ + new ImagePixelExtractorTransform.Column() { Source= "ImageCropped", Name = "ImagePixels", UseAlpha=true} + } + }, cropped); + + IDataView backToBitmaps = new VectorToImageTransform(env, new VectorToImageTransform.Arguments() + { + InterleaveArgb = false, + Column = new VectorToImageTransform.Column[1]{ + new VectorToImageTransform.Column() { Source= "ImagePixels", Name = "ImageRestored" , ImageHeight=imageHeight, ImageWidth=imageWidth, ContainsAlpha=true} + } + }, pixels); + + var fname = nameof(TestBackAndForthConversionWithAlphaNoInterleaveNoOffset) + "_model.zip"; + + var fh = env.CreateOutputFile(fname); + using (var ch = env.Start("save")) + TrainUtils.SaveModel(env, ch, fh, null, new RoleMappedData(backToBitmaps)); + + backToBitmaps = ModelFileUtils.LoadPipeline(env, fh.OpenReadStream(), new MultiFileSource(dataFile)); + DeleteOutputPath(fname); + + + backToBitmaps.Schema.TryGetColumnIndex("ImageRestored", out int bitmapColumn); + backToBitmaps.Schema.TryGetColumnIndex("ImageCropped", out int cropBitmapColumn); + using (var cursor = backToBitmaps.GetRowCursor((x) => true)) + { + var bitmapGetter = cursor.GetGetter(bitmapColumn); + Bitmap restoredBitmap = default; + + var bitmapCropGetter = cursor.GetGetter(cropBitmapColumn); + Bitmap croppedBitmap = default; + while (cursor.MoveNext()) + { + bitmapGetter(ref restoredBitmap); + Assert.NotNull(restoredBitmap); + bitmapCropGetter(ref croppedBitmap); + Assert.NotNull(croppedBitmap); + for (int x = 0; x < imageWidth; x++) + for (int y = 0; y < imageHeight; y++) + { + var c = croppedBitmap.GetPixel(x, y); + var r = restoredBitmap.GetPixel(x, y); + Assert.True(c == r); + } + } + } + } + Done(); + } + + [Fact] + public void TestBackAndForthConversionWithoutAlphaNoInterleaveNoOffset() + { + using (var env = new TlcEnvironment()) + { + var imageHeight = 100; + var imageWidth = 130; + var dataFile = GetDataPath("images/images.tsv"); + var imageFolder = Path.GetDirectoryName(dataFile); + var data = env.CreateLoader("Text{col=ImagePath:TX:0 col=Name:TX:1}", new MultiFileSource(dataFile)); + var images = ImageLoaderTransform.Create(env, new ImageLoaderTransform.Arguments() + { + Column = new ImageLoaderTransform.Column[1] + { + new ImageLoaderTransform.Column() { Source= "ImagePath", Name="ImageReal" } + }, + ImageFolder = imageFolder + }, data); + var cropped = ImageResizerTransform.Create(env, new ImageResizerTransform.Arguments() + { + Column = new ImageResizerTransform.Column[1]{ + new ImageResizerTransform.Column() { Source = "ImageReal", Name= "ImageCropped", ImageHeight =imageHeight, ImageWidth = imageWidth, Resizing = ImageResizerTransform.ResizingKind.IsoCrop} + } + }, images); + + var pixels = ImagePixelExtractorTransform.Create(env, new ImagePixelExtractorTransform.Arguments() + { + InterleaveArgb = false, + Column = new ImagePixelExtractorTransform.Column[1]{ + new ImagePixelExtractorTransform.Column() { Source= "ImageCropped", Name = "ImagePixels", UseAlpha=false} + } + }, cropped); + + IDataView backToBitmaps = new VectorToImageTransform(env, new VectorToImageTransform.Arguments() + { + InterleaveArgb = false, + Column = new VectorToImageTransform.Column[1]{ + new VectorToImageTransform.Column() { Source= "ImagePixels", Name = "ImageRestored" , ImageHeight=imageHeight, ImageWidth=imageWidth, ContainsAlpha=false} + } + }, pixels); + + var fname = nameof(TestBackAndForthConversionWithoutAlphaNoInterleaveNoOffset) + "_model.zip"; + + var fh = env.CreateOutputFile(fname); + using (var ch = env.Start("save")) + TrainUtils.SaveModel(env, ch, fh, null, new RoleMappedData(backToBitmaps)); + + backToBitmaps = ModelFileUtils.LoadPipeline(env, fh.OpenReadStream(), new MultiFileSource(dataFile)); + DeleteOutputPath(fname); + + + backToBitmaps.Schema.TryGetColumnIndex("ImageRestored", out int bitmapColumn); + backToBitmaps.Schema.TryGetColumnIndex("ImageCropped", out int cropBitmapColumn); + using (var cursor = backToBitmaps.GetRowCursor((x) => true)) + { + var bitmapGetter = cursor.GetGetter(bitmapColumn); + Bitmap restoredBitmap = default; + + var bitmapCropGetter = cursor.GetGetter(cropBitmapColumn); + Bitmap croppedBitmap = default; + while (cursor.MoveNext()) + { + bitmapGetter(ref restoredBitmap); + Assert.NotNull(restoredBitmap); + bitmapCropGetter(ref croppedBitmap); + Assert.NotNull(croppedBitmap); + for (int x = 0; x < imageWidth; x++) + for (int y = 0; y < imageHeight; y++) + { + var c = croppedBitmap.GetPixel(x, y); + var r = restoredBitmap.GetPixel(x, y); + Assert.True(c.R == r.R && c.G == r.G && c.B == r.B); } } }