!19748 Fix param check and default value of center in Rotate and RandomRotation Ops

Merge pull request !19748 from xiaotianci/fix_rotate_center
This commit is contained in:
i-robot 2021-07-10 08:07:00 +00:00 committed by Gitee
commit 53633ebfd8
14 changed files with 58 additions and 59 deletions

View File

@ -642,13 +642,13 @@ class RandomRotation final : public TensorTransform {
/// - InterpolationMode::kArea, Interpolation method is pixel area interpolation.
/// - InterpolationMode::kCubicPil, Interpolation method is bicubic interpolation like implemented in pillow.
/// \param[in] expand A boolean representing whether the image is expanded after rotation.
/// \param[in] center A float vector of size 2, representing the x and y center of rotation.
/// \param[in] center A float vector of size 2 or empty, representing the x and y center of rotation
/// or the center of the image.
/// \param[in] fill_value A vector representing the value to fill the area outside the transform
/// in the output image. If 1 value is provided, it is used for all RGB channels.
/// If 3 values are provided, it is used to fill R, G, B channels respectively.
RandomRotation(std::vector<float> degrees, InterpolationMode resample = InterpolationMode::kNearestNeighbour,
bool expand = false, std::vector<float> center = {-1, -1},
std::vector<uint8_t> fill_value = {0, 0, 0});
bool expand = false, std::vector<float> center = {}, std::vector<uint8_t> fill_value = {0, 0, 0});
/// \brief Destructor.
~RandomRotation() = default;

View File

@ -323,12 +323,13 @@ class Rotate final : public TensorTransform {
/// - InterpolationMode::kArea, Interpolation method is pixel area interpolation.
/// - InterpolationMode::kCubicPil, Interpolation method is bicubic interpolation like implemented in pillow.
/// \param[in] expand A boolean representing whether the image is expanded after rotation.
/// \param[in] center A float vector of size 2, representing the x and y center of rotation.
/// \param[in] center A float vector of size 2 or empty, representing the x and y center of rotation
/// or the center of the image.
/// \param[in] fill_value A vector representing the value to fill the area outside the transform
/// in the output image. If 1 value is provided, it is used for all RGB channels.
/// If 3 values are provided, it is used to fill R, G, B channels respectively.
Rotate(float degrees, InterpolationMode resample = InterpolationMode::kNearestNeighbour, bool expand = false,
std::vector<float> center = {-1, -1}, std::vector<uint8_t> fill_value = {0, 0, 0});
std::vector<float> center = {}, std::vector<uint8_t> fill_value = {0, 0, 0});
/// \brief Destructor.
~Rotate() = default;

View File

