提交 ce0c7426 编写于 作者: A A. Unique TensorFlower 提交者: TensorFlower Gardener

Implementation for flip (up to down) + tests.

PiperOrigin-RevId: 561184976
上级 8c7a63c7
......@@ -90,3 +90,25 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "flip_up_down",
srcs = ["flip_up_down.cc"],
hdrs = ["flip_up_down.h"],
deps = [
"//tensorflow/lite/experimental/ml_adjacent:lib",
"//tensorflow/lite/kernels/internal:compatibility",
],
)
cc_test(
name = "flip_up_down_test",
srcs = ["flip_up_down_test.cc"],
deps = [
":flip_up_down",
"//tensorflow/lite/experimental/ml_adjacent:lib",
"//tensorflow/lite/experimental/ml_adjacent/data:owning_vector_ref",
"@com_google_absl//absl/types:span",
"@com_google_googletest//:gtest_main",
],
)
/* Copyright 2023 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.
==============================================================================*/
#include <cstring>
#include "tensorflow/lite/experimental/ml_adjacent/lib.h"
#include "tensorflow/lite/kernels/internal/compatibility.h"
namespace ml_adj {
namespace flip_up_down {
namespace {
using ::ml_adj::algo::Algo;
using ::ml_adj::algo::InputPack;
using ::ml_adj::algo::OutputPack;
using ::ml_adj::data::DataRef;
using ::ml_adj::data::MutableDataRef;
using ::ml_adj::data::TypeWidth;
void FlipUpDown(dim_t batches, dim_t input_height, dim_t input_width,
const char* input_data, char* output_data, dim_t chunk_size) {
const dim_t row_stride = input_width * chunk_size;
const dim_t batch_stride = row_stride * input_height;
// Iterate over batches to flip multi-channel image.
for (int b = 0; b < batches; ++b) {
const char* src_data_prt = input_data + b * batch_stride;
char* dst_data_prt = output_data + b * batch_stride;
for (int y = 0; y < input_height; ++y) {
const char* src_ptr_row =
src_data_prt + (input_height - y - 1) * row_stride;
char* dst_ptr_row = dst_data_prt + y * row_stride;
std::memcpy(dst_ptr_row, src_ptr_row, row_stride);
}
}
}
// Flips the given input vertically. Supports any datatype.
void ComputeFlipUpDown(const InputPack& inputs, const OutputPack& outputs) {
TFLITE_DCHECK(inputs.size() == 1);
TFLITE_DCHECK(outputs.size() == 1);
// Extract input image data.
const DataRef* img = inputs[0];
const char* img_data = reinterpret_cast<const char*>(img->Data());
const dim_t num_batches = img->Dims()[0];
const dim_t height = img->Dims()[1];
const dim_t width = img->Dims()[2];
const dim_t num_channels = img->Dims()[3];
const dim_t chunk_size = TypeWidth(img->Type()) * num_channels;
// Resize output buffer.
MutableDataRef* output = outputs[0];
output->Resize({num_batches, height, width, num_channels});
char* output_data = reinterpret_cast<char*>(output->Data());
FlipUpDown(num_batches, height, width, img_data, output_data, chunk_size);
}
} // namespace
const Algo* Impl_FlipUpDown() {
static const Algo flip_up_down = {&ComputeFlipUpDown, nullptr};
return &flip_up_down;
}
} // namespace flip_up_down
} // namespace ml_adj
/* Copyright 2023 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_EXPERIMENTAL_ML_ADJACENT_ALGO_FLIP_UP_DOWN_H_
#define TENSORFLOW_LITE_EXPERIMENTAL_ML_ADJACENT_ALGO_FLIP_UP_DOWN_H_
#include "tensorflow/lite/experimental/ml_adjacent/lib.h"
namespace ml_adj {
namespace flip_up_down {
// Flip (up to down)
//
// Inputs: [img: any]
// Ouputs: [img: any]
//
// Flips the given image vertically (up to down).
// Mimics semantic of `tf.image.flip_up_down.
// https://www.tensorflow.org/api_docs/python/tf/image/flip_up_down
const algo::Algo* Impl_FlipUpDown();
} // namespace flip_up_down
} // namespace ml_adj
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ML_ADJACENT_ALGO_FLIP_UP_DOWN_H_
/* Copyright 2023 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.
==============================================================================*/
#include "tensorflow/lite/experimental/ml_adjacent/algo/flip_up_down.h"
#include <cstring>
#include <vector>
#include <gtest/gtest.h>
#include "tensorflow/lite/experimental/ml_adjacent/data/owning_vector_ref.h"
#include "tensorflow/lite/experimental/ml_adjacent/lib.h"
using ::ml_adj::algo::Algo;
using ::ml_adj::data::OwningVectorRef;
namespace ml_adj {
namespace flip_up_down {
namespace {
struct FlipUpDownTestParams {
const std::vector<dim_t> img_dims;
const std::vector<float> img_data;
const std::vector<float> expected_data;
const std::vector<dim_t> expected_shape;
};
class FlipUpDownTest : public ::testing::TestWithParam<FlipUpDownTestParams> {};
TEST_P(FlipUpDownTest, FloatPixelType) {
constexpr float kAbsError = 0.01f;
const FlipUpDownTestParams& params = GetParam();
// Image input.
OwningVectorRef img(etype_t::f32);
img.Resize(dims_t(params.img_dims));
ASSERT_EQ(img.Bytes(), params.img_data.size() * sizeof(float));
std::memcpy(img.Data(), params.img_data.data(), img.Bytes());
// Empty output image.
OwningVectorRef output(etype_t::f32);
// Flip image vertically.
const Algo* flip_up_down = Impl_FlipUpDown();
flip_up_down->process({&img}, {&output});
// Check resize output.
ASSERT_EQ(output.Bytes(), params.expected_data.size() * sizeof(float));
ASSERT_EQ(output.Dims(), params.expected_shape);
const float* out_data = reinterpret_cast<float*>(output.Data());
for (int i = 0; i < output.NumElements(); ++i) {
EXPECT_NEAR(out_data[i], params.expected_data[i], kAbsError)
<< "out_data[" << i << "] = " << out_data[i] << ", expected_data[" << i
<< "] = " << params.expected_data[i];
}
}
INSTANTIATE_TEST_SUITE_P(
FlipUpDownTests, FlipUpDownTest,
testing::ValuesIn({
FlipUpDownTestParams{/*img_dims=*/{1, 3, 3, 1},
/*img_data=*/
{11, 12, 13, //
21, 22, 23, //
31, 32, 33},
/*expected_data=*/
{31, 32, 33, //
21, 22, 23, //
11, 12, 13},
/*expected_shape=*/{1, 3, 3, 1}},
FlipUpDownTestParams{/*img_dims=*/{1, 3, 3, 2},
/*img_data=*/
{11, 2, 12, 3, 13, 4, //
21, 3, 22, 4, 23, 5, //
31, 4, 32, 5, 33, 6},
/*expected_data=*/
{31, 4, 32, 5, 33, 6, //
21, 3, 22, 4, 23, 5, //
11, 2, 12, 3, 13, 4},
/*expected_shape=*/{1, 3, 3, 2}},
FlipUpDownTestParams{/*img_dims=*/{2, 3, 3, 2},
/*img_data=*/
{11, 2, 12, 3, 13, 4, //
21, 3, 22, 4, 23, 5, //
31, 4, 32, 5, 33, 6, //
//
13, 4, 12, 3, 11, 2, //
23, 5, 22, 4, 21, 3, //
33, 6, 32, 5, 31, 4},
/*expected_data=*/
{31, 4, 32, 5, 33, 6, //
21, 3, 22, 4, 23, 5, //
11, 2, 12, 3, 13, 4, //
//
33, 6, 32, 5, 31, 4, //
23, 5, 22, 4, 21, 3, //
13, 4, 12, 3, 11, 2},
/*expected_shape=*/{2, 3, 3, 2}},
}));
} // namespace
} // namespace flip_up_down
} // namespace ml_adj
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册