!3447 Add Crop and SwapRedBlue to C++ API

Merge pull request !3447 from EricZ/crop_rbswap
This commit is contained in:
mindspore-ci-bot 2020-07-25 18:47:05 +08:00 committed by Gitee
commit 7478c26b75
11 changed files with 425 additions and 1 deletions

View File

@ -18,6 +18,7 @@
#include "minddata/dataset/kernels/image/image_utils.h"
#include "minddata/dataset/kernels/image/center_crop_op.h"
#include "minddata/dataset/kernels/image/crop_op.h"
#include "minddata/dataset/kernels/image/cut_out_op.h"
#include "minddata/dataset/kernels/image/decode_op.h"
#include "minddata/dataset/kernels/image/normalize_op.h"
@ -28,6 +29,7 @@
#include "minddata/dataset/kernels/image/random_rotation_op.h"
#include "minddata/dataset/kernels/image/random_vertical_flip_op.h"
#include "minddata/dataset/kernels/image/resize_op.h"
#include "minddata/dataset/kernels/image/swap_red_blue_op.h"
#include "minddata/dataset/kernels/image/uniform_aug_op.h"
namespace mindspore {
@ -49,6 +51,16 @@ std::shared_ptr<CenterCropOperation> CenterCrop(std::vector<int32_t> size) {
return op;
}
// Function to create CropOperation.
std::shared_ptr<CropOperation> Crop(std::vector<int32_t> coordinates, std::vector<int32_t> size) {
auto op = std::make_shared<CropOperation>(coordinates, size);
// Input validation
if (!op->ValidateParams()) {
return nullptr;
}
return op;
}
// Function to create CutOutOp.
std::shared_ptr<CutOutOperation> CutOut(int32_t length, int32_t num_patches) {
auto op = std::make_shared<CutOutOperation>(length, num_patches);
@ -155,6 +167,16 @@ std::shared_ptr<ResizeOperation> Resize(std::vector<int32_t> size, Interpolation
return op;
}
// Function to create SwapRedBlueOperation.
std::shared_ptr<SwapRedBlueOperation> SwapRedBlue() {
auto op = std::make_shared<SwapRedBlueOperation>();
// Input validation
if (!op->ValidateParams()) {
return nullptr;
}
return op;
}
// Function to create UniformAugOperation.
std::shared_ptr<UniformAugOperation> UniformAugment(std::vector<std::shared_ptr<TensorOperation>> transforms,
int32_t num_ops) {
@ -192,6 +214,36 @@ std::shared_ptr<TensorOp> CenterCropOperation::Build() {
return tensor_op;
}
// CropOperation.
CropOperation::CropOperation(std::vector<int32_t> coordinates, std::vector<int32_t> size)
: coordinates_(coordinates), size_(size) {}
bool CropOperation::ValidateParams() {
// Do some input validation.
if (coordinates_.empty() || coordinates_.size() > 2) {
MS_LOG(ERROR) << "Crop: coordinates must be a vector of one or two values";
return false;
}
if (size_.empty() || size_.size() > 2) {
MS_LOG(ERROR) << "Crop: size must be a vector of one or two values";
return false;
}
return true;
}
std::shared_ptr<TensorOp> CropOperation::Build() {
int32_t x, y, height, width;
x = coordinates_[0];
y = coordinates_[1];
height = size_[0];
width = size_[1];
std::shared_ptr<CropOp> tensor_op = std::make_shared<CropOp>(x, y, height, width);
return tensor_op;
}
// CutOutOperation
CutOutOperation::CutOutOperation(int32_t length, int32_t num_patches) : length_(length), num_patches_(num_patches) {}
@ -472,6 +524,16 @@ std::shared_ptr<TensorOp> ResizeOperation::Build() {
return std::make_shared<ResizeOp>(height, width, interpolation_);
}
// SwapRedBlueOperation.
SwapRedBlueOperation::SwapRedBlueOperation() {}
bool SwapRedBlueOperation::ValidateParams() { return true; }
std::shared_ptr<TensorOp> SwapRedBlueOperation::Build() {
std::shared_ptr<SwapRedBlueOp> tensor_op = std::make_shared<SwapRedBlueOp>();
return tensor_op;
}
// UniformAugOperation
UniformAugOperation::UniformAugOperation(std::vector<std::shared_ptr<TensorOperation>> transforms, int32_t num_ops)
: transforms_(transforms), num_ops_(num_ops) {}

View File

@ -58,6 +58,8 @@ class RandomRotationOperation;
class PadOperation;
class CutOutOperation;
class RandomColorAdjustOperation;
class CropOperation;
class SwapRedBlueOperation;
/// \brief Function to create a Normalize TensorOperation.
/// \notes Normalize the input image with respect to mean and standard deviation.
@ -183,6 +185,18 @@ std::shared_ptr<RandomColorAdjustOperation> RandomColorAdjust(std::vector<float>
std::vector<float> saturation = {1.0, 1.0},
std::vector<float> hue = {0.0, 0.0});
/// \brief Function to create a Crop TensorOp
/// \notes Crop an image based on location and crop size
/// \param[in] coordinates Starting location of crop. Must be a vector of two values, in the form of {x_coor, y_coor}
/// \param[in] size Size of the cropped area. Must be a vector of two values, in the form of {height, width}
/// \return Shared pointer to the current TensorOp
std::shared_ptr<CropOperation> Crop(std::vector<int32_t> coordinates, std::vector<int32_t> size);
/// \brief Function to create a SwapRedBlue TensorOp
/// \notes Swaps the red and blue channels in image
/// \return Shared pointer to the current TensorOp
std::shared_ptr<SwapRedBlueOperation> SwapRedBlue();
/* ####################################### Derived TensorOperation classes ################################# */
class NormalizeOperation : public TensorOperation {
@ -373,6 +387,32 @@ class RandomColorAdjustOperation : public TensorOperation {
std::vector<float> saturation_;
std::vector<float> hue_;
};
class CropOperation : public TensorOperation {
public:
CropOperation(std::vector<int32_t> coordinates, std::vector<int32_t> size);
~CropOperation() = default;
std::shared_ptr<TensorOp> Build() override;
bool ValidateParams() override;
private:
std::vector<int32_t> coordinates_;
std::vector<int32_t> size_;
};
class SwapRedBlueOperation : public TensorOperation {
public:
SwapRedBlueOperation();
~SwapRedBlueOperation() = default;
std::shared_ptr<TensorOp> Build() override;
bool ValidateParams() override;
};
} // namespace vision
} // namespace api
} // namespace dataset

View File

@ -3,6 +3,7 @@ set_property(SOURCE ${_CURRENT_SRC_FILES} PROPERTY COMPILE_DEFINITIONS SUBMODULE
add_library(kernels-image OBJECT
auto_contrast_op.cc
center_crop_op.cc
crop_op.cc
cut_out_op.cc
decode_op.cc
equalize_op.cc
@ -28,6 +29,7 @@ add_library(kernels-image OBJECT
rescale_op.cc
resize_bilinear_op.cc
resize_op.cc
swap_red_blue_op.cc
uniform_aug_op.cc
resize_with_bbox_op.cc
random_resize_with_bbox_op.cc

View File

@ -0,0 +1,45 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* 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 "minddata/dataset/kernels/image/crop_op.h"
#include "minddata/dataset/kernels/image/image_utils.h"
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
Status CropOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
CHECK_FAIL_RETURN_UNEXPECTED(input->shape().Size() >= 2, "The shape size " + std::to_string(input->shape().Size()) +
" of input tensor is invalid");
int32_t input_h = static_cast<int>(input->shape()[0]);
int32_t input_w = static_cast<int>(input->shape()[1]);
CHECK_FAIL_RETURN_UNEXPECTED(y_ + height_ <= input_h, "Crop height dimensions exceed image dimensions");
CHECK_FAIL_RETURN_UNEXPECTED(x_ + width_ <= input_w, "Crop width dimensions exceed image dimensions");
return Crop(input, output, x_, y_, height_, width_);
}
Status CropOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
outputs.clear();
TensorShape out = TensorShape{height_, width_};
if (inputs[0].Rank() == 2) outputs.emplace_back(out);
if (inputs[0].Rank() == 3) outputs.emplace_back(out.AppendDim(inputs[0][2]));
if (!outputs.empty()) return Status::OK();
return Status(StatusCode::kUnexpectedError, "Input has a wrong shape");
}
} // namespace dataset
} // namespace mindspore

