/// <summary>
        /// Constructs and returns an instance of <see cref="AndroidChestXRayAIClient"/>
        /// with the models loaded using the provided <see cref="AssetManager"/>.
        /// </summary>
        /// <param name="assets">An <see cref="AssetManager"/> that can be used to load the model files.</param>
        /// <returns>The constructed <see cref="AndroidChestXRayAIClient"/> instance.</returns>
        public static AndroidChestXRayAIClient NewInstance(AssetManager assets)
        {
            TensorFlowImageModel model = new TensorFlowImageModel(
                assets,
                ModelConstants.AssetPath,
                ModelConstants.InputTensorName,
                new string[] { ModelConstants.OutputNodeName, ModelConstants.ActivationMapNodeName },
                new int[] { Enum.GetValues(typeof(ChestCondition)).Length, CAMProcessor.Rows * CAMProcessor.Cols * CAMProcessor.Channels });

            System.Diagnostics.Debug.WriteLine("ChestXRay TensorFlow ML Model loaded");

            CAMProcessor camProcessor = new CAMProcessor(CAMProcessor.ModelOutputOrder.RCCh);

            return(new AndroidChestXRayAIClient(model, camProcessor));
        }
        /// <summary>
        /// Constructs and returns an instance of <see cref="iOSChestXRayAIClient"/> with the CoreML models loaded.
        /// </summary>
        /// <returns>The constructed <see cref="iOSChestXRayAIClient"/> instance.</returns>
        public static iOSChestXRayAIClient NewInstance()
        {
            CoreMLImageModel scoreModel = new CoreMLImageModel(
                ModelConstants.ScoreModel.ResourceName,
                ModelConstants.ScoreModel.InputFeatureName,
                ModelConstants.ScoreModel.OutputFeatureName);

            System.Diagnostics.Debug.WriteLine($"{ModelConstants.ScoreModel.ResourceName} CoreML Model loaded");

            CoreMLImageModel camModel = new CoreMLImageModel(
                ModelConstants.CAMModel.ResourceName,
                ModelConstants.CAMModel.InputFeatureName,
                ModelConstants.CAMModel.OutputFeatureName);

            System.Diagnostics.Debug.WriteLine($"{ModelConstants.CAMModel.ResourceName} CoreML Model loaded");

            CAMProcessor camProcessor = new CAMProcessor(CAMProcessor.ModelOutputOrder.ChRC);

            return(new iOSChestXRayAIClient(scoreModel, camModel, camProcessor));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="AndroidChestXRayAIClient"> class.
 /// This constructor is private since this class is responsible for both instantiating and disposing of the IAIImageModel objects,
 /// so we want to limit the instantiation of this class to within this class itself (to prevent externally created IAIImageModel objects from being passed into the class).
 /// </summary>
 /// <param name="model">An AI model that can produce outputs for both scores and CAMs (index 0 of the model output should be scores, index 1 should be CAM data)</param>
 /// <param name="camProcessor">An instance of <see cref="CAMProcessor"/> that can process the CAM output from the provided model.</param>
 private AndroidChestXRayAIClient(IAIImageModel <float[][]> model, CAMProcessor camProcessor) : base(camProcessor)
 {
     this.model = model;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="iOSChestXRayAIClient"> class.
 /// This constructor is private since this class is responsible for both instantiating and disposing of the IAIImageModel objects,
 /// so we want to limit the instantiation of this class to within this class itself (to prevent externally created IAIImageModel objects from being passed into the class).
 /// </summary>
 private iOSChestXRayAIClient(IAIImageModel <float[]> scoreModel, IAIImageModel <float[]> camModel, CAMProcessor camProcessor) : base(camProcessor)
 {
     this.scoreModel = scoreModel;
     this.camModel   = camModel;
 }