# Path: automl_video_ondevice/shot_classification/base_shot_classification.py
# class BaseShotClassificationInference:
#   """Interface that must be implemented for support of different model types."""
# 
#   def __init__(self, frozen_graph_path: str, label_map_path: str,
#                config: ShotClassificationConfig):
#     """Constructor for BaseShotClassificationInference.
# 
#     Args:
#       frozen_graph_path: String value for the file path of frozen graph.
#       label_map_path: String value for the file path of the label map.
#       config: ShotClassificationConfig object with shot classification configs.
#     """
#     raise NotImplementedError()
# 
#   def input_size(self) -> Size:
#     """Calculate / grab optimal input size.
# 
#     The user is expected to ensure the size of their input image is correct.
#     This is in case the user wants to do any acceleration of image resizing
#     themselves.
# 
#     Some inference engines require a specific input image size such as the
#     TFLite models, however some Tensorflow models accept a dynamic input. For
#     a dynamic input, the size outputed will have the dimensions -1, -1.
# 
#     Returns:
#       The expected input size, of the type Size.
#     """
#     return Size(256, 256)
# 
#   def run(self, timestamp: Union[int, float], frame: np.ndarray,
#           annotations: List[ShotClassificationAnnotation]) -> bool:
#     """Run inferencing for a single frame, to calculate annotations.
# 
#     Args:
#       timestamp: Generally an integer representing the microsecond of the frame,
#         however any unique number is also accepted.
#       frame: A numpy array of the shape (h, w, 3), representing an RGB image.
#         Each color channel should be a number [0, 256).
#       annotations: A list to append the output annotations to. For normal use-
#         case, this should be an empty list. The output annotations will be of
#         type ShotClassificationAnnotation.
# 
#     Returns:
#       A boolean, True if successful and False if unsuccessful.
#     """
#     raise NotImplementedError('Shot classification has not been implemented.')
# 
# Path: automl_video_ondevice/shot_classification/config.py
# class ShotClassificationConfig:
#   device: str = ""
# 
#   # Number of highest scoring labels to output.
#   # If max_results is -1 then all labels are used.
#   top_k: int = 5
# 
#   # Only labels with scores > threshold are output.
#   score_threshold: float = 0.0
# 
#   # Outputs duplicate results for several frames.
#   # Predictions from the classification model is done every 25 frames. If
#   # duplicate_results is true then each 25 frame input will return the previous
#   # output, otherwise the output array will be have a single None value.
#   duplicate_results: bool = False
# 
#   # Waits this number of frames before running inference.
#   # This is ignored by the LSTM model.
#   inference_rate: int = 25
# 
#   # Sliding window size.
#   # This is ignored by the LSTM model.
#   sliding_window_size: int = 64
# 
# Path: automl_video_ondevice/types.py
# class ShotClassificationAnnotation:
#   timestamp: float
#   class_name: str
#   confidence_score: float
# 
# Path: automl_video_ondevice/types.py
# class Size:
#   width: int
#   height: int


import copy
import numpy as np
import tensorflow.compat.v1 as tf
import automl_video_ondevice.utils as vot_utils
import tensorflow.contrib.tensorrt as trt  # pylint: disable=g-explicit-tensorflow-version-import,unused-import
from typing import List
from typing import Union
from automl_video_ondevice.shot_classification.base_shot_classification import BaseShotClassificationInference
from automl_video_ondevice.shot_classification.config import ShotClassificationConfig
from automl_video_ondevice.types import ShotClassificationAnnotation
from automl_video_ondevice.types import Size

  def _check_lstm(self, graph_def: tf.GraphDef) -> bool:
    """Checks to see if the input frozen graph is an LSTM graph.

    LSTM is determined by the existence of the raw_outputs/lstm_c and
    raw_outputs/lstm_h nodes. Some informational tensorflow node may be used in
    the future for determining the model type.

    Args:
      graph_def: Loaded frozen graph. This should not be a loaded tensorflow
        session, since LSTM needs to be determined before the model is loaded.
    Returns:
      If the frozen graph is of an LSTM model.
    """
    for node in graph_def.node:
      if node.name == 'raw_outputs/lstm_c' or node.name == 'raw_outputs/lstm_h':
        return True
    return False

  def input_size(self) -> Size:
    """Calculate / grab optimal input size.

    The user is expected to ensure the size of their input image is correct.
    This is in case the user wants to do any acceleration of image resizing
    themselves. Although this model accepts any input size, it is currently
    recommended that the input is the same as the size used in training.

    Returns:
      The expected input size, of the type Size.
    """

