Browse Source

!3447 Add Crop and SwapRedBlue to C++ API

Merge pull request !3447 from EricZ/crop_rbswap
tags/v0.7.0-beta
mindspore-ci-bot Gitee 5 years ago
parent
commit
7478c26b75
11 changed files with 425 additions and 1 deletions
  1. +62
    -0
      mindspore/ccsrc/minddata/dataset/api/transforms.cc
  2. +40
    -0
      mindspore/ccsrc/minddata/dataset/include/transforms.h
  3. +2
    -0
      mindspore/ccsrc/minddata/dataset/kernels/image/CMakeLists.txt
  4. +45
    -0
      mindspore/ccsrc/minddata/dataset/kernels/image/crop_op.cc
  5. +63
    -0
      mindspore/ccsrc/minddata/dataset/kernels/image/crop_op.h
  6. +29
    -0
      mindspore/ccsrc/minddata/dataset/kernels/image/swap_red_blue_op.cc
  7. +57
    -0
      mindspore/ccsrc/minddata/dataset/kernels/image/swap_red_blue_op.h
  8. +2
    -0
      mindspore/ccsrc/minddata/dataset/kernels/tensor_op.h
  9. +2
    -1
      tests/ut/cpp/dataset/CMakeLists.txt
  10. +77
    -0
      tests/ut/cpp/dataset/crop_op_test.cc
  11. +46
    -0
      tests/ut/cpp/dataset/swap_red_blue_test.cc

+ 62
- 0
mindspore/ccsrc/minddata/dataset/api/transforms.cc 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) {}


+ 40
- 0
mindspore/ccsrc/minddata/dataset/include/transforms.h 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


+ 2
- 0
mindspore/ccsrc/minddata/dataset/kernels/image/CMakeLists.txt 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


+ 45
- 0
mindspore/ccsrc/minddata/dataset/kernels/image/crop_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

+ 63
- 0
mindspore/ccsrc/minddata/dataset/kernels/image/crop_op.h 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_

+ 29
- 0
mindspore/ccsrc/minddata/dataset/kernels/image/swap_red_blue_op.cc 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

+ 57
- 0
mindspore/ccsrc/minddata/dataset/kernels/image/swap_red_blue_op.h 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_

+ 2
- 0
mindspore/ccsrc/minddata/dataset/kernels/tensor_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


+ 2
- 1
tests/ut/cpp/dataset/CMakeLists.txt 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})


+ 77
- 0
tests/ut/cpp/dataset/crop_op_test.cc 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.";
}


+ 46
- 0
tests/ut/cpp/dataset/swap_red_blue_test.cc 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());
}


Loading…
Cancel
Save