View File

@ -0,0 +1,63 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* 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 MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_CROP_OP_H_
#define MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_CROP_OP_H_
#include <memory>
#include <vector>
#include <string>
#include "minddata/dataset/core/tensor.h"
#include "minddata/dataset/kernels/image/image_utils.h"
#include "minddata/dataset/kernels/tensor_op.h"
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
class CropOp : public TensorOp {
public:
/// \brief Constructor to Crop Op
/// \param[in] x - the horizontal starting coordinate
/// \param[in] y - the vertical starting coordinate
/// \param[in] height - the height of the crop box
/// \param[in] width - the width of the crop box
explicit CropOp(int32_t x, int32_t y, int32_t height, int32_t width) : x_(x), y_(y), height_(height), width_(width) {}
CropOp(const CropOp &rhs) = default;
CropOp(CropOp &&rhs) = default;
~CropOp() override = default;
void Print(std::ostream &out) const override {
out << "CropOp x: " << x_ << " y: " << y_ << " w: " << width_ << " h: " << height_;
}
Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override;
Status OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) override;
std::string Name() const override { return kCropOp; }
protected:
int32_t x_;
int32_t y_;
int32_t height_;
int32_t width_;
};
} // namespace dataset
} // namespace mindspore
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_CROP_OP_H_

View File