# Path: automl_video_ondevice/shot_classification/base_shot_classification.py
# class BaseShotClassificationInference:
#   """Interface that must be implemented for support of different model types."""
# 
#   def __init__(self, frozen_graph_path: str, label_map_path: str,
#                config: ShotClassificationConfig):
#     """Constructor for BaseShotClassificationInference.
# 
#     Args:
#       frozen_graph_path: String value for the file path of frozen graph.
#       label_map_path: String value for the file path of the label map.
#       config: ShotClassificationConfig object with shot classification configs.
#     """
#     raise NotImplementedError()
# 
#   def input_size(self) -> Size:
#     """Calculate / grab optimal input size.
# 
#     The user is expected to ensure the size of their input image is correct.
#     This is in case the user wants to do any acceleration of image resizing
#     themselves.
# 
#     Some inference engines require a specific input image size such as the
#     TFLite models, however some Tensorflow models accept a dynamic input. For
#     a dynamic input, the size outputed will have the dimensions -1, -1.
# 
#     Returns:
#       The expected input size, of the type Size.
#     """
#     return Size(256, 256)
# 
#   def run(self, timestamp: Union[int, float], frame: np.ndarray,
#           annotations: List[ShotClassificationAnnotation]) -> bool:
#     """Run inferencing for a single frame, to calculate annotations.
# 
#     Args:
#       timestamp: Generally an integer representing the microsecond of the frame,
#         however any unique number is also accepted.
#       frame: A numpy array of the shape (h, w, 3), representing an RGB image.
#         Each color channel should be a number [0, 256).
#       annotations: A list to append the output annotations to. For normal use-
#         case, this should be an empty list. The output annotations will be of
#         type ShotClassificationAnnotation.
# 
#     Returns:
#       A boolean, True if successful and False if unsuccessful.
#     """
#     raise NotImplementedError('Shot classification has not been implemented.')
# 
# Path: automl_video_ondevice/shot_classification/config.py
# class ShotClassificationConfig:
#   device: str = ""
# 
#   # Number of highest scoring labels to output.
#   # If max_results is -1 then all labels are used.
#   top_k: int = 5
# 
#   # Only labels with scores > threshold are output.
#   score_threshold: float = 0.0
# 
#   # Outputs duplicate results for several frames.
#   # Predictions from the classification model is done every 25 frames. If
#   # duplicate_results is true then each 25 frame input will return the previous
#   # output, otherwise the output array will be have a single None value.
#   duplicate_results: bool = False
# 
#   # Waits this number of frames before running inference.
#   # This is ignored by the LSTM model.
#   inference_rate: int = 25
# 
#   # Sliding window size.
#   # This is ignored by the LSTM model.
#   sliding_window_size: int = 64
# 
# Path: automl_video_ondevice/types.py
# class ShotClassificationAnnotation:
#   timestamp: float
#   class_name: str
#   confidence_score: float
# 
# Path: automl_video_ondevice/types.py
# class Size:
#   width: int
#   height: int


# Path: automl_video_ondevice/shot_classification/tf_shot_classification.py
import copy
import numpy as np
import tensorflow.compat.v1 as tf
import automl_video_ondevice.utils as vot_utils
import tensorflow.contrib.tensorrt as trt  # pylint: disable=g-explicit-tensorflow-version-import,unused-import
from typing import List
from typing import Union
from automl_video_ondevice.shot_classification.base_shot_classification import BaseShotClassificationInference
from automl_video_ondevice.shot_classification.config import ShotClassificationConfig
from automl_video_ondevice.types import ShotClassificationAnnotation
from automl_video_ondevice.types import Size


  def _check_lstm(self, graph_def: tf.GraphDef) -> bool:
    """Checks to see if the input frozen graph is an LSTM graph.

    LSTM is determined by the existence of the raw_outputs/lstm_c and
    raw_outputs/lstm_h nodes. Some informational tensorflow node may be used in
    the future for determining the model type.

    Args:
      graph_def: Loaded frozen graph. This should not be a loaded tensorflow
        session, since LSTM needs to be determined before the model is loaded.
    Returns:
      If the frozen graph is of an LSTM model.
    """
    for node in graph_def.node:
      if node.name == 'raw_outputs/lstm_c' or node.name == 'raw_outputs/lstm_h':
        return True
    return False

  def input_size(self) -> Size:
    """Calculate / grab optimal input size.

    The user is expected to ensure the size of their input image is correct.
    This is in case the user wants to do any acceleration of image resizing
    themselves. Although this model accepts any input size, it is currently
    recommended that the input is the same as the size used in training.

    Returns:
      The expected input size, of the type Size.
    """

    return Size(256, 256)