blob: 90a7491e7ddb43f5c95b638a915232ce0fc9f078 [file] [log] [blame]
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_LITE_SUPPORT_CC_TASK_VISION_UTILS_FRAME_BUFFER_UTILS_H_
#define TENSORFLOW_LITE_SUPPORT_CC_TASK_VISION_UTILS_FRAME_BUFFER_UTILS_H_
#include <memory>
#include <vector>
#include "absl/status/status.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
#include "tensorflow_lite_support/cc/port/integral_types.h"
#include "tensorflow_lite_support/cc/task/vision/core/frame_buffer.h"
#include "tensorflow_lite_support/cc/task/vision/proto/bounding_box_proto_inc.h"
#include "tensorflow_lite_support/cc/task/vision/utils/frame_buffer_utils_interface.h"
namespace tflite {
namespace task {
namespace vision {
// Returns the minimal buffer size for a plane in bytes based on the given
// format and dimensions.
int GetBufferByteSize(FrameBuffer::Dimension dimension,
FrameBuffer::Format format);
// Rotates the `from_box` in `from_orientation` to `to_orientation` within an
// image of size `from_dimension`.
BoundingBox OrientBoundingBox(const BoundingBox& from_box,
FrameBuffer::Orientation from_orientation,
FrameBuffer::Orientation to_orientation,
FrameBuffer::Dimension from_dimension);
// Same as OrientBoundingBox but from normalized coordinates.
BoundingBox OrientAndDenormalizeBoundingBox(
float from_left, float from_top, float from_right, float from_bottom,
FrameBuffer::Orientation from_orientation,
FrameBuffer::Orientation to_orientation,
FrameBuffer::Dimension from_dimension);
// Rotates `(from_x, from_y)` coordinates from an image of dimension
// `from_dimension` and orientation `from_orientation` into `(to_x, to_y)`
// coordinates with orientation `to_orientation`.
void OrientCoordinates(int from_x, int from_y,
FrameBuffer::Orientation from_orientation,
FrameBuffer::Orientation to_orientation,
FrameBuffer::Dimension from_dimension, int* to_x,
int* to_y);
// Returns whether the conversion from from_orientation to to_orientation
// requires 90 or 270 degrees rotation.
bool RequireDimensionSwap(FrameBuffer::Orientation from_orientation,
FrameBuffer::Orientation to_orientation);
// Structure to express parameters needed to achieve orientation conversion.
struct OrientParams {
// Counterclockwise rotation angle in degrees. This is expressed as a
// multiple of 90 degrees.
int rotation_angle_deg;
// Flipping operation. It must come after the rotation.
enum class FlipType { kHorizontal, kVertical };
absl::optional<FlipType> flip;
};
// Returns rotation angle and the need for horizontal flipping or vertical
// flipping.
OrientParams GetOrientParams(FrameBuffer::Orientation from_orientation,
FrameBuffer::Orientation to_orientation);
// The parameters needed to crop / resize.
//
// The coordinate system has its origin at the upper left corner, and
// positive values extend down and to the right from it.
//
// After the operation, the `crop_origin` will become the new origin.
// `crop_width` and `crop_height` defines the desired cropping region. After
// cropping, a resize is performed based on the `resize_width` and
// `resize_height`.
//
// To perform just cropping, the `crop_width` and `crop_height` should be the
// same as `resize_width` `and resize_height`.
struct CropResizeOperation {
CropResizeOperation(int crop_origin_x, int crop_origin_y,
FrameBuffer::Dimension crop_dimension,
FrameBuffer::Dimension resize_dimension)
: crop_origin_x(crop_origin_x),
crop_origin_y(crop_origin_y),
crop_dimension(crop_dimension),
resize_dimension(resize_dimension) {}
int crop_origin_x;
int crop_origin_y;
FrameBuffer::Dimension crop_dimension;
FrameBuffer::Dimension resize_dimension;
};
// The parameters needed to convert to the specified format.
struct ConvertOperation {
explicit ConvertOperation(FrameBuffer::Format to_format)
: to_format(to_format) {}
FrameBuffer::Format to_format;
};
// The parameters needed to change the orientation.
struct OrientOperation {
explicit OrientOperation(FrameBuffer::Orientation to_orientation)
: to_orientation(to_orientation) {}
FrameBuffer::Orientation to_orientation;
};
// A variant of the supported operations on FrameBuffers. Alias for user
// convenience.
using FrameBufferOperation =
absl::variant<CropResizeOperation, ConvertOperation, OrientOperation>;
// Image processing utility. This utility provides both basic image buffer
// manipulations (e.g. rotation, format conversion, resizing, etc) as well as
// capability for chaining pipeline executions. The actual buffer processing
// engine is configurable to allow optimization based on platforms.
//
// Examples:
//
// // Create an instance of FrameBufferUtils with Halide processing engine.
// std::unique_ptr<FrameBufferUtils> utils = FrameBufferUtils::Create(kHalide);
//
// // Perform single basic operation by each individual call.
// std::unique_ptr<FrameBuffer> input = FrameBuffer::Create(...);
// std::unique_ptr<FrameBuffer> output = FrameBuffer::Create(...);
// utils->Orient(*input, output.get());
// utils->Resize(*input, output.get());
//
// // Chaining processing operations.
// const std::vector<FrameBufferOperation> operations = {
// ConvertOperation(FrameBuffer::Format::kNV21),
// CropResizeOperation(/*crop_origin_x=*/20, /*crop_origin_y=*/20,
// /*crop_width=*/10, /*crop_height=*/10,
// /*resize_width=*/10, /*resize_height=*/10),
// OrientOperation(FrameBuffer::Orientation::kLeftTop)};
// utils->Execute(*input, operations, output.get());
class FrameBufferUtils {
public:
// Counter-clockwise rotation in degree.
enum class RotationDegree { k0 = 0, k90 = 1, k180 = 2, k270 = 3 };
// Underlying process engine used for performing operations.
enum class ProcessEngine {
kLibyuv,
};
// Factory method FrameBufferUtils instance. The processing engine is
// defined by `engine`.
static std::unique_ptr<FrameBufferUtils> Create(ProcessEngine engine) {
return absl::make_unique<FrameBufferUtils>(engine);
}
explicit FrameBufferUtils(ProcessEngine engine);
// Performs cropping operation.
//
// The coordinate system has its origin at the upper left corner, and
// positive values extend down and to the right from it. After cropping,
// (x0, y0) becomes (0, 0). The new width and height are
// (x1 - x0 + 1, y1 - y0 + 1).
//
// The `output_buffer` should have metadata populated and its backing buffer
// should be big enough to store the operation result. If the `output_buffer`
// size dimension does not match with crop dimension, then a resize is
// automatically performed.
absl::Status Crop(const FrameBuffer& buffer, int x0, int y0, int x1, int y1,
FrameBuffer* output_buffer);
// Performs resizing operation.
//
// The resize dimension is determined based on output_buffer's size metadata.
//
// The output_buffer should have metadata populated and its backing buffer
// should be big enough to store the operation result.
absl::Status Resize(const FrameBuffer& buffer, FrameBuffer* output_buffer);
// Performs rotation operation.
//
// The rotation is specified in counter-clockwise direction.
//
// The output_buffer should have metadata populated and its backing buffer
// should be big enough to store the operation result.
absl::Status Rotate(const FrameBuffer& buffer, RotationDegree rotation,
FrameBuffer* output_buffer);
// Performs horizontal flip operation.
//
// The `output_buffer` should have metadata populated and its backing buffer
// should be big enough to store the operation result.
absl::Status FlipHorizontally(const FrameBuffer& buffer,
FrameBuffer* output_buffer);
// Performs vertical flip operation.
//
// The `output_buffer` should have metadata populated and its backing buffer
// should be big enough to store the operation result.
absl::Status FlipVertically(const FrameBuffer& buffer,
FrameBuffer* output_buffer);
// Performs buffer format conversion.
//
// The `output_buffer` should have metadata populated and its backing buffer
// should be big enough to store the operation result.
absl::Status Convert(const FrameBuffer& buffer, FrameBuffer* output_buffer);
// Performs buffer orientation conversion. Depends on the orientations, this
// method may perform rotation and optional flipping operations.
//
// If `buffer` and `output_buffer` has the same orientation, then a copy
// operation will performed.
//
// The `output_buffer` should have metadata populated and its backing buffer
// should be big enough to store the operation result.
absl::Status Orient(const FrameBuffer& buffer, FrameBuffer* output_buffer);
// Performs the image processing operations specified, in that order.
//
// The `output_buffer` should have metadata populated and its backing buffer
// should be big enough to store the operation result.
absl::Status Execute(const FrameBuffer& buffer,
const std::vector<FrameBufferOperation>& operations,
FrameBuffer* output_buffer);
// Performs a chain of operations to convert `buffer` to desired metadata
// (width, height, format, orientation) defined by `output_buffer` and
// optional cropping (`bounding_box`).
//
// Internally, a chain of operations is constructed. For performance
// optimization, operations are performed in the following order: crop,
// resize, convert color space format, and rotate.
//
// The `output_buffer` should have metadata populated and its backing buffer
// should be big enough to store the operation result. Insufficient backing
// buffer size may cause garbage result or crash. Use `GetBufferByteSize` to
// calculate the minimal buffer size.
//
// If the `buffer` is already in desired format, then an extra copy will be
// performed.
//
// The input param `bounding_box` is defined in the `buffer` coordinate space.
absl::Status Preprocess(const FrameBuffer& buffer,
absl::optional<BoundingBox> bounding_box,
FrameBuffer* output_buffer);
private:
// Returns the new FrameBuffer size after the operation is applied.
FrameBuffer::Dimension GetSize(const FrameBuffer& buffer,
const FrameBufferOperation& operation);
// Returns the new FrameBuffer orientation after command is processed.
FrameBuffer::Orientation GetOrientation(
const FrameBuffer& buffer, const FrameBufferOperation& operation);
// Returns the new FrameBuffer format after command is processed.
FrameBuffer::Format GetFormat(const FrameBuffer& buffer,
const FrameBufferOperation& operation);
// Returns Plane struct based on one dimension buffer and its metadata. If
// an error occurred, it will return an empty vector.
std::vector<FrameBuffer::Plane> GetPlanes(const uint8* buffer,
FrameBuffer::Dimension dimension,
FrameBuffer::Format format);
// Executes command with params.
absl::Status Execute(const FrameBuffer& buffer,
const FrameBufferOperation& operation,
FrameBuffer* output_buffer);
// Execution engine conforms to FrameBufferUtilsInterface.
std::unique_ptr<FrameBufferUtilsInterface> utils_;
};
} // namespace vision
} // namespace task
} // namespace tflite
#endif // TENSORFLOW_LITE_SUPPORT_CC_TASK_VISION_UTILS_FRAME_BUFFER_UTILS_H_