@ -0,0 +1,29 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* 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 "minddata/dataset/kernels/image/swap_red_blue_op.h"
#include "minddata/dataset/kernels/image/image_utils.h"
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
Status SwapRedBlueOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
return SwapRedAndBlue(input, output);
}
} // namespace dataset
} // namespace mindspore

View File

@ -0,0 +1,57 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* 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 MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_SWAP_RED_BLUE_OP_H_
#define MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_SWAP_RED_BLUE_OP_H_
#include <memory>
#include <vector>
#include <string>
#include "minddata/dataset/core/tensor.h"
#include "minddata/dataset/kernels/image/image_utils.h"
#include "minddata/dataset/kernels/tensor_op.h"
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
class SwapRedBlueOp : public TensorOp {
public:
// SwapRedBlues the image to the output specified size. If only one value is provided,
// the it will crop the smaller size and maintains the aspect ratio.
// @param size1: the first size of output. If only this parameter is provided
// the smaller dimension will be cropd to this and then the other dimension changes
// such that the aspect ratio is maintained.
// @param size2: the second size of output. If this is also provided, the output size
// will be (size1, size2)
// @param InterpolationMode: the interpolation mode being used.
SwapRedBlueOp() {}
SwapRedBlueOp(const SwapRedBlueOp &rhs) = default;
SwapRedBlueOp(SwapRedBlueOp &&rhs) = default;
~SwapRedBlueOp() override = default;
void Print(std::ostream &out) const override { out << "SwapRedBlueOp x"; }
Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override;
std::string Name() const override { return kSwapRedBlueOp; }
};
} // namespace dataset
} // namespace mindspore
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_SWAP_RED_BLUE_OP_H_

View File

@ -92,6 +92,7 @@ constexpr char kBoundingBoxAugmentOp[] = "BoundingBoxAugmentOp";
constexpr char kDecodeOp[] = "DecodeOp";
constexpr char kCenterCropOp[] = "CenterCropOp";
constexpr char kCutOutOp[] = "CutOutOp";
constexpr char kCropOp[] = "CropOp";
constexpr char kEqualizeOp[] = "EqualizeOp";
constexpr char kHwcToChwOp[] = "HwcToChwOp";
constexpr char kInvertOp[] = "InvertOp";
@ -114,6 +115,7 @@ constexpr char kRescaleOp[] = "RescaleOp";
constexpr char kResizeBilinearOp[] = "ResizeBilinearOp";
constexpr char kResizeOp[] = "ResizeOp";
constexpr char kResizeWithBBoxOp[] = "ResizeWithBBoxOp";
constexpr char kSwapRedBlueOp[] = "SwapRedBlueOp";
constexpr char kUniformAugOp[] = "UniformAugOp";
// text

View File

