message: Resize graph inside Preprocess().
diff: @@ -54,6 +54,25 @@ bool ImagePreprocessor::IsImagePreprocessingNeeded(
  return false;
  }
  +// Returns true if the model expects dynamic image shape, false otherwise.
  +bool ImagePreprocessor::IsInputImageDynamic()
  +{
  + // Determine if the input shape is resizable.
  + const TfLiteIntArray* dims_signature = Tensor()->dims_signature;
  +
  + if (dims_signature == nullptr) return false;
  +
  + bool height_or_width_mutable = dims_signature->data[1] == -1 ||
  + dims_signature->data[2] == -1;
  + // Only the HXW dimensions support mutability.
  + bool batch_and_color_fixed = dims_signature->data[0] != -1 &&
  + dims_signature->data[3] != -1;
  +
  + if (height_or_width_mutable && batch_and_color_fixed) return true;
  +
  + return false;
  +}
  +
  absl::Status ImagePreprocessor::Init(
  const vision::FrameBufferUtils::ProcessEngine& process_engine) {
  frame_buffer_utils_ = vision::FrameBufferUtils::Create(process_engine);
  @@ -91,7 +110,7 @@ absl::Status ImagePreprocessor::Preprocess(const FrameBuffer& frame_buffer,
  std::unique_ptr<FrameBuffer> preprocessed_frame_buffer;
  std::vector<uint8> preprocessed_data;
  - if (IsImagePreprocessingNeeded(frame_buffer, roi)) {
  + if (IsImagePreprocessingNeeded(frame_buffer, roi) && !IsInputImageDynamic()) {
  // Preprocess input image to fit model requirements.
  // For now RGB is the only color space supported, which is ensured by
  // `InitInternal`.
  @@ -114,6 +133,39 @@ absl::Status ImagePreprocessor::Preprocess(const FrameBuffer& frame_buffer,
  } else {
  // Input frame buffer already targets model requirements: skip image
  // preprocessing. For RGB, the data is always stored in a single plane.
  +
  + // If dynamic, it will re-dim the entire graph as per the input.
  + if (IsInputImageDynamic()) {
  + // Determine if the input shape is resizable.
  + const TfLiteIntArray* dims_signature = Tensor()->dims_signature;
  +
  + const bool height_mutable = dims_signature->data[1] == -1;
  + const bool width_mutable = dims_signature->data[2] == -1;
  +
  + if (height_mutable || width_mutable) {
  + const TfLiteIntArray* dims = Tensor()->dims;
  + const Interpreter* interpreter = engine_->interpreter();
  +
  + // The expected BXHXWXD values of the model.
  + const int expected_batch = Tensor()->dims->data[0];
  + int expected_height = Tensor()->dims->data[1];
  + int expected_width = Tensor()->dims->data[2];
  + const int expected_depth = Tensor()->dims->data[3];
  +
  + // HXW of the input image.
  + int image_height = frame_buffer.dimension().height;
  + int image_width = frame_buffer.dimension().width;
  +
  + int height = height_mutable ? image_height : expected_height;
  + int width = width_mutable ? image_width : expected_width;
  +
  + const std::vector<int> new_dims {expected_batch, height, width, expected_depth};
  +
  +
  + interpreter->ResizeInputTensorStrict(0, new_dims);
  + }
  + }
  +
  input_data = frame_buffer.plane(0).buffer;
  input_data_byte_size = frame_buffer.plane(0).stride.row_stride_bytes *
  frame_buffer.dimension().height;
  