using System.Threading; using UnityEngine; #if TFLITE_UNITASK_ENABLED using Cysharp.Threading.Tasks; #endif // TFLITE_UNITASK_ENABLED namespace TensorFlowLite { /// /// Base class for predictor that takes a Texture as an input /// /// A type of input tensor (float, sbyte etc.) [System.Obsolete("BaseImagePredictor is obsolete, use BaseVisionTask instead")] public abstract class BaseImagePredictor : System.IDisposable where T : struct { protected readonly Interpreter interpreter; protected readonly int width; protected readonly int height; protected readonly int channels; protected readonly T[,,] inputTensor; protected readonly TextureToTensor tex2tensor; protected readonly TextureResizer resizer; protected TextureResizer.ResizeOptions resizeOptions; public Texture inputTex { get { return (tex2tensor.texture != null) ? tex2tensor.texture as Texture : resizer.texture as Texture; } } public Material transformMat => resizer.material; public TextureResizer.ResizeOptions ResizeOptions { get => resizeOptions; set => resizeOptions = value; } public BaseImagePredictor(byte[] modelData, InterpreterOptions options) { try { interpreter = new Interpreter(modelData, options); } catch (System.Exception e) { interpreter?.Dispose(); throw e; } #if UNITY_EDITOR interpreter.LogIOInfo(); #endif // Initialize inputs { var inputShape0 = interpreter.GetInputTensorInfo(0).shape; height = inputShape0[1]; width = inputShape0[2]; channels = inputShape0[3]; inputTensor = new T[height, width, channels]; int inputCount = interpreter.GetInputTensorCount(); for (int i = 0; i < inputCount; i++) { int[] shape = interpreter.GetInputTensorInfo(i).shape; interpreter.ResizeInputTensor(i, shape); } interpreter.AllocateTensors(); } tex2tensor = new TextureToTensor(); resizer = new TextureResizer(); resizeOptions = new TextureResizer.ResizeOptions() { aspectMode = AspectMode.Fill, rotationDegree = 0, mirrorHorizontal = false, mirrorVertical = false, width = width, height = height, }; } public BaseImagePredictor(string modelPath, InterpreterOptions options) : this(FileUtil.LoadFile(modelPath), options) { } public BaseImagePredictor(string modelPath, TfLiteDelegateType delegateType) : this(modelPath, CreateOptions(delegateType)) { } protected static InterpreterOptions CreateOptions(TfLiteDelegateType delegateType) { var options = new InterpreterOptions(); options.AutoAddDelegate(delegateType, typeof(T)); return options; } public virtual void Dispose() { interpreter?.Dispose(); tex2tensor?.Dispose(); resizer?.Dispose(); } public abstract void Invoke(Texture inputTex); protected void ToTensor(Texture inputTex, float[,,] inputs) { RenderTexture tex = resizer.Resize(inputTex, resizeOptions); tex2tensor.ToTensor(tex, inputs); } protected void ToTensor(RenderTexture inputTex, float[,,] inputs, bool resize) { RenderTexture tex = resize ? resizer.Resize(inputTex, resizeOptions) : inputTex; tex2tensor.ToTensor(tex, inputs); } protected void ToTensor(Texture inputTex, float[,,] inputs, float offset, float scale) { RenderTexture tex = resizer.Resize(inputTex, resizeOptions); tex2tensor.ToTensor(tex, inputs, offset, scale); } protected void ToTensor(Texture inputTex, byte[,,] inputs) { RenderTexture tex = resizer.Resize(inputTex, resizeOptions); tex2tensor.ToTensor(tex, inputs); } protected void ToTensor(Texture inputTex, int[,,] inputs) { RenderTexture tex = resizer.Resize(inputTex, resizeOptions); tex2tensor.ToTensor(tex, inputs); } // ToTensorAsync methods are only available when UniTask is installed via Unity Package Manager. // TODO: consider using native Task or Unity Coroutine #if TFLITE_UNITASK_ENABLED protected async UniTask ToTensorAsync(Texture inputTex, float[,,] inputs, CancellationToken cancellationToken) { RenderTexture tex = resizer.Resize(inputTex, resizeOptions); await tex2tensor.ToTensorAsync(tex, inputs, cancellationToken); return true; } protected async UniTask ToTensorAsync(RenderTexture inputTex, float[,,] inputs, bool resize, CancellationToken cancellationToken) { RenderTexture tex = resize ? resizer.Resize(inputTex, resizeOptions) : inputTex; await tex2tensor.ToTensorAsync(tex, inputs, cancellationToken); return true; } protected async UniTask ToTensorAsync(Texture inputTex, byte[,,] inputs, CancellationToken cancellationToken) { RenderTexture tex = resizer.Resize(inputTex, resizeOptions); await tex2tensor.ToTensorAsync(tex, inputs, cancellationToken); return true; } protected async UniTask ToTensorAsync(Texture inputTex, int[,,] inputs, CancellationToken cancellationToken) { RenderTexture tex = resizer.Resize(inputTex, resizeOptions); await tex2tensor.ToTensorAsync(tex, inputs, cancellationToken); return true; } #endif // TFLITE_UNITASK_ENABLED } }