Project import generated by Copybara.
GitOrigin-RevId: f4b1fe3f15810450fb6539e733f6a260d3ee082c
This commit is contained in:
@@ -81,6 +81,12 @@ mediapipe_proto_library(
|
||||
deps = ["//mediapipe/framework/formats/annotation:rasterization_proto"],
|
||||
)
|
||||
|
||||
mediapipe_proto_library(
|
||||
name = "affine_transform_data_proto",
|
||||
srcs = ["affine_transform_data.proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
mediapipe_proto_library(
|
||||
name = "time_series_header_proto",
|
||||
srcs = ["time_series_header.proto"],
|
||||
@@ -119,6 +125,31 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "affine_transform",
|
||||
srcs = ["affine_transform.cc"],
|
||||
hdrs = ["affine_transform.h"],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
deps = [
|
||||
"//mediapipe/framework:port",
|
||||
"//mediapipe/framework:type_map",
|
||||
"//mediapipe/framework/formats:affine_transform_data_cc_proto",
|
||||
"//mediapipe/framework/port:integral_types",
|
||||
"//mediapipe/framework/port:logging",
|
||||
"//mediapipe/framework/port:point",
|
||||
"//mediapipe/framework/port:ret_check",
|
||||
"//mediapipe/framework/port:status",
|
||||
"//mediapipe/framework/port:statusor",
|
||||
"//mediapipe/framework/tool:status_util",
|
||||
"@com_google_absl//absl/base:core_headers",
|
||||
"@com_google_absl//absl/memory",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_protobuf//:protobuf",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "image_frame",
|
||||
srcs = ["image_frame.cc"],
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
// 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
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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.
|
||||
//
|
||||
// A container for affine transform data
|
||||
// This wrapper provides two functionalities:
|
||||
// 1. Factory methods for creation of Transform objects and thus
|
||||
// AffineTransformData protocol buffers. These methods guarantee a valid
|
||||
// affine transform data and are the preferred way of creating such.
|
||||
// 2. Accessors which allow for access of the data and the convertion to proto
|
||||
// format
|
||||
|
||||
#ifndef MEDIAPIPE_FRAMEWORK_FORMATS_AFFINE_TRANSFORM_H_
|
||||
#define MEDIAPIPE_FRAMEWORK_FORMATS_AFFINE_TRANSFORM_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "mediapipe/framework/formats/affine_transform_data.pb.h"
|
||||
#include "mediapipe/framework/port.h"
|
||||
#include "mediapipe/framework/port/point2.h"
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
class AffineTransform {
|
||||
public:
|
||||
// CREATION METHODS.
|
||||
AffineTransform();
|
||||
|
||||
// Constructs a affine transform wrapping the specified affine transform data.
|
||||
// Checks the validity of the input and crashes upon failure.
|
||||
explicit AffineTransform(const AffineTransformData& transform_data);
|
||||
|
||||
static AffineTransform Create(const Point2_f& translation = Point2_f(0, 0),
|
||||
const Point2_f& scale = Point2_f(1, 1),
|
||||
float rotation = 0,
|
||||
const Point2_f& shear = Point2_f(0, 0));
|
||||
|
||||
// ACCESSORS
|
||||
// Accessor for the composition matrix
|
||||
std::vector<float> GetCompositionMatrix();
|
||||
|
||||
Point2_f GetScale() const;
|
||||
Point2_f GetTranslation() const;
|
||||
Point2_f GetShear() const;
|
||||
float GetRotation() const;
|
||||
|
||||
void SetScale(const Point2_f& scale);
|
||||
void SetTranslation(const Point2_f& translation);
|
||||
void SetShear(const Point2_f& shear);
|
||||
void SetRotation(float rotation);
|
||||
|
||||
void AddScale(const Point2_f& scale);
|
||||
void AddTranslation(const Point2_f& translation);
|
||||
void AddShear(const Point2_f& shear);
|
||||
void AddRotation(float rotation);
|
||||
|
||||
// Serializes and deserializes the affine transform object.
|
||||
void ConvertToProto(AffineTransformData* proto) const;
|
||||
AffineTransformData ConvertToProto() const;
|
||||
void SetFromProto(const AffineTransformData& proto);
|
||||
|
||||
bool Equals(const AffineTransform& other, float epsilon = 0.001f) const;
|
||||
|
||||
static bool Equal(const AffineTransform& lhs, const AffineTransform& rhs,
|
||||
float epsilon = 0.001f);
|
||||
|
||||
private:
|
||||
// The wrapped transform data.
|
||||
AffineTransformData affine_transform_data_;
|
||||
std::vector<float> matrix_ = {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
bool is_dirty_ = false;
|
||||
};
|
||||
} // namespace mediapipe
|
||||
|
||||
#endif // MEDIAPIPE_FRAMEWORK_FORMATS_AFFINE_TRANSFORM_H_
|
||||
@@ -0,0 +1,33 @@
|
||||
// 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.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package mediapipe;
|
||||
|
||||
option objc_class_prefix = "MediaPipe";
|
||||
|
||||
// Proto for serializing Vector2 data
|
||||
message Vector2Data {
|
||||
optional float x = 1;
|
||||
optional float y = 2;
|
||||
}
|
||||
|
||||
// Proto for serializing Affine Transform data.
|
||||
message AffineTransformData {
|
||||
optional Vector2Data translation = 1;
|
||||
optional Vector2Data scale = 2;
|
||||
optional Vector2Data shear = 3;
|
||||
optional float rotation = 4; // in radians
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "mediapipe/framework/formats/affine_transform.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "mediapipe/framework/formats/affine_transform_data.pb.h"
|
||||
#include "mediapipe/framework/port/point2.h"
|
||||
#include "testing/base/public/gmock.h"
|
||||
#include "testing/base/public/gunit.h"
|
||||
|
||||
namespace mediapipe {
|
||||
|
||||
TEST(AffineTransformTest, TraslationTest) {
|
||||
AffineTransform transform;
|
||||
transform.SetTranslation(Point2_f(10, -3));
|
||||
|
||||
auto trans = transform.GetTranslation();
|
||||
EXPECT_FLOAT_EQ(10, trans.x());
|
||||
EXPECT_FLOAT_EQ(-3, trans.y());
|
||||
|
||||
transform.AddTranslation(Point2_f(-10, 3));
|
||||
|
||||
trans = transform.GetTranslation();
|
||||
EXPECT_FLOAT_EQ(0, trans.x());
|
||||
EXPECT_FLOAT_EQ(0, trans.y());
|
||||
}
|
||||
|
||||
TEST(AffineTransformTest, ScaleTest) {
|
||||
AffineTransform transform;
|
||||
transform.SetScale(Point2_f(10, -3));
|
||||
|
||||
auto scale = transform.GetScale();
|
||||
EXPECT_FLOAT_EQ(10, scale.x());
|
||||
EXPECT_FLOAT_EQ(-3, scale.y());
|
||||
|
||||
transform.AddScale(Point2_f(-10, 3));
|
||||
|
||||
scale = transform.GetScale();
|
||||
EXPECT_FLOAT_EQ(0, scale.x());
|
||||
EXPECT_FLOAT_EQ(0, scale.y());
|
||||
}
|
||||
|
||||
TEST(AffineTransformTest, RotationTest) {
|
||||
AffineTransform transform;
|
||||
transform.SetRotation(0.7);
|
||||
|
||||
float rot = transform.GetRotation();
|
||||
EXPECT_FLOAT_EQ(0.7, rot);
|
||||
|
||||
transform.AddRotation(-0.7);
|
||||
rot = transform.GetRotation();
|
||||
EXPECT_FLOAT_EQ(0, rot);
|
||||
}
|
||||
|
||||
TEST(AffineTransformTest, ShearTest) {
|
||||
AffineTransform transform;
|
||||
transform.SetShear(Point2_f(10, -3));
|
||||
|
||||
auto shear = transform.GetShear();
|
||||
EXPECT_FLOAT_EQ(10, shear.x());
|
||||
EXPECT_FLOAT_EQ(-3, shear.y());
|
||||
|
||||
transform.AddShear(Point2_f(-10, 3));
|
||||
|
||||
shear = transform.GetShear();
|
||||
EXPECT_FLOAT_EQ(0, shear.x());
|
||||
EXPECT_FLOAT_EQ(0, shear.y());
|
||||
}
|
||||
|
||||
TEST(AffineTransformTest, TransformTest) {
|
||||
AffineTransform transform1;
|
||||
transform1 = AffineTransform::Create(Point2_f(0.1, -0.2), Point2_f(0.3, -0.4),
|
||||
0.5, Point2_f(0.6, -0.7));
|
||||
|
||||
AffineTransform transform2;
|
||||
transform2 = AffineTransform::Create(Point2_f(0.1, -0.2), Point2_f(0.3, -0.4),
|
||||
0.5, Point2_f(0.6, -0.7));
|
||||
|
||||
EXPECT_THAT(true, transform1.Equals(transform2));
|
||||
EXPECT_THAT(true, AffineTransform::Equal(transform1, transform2));
|
||||
|
||||
transform1 = AffineTransform::Create(Point2_f(0.00001, -0.00002),
|
||||
Point2_f(0.00003, -0.00004), 0.00005,
|
||||
Point2_f(0.00006, -0.00007));
|
||||
|
||||
transform2 = AffineTransform::Create(Point2_f(0.00001, -0.00002),
|
||||
Point2_f(0.00003, -0.00004), 0.00005,
|
||||
Point2_f(0.00006, -0.00007));
|
||||
|
||||
EXPECT_THAT(true, transform1.Equals(transform2, 0.000001));
|
||||
EXPECT_THAT(true, AffineTransform::Equal(transform1, transform2, 0.000001));
|
||||
}
|
||||
|
||||
} // namespace mediapipe
|
||||
Reference in New Issue
Block a user