mediapipe/mediapipe/framework/formats/affine_transform.cc
MediaPipe Team 6abec128ed Project import generated by Copybara.
GitOrigin-RevId: f4b1fe3f15810450fb6539e733f6a260d3ee082c
2021-09-01 18:15:31 -07:00

229 lines
6.8 KiB
C++

// Copyright 2021 The MediaPipe Authors.
//
// 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.
#include "mediapipe/framework/formats/affine_transform.h"
#include <algorithm>
#include <cmath>
#include <memory>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/strings/substitute.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/integral_types.h"
#include "mediapipe/framework/port/logging.h"
#include "mediapipe/framework/port/point2.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/statusor.h"
#include "mediapipe/framework/tool/status_util.h"
#include "mediapipe/framework/type_map.h"
namespace mediapipe {
using ::mediapipe::AffineTransformData;
AffineTransform::AffineTransform() { SetScale(Point2_f(1, 1)); }
AffineTransform::AffineTransform(
const AffineTransformData& affine_transform_data)
: affine_transform_data_(affine_transform_data), is_dirty_(true) {
// make sure scale is set to default (1, 1) when none provided
if (!affine_transform_data_.has_scale()) {
SetScale(Point2_f(1, 1));
}
}
AffineTransform AffineTransform::Create(const Point2_f& translation,
const Point2_f& scale, float rotation,
const Point2_f& shear) {
AffineTransformData affine_transform_data;
auto* t = affine_transform_data.mutable_translation();
t->set_x(translation.x());
t->set_y(translation.y());
auto* s = affine_transform_data.mutable_scale();
s->set_x(scale.x());
s->set_y(scale.y());
s = affine_transform_data.mutable_shear();
s->set_x(shear.x());
s->set_y(shear.y());
affine_transform_data.set_rotation(rotation);
return AffineTransform(affine_transform_data);
}
// Accessor for the composition matrix
std::vector<float> AffineTransform::GetCompositionMatrix() {
float r = affine_transform_data_.rotation();
const auto t = affine_transform_data_.translation();
const auto sc = affine_transform_data_.scale();
const auto sh = affine_transform_data_.shear();
if (is_dirty_) {
// Composition matrix M = T*R*Sh*Sc
// Column based to match GL matrix store order
float cos_r = std::cos(r);
float sin_r = std::sin(r);
matrix_[0] = (cos_r + sin_r * -sh.y()) * sc.x();
matrix_[1] = (-sin_r + cos_r * -sh.y()) * sc.x();
matrix_[2] = 0;
matrix_[3] = (cos_r * -sh.x() + sin_r) * sc.y();
matrix_[4] = (-sin_r * -sh.x() + cos_r) * sc.y();
matrix_[5] = 0;
matrix_[6] = t.x();
matrix_[7] = -t.y();
matrix_[8] = 1;
is_dirty_ = false;
}
return matrix_;
}
Point2_f AffineTransform::GetScale() const {
return Point2_f(affine_transform_data_.scale().x(),
affine_transform_data_.scale().y());
}
Point2_f AffineTransform::GetTranslation() const {
return Point2_f(affine_transform_data_.translation().x(),
affine_transform_data_.translation().y());
}
Point2_f AffineTransform::GetShear() const {
return Point2_f(affine_transform_data_.shear().x(),
affine_transform_data_.shear().y());
}
float AffineTransform::GetRotation() const {
return affine_transform_data_.rotation();
}
void AffineTransform::SetScale(const Point2_f& scale) {
auto* s = affine_transform_data_.mutable_scale();
s->set_x(scale.x());
s->set_y(scale.y());
is_dirty_ = true;
}
void AffineTransform::SetTranslation(const Point2_f& translation) {
auto* t = affine_transform_data_.mutable_translation();
t->set_x(translation.x());
t->set_y(translation.y());
is_dirty_ = true;
}
void AffineTransform::SetShear(const Point2_f& shear) {
auto* s = affine_transform_data_.mutable_shear();
s->set_x(shear.x());
s->set_y(shear.y());
is_dirty_ = true;
}
void AffineTransform::SetRotation(float rotationInRadians) {
affine_transform_data_.set_rotation(rotationInRadians);
is_dirty_ = true;
}
void AffineTransform::AddScale(const Point2_f& scale) {
auto* s = affine_transform_data_.mutable_scale();
s->set_x(s->x() + scale.x());
s->set_y(s->y() + scale.y());
is_dirty_ = true;
}
void AffineTransform::AddTranslation(const Point2_f& translation) {
auto* t = affine_transform_data_.mutable_translation();
t->set_x(t->x() + translation.x());
t->set_y(t->y() + translation.y());
is_dirty_ = true;
}
void AffineTransform::AddShear(const Point2_f& shear) {
auto* s = affine_transform_data_.mutable_shear();
s->set_x(s->x() + shear.x());
s->set_y(s->y() + shear.y());
is_dirty_ = true;
}
void AffineTransform::AddRotation(float rotationInRadians) {
affine_transform_data_.set_rotation(affine_transform_data_.rotation() +
rotationInRadians);
is_dirty_ = true;
}
void AffineTransform::SetFromProto(const AffineTransformData& proto) {
affine_transform_data_ = proto;
}
void AffineTransform::ConvertToProto(AffineTransformData* proto) const {
*proto = affine_transform_data_;
}
AffineTransformData AffineTransform::ConvertToProto() const {
AffineTransformData affine_transform_data;
ConvertToProto(&affine_transform_data);
return affine_transform_data;
}
bool compare(float lhs, float rhs, float epsilon = 0.001f) {
return std::fabs(lhs - rhs) < epsilon;
}
bool AffineTransform::Equals(const AffineTransform& other,
float epsilon) const {
auto trans1 = GetTranslation();
auto trans2 = other.GetTranslation();
if (!(compare(trans1.x(), trans2.x(), epsilon) &&
compare(trans1.y(), trans2.y(), epsilon)))
return false;
auto scale1 = GetScale();
auto scale2 = other.GetScale();
if (!(compare(scale1.x(), scale2.x(), epsilon) &&
compare(scale1.y(), scale2.y(), epsilon)))
return false;
auto shear1 = GetShear();
auto shear2 = other.GetShear();
if (!(compare(shear1.x(), shear2.x(), epsilon) &&
compare(shear1.y(), shear2.y(), epsilon)))
return false;
auto rot1 = GetRotation();
auto rot2 = other.GetRotation();
if (!compare(rot1, rot2, epsilon)) {
return false;
}
return true;
}
bool AffineTransform::Equal(const AffineTransform& lhs,
const AffineTransform& rhs, float epsilon) {
return lhs.Equals(rhs, epsilon);
}
MEDIAPIPE_REGISTER_TYPE(mediapipe::AffineTransform,
"::mediapipe::AffineTransform", nullptr, nullptr);
} // namespace mediapipe