@ -55,7 +55,7 @@ SET(DE_UT_SRCS
resize_bilinear_op_test.cc
resize_op_test.cc
resize_with_bbox_op_test.cc
schema_test.cc
schema_test.cc
shuffle_op_test.cc
stand_alone_samplers_test.cc
status_test.cc
@ -96,6 +96,7 @@ SET(DE_UT_SRCS
sliding_window_op_test.cc
epoch_ctrl_op_test.cc
sentence_piece_vocab_op_test.cc
swap_red_blue_test.cc
)
add_executable(de_ut_tests ${DE_UT_SRCS})

View File

@ -0,0 +1,77 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* 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 "common/common.h"
#include "common/cvop_common.h"
#include "minddata/dataset/kernels/image/crop_op.h"
#include "utils/log_adapter.h"
using namespace mindspore::dataset;
using mindspore::MsLogLevel::INFO;
using mindspore::ExceptionType::NoExceptionType;
using mindspore::LogStream;
class MindDataTestCropOp : public UT::CVOP::CVOpCommon {
protected:
MindDataTestCropOp() : CVOpCommon() {}
std::shared_ptr<Tensor> output_tensor_;
};
TEST_F(MindDataTestCropOp, TestOp1) {
MS_LOG(INFO) << "Doing testCrop.";
// Crop params
int crop_height = 18;
int crop_width = 12;
std::unique_ptr<CropOp> op(new CropOp(0, 0, crop_height, crop_width));
EXPECT_TRUE(op->OneToOne());
Status s = op->Compute(input_tensor_, &output_tensor_);
size_t actual = 0;
if (s == Status::OK()) {
actual = output_tensor_->shape()[0] * output_tensor_->shape()[1] * output_tensor_->shape()[2];
}
EXPECT_EQ(crop_height, output_tensor_->shape()[1]);
EXPECT_EQ(actual, crop_height * crop_width * 3);
EXPECT_EQ(s, Status::OK());
}
TEST_F(MindDataTestCropOp, TestOp2) {
MS_LOG(INFO) << "Doing testCrop negative coordinates.";
// Crop params
unsigned int crop_height = 10;
unsigned int crop_width = 10;
std::unique_ptr<CropOp> op(
new CropOp(-10, -10, crop_height, crop_width));
EXPECT_TRUE(op->OneToOne());
Status s = op->Compute(input_tensor_, &output_tensor_);
EXPECT_EQ(false, s.IsOk());
MS_LOG(INFO) << "testCrop coordinate exception end.";
}
TEST_F(MindDataTestCropOp, TestOp3) {
MS_LOG(INFO) << "Doing testCrop size too large.";
// Crop params
unsigned int crop_height = 1200000;
unsigned int crop_width = 1200000;
std::unique_ptr<CropOp> op(
new CropOp(0, 0, crop_height, crop_width));
EXPECT_TRUE(op->OneToOne());
Status s = op->Compute(input_tensor_, &output_tensor_);
EXPECT_EQ(false, s.IsOk());
MS_LOG(INFO) << "testCrop size exception end.";
}

View File

@ -0,0 +1,46 @@
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* 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 "common/common.h"
#include "common/cvop_common.h"
#include "minddata/dataset/kernels/image/swap_red_blue_op.h"
#include "utils/log_adapter.h"
using namespace mindspore::dataset;
using mindspore::MsLogLevel::INFO;
using mindspore::ExceptionType::NoExceptionType;
using mindspore::LogStream;
class MindDataTestSwapRedBlueOp : public UT::CVOP::CVOpCommon {
protected:
MindDataTestSwapRedBlueOp() : CVOpCommon() {}
std::shared_ptr<Tensor> output_tensor_;
};
TEST_F(MindDataTestSwapRedBlueOp, TestOp1) {
MS_LOG(INFO) << "Doing testSwapRedBlue.";
// SwapRedBlue params
std::unique_ptr<SwapRedBlueOp> op(new SwapRedBlueOp());
EXPECT_TRUE(op->OneToOne());
Status s = op->Compute(input_tensor_, &output_tensor_);
size_t actual = 0;
if (s == Status::OK()) {
actual = output_tensor_->shape()[0] * output_tensor_->shape()[1] * output_tensor_->shape()[2];
}
EXPECT_EQ(actual, input_tensor_->shape()[0] * input_tensor_->shape()[1] * 3);
EXPECT_EQ(s, Status::OK());
}