@@ -908,5 +908,103 @@ private class DataPoint
908
908
[ VectorType ( InputSize ) ]
909
909
public double [ ] Features { get ; set ; }
910
910
}
911
+
912
+ public class InMemoryImage
913
+ {
914
+ [ ImageType ( 229 , 299 ) ]
915
+ public Bitmap LoadedImage ;
916
+ public string Label ;
917
+
918
+ public static List < InMemoryImage > LoadFromTsv ( MLContext mlContext , string tsvPath , string imageFolder )
919
+ {
920
+ var inMemoryImages = new List < InMemoryImage > ( ) ;
921
+ var tsvFile = mlContext . Data . LoadFromTextFile ( tsvPath , columns : new [ ]
922
+ {
923
+ new TextLoader . Column ( "ImagePath" , DataKind . String , 0 ) ,
924
+ new TextLoader . Column ( "Label" , DataKind . String , 1 ) ,
925
+ }
926
+ ) ;
927
+
928
+ using ( var cursor = tsvFile . GetRowCursorForAllColumns ( ) )
929
+ {
930
+ var pathBuffer = default ( ReadOnlyMemory < char > ) ;
931
+ var labelBuffer = default ( ReadOnlyMemory < char > ) ;
932
+ var pathGetter = cursor . GetGetter < ReadOnlyMemory < char > > ( tsvFile . Schema [ "ImagePath" ] ) ;
933
+ var labelGetter = cursor . GetGetter < ReadOnlyMemory < char > > ( tsvFile . Schema [ "Label" ] ) ;
934
+ while ( cursor . MoveNext ( ) )
935
+ {
936
+ pathGetter ( ref pathBuffer ) ;
937
+ labelGetter ( ref labelBuffer ) ;
938
+
939
+ var label = labelBuffer . ToString ( ) ;
940
+ var fileName = pathBuffer . ToString ( ) ;
941
+ var imagePath = Path . Combine ( imageFolder , fileName ) ;
942
+
943
+ inMemoryImages . Add (
944
+ new InMemoryImage ( )
945
+ {
946
+ Label = label ,
947
+ LoadedImage = ( Bitmap ) Image . FromFile ( imagePath )
948
+ }
949
+ ) ;
950
+ }
951
+ }
952
+
953
+ return inMemoryImages ;
954
+
955
+ }
956
+ }
957
+
958
+ public class InMemoryImageOutput : InMemoryImage
959
+ {
960
+ [ ImageType ( 100 , 100 ) ]
961
+ public Bitmap ResizedImage ;
962
+ }
963
+
964
+ [ Fact ]
965
+ public void ResizeInMemoryImages ( )
966
+ {
967
+ var mlContext = new MLContext ( seed : 1 ) ;
968
+ var dataFile = GetDataPath ( "images/images.tsv" ) ;
969
+ var imageFolder = Path . GetDirectoryName ( dataFile ) ;
970
+ var dataObjects = InMemoryImage . LoadFromTsv ( mlContext , dataFile , imageFolder ) ;
971
+
972
+ var dataView = mlContext . Data . LoadFromEnumerable < InMemoryImage > ( dataObjects ) ;
973
+ var pipeline = mlContext . Transforms . ResizeImages ( "ResizedImage" , 100 , 100 , nameof ( InMemoryImage . LoadedImage ) ) ;
974
+
975
+ // Check that the output is resized, and that it didn't resize the original image object
976
+ var model = pipeline . Fit ( dataView ) ;
977
+ var resizedDV = model . Transform ( dataView ) ;
978
+ var rowView = resizedDV . Preview ( ) . RowView ;
979
+ var resizedImage = ( Bitmap ) rowView . First ( ) . Values . Last ( ) . Value ;
980
+ Assert . Equal ( 100 , resizedImage . Height ) ;
981
+ Assert . NotEqual ( 100 , dataObjects [ 0 ] . LoadedImage . Height ) ;
982
+
983
+ // Also check usage of prediction Engine
984
+ // And that the references to the original image objects aren't lost
985
+ var predEngine = mlContext . Model . CreatePredictionEngine < InMemoryImage , InMemoryImageOutput > ( model ) ;
986
+ for ( int i = 0 ; i < dataObjects . Count ( ) ; i ++ )
987
+ {
988
+ var prediction = predEngine . Predict ( dataObjects [ i ] ) ;
989
+ Assert . Equal ( 100 , prediction . ResizedImage . Height ) ;
990
+ Assert . NotEqual ( 100 , prediction . LoadedImage . Height ) ;
991
+ Assert . True ( prediction . LoadedImage == dataObjects [ i ] . LoadedImage ) ;
992
+ Assert . False ( prediction . ResizedImage == dataObjects [ i ] . LoadedImage ) ;
993
+ }
994
+
995
+ // Check that the last in-memory image hasn't been disposed
996
+ // By running ResizeImageTransformer (see https://github.com/dotnet/machinelearning/issues/4126)
997
+ bool disposed = false ;
998
+ try
999
+ {
1000
+ int i = dataObjects . Last ( ) . LoadedImage . Height ;
1001
+ }
1002
+ catch
1003
+ {
1004
+ disposed = true ;
1005
+ }
1006
+
1007
+ Assert . False ( disposed , "The last in memory image had been disposed by running ResizeImageTransformer" ) ;
1008
+ }
911
1009
}
912
1010
}
0 commit comments