@ -627,8 +627,9 @@ Status CropAndResize(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tenso
}
}
Status Rotate(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, float fx, float fy, float degree,
InterpolationMode interpolation, bool expand, uint8_t fill_r, uint8_t fill_g, uint8_t fill_b) {
Status Rotate(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, std::vector<float> center,
float degree, InterpolationMode interpolation, bool expand, uint8_t fill_r, uint8_t fill_g,
uint8_t fill_b) {
try {
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input);
if (!input_cv->mat().data) {
@ -642,12 +643,14 @@ Status Rotate(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *out
if (input_img.cols > (MAX_INT_PRECISION * 2) || input_img.rows > (MAX_INT_PRECISION * 2)) {
RETURN_STATUS_UNEXPECTED("Rotate: image is too large and center is not precise.");
}
// default to center of image
if (fx == -1) {
float fx = 0, fy = 0;
if (center.empty()) {
// default to center of image
fx = (input_img.cols - 1) / 2.0;
}
if (fy == -1) {
fy = (input_img.rows - 1) / 2.0;
} else {
fx = center[0];
fy = center[1];
}
cv::Mat output_img;
cv::Scalar fill_color = cv::Scalar(fill_b, fill_g, fill_r);

View File

@ -183,13 +183,12 @@ Status CropAndResize(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tenso
/// \brief Returns rotated image
/// \param input: Tensor of shape <H,W,C> or <H,W> and any OpenCv compatible type, see CVTensor.
/// \param fx: rotation center x coordinate
/// \param fy: rotation center y coordinate
/// \param center: rotation center
/// \param degree: degree to rotate
/// \param expand: if reshape is necessary
/// \param output: rotated image of same input type.
Status Rotate(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, float fx, float fy, float degree,
InterpolationMode interpolation = InterpolationMode::kNearestNeighbour, bool expand = false,
Status Rotate(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, std::vector<float> center,
float degree, InterpolationMode interpolation = InterpolationMode::kNearestNeighbour, bool expand = false,
uint8_t fill_r = 0, uint8_t fill_g = 0, uint8_t fill_b = 0);
/// \brief Returns Normalized image

View File

@ -24,8 +24,7 @@
namespace mindspore {
namespace dataset {
const float RandomRotationOp::kDefCenterX = -1;
const float RandomRotationOp::kDefCenterY = -1;
const std::vector<float> RandomRotationOp::kDefCenter = {};
const InterpolationMode RandomRotationOp::kDefInterpolation = InterpolationMode::kNearestNeighbour;
const bool RandomRotationOp::kDefExpand = false;
const uint8_t RandomRotationOp::kDefFillR = 0;
@ -34,11 +33,10 @@ const uint8_t RandomRotationOp::kDefFillB = 0;
// constructor
RandomRotationOp::RandomRotationOp(float start_degree, float end_degree, InterpolationMode resample, bool expand,
float center_x, float center_y, uint8_t fill_r, uint8_t fill_g, uint8_t fill_b)
std::vector<float> center, uint8_t fill_r, uint8_t fill_g, uint8_t fill_b)
: degree_start_(start_degree),
degree_end_(end_degree),
center_x_(center_x),
center_y_(center_y),
center_(center),
interpolation_(resample),
expand_(expand),
fill_r_(fill_r),
@ -60,8 +58,9 @@ Status RandomRotationOp::Compute(const std::shared_ptr<Tensor> &input, std::shar
float mid = (degree_end_ + degree_start_) / 2;
float degree = mid + random_double * degree_range;
return Rotate(input, output, center_x_, center_y_, degree, interpolation_, expand_, fill_r_, fill_g_, fill_b_);
return Rotate(input, output, center_, degree, interpolation_, expand_, fill_r_, fill_g_, fill_b_);
}
Status RandomRotationOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
outputs.clear();

View File

@ -31,8 +31,7 @@ namespace dataset {
class RandomRotationOp : public TensorOp {
public:
// Default values, also used by python_bindings.cc
static const float kDefCenterX;
static const float kDefCenterY;
static const std::vector<float> kDefCenter;
static const InterpolationMode kDefInterpolation;
static const bool kDefExpand;
static const uint8_t kDefFillR;
@ -44,8 +43,7 @@ class RandomRotationOp : public TensorOp {
// @param endDegree ending range for random degree
// @param interpolation DE interpolation mode for rotation
// @param expand option for the output image shape to change
// @param center_x coordinate for center of image rotation
// @param center_y coordinate for center of image rotation
// @param center coordinate for center of image rotation
// @param fill_r R value for the color to pad with
// @param fill_g G value for the color to pad with
// @param fill_b B value for the color to pad with
@ -53,8 +51,8 @@ class RandomRotationOp : public TensorOp {
// @details the output shape, if changed, will contain the entire rotated image
// @note maybe using unsigned long int isn't the best here according to our coding rules
RandomRotationOp(float start_degree, float end_degree, InterpolationMode resample = kDefInterpolation,
bool expand = kDefExpand, float center_x = kDefCenterX, float center_y = kDefCenterY,
uint8_t fill_r = kDefFillR, uint8_t fill_g = kDefFillG, uint8_t fill_b = kDefFillB);
bool expand = kDefExpand, std::vector<float> center = kDefCenter, uint8_t fill_r = kDefFillR,
uint8_t fill_g = kDefFillG, uint8_t fill_b = kDefFillB);
~RandomRotationOp() override = default;
@ -63,6 +61,7 @@ class RandomRotationOp : public TensorOp {
// and transforms its data using openCV, the output memory is manipulated to contain the result
// @return Status The status code returned
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 kRandomRotationOp; }
@ -70,8 +69,7 @@ class RandomRotationOp : public TensorOp {
private:
float degree_start_;
float degree_end_;
float center_x_;
float center_y_;
std::vector<float> center_;
InterpolationMode interpolation_;
bool expand_;
uint8_t fill_r_;

View File

@ -24,8 +24,7 @@
namespace mindspore {
namespace dataset {
const float RotateOp::kDefCenterX = -1;
const float RotateOp::kDefCenterY = -1;
const std::vector<float> RotateOp::kDefCenter = {};
const InterpolationMode RotateOp::kDefInterpolation = InterpolationMode::kNearestNeighbour;
const bool RotateOp::kDefExpand = false;
const uint8_t RotateOp::kDefFillR = 0;
@ -34,11 +33,10 @@ const uint8_t RotateOp::kDefFillB = 0;
RotateOp::RotateOp(int angle_id) : angle_id_(angle_id) {}
RotateOp::RotateOp(float degrees, InterpolationMode resample, bool expand, float center_x, float center_y,
uint8_t fill_r, uint8_t fill_g, uint8_t fill_b)
RotateOp::RotateOp(float degrees, InterpolationMode resample, bool expand, std::vector<float> center, uint8_t fill_r,
uint8_t fill_g, uint8_t fill_b)
: degrees_(degrees),
center_x_(center_x),
center_y_(center_y),
center_(center),
interpolation_(resample),
expand_(expand),
fill_r_(fill_r),
@ -48,7 +46,7 @@ RotateOp::RotateOp(float degrees, InterpolationMode resample, bool expand, float
Status RotateOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
#ifndef ENABLE_ANDROID
return Rotate(input, output, center_x_, center_y_, degrees_, interpolation_, expand_, fill_r_, fill_g_, fill_b_);
return Rotate(input, output, center_, degrees_, interpolation_, expand_, fill_r_, fill_g_, fill_b_);
#else
return Rotate(input, output, angle_id_);
#endif

View File

@ -30,8 +30,7 @@ namespace dataset {
class RotateOp : public TensorOp {
public:
// Default values, also used by python_bindings.cc
static const float kDefCenterX;
static const float kDefCenterY;
static const std::vector<float> kDefCenter;
static const InterpolationMode kDefInterpolation;
static const bool kDefExpand;
static const uint8_t kDefFillR;
@ -42,8 +41,8 @@ class RotateOp : public TensorOp {
explicit RotateOp(int angle_id);
explicit RotateOp(float degrees, InterpolationMode resample = kDefInterpolation, bool expand = kDefExpand,
float center_x = kDefCenterX, float center_y = kDefCenterY, uint8_t fill_r = kDefFillR,
uint8_t fill_g = kDefFillG, uint8_t fill_b = kDefFillB);
std::vector<float> center = kDefCenter, uint8_t fill_r = kDefFillR, uint8_t fill_g = kDefFillG,
uint8_t fill_b = kDefFillB);
~RotateOp() override = default;
@ -61,8 +60,7 @@ class RotateOp : public TensorOp {
private:
float degrees_;
float center_x_;
float center_y_;
std::vector<float> center_;
InterpolationMode interpolation_;
bool expand_;
uint8_t fill_r_;

View File

@ -64,9 +64,9 @@ Status RandomRotationOperation::ValidateParams() {
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
// center
if (center_.empty() || center_.size() != 2) {
if (center_.size() != 0 && center_.size() != 2) {
std::string err_msg =
"RandomRotation: center must be a vector of two values, got: " + std::to_string(center_.size());
"RandomRotation: center must be a vector of two values or empty, got: " + std::to_string(center_.size());
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
@ -97,7 +97,7 @@ std::shared_ptr<TensorOp> RandomRotationOperation::Build() {
}
std::shared_ptr<RandomRotationOp> tensor_op = std::make_shared<RandomRotationOp>(
start_degree, end_degree, interpolation_mode_, expand_, center_[0], center_[1], fill_r, fill_g, fill_b);
start_degree, end_degree, interpolation_mode_, expand_, center_, fill_r, fill_g, fill_b);
return tensor_op;
}

View File

@ -37,8 +37,9 @@ std::string RotateOperation::Name() const { return kRotateOperation; }
Status RotateOperation::ValidateParams() {
#ifndef ENABLE_ANDROID
// center
if (center_.empty() || center_.size() != 2) {
std::string err_msg = "Rotate: center must be a vector of two values, got: " + std::to_string(center_.size());
if (center_.size() != 0 && center_.size() != 2) {
std::string err_msg =
"Rotate: center must be a vector of two values or empty, got: " + std::to_string(center_.size());
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
@ -62,7 +63,7 @@ std::shared_ptr<TensorOp> RotateOperation::Build() {
}
std::shared_ptr<RotateOp> tensor_op =
std::make_shared<RotateOp>(degrees_, interpolation_mode_, expand_, center_[0], center_[1], fill_r, fill_g, fill_b);
std::make_shared<RotateOp>(degrees_, interpolation_mode_, expand_, center_, fill_r, fill_g, fill_b);
return tensor_op;
#else
return rotate_op_;

View File

@ -90,6 +90,7 @@ DE_C_INTER_MODE = {Inter.NEAREST: cde.InterpolationMode.DE_INTER_NEAREST_NEIGHBO
DE_C_SLICE_MODE = {SliceMode.PAD: cde.SliceMode.DE_SLICE_PAD,
SliceMode.DROP: cde.SliceMode.DE_SLICE_DROP}
def parse_padding(padding):
""" Parses and prepares the padding tuple"""
if isinstance(padding, numbers.Number):
@ -1214,7 +1215,7 @@ class RandomRotation(ImageTensorOperation):
if degrees[0] > degrees[1]:
degrees[1] += 360
if center is None:
center = (-1, -1)
center = ()
if isinstance(fill_value, int):
fill_value = tuple([fill_value] * 3)
self.degrees = degrees
@ -1525,7 +1526,7 @@ class Rotate(ImageTensorOperation):
if isinstance(degrees, (int, float)):
degrees = degrees % 360
if center is None:
center = (-1, -1)
center = ()
if isinstance(fill_value, int):
fill_value = tuple([fill_value] * 3)
self.degrees = degrees
@ -1576,6 +1577,7 @@ class SlicePatches(ImageTensorOperation):
return cde.SlicePatchesOperation(self.num_height, self.num_width,
DE_C_SLICE_MODE[self.slice_mode], self.fill_value)
class SoftDvppDecodeRandomCropResizeJpeg(ImageTensorOperation):
"""
A combination of `Crop`, `Decode` and `Resize` using the simulation algorithm of Ascend series chip DVPP module.

View File

@ -20,8 +20,9 @@ import numpy as np
from mindspore._c_dataengine import TensorOp, TensorOperation
from mindspore.dataset.core.validator_helpers import check_value, check_uint8, FLOAT_MAX_INTEGER, check_pos_float32, \
check_float32, check_2tuple, check_range, check_positive, INT32_MAX, parse_user_args, type_check, type_check_list, \
check_c_tensor_op, UINT8_MAX, check_value_normalize_std, check_value_cutoff, check_value_ratio, check_odd
check_float32, check_2tuple, check_range, check_positive, INT32_MAX, INT32_MIN, parse_user_args, type_check, \
type_check_list, check_c_tensor_op, UINT8_MAX, check_value_normalize_std, check_value_cutoff, check_value_ratio, \
check_odd
from .utils import Inter, Border, ImageBatchFormat, SliceMode
@ -427,7 +428,7 @@ def check_resample_expand_center_fill_value_params(resample, expand, center, fil
check_2tuple(center, "center")
for value in center:
type_check(value, (int, float), "center")
check_value(value, [-1, INT32_MAX], "center")
check_value(value, [INT32_MIN, INT32_MAX], "center")
check_fill_value(fill_value)
@ -528,6 +529,7 @@ def check_slice_patches(method):
return new_method
def check_random_perspective(method):
"""Wrapper method to check the parameters of random perspective."""

View File

@ -35,11 +35,10 @@ TEST_F(MindDataTestRandomRotationOp, TestOp) {
float sDegree = -180;
float eDegree = 180;
// use compute center to use for rotation
float xCenter = -1;
float yCenter = -1;
std::vector<float> center = {};
bool expand = false;
std::unique_ptr<RandomRotationOp> op(
new RandomRotationOp(sDegree, eDegree, InterpolationMode::kLinear, expand, xCenter, yCenter));
new RandomRotationOp(sDegree, eDegree, InterpolationMode::kLinear, expand, center));
EXPECT_TRUE(op->OneToOne());
Status s = op->Compute(input_tensor_, &output_tensor);
EXPECT_TRUE(s.IsOk());

View File

@ -36,11 +36,10 @@ TEST_F(MindDataTestToFloat16Op, TestOp) {
float s_degree = -180;
float e_degree = 180;
// use compute center to use for rotation
float x_center = -1;
float y_center = -1;
std::vector<float> center = {};
bool expand = false;
std::unique_ptr<RandomRotationOp> op(
new RandomRotationOp(s_degree, e_degree, InterpolationMode::kLinear, expand, x_center, y_center));
new RandomRotationOp(s_degree, e_degree, InterpolationMode::kLinear, expand, center));
EXPECT_TRUE(op->OneToOne());
Status s = op->Compute(input_tensor_, &output_tensor);
EXPECT_TRUE(s.IsOk());