From 60fafc78722e551590364cd62c2222de5eb24655 Mon Sep 17 00:00:00 2001 From: c q Date: Fri, 26 Apr 2019 11:19:10 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: c q --- src/TensorFlowNET.Core/Sessions/BaseSession.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TensorFlowNET.Core/Sessions/BaseSession.cs b/src/TensorFlowNET.Core/Sessions/BaseSession.cs index 6917ad91..38eb5ba4 100644 --- a/src/TensorFlowNET.Core/Sessions/BaseSession.cs +++ b/src/TensorFlowNET.Core/Sessions/BaseSession.cs @@ -25,6 +25,7 @@ namespace Tensorflow else { _graph = graph; + } _target = UTF8Encoding.UTF8.GetBytes(target); From e67152cf7ff5f2fa1bda3d9c4c7090e27c472dee Mon Sep 17 00:00:00 2001 From: c q Date: Fri, 26 Apr 2019 12:17:08 +0800 Subject: [PATCH 2/3] test commit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 04f29b6e..2c593a42 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # TensorFlow.NET TensorFlow.NET provides a .NET Standard binding for [TensorFlow](https://www.tensorflow.org/). It aims to implement the complete Tensorflow API in CSharp which allows .NET developers to develop, train and deploy Machine Learning models with the cross-platform .NET Standard framework. - +Here is a simple test [![Join the chat at https://gitter.im/publiclab/publiclab](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/sci-sharp/community) [![Tensorflow.NET](https://ci.appveyor.com/api/projects/status/wx4td43v2d3f2xj6?svg=true)](https://ci.appveyor.com/project/Haiping-Chen/tensorflow-net) [![codecov](https://codecov.io/gh/SciSharp/NumSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SciSharp/NumSharp) From f8324e87e5bfae151c63fd6dab648137323e763e Mon Sep 17 00:00:00 2001 From: c q Date: Fri, 26 Apr 2019 20:15:54 +0800 Subject: [PATCH 3/3] Add object detection example Add byte type support in Session and Tensor Add pbtxtParser class to utility --- .../Sessions/BaseSession.cs | 7 +- .../Sessions/_FetchMapper.cs | 9 + .../Tensors/Tensor.Creation.cs | 3 +- src/TensorFlowNET.Core/Tensors/Tensor.cs | 1 + .../TensorFlowNET.Examples/ObjectDetection.cs | 173 ++++++++++++++++++ .../TensorFlowNET.Examples.csproj | 1 + .../Utility/PbtxtParser.cs | 74 ++++++++ 7 files changed, 266 insertions(+), 2 deletions(-) create mode 100644 test/TensorFlowNET.Examples/ObjectDetection.cs create mode 100644 test/TensorFlowNET.Examples/Utility/PbtxtParser.cs diff --git a/src/TensorFlowNET.Core/Sessions/BaseSession.cs b/src/TensorFlowNET.Core/Sessions/BaseSession.cs index 38eb5ba4..06862cdb 100644 --- a/src/TensorFlowNET.Core/Sessions/BaseSession.cs +++ b/src/TensorFlowNET.Core/Sessions/BaseSession.cs @@ -25,7 +25,6 @@ namespace Tensorflow else { _graph = graph; - } _target = UTF8Encoding.UTF8.GetBytes(target); @@ -212,6 +211,12 @@ namespace Tensorflow var str = UTF8Encoding.Default.GetString(bytes, 9, bytes[8]); nd = np.array(str).reshape(); break; + case TF_DataType.TF_UINT8: + var _bytes = new byte[tensor.size]; + for (ulong i = 0; i < tensor.size; i++) + _bytes[i] = *(byte*)(offset + (int)(tensor.itemsize * i)); + nd = np.array(_bytes).reshape(ndims); + break; case TF_DataType.TF_INT16: var shorts = new short[tensor.size]; for (ulong i = 0; i < tensor.size; i++) diff --git a/src/TensorFlowNET.Core/Sessions/_FetchMapper.cs b/src/TensorFlowNET.Core/Sessions/_FetchMapper.cs index 6d4b3b40..12a4591b 100644 --- a/src/TensorFlowNET.Core/Sessions/_FetchMapper.cs +++ b/src/TensorFlowNET.Core/Sessions/_FetchMapper.cs @@ -30,6 +30,15 @@ namespace Tensorflow case "Single": nd.SetData(values.Select(x => (float)x).ToArray()); break; + case "NDArray": + // nd.SetData(values.ToArray()); + //NDArray[] arr = new NDArray[values.Count]; + //for (int i=0; i (NDArray)x).ToArray(); + nd = new NDArray(arr); + break; + default: + break; } return nd; diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs index 5f26becd..3b8b65dd 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.Creation.cs @@ -67,7 +67,8 @@ namespace Tensorflow case "Double": Marshal.Copy(nd1.Data(), 0, dotHandle, nd.size); break; - //case "Byte": + case "Byte": + Marshal.Copy(nd1.Data(), 0, dotHandle, nd.size); /*var bb = nd.Data(); var bytes = Marshal.AllocHGlobal(bb.Length); Marshal.Copy(bb, 0, bytes, bb.Length); diff --git a/src/TensorFlowNET.Core/Tensors/Tensor.cs b/src/TensorFlowNET.Core/Tensors/Tensor.cs index 0c2e84d5..46a0e264 100644 --- a/src/TensorFlowNET.Core/Tensors/Tensor.cs +++ b/src/TensorFlowNET.Core/Tensors/Tensor.cs @@ -195,6 +195,7 @@ namespace Tensorflow case "Double": return TF_DataType.TF_DOUBLE; case "Byte": + return TF_DataType.TF_UINT8; case "String": return TF_DataType.TF_STRING; default: diff --git a/test/TensorFlowNET.Examples/ObjectDetection.cs b/test/TensorFlowNET.Examples/ObjectDetection.cs new file mode 100644 index 00000000..8c96c45a --- /dev/null +++ b/test/TensorFlowNET.Examples/ObjectDetection.cs @@ -0,0 +1,173 @@ +using Newtonsoft.Json; +using NumSharp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Tensorflow; +using TensorFlowNET.Examples.Utility; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; + +namespace TensorFlowNET.Examples +{ + + public class ObjectDetection : Python, IExample + { + public int Priority => 7; + public bool Enabled { get; set; } = true; + public string Name => "Image Recognition"; + public float MIN_SCORE = 0.5f; + + string modelDir = "ssd_mobilenet_v1_coco_2018_01_28"; + string imageDir = "images"; + string pbFile = "frozen_inference_graph.pb"; + string labelFile = "mscoco_label_map.pbtxt"; + string picFile = "input.jpg"; + + public bool Run() + { + //buildOutputImage(null); + + // read in the input image + var imgArr = ReadTensorFromImageFile(Path.Join(imageDir, "input.jpg")); + + var graph = new Graph().as_default(); + graph.Import(Path.Join(modelDir, pbFile)); + + var tensorNum = graph.OperationByName("num_detections").outputs[0]; + var tensorBoxes = graph.OperationByName("detection_boxes").outputs[0]; + var tensorScores = graph.OperationByName("detection_scores").outputs[0]; + var tensorClasses = graph.OperationByName("detection_classes").outputs[0]; + + var imgTensor = graph.OperationByName("image_tensor").outputs[0]; + + + + Tensor[] outTensorArr = new Tensor[] { tensorNum, tensorBoxes, tensorScores, tensorClasses }; + + with(tf.Session(graph), sess => + { + var results = sess.run(outTensorArr, new FeedItem(imgTensor, imgArr)); + + //NDArray scores = results.Array.GetValue(2) as NDArray; + + //floatscores.Data(); + NDArray[] resultArr = results.Data(); + + //float[] scores = resultArr[2].Data(); + buildOutputImage(resultArr); + }); + + return true; + } + + public void PrepareData() + { + if (!Directory.Exists(modelDir)) + Directory.CreateDirectory(modelDir); + + if (!File.Exists(Path.Join(modelDir, "ssd_mobilenet_v1_coco.tar.gz"))) + { + // get model file + string url = "http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_2018_01_28.tar.gz"; + + Utility.Web.Download(url, modelDir, "ssd_mobilenet_v1_coco.tar.gz"); + } + + if (!File.Exists(Path.Join(modelDir, "frozen_inference_graph.pb"))) + { + Utility.Compress.ExtractTGZ(Path.Join(modelDir, "ssd_mobilenet_v1_coco.tar.gz"), "./"); + } + + + // download sample picture + if (!Directory.Exists(imageDir)) + Directory.CreateDirectory(imageDir); + + if (!File.Exists(Path.Join(imageDir, "input.jpg"))) + { + string url = $"https://github.com/tensorflow/models/raw/master/research/object_detection/test_images/image2.jpg"; + Utility.Web.Download(url, imageDir, "input.jpg"); + } + + // download the pbtxt file + if (!File.Exists(Path.Join(modelDir, "mscoco_label_map.pbtxt"))) + { + string url = $"https://github.com/tensorflow/models/blob/master/research/object_detection/data/mscoco_label_map.pbtxt"; + Utility.Web.Download(url, modelDir, "mscoco_label_map.pbtxt"); + } + } + + private NDArray ReadTensorFromImageFile(string file_name) + { + return with(tf.Graph().as_default(), graph => + { + var file_reader = tf.read_file(file_name, "file_reader"); + var decodeJpeg = tf.image.decode_jpeg(file_reader, channels: 3, name: "DecodeJpeg"); + var casted = tf.cast(decodeJpeg, TF_DataType.TF_UINT8); + var dims_expander = tf.expand_dims(casted, 0); + return with(tf.Session(graph), sess => sess.run(dims_expander)); + }); + } + + private void buildOutputImage(NDArray[] resultArr) + { + // get pbtxt items + PbtxtItems pbTxtItems = PbtxtParser.ParsePbtxtFile(Path.Join(modelDir, "mscoco_label_map.pbtxt")); + + // get bitmap + Bitmap bitmap = new Bitmap(Path.Join(imageDir, "input.jpg")); + + float[] scores = resultArr[2].Data(); + + for (int i=0; i MIN_SCORE) + { + //var boxes = resultArr[1].Data(); + float[] boxes = resultArr[1].Data(); + float top = boxes[i * 4] * bitmap.Height; + float left = boxes[i * 4 + 1] * bitmap.Width; + float bottom = boxes[i * 4 + 2] * bitmap.Height; + float right = boxes[i * 4 + 3] * bitmap.Width; + + Rectangle rect = new Rectangle() + { + X = (int)left, + Y = (int)top, + Width = (int)(right - left), + Height = (int)(bottom - top) + }; + + float[] ids = resultArr[3].Data(); + + string name = pbTxtItems.items.Where(w => w.id == (int)ids[i]).Select(s=>s.display_name).FirstOrDefault(); + + drawObjectOnBitmap(bitmap, rect, score, name); + } + } + + bitmap.Save(Path.Join(imageDir, "output.jpg")); + } + + private void drawObjectOnBitmap(Bitmap bmp, Rectangle rect, float score, string name) + { + using (Graphics graphic = Graphics.FromImage(bmp)) + { + graphic.SmoothingMode = SmoothingMode.AntiAlias; + + using (Pen pen = new Pen(Color.Red, 2)) + { + graphic.DrawRectangle(pen, rect); + + Point p = new Point(rect.Right + 5, rect.Top + 5); + string text = string.Format("{0}:{1}%", name, (int)(score * 100)); + graphic.DrawString(text, new Font("Verdana", 8), Brushes.Red, p); + } + } + } + } +} diff --git a/test/TensorFlowNET.Examples/TensorFlowNET.Examples.csproj b/test/TensorFlowNET.Examples/TensorFlowNET.Examples.csproj index c7e22315..2920a534 100644 --- a/test/TensorFlowNET.Examples/TensorFlowNET.Examples.csproj +++ b/test/TensorFlowNET.Examples/TensorFlowNET.Examples.csproj @@ -10,6 +10,7 @@ + diff --git a/test/TensorFlowNET.Examples/Utility/PbtxtParser.cs b/test/TensorFlowNET.Examples/Utility/PbtxtParser.cs new file mode 100644 index 00000000..45d6ebb8 --- /dev/null +++ b/test/TensorFlowNET.Examples/Utility/PbtxtParser.cs @@ -0,0 +1,74 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TensorFlowNET.Examples.Utility +{ + public class PbtxtItem + { + public string name { get; set; } + public int id { get; set; } + public string display_name { get; set; } + } + public class PbtxtItems + { + public List items { get; set; } + } + + public class PbtxtParser + { + public static PbtxtItems ParsePbtxtFile(string filePath) + { + string line; + string newText = "{\"items\":["; + + try + { + using (System.IO.StreamReader reader = new System.IO.StreamReader(filePath)) + { + + while ((line = reader.ReadLine()) != null) + { + string newline = string.Empty; + + if (line.Contains("{")) + { + newline = line.Replace("item", "").Trim(); + //newText += line.Insert(line.IndexOf("=") + 1, "\"") + "\","; + newText += newline; + } + else if (line.Contains("}")) + { + newText = newText.Remove(newText.Length - 1); + newText += line; + newText += ","; + } + else + { + newline = line.Replace(":", "\":").Trim(); + newline = "\"" + newline;// newline.Insert(0, "\""); + newline += ","; + + newText += newline; + } + + } + + newText = newText.Remove(newText.Length - 1); + newText += "]}"; + + reader.Close(); + } + + PbtxtItems items = JsonConvert.DeserializeObject(newText); + + return items; + } + catch (Exception ex) + { + return null; + } + } + } +}