diff --git a/src/TensorFlowNET.Core/APIs/tf.array.cs b/src/TensorFlowNET.Core/APIs/tf.array.cs index f2402a6f..df8e69c3 100644 --- a/src/TensorFlowNET.Core/APIs/tf.array.cs +++ b/src/TensorFlowNET.Core/APIs/tf.array.cs @@ -139,5 +139,16 @@ namespace Tensorflow /// public Tensor shape(Tensor input, string name = null, TF_DataType out_type = TF_DataType.TF_INT32) => array_ops.shape_internal(input, name, optimize: true, out_type: out_type); + + /// + /// Unpacks the given dimension of a rank-`R` tensor into rank-`(R-1)` tensors. + /// + /// + /// + /// + /// + /// + public Tensor[] unstack(Tensor value, int? num = null, int axis = 0, string name = "unstack") + => array_ops.unstack(value, num: num, axis: axis, name: name); } } diff --git a/src/TensorFlowNET.Core/APIs/tf.image.cs b/src/TensorFlowNET.Core/APIs/tf.image.cs index 832010e5..57b8b093 100644 --- a/src/TensorFlowNET.Core/APIs/tf.image.cs +++ b/src/TensorFlowNET.Core/APIs/tf.image.cs @@ -40,6 +40,11 @@ namespace Tensorflow public Tensor resize_bilinear(Tensor images, Tensor size, bool align_corners = false, string name = null) => gen_image_ops.resize_bilinear(images, size, align_corners: align_corners, name: name); + public Tensor resize_images(Tensor images, Tensor size, ResizeMethod method = ResizeMethod.BILINEAR, + bool align_corners = false, bool preserve_aspect_ratio = false, string name = null) + => image_ops_impl.resize_images(images, size, method: method, + align_corners: align_corners, preserve_aspect_ratio: preserve_aspect_ratio, name: name); + public Tensor convert_image_dtype(Tensor image, TF_DataType dtype, bool saturate = false, string name = null) => gen_image_ops.convert_image_dtype(image, dtype, saturate: saturate, name: name); diff --git a/src/TensorFlowNET.Core/Operations/array_ops.py.cs b/src/TensorFlowNET.Core/Operations/array_ops.py.cs index 83a469dc..c52e2821 100644 --- a/src/TensorFlowNET.Core/Operations/array_ops.py.cs +++ b/src/TensorFlowNET.Core/Operations/array_ops.py.cs @@ -308,6 +308,18 @@ namespace Tensorflow public static (Tensor, Tensor) unique(Tensor x, TF_DataType out_idx = TF_DataType.TF_INT32, string name = null) => gen_array_ops.unique(x, out_idx: out_idx, name: name); + public static Tensor[] unstack(Tensor value, int? num = null, int axis = 0, string name = "unstack") + { + if(num == null) + { + value = ops.convert_to_tensor(value); + var value_shape = value.TensorShape; + num = value_shape.dims[axis]; + } + + return gen_array_ops.unpack(value, num: num.Value, axis: axis, name: name); + } + public static Tensor where(Tensor condition, object x = null, object y = null, string name = null) { if( x == null && y == null) diff --git a/src/TensorFlowNET.Core/Operations/gen_array_ops.cs b/src/TensorFlowNET.Core/Operations/gen_array_ops.cs index ea020599..3e9ce699 100644 --- a/src/TensorFlowNET.Core/Operations/gen_array_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_array_ops.cs @@ -248,6 +248,12 @@ namespace Tensorflow return (_op.outputs[0], _op.outputs[1]); } + public static Tensor[] unpack(Tensor value, int num, int axis = 0, string name = null) + { + var _op = _op_def_lib._apply_op_helper("Unpack", name, new { value, num, axis }); + return _op.outputs; + } + public static Tensor where() { throw new NotImplementedException("where"); diff --git a/src/TensorFlowNET.Core/Operations/image_ops_impl.cs b/src/TensorFlowNET.Core/Operations/image_ops_impl.cs index 6cf9f77e..b7573b92 100644 --- a/src/TensorFlowNET.Core/Operations/image_ops_impl.cs +++ b/src/TensorFlowNET.Core/Operations/image_ops_impl.cs @@ -129,6 +129,22 @@ namespace Tensorflow throw new NotImplementedException(""); } + /// + /// Resize `images` to `size` using the specified `method`. + /// + /// + /// + /// + /// + /// + /// + /// + public static Tensor resize_images(Tensor images, Tensor size, ResizeMethod method = ResizeMethod.BILINEAR, + bool align_corners = false, bool preserve_aspect_ratio = false, string name = null) + { + throw new NotImplementedException(""); + } + /// /// Resize `images` to `size` using nearest neighbor interpolation. /// @@ -146,4 +162,12 @@ namespace Tensorflow half_pixel_centers: half_pixel_centers, name: name); } + + public enum ResizeMethod + { + BILINEAR = 0, + NEAREST_NEIGHBOR = 1, + BICUBIC = 2, + AREA = 3 + } } diff --git a/src/TensorFlowNET.Core/Tensors/shape_utils.cs b/src/TensorFlowNET.Core/Tensors/shape_utils.cs new file mode 100644 index 00000000..859d931b --- /dev/null +++ b/src/TensorFlowNET.Core/Tensors/shape_utils.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using static Tensorflow.Binding; + +namespace Tensorflow +{ + public class shape_utils + { + public static Tensor static_or_dynamic_map_fn(Func fn, Tensor elems, TF_DataType dtype = TF_DataType.DtInvalid, + int parallel_iterations = 32, bool back_prop = true) + { + var outputs = tf.unstack(elems).Select(arg => fn(arg)).ToArray(); + + throw new NotImplementedException(""); + } + } +} diff --git a/src/TensorFlowNET.Models/ObjectDetection/Core/Preprocessor.cs b/src/TensorFlowNET.Models/ObjectDetection/Core/Preprocessor.cs new file mode 100644 index 00000000..ac3cc805 --- /dev/null +++ b/src/TensorFlowNET.Models/ObjectDetection/Core/Preprocessor.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Text; +using static Tensorflow.Binding; + +namespace Tensorflow.Models.ObjectDetection.Core +{ + public class Preprocessor + { + public static Tensor[] resize_to_range(ResizeToRangeArgs args) + { + var image = args.image; + var min_dimension = args.min_dimension; + var max_dimension = args.max_dimension; + var method = args.method; + var align_corners = args.align_corners; + + if (image.NDims != 3) + throw new ValueError("Image should be 3D tensor"); + + + Func _resize_landscape_image = (image1) => + { + return tf.image.resize_images(image1, + tf.stack(new[] { min_dimension, max_dimension }), + method: method, + align_corners: align_corners, + preserve_aspect_ratio: true); + }; + Func _resize_portrait_image = (image1) => + { + return tf.image.resize_images(image1, + tf.stack(new[] { min_dimension, max_dimension }), + method: method, + align_corners: align_corners, + preserve_aspect_ratio: true); + }; + + return tf_with(tf.name_scope("ResizeToRange", values: new { image, min_dimension }), delegate + { + Tensor new_image, new_size; + + if (image.TensorShape.is_fully_defined()) + throw new NotImplementedException(""); + else + { + new_image = tf.cond( + tf.less(tf.shape(image)[0], tf.shape(image)[1]), + () => _resize_landscape_image(image), + () => _resize_portrait_image(image)); + new_size = tf.shape(new_image); + } + + if (args.pad_to_max_dimension) + { + throw new NotImplementedException(""); + } + + var result = new List { new_image }; + if (args.masks != null) + throw new NotImplementedException(""); + + result.Add(new_size); + + return result.ToArray(); + }); + } + } +} diff --git a/src/TensorFlowNET.Models/ObjectDetection/Core/ResizeToRangeArgs.cs b/src/TensorFlowNET.Models/ObjectDetection/Core/ResizeToRangeArgs.cs new file mode 100644 index 00000000..2fe799a6 --- /dev/null +++ b/src/TensorFlowNET.Models/ObjectDetection/Core/ResizeToRangeArgs.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; +using static Tensorflow.tensorflow.image_internal; + +namespace Tensorflow.Models.ObjectDetection.Core +{ + public class ResizeToRangeArgs + { + public Tensor image { get; set; } + public int[] masks { get; set; } + public int min_dimension { get; set; } + public int max_dimension { get; set; } + public ResizeMethod method {get;set;} + public bool align_corners { get; set; } + public bool pad_to_max_dimension { get; set; } + public int[] per_channel_pad_value { get; set; } + } +} diff --git a/src/TensorFlowNET.Models/ObjectDetection/MetaArchitectures/FasterRCNNMetaArch.cs b/src/TensorFlowNET.Models/ObjectDetection/MetaArchitectures/FasterRCNNMetaArch.cs index 083d4e4f..beb18198 100644 --- a/src/TensorFlowNET.Models/ObjectDetection/MetaArchitectures/FasterRCNNMetaArch.cs +++ b/src/TensorFlowNET.Models/ObjectDetection/MetaArchitectures/FasterRCNNMetaArch.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using static Tensorflow.Binding; namespace Tensorflow.Models.ObjectDetection { @@ -13,8 +14,23 @@ namespace Tensorflow.Models.ObjectDetection _args = args; } - public (Tensor, Tensor) preprocess(Tensor tensor) + /// + /// Feature-extractor specific preprocessing. + /// + /// + /// + public (Tensor, Tensor) preprocess(Tensor inputs) { + tf_with(tf.name_scope("Preprocessor"), delegate + { + /*var outputs = shape_utils.static_or_dynamic_map_fn( + _image_resizer_fn, + elems: inputs, + dtype: new[] { tf.float32, tf.int32 }, + parallel_iterations: _parallel_iterations);*/ + + }); + throw new NotImplementedException(""); } }