Search code examples
c#unity-game-enginetensorflowsharp

How to encode .JPG file from a Tensor with TensorFlowSharp?


I want save .JPG image file from a Tensor with TensorFlowSharp. I tried GetValue() to get the value of tensor, but I always met an issue InvalidCastException: Specified cast is not valid.

the issue shown in unity is below:

InvalidCastException: Specified cast is not valid. TensorFlowModel.CallTFmodel.CallTFmodel_Start (System.Byte[] originalbytes, System.String SendPathName) (at Assets/Sample/Glass/Scripts/CallTFmodel.cs:84) Camera2picture+d__9.MoveNext () (at Assets/Sample/Glass/Scripts/Camera2picture.cs:71) UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at /Users/builduser/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)

var runner = session.GetRunner();

// "input", "ps";
runner.AddInput(graph["images"][0], tensorNormalized).Fetch(graph["Tanh"][0]); 
var output = runner.Run();
var result = output[0];

// the issue is happened here. 
byte[] result_bytes = (byte[])result.GetValue(jagged:true); 
// my target is to use GetValue() to transform tensor to array with type byte.
// this line is to write the byte array to a image file.
File.WriteAllBytes(SendPathName, result_bytes); 

My target is to find a way to save a tensor to .JPG image file with TensorFlowSharp, but unfortunately I try many times cannot find a solution to do it.


Solution

  • In TensorflowSharp you can do it like this:

        private byte[] TensorToBitmap(TFTensor image)
        {
            var graph = new TFGraph();
            var input = graph.Placeholder(TFDataType.Float);
            var output = graph.Cast(input, TFDataType.UInt8);
            output = graph.EncodeJpeg(output);
    
            using (var session = new TFSession(graph))
            {
                var result = session.Run(
                    inputs: new[] { input },
                    inputValues: new[] { image },
                    outputs: new[] { output });
    
                var tensor = result[0];
                byte[] buffer = new byte[(int)tensor.TensorByteSize - 10];
                System.Runtime.InteropServices.Marshal.Copy(tensor.Data + 10, buffer, 0, buffer.Length);
                return buffer;
            }
        }
    

    I dont know why, but you have to skip the first 10 bytes.