Browse Source

!7848 Add five transforms API

Merge pull request !7848 from shenwei41/new_master
tags/v1.1.0
mindspore-ci-bot Gitee 5 years ago
parent
commit
2ba20dc8e7
3 changed files with 1008 additions and 101 deletions
  1. +316
    -98
      mindspore/ccsrc/minddata/dataset/api/vision.cc
  2. +121
    -0
      mindspore/ccsrc/minddata/dataset/include/vision.h
  3. +571
    -3
      tests/ut/cpp/dataset/c_api_vision_test.cc

+ 316
- 98
mindspore/ccsrc/minddata/dataset/api/vision.cc View File

@@ -21,6 +21,7 @@
#endif
// Kernel image headers (in alphabetical order)
#ifndef ENABLE_ANDROID
#include "minddata/dataset/kernels/image/auto_contrast_op.h"
#include "minddata/dataset/kernels/image/center_crop_op.h"
#endif
#include "minddata/dataset/kernels/image/crop_op.h"
@@ -31,6 +32,7 @@
#include "minddata/dataset/kernels/image/decode_op.h"
#ifndef ENABLE_ANDROID
#include "minddata/dataset/kernels/image/hwc_to_chw_op.h"
#include "minddata/dataset/kernels/image/invert_op.h"
#include "minddata/dataset/kernels/image/mixup_batch_op.h"
#endif
#include "minddata/dataset/kernels/image/normalize_op.h"
@@ -42,12 +44,15 @@
#include "minddata/dataset/kernels/image/random_crop_and_resize_op.h"
#include "minddata/dataset/kernels/image/random_crop_op.h"
#include "minddata/dataset/kernels/image/random_crop_decode_resize_op.h"
#include "minddata/dataset/kernels/image/random_crop_with_bbox_op.h"
#include "minddata/dataset/kernels/image/random_horizontal_flip_op.h"
#include "minddata/dataset/kernels/image/random_horizontal_flip_with_bbox_op.h"
#include "minddata/dataset/kernels/image/random_posterize_op.h"
#include "minddata/dataset/kernels/image/random_rotation_op.h"
#include "minddata/dataset/kernels/image/random_sharpness_op.h"
#include "minddata/dataset/kernels/image/random_solarize_op.h"
#include "minddata/dataset/kernels/image/random_vertical_flip_op.h"
#include "minddata/dataset/kernels/image/random_vertical_flip_with_bbox_op.h"
#include "minddata/dataset/kernels/image/rescale_op.h"
#endif
#include "minddata/dataset/kernels/image/resize_op.h"
@@ -68,6 +73,16 @@ namespace vision {
// FUNCTIONS TO CREATE VISION TRANSFORM OPERATIONS
// (In alphabetical order)

// Function to create AutoContrastOperation.
std::shared_ptr<AutoContrastOperation> AutoContrast(float cutoff, std::vector<uint32_t> ignore) {
auto op = std::make_shared<AutoContrastOperation>(cutoff, ignore);
// Input validation
if (!op->ValidateParams()) {
return nullptr;
}
return op;
}

// Function to create CenterCropOperation.
std::shared_ptr<CenterCropOperation> CenterCrop(std::vector<int32_t> size) {
auto op = std::make_shared<CenterCropOperation>(size);
@@ -129,6 +144,16 @@ std::shared_ptr<HwcToChwOperation> HWC2CHW() {
return op;
}

// Function to create InvertOperation.
std::shared_ptr<InvertOperation> Invert() {
auto op = std::make_shared<InvertOperation>();
// Input validation
if (!op->ValidateParams()) {
return nullptr;
}
return op;
}

// Function to create MixUpBatchOperation.
std::shared_ptr<MixUpBatchOperation> MixUpBatch(float alpha) {
auto op = std::make_shared<MixUpBatchOperation>(alpha);
@@ -229,6 +254,18 @@ std::shared_ptr<RandomCropDecodeResizeOperation> RandomCropDecodeResize(std::vec
return op;
}

// Function to create RandomCropWithBBoxOperation.
std::shared_ptr<RandomCropWithBBoxOperation> RandomCropWithBBox(std::vector<int32_t> size, std::vector<int32_t> padding,
bool pad_if_needed, std::vector<uint8_t> fill_value,
BorderType padding_mode) {
auto op = std::make_shared<RandomCropWithBBoxOperation>(size, padding, pad_if_needed, fill_value, padding_mode);
// Input validation
if (!op->ValidateParams()) {
return nullptr;
}
return op;
}

// Function to create RandomHorizontalFlipOperation.
std::shared_ptr<RandomHorizontalFlipOperation> RandomHorizontalFlip(float prob) {
auto op = std::make_shared<RandomHorizontalFlipOperation>(prob);
@@ -239,6 +276,16 @@ std::shared_ptr<RandomHorizontalFlipOperation> RandomHorizontalFlip(float prob)
return op;
}

// Function to create RandomHorizontalFlipOperation.
std::shared_ptr<RandomHorizontalFlipWithBBoxOperation> RandomHorizontalFlipWithBBox(float prob) {
auto op = std::make_shared<RandomHorizontalFlipWithBBoxOperation>(prob);
// Input validation
if (!op->ValidateParams()) {
return nullptr;
}
return op;
}

// Function to create RandomPosterizeOperation.
std::shared_ptr<RandomPosterizeOperation> RandomPosterize(const std::vector<uint8_t> &bit_range) {
auto op = std::make_shared<RandomPosterizeOperation>(bit_range);
@@ -303,6 +350,16 @@ std::shared_ptr<RandomVerticalFlipOperation> RandomVerticalFlip(float prob) {
return op;
}

// Function to create RandomVerticalFlipWithBBoxOperation.
std::shared_ptr<RandomVerticalFlipWithBBoxOperation> RandomVerticalFlipWithBBox(float prob) {
auto op = std::make_shared<RandomVerticalFlipWithBBoxOperation>(prob);
// Input validation
if (!op->ValidateParams()) {
return nullptr;
}
return op;
}

// Function to create RescaleOperation.
std::shared_ptr<RescaleOperation> Rescale(float rescale, float shift) {
auto op = std::make_shared<RescaleOperation>(rescale, shift);
@@ -368,6 +425,60 @@ std::shared_ptr<UniformAugOperation> UniformAugment(std::vector<std::shared_ptr<

#endif
/* ####################################### Validator Functions ############################################ */
Status ValidateVectorFillvalue(const std::string &dataset_name, const std::vector<uint8_t> &fill_value) {
if (fill_value.empty() || (fill_value.size() != 1 && fill_value.size() != 3)) {
std::string err_msg = dataset_name + ": fill_value vector has incorrect size: " + std::to_string(fill_value.size());
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
for (uint8_t single_fill_value : fill_value) {
if (single_fill_value > 255) {
std::string err_msg =
dataset_name + ": fill_value has to be between 0 and 255, got:" + std::to_string(single_fill_value);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
}

return Status::OK();
}

Status ValidateVectorProbability(const std::string &dataset_name, const float &probability) {
if (probability < 0.0 || probability > 1.0) {
std::string err_msg =
dataset_name + ": probability must be between 0.0 and 1.0, got: " + std::to_string(probability);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}

return Status::OK();
}

Status ValidateVectorPadding(const std::string &dataset_name, const std::vector<int32_t> &padding) {
if (padding.empty() || padding.size() == 3 || padding.size() > 4) {
std::string err_msg = dataset_name + ": padding vector has incorrect size: " + std::to_string(padding.size());
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
for (int32_t i = 0; i < padding.size(); ++i) {
if (padding[i] < 0) {
std::string err_msg =
dataset_name +
": invalid padding, padding value must be greater than or equal to 0, got: " + std::to_string(padding[i]);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
if (padding[i] == INT_MAX) {
std::string err_msg =
dataset_name + ": invalid padding, padding value too large, got: " + std::to_string(padding[i]);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
}

return Status::OK();
}

Status ValidateVectorPositive(const std::string &dataset_name, const std::vector<int32_t> &size) {
for (int32_t i = 0; i < size.size(); ++i) {
if (size[i] <= 0) {
@@ -387,6 +498,34 @@ bool CmpFloat(const float &a, const float &b, float epsilon = 0.0000000001f) { r

// (In alphabetical order)
#ifndef ENABLE_ANDROID

// AutoContrastOperation
AutoContrastOperation::AutoContrastOperation(float cutoff, std::vector<uint32_t> ignore)
: cutoff_(cutoff), ignore_(ignore) {}

Status AutoContrastOperation::ValidateParams() {
if (cutoff_ < 0 || cutoff_ > 100) {
std::string err_msg = "AutoContrast: cutoff has to be between 0 and 100, got: " + std::to_string(cutoff_);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}

for (uint32_t single_ignore : ignore_) {
if (single_ignore > 255) {
std::string err_msg =
"AutoContrast: invalid size, ignore has to be between 0 and 255, got: " + std::to_string(single_ignore);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
}
return Status::OK();
}

std::shared_ptr<TensorOp> AutoContrastOperation::Build() {
std::shared_ptr<AutoContrastOp> tensor_op = std::make_shared<AutoContrastOp>(cutoff_, ignore_);
return tensor_op;
}

// CenterCropOperation
CenterCropOperation::CenterCropOperation(std::vector<int32_t> size) : size_(size) {}

@@ -542,6 +681,11 @@ Status HwcToChwOperation::ValidateParams() { return Status::OK(); }

std::shared_ptr<TensorOp> HwcToChwOperation::Build() { return std::make_shared<HwcToChwOp>(); }

// InvertOperation
Status InvertOperation::ValidateParams() { return Status::OK(); }

std::shared_ptr<TensorOp> InvertOperation::Build() { return std::make_shared<InvertOp>(); }

// MixUpOperation
MixUpBatchOperation::MixUpBatchOperation(float alpha) : alpha_(alpha) {}

@@ -598,37 +742,9 @@ PadOperation::PadOperation(std::vector<int32_t> padding, std::vector<uint8_t> fi

Status PadOperation::ValidateParams() {
// padding
if (padding_.empty() || padding_.size() == 3 || padding_.size() > 4) {
std::string err_msg = "Pad: padding vector has incorrect size: " + std::to_string(padding_.size());
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
for (int32_t i = 0; i < padding_.size(); ++i) {
if (padding_[i] < 0) {
std::string err_msg =
"Pad: invalid padding, padding value must be greater than or equal to 0, got: " + std::to_string(padding_[i]);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
if (padding_[i] == INT_MAX) {
std::string err_msg = "Pad: invalid padding, padding value too large, got: " + std::to_string(padding_[i]);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
}
RETURN_IF_NOT_OK(ValidateVectorPadding("Pad", padding_));
// fill_value
if (fill_value_.empty() || (fill_value_.size() != 1 && fill_value_.size() != 3)) {
std::string err_msg = "Pad: fill_value vector has incorrect size: " + std::to_string(fill_value_.size());
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
for (int32_t i = 0; i < fill_value_.size(); ++i) {
if (fill_value_[i] < 0 || fill_value_[i] > 255) {
std::string err_msg = "Pad: fill_value has to be between 0 and 255, got:" + std::to_string(fill_value_[i]);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
}
RETURN_IF_NOT_OK(ValidateVectorFillvalue("Pad", fill_value_));
return Status::OK();
}

@@ -975,37 +1091,9 @@ Status RandomCropOperation::ValidateParams() {
}
RETURN_IF_NOT_OK(ValidateVectorPositive("RandomCrop", size_));
// padding
if (padding_.empty() || padding_.size() != 4) {
std::string err_msg = "RandomCrop: padding vector has incorrect size: " + std::to_string(padding_.size());
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
for (int32_t i = 0; i < padding_.size(); ++i) {
if (padding_[i] < 0) {
std::string err_msg = "RandomCrop: invalid padding, padding value must be greater than or equal to 0, got: " +
std::to_string(padding_[i]);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
if (padding_[i] == INT_MAX) {
std::string err_msg = "RandomCrop: invalid padding, padding value too large, got: " + std::to_string(padding_[i]);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
}
RETURN_IF_NOT_OK(ValidateVectorPadding("RandomCrop", padding_));
// fill_value
if (fill_value_.empty() || fill_value_.size() != 3) {
std::string err_msg = "RandomCrop: fill_value vector has incorrect size: " + std::to_string(fill_value_.size());
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
for (int32_t i = 0; i < fill_value_.size(); ++i) {
if (fill_value_[i] < 0 || fill_value_[i] > 255) {
std::string err_msg = "RandomCrop: fill_value has to be between 0 and 255, got:" + std::to_string(fill_value_[i]);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
}
RETURN_IF_NOT_OK(ValidateVectorFillvalue("RandomCrop", fill_value_));
return Status::OK();
}

@@ -1018,14 +1106,37 @@ std::shared_ptr<TensorOp> RandomCropOperation::Build() {
crop_width = size_[1];
}

int32_t pad_top = padding_[0];
int32_t pad_bottom = padding_[1];
int32_t pad_left = padding_[2];
int32_t pad_right = padding_[3];
int32_t pad_top, pad_bottom, pad_left, pad_right;
switch (padding_.size()) {
case 1:
pad_left = padding_[0];
pad_top = padding_[0];
pad_right = padding_[0];
pad_bottom = padding_[0];
break;
case 2:
pad_left = padding_[0];
pad_top = padding_[1];
pad_right = padding_[0];
pad_bottom = padding_[1];
break;
default:
pad_left = padding_[0];
pad_top = padding_[1];
pad_right = padding_[2];
pad_bottom = padding_[3];
}

uint8_t fill_r, fill_g, fill_b;
fill_r = fill_value_[0];
fill_g = fill_value_[0];
fill_b = fill_value_[0];

uint8_t fill_r = fill_value_[0];
uint8_t fill_g = fill_value_[1];
uint8_t fill_b = fill_value_[2];
if (fill_value_.size() == 3) {
fill_r = fill_value_[0];
fill_g = fill_value_[1];
fill_b = fill_value_[2];
}

auto tensor_op = std::make_shared<RandomCropOp>(crop_height, crop_width, pad_top, pad_bottom, pad_left, pad_right,
padding_mode_, pad_if_needed_, fill_r, fill_g, fill_b);
@@ -1125,15 +1236,83 @@ std::shared_ptr<TensorOp> RandomCropDecodeResizeOperation::Build() {
return tensor_op;
}

// RandomHorizontalFlipOperation
RandomHorizontalFlipOperation::RandomHorizontalFlipOperation(float probability) : probability_(probability) {}
// RandomCropWithBBoxOperation
RandomCropWithBBoxOperation::RandomCropWithBBoxOperation(std::vector<int32_t> size, std::vector<int32_t> padding,
bool pad_if_needed, std::vector<uint8_t> fill_value,
BorderType padding_mode)
: size_(size),
padding_(padding),
pad_if_needed_(pad_if_needed),
fill_value_(fill_value),
padding_mode_(padding_mode) {}

Status RandomHorizontalFlipOperation::ValidateParams() {
if (probability_ < 0.0 || probability_ > 1.0) {
std::string err_msg = "RandomHorizontalFlip: probability must be between 0.0 and 1.0.";
Status RandomCropWithBBoxOperation::ValidateParams() {
// size
if (size_.empty() || size_.size() > 2) {
std::string err_msg = "RandomCropWithBBox: size must be a vector of one or two values";
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
RETURN_IF_NOT_OK(ValidateVectorPositive("RandomCropWithBBox", size_));
// padding
RETURN_IF_NOT_OK(ValidateVectorPadding("RandomCropWithBBox", padding_));
// fill_value
RETURN_IF_NOT_OK(ValidateVectorFillvalue("RandomCropWithBBox", fill_value_));
return Status::OK();
}

std::shared_ptr<TensorOp> RandomCropWithBBoxOperation::Build() {
int32_t crop_height = size_[0];
int32_t crop_width = size_[0];

// User has specified the crop_width value.
if (size_.size() == 2) {
crop_width = size_[1];
}

int32_t pad_top, pad_bottom, pad_left, pad_right;
switch (padding_.size()) {
case 1:
pad_left = padding_[0];
pad_top = padding_[0];
pad_right = padding_[0];
pad_bottom = padding_[0];
break;
case 2:
pad_left = padding_[0];
pad_top = padding_[1];
pad_right = padding_[0];
pad_bottom = padding_[1];
break;
default:
pad_left = padding_[0];
pad_top = padding_[1];
pad_right = padding_[2];
pad_bottom = padding_[3];
}

uint8_t fill_r, fill_g, fill_b;
fill_r = fill_value_[0];
fill_g = fill_value_[0];
fill_b = fill_value_[0];

if (fill_value_.size() == 3) {
fill_r = fill_value_[0];
fill_g = fill_value_[1];
fill_b = fill_value_[2];
}

auto tensor_op =
std::make_shared<RandomCropWithBBoxOp>(crop_height, crop_width, pad_top, pad_bottom, pad_left, pad_right,
padding_mode_, pad_if_needed_, fill_r, fill_g, fill_b);
return tensor_op;
}

// RandomHorizontalFlipOperation
RandomHorizontalFlipOperation::RandomHorizontalFlipOperation(float probability) : probability_(probability) {}

Status RandomHorizontalFlipOperation::ValidateParams() {
RETURN_IF_NOT_OK(ValidateVectorProbability("RandomHorizontalFlip", probability_));

return Status::OK();
}
@@ -1143,6 +1322,22 @@ std::shared_ptr<TensorOp> RandomHorizontalFlipOperation::Build() {
return tensor_op;
}

// RandomHorizontalFlipWithBBoxOperation
RandomHorizontalFlipWithBBoxOperation::RandomHorizontalFlipWithBBoxOperation(float probability)
: probability_(probability) {}

Status RandomHorizontalFlipWithBBoxOperation::ValidateParams() {
RETURN_IF_NOT_OK(ValidateVectorProbability("RandomHorizontalFlipWithBBox", probability_));

return Status::OK();
}

std::shared_ptr<TensorOp> RandomHorizontalFlipWithBBoxOperation::Build() {
std::shared_ptr<RandomHorizontalFlipWithBBoxOp> tensor_op =
std::make_shared<RandomHorizontalFlipWithBBoxOp>(probability_);
return tensor_op;
}

// RandomPosterizeOperation
RandomPosterizeOperation::RandomPosterizeOperation(const std::vector<uint8_t> &bit_range) : bit_range_(bit_range) {}

@@ -1253,16 +1448,21 @@ RandomRotationOperation::RandomRotationOperation(std::vector<float> degrees, Int

Status RandomRotationOperation::ValidateParams() {
// degrees
if (degrees_.size() != 2) {
if (degrees_.size() != 2 && degrees_.size() != 1) {
std::string err_msg =
"RandomRotation: degrees must be a vector of two values, got: " + std::to_string(degrees_.size());
MS_LOG(ERROR) << "RandomRotation: degrees must be a vector of two values, got: " << degrees_;
"RandomRotation: degrees must be a vector of one or two values, got: " + std::to_string(degrees_.size());
MS_LOG(ERROR) << "RandomRotation: degrees must be a vector of one or two values, got: " << degrees_;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
if (degrees_[1] < degrees_[0]) {
if ((degrees_[1] < degrees_[0]) && (degrees_.size() == 2)) {
std::string err_msg = "RandomRotation: degrees must be in the format of (min, max).";
MS_LOG(ERROR) << "RandomRotation: degrees must be in the format of (min, max), got: " << degrees_;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
} else if ((degrees_[0] <= 0) && degrees_.size() == 1) {
std::string err_msg = "RandomRotation: if the degress has one element, the value must be greater than 0.";
MS_LOG(ERROR) << "RandomRotation: if the degress has one element, the value must be greater than 0, got: "
<< degrees_;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
// center
if (center_.empty() || center_.size() != 2) {
@@ -1272,27 +1472,33 @@ Status RandomRotationOperation::ValidateParams() {
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
// fill_value
if (fill_value_.empty() || fill_value_.size() != 3) {
std::string err_msg =
"RandomRotation: fill_value must be a vector of two values, got: " + std::to_string(fill_value_.size());
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
for (int32_t i = 0; i < fill_value_.size(); ++i) {
if (fill_value_[i] < 0 || fill_value_[i] > 255) {
std::string err_msg =
"RandomRotation: fill_value has to be between 0 and 255, got: " + std::to_string(fill_value_[i]);
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
}
RETURN_IF_NOT_OK(ValidateVectorFillvalue("RandomRotation", fill_value_));
return Status::OK();
}

std::shared_ptr<TensorOp> RandomRotationOperation::Build() {
std::shared_ptr<RandomRotationOp> tensor_op =
std::make_shared<RandomRotationOp>(degrees_[0], degrees_[1], center_[0], center_[1], interpolation_mode_, expand_,
fill_value_[0], fill_value_[1], fill_value_[2]);
float start_degree, end_degree;
if (degrees_.size() == 1) {
start_degree = -degrees_[0];
end_degree = degrees_[0];
} else if (degrees_.size() == 2) {
start_degree = degrees_[0];
end_degree = degrees_[1];
}

uint8_t fill_r, fill_g, fill_b;
fill_r = fill_value_[0];
fill_g = fill_value_[0];
fill_b = fill_value_[0];

if (fill_value_.size() == 3) {
fill_r = fill_value_[0];
fill_g = fill_value_[1];
fill_b = fill_value_[2];
}

std::shared_ptr<RandomRotationOp> tensor_op = std::make_shared<RandomRotationOp>(
start_degree, end_degree, center_[0], center_[1], interpolation_mode_, expand_, fill_r, fill_g, fill_b);
return tensor_op;
}

@@ -1355,11 +1561,7 @@ std::shared_ptr<TensorOp> RandomSolarizeOperation::Build() {
RandomVerticalFlipOperation::RandomVerticalFlipOperation(float probability) : probability_(probability) {}

Status RandomVerticalFlipOperation::ValidateParams() {
if (probability_ < 0.0 || probability_ > 1.0) {
std::string err_msg = "RandomVerticalFlip: probability must be between 0.0 and 1.0.";
MS_LOG(ERROR) << err_msg;
RETURN_STATUS_SYNTAX_ERROR(err_msg);
}
RETURN_IF_NOT_OK(ValidateVectorProbability("RandomVerticalFlip", probability_));

return Status::OK();
}
@@ -1369,6 +1571,22 @@ std::shared_ptr<TensorOp> RandomVerticalFlipOperation::Build() {
return tensor_op;
}

// RandomVerticalFlipWithBBoxOperation
RandomVerticalFlipWithBBoxOperation::RandomVerticalFlipWithBBoxOperation(float probability)
: probability_(probability) {}

Status RandomVerticalFlipWithBBoxOperation::ValidateParams() {
RETURN_IF_NOT_OK(ValidateVectorProbability("RandomVerticalFlipWithBBox", probability_));

return Status::OK();
}

std::shared_ptr<TensorOp> RandomVerticalFlipWithBBoxOperation::Build() {
std::shared_ptr<RandomVerticalFlipWithBBoxOp> tensor_op =
std::make_shared<RandomVerticalFlipWithBBoxOp>(probability_);
return tensor_op;
}

// RescaleOperation
RescaleOperation::RescaleOperation(float rescale, float shift) : rescale_(rescale), shift_(shift) {}



+ 121
- 0
mindspore/ccsrc/minddata/dataset/include/vision.h View File

@@ -32,6 +32,7 @@ namespace vision {

// Transform Op classes (in alphabetical order)
#ifndef ENABLE_ANDROID
class AutoContrastOperation;
class CenterCropOperation;
#endif
class CropOperation;
@@ -42,6 +43,7 @@ class CutOutOperation;
class DecodeOperation;
#ifndef ENABLE_ANDROID
class HwcToChwOperation;
class InvertOperation;
class MixUpBatchOperation;
#endif
class NormalizeOperation;
@@ -52,13 +54,16 @@ class RandomColorOperation;
class RandomColorAdjustOperation;
class RandomCropOperation;
class RandomCropDecodeResizeOperation;
class RandomCropWithBBoxOperation;
class RandomHorizontalFlipOperation;
class RandomHorizontalFlipWithBBoxOperation;
class RandomPosterizeOperation;
class RandomResizedCropOperation;
class RandomRotationOperation;
class RandomSharpnessOperation;
class RandomSolarizeOperation;
class RandomVerticalFlipOperation;
class RandomVerticalFlipWithBBoxOperation;
class RescaleOperation;
#endif
class ResizeOperation;
@@ -68,6 +73,13 @@ class RgbaToRgbOperation;
class SwapRedBlueOperation;
class UniformAugOperation;

/// \brief Function to create a AutoContrast TensorOperation.
/// \notes Apply automatic contrast on input image.
/// \param[in] cutoff Percent of pixels to cut off from the histogram, the valid range of cutoff value is 0 to 100.
/// \param[in] ignore Pixel values to ignore.
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<AutoContrastOperation> AutoContrast(float cutoff = 0.0, std::vector<uint32_t> ignore = {});

/// \brief Function to create a CenterCrop TensorOperation.
/// \notes Crops the input image at the center to the given size.
/// \param[in] size A vector representing the output size of the cropped image.
@@ -113,6 +125,11 @@ std::shared_ptr<DecodeOperation> Decode(bool rgb = true);
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<HwcToChwOperation> HWC2CHW();

/// \brief Function to create a Invert TensorOperation.
/// \notes Apply invert on input image in RGB mode.
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<InvertOperation> Invert();

/// \brief Function to create a MixUpBatch TensorOperation.
/// \notes Apply MixUp transformation on an input batch of images and labels. The labels must be in
/// one-hot format and Batch must be called before calling this function.
@@ -232,12 +249,38 @@ std::shared_ptr<RandomCropDecodeResizeOperation> RandomCropDecodeResize(
std::vector<int32_t> size, std::vector<float> scale = {0.08, 1.0}, std::vector<float> ratio = {3. / 4, 4. / 3},
InterpolationMode interpolation = InterpolationMode::kLinear, int32_t max_attempts = 10);

/// \brief Function to create a RandomCropWithBBox TensorOperation.
/// \Crop the input image at a random location and adjust bounding boxes accordingly.
/// \param[in] size A vector representing the output size of the cropped image.
/// If size is a single value, a square crop of size (size, size) is returned.
/// If size has 2 values, it should be (height, width).
/// \param[in] padding A vector with the value of pixels to pad the image. If 4 values are provided,
/// it pads the left, top, right and bottom respectively.
/// \param[in] pad_if_needed A boolean whether to pad the image if either side is smaller than
/// the given output size.
/// \param[in] fill_value A vector representing the pixel intensity of the borders, it is used to
/// fill R, G, B channels respectively.
/// \param[in] padding_mode The method of padding (default=BorderType::kConstant).It can be any of
/// [BorderType::kConstant, BorderType::kEdge, BorderType::kReflect, BorderType::kSymmetric].
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<RandomCropWithBBoxOperation> RandomCropWithBBox(std::vector<int32_t> size,
std::vector<int32_t> padding = {0, 0, 0, 0},
bool pad_if_needed = false,
std::vector<uint8_t> fill_value = {0, 0, 0},
BorderType padding_mode = BorderType::kConstant);

/// \brief Function to create a RandomHorizontalFlip TensorOperation.
/// \notes Tensor operation to perform random horizontal flip.
/// \param[in] prob A float representing the probability of flip.
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<RandomHorizontalFlipOperation> RandomHorizontalFlip(float prob = 0.5);

/// \brief Function to create a RandomHorizontalFlipWithBBox TensorOperation.
/// \notes Flip the input image horizontally, randomly with a given probability and adjust bounding boxes accordingly.
/// \param[in] prob A float representing the probability of flip.
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<RandomHorizontalFlipWithBBoxOperation> RandomHorizontalFlipWithBBox(float prob = 0.5);

/// \brief Function to create a RandomPosterize TensorOperation.
/// \notes Tensor operation to perform random posterize.
/// \param[in] bit_range - uint8_t vector representing the minimum and maximum bit in range. (Default={4, 8})
@@ -293,6 +336,12 @@ std::shared_ptr<RandomSolarizeOperation> RandomSolarize(std::vector<uint8_t> thr
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<RandomVerticalFlipOperation> RandomVerticalFlip(float prob = 0.5);

/// \brief Function to create a RandomVerticalFlipWithBBox TensorOperation.
/// \notes Flip the input image vertically, randomly with a given probability and adjust bounding boxes accordingly.
/// \param[in] prob A float representing the probability of flip.
/// \return Shared pointer to the current TensorOperation.
std::shared_ptr<RandomVerticalFlipWithBBoxOperation> RandomVerticalFlipWithBBox(float prob = 0.5);

/// \brief Function to create a RescaleOperation TensorOperation.
/// \notes Tensor operation to rescale the input image.
/// \param[in] rescale Rescale factor.
@@ -337,6 +386,21 @@ std::shared_ptr<UniformAugOperation> UniformAugment(std::vector<std::shared_ptr<

/* ####################################### Derived TensorOperation classes ################################# */

class AutoContrastOperation : public TensorOperation {
public:
explicit AutoContrastOperation(float cutoff = 0.0, std::vector<uint32_t> ignore = {});

~AutoContrastOperation() = default;

std::shared_ptr<TensorOp> Build() override;

Status ValidateParams() override;

private:
float cutoff_;
std::vector<uint32_t> ignore_;
};

class CenterCropOperation : public TensorOperation {
public:
explicit CenterCropOperation(std::vector<int32_t> size);
@@ -423,6 +487,15 @@ class HwcToChwOperation : public TensorOperation {
Status ValidateParams() override;
};

class InvertOperation : public TensorOperation {
public:
~InvertOperation() = default;

std::shared_ptr<TensorOp> Build() override;

Status ValidateParams() override;
};

class MixUpBatchOperation : public TensorOperation {
public:
explicit MixUpBatchOperation(float alpha = 1);
@@ -566,6 +639,26 @@ class RandomCropDecodeResizeOperation : public TensorOperation {
int32_t max_attempts_;
};

class RandomCropWithBBoxOperation : public TensorOperation {
public:
RandomCropWithBBoxOperation(std::vector<int32_t> size, std::vector<int32_t> padding = {0, 0, 0, 0},
bool pad_if_needed = false, std::vector<uint8_t> fill_value = {0, 0, 0},
BorderType padding_mode = BorderType::kConstant);

~RandomCropWithBBoxOperation() = default;

std::shared_ptr<TensorOp> Build() override;

Status ValidateParams() override;

private:
std::vector<int32_t> size_;
std::vector<int32_t> padding_;
bool pad_if_needed_;
std::vector<uint8_t> fill_value_;
BorderType padding_mode_;
};

class RandomHorizontalFlipOperation : public TensorOperation {
public:
explicit RandomHorizontalFlipOperation(float probability = 0.5);
@@ -580,6 +673,20 @@ class RandomHorizontalFlipOperation : public TensorOperation {
float probability_;
};

class RandomHorizontalFlipWithBBoxOperation : public TensorOperation {
public:
explicit RandomHorizontalFlipWithBBoxOperation(float probability = 0.5);

~RandomHorizontalFlipWithBBoxOperation() = default;

std::shared_ptr<TensorOp> Build() override;

Status ValidateParams() override;

private:
float probability_;
};

class RandomPosterizeOperation : public TensorOperation {
public:
explicit RandomPosterizeOperation(const std::vector<uint8_t> &bit_range = {4, 8});
@@ -676,6 +783,20 @@ class RandomVerticalFlipOperation : public TensorOperation {
float probability_;
};

class RandomVerticalFlipWithBBoxOperation : public TensorOperation {
public:
explicit RandomVerticalFlipWithBBoxOperation(float probability = 0.5);

~RandomVerticalFlipWithBBoxOperation() = default;

std::shared_ptr<TensorOp> Build() override;

Status ValidateParams() override;

private:
float probability_;
};

class RescaleOperation : public TensorOperation {
public:
explicit RescaleOperation(float rescale, float shift);


+ 571
- 3
tests/ut/cpp/dataset/c_api_vision_test.cc View File

@@ -33,9 +33,11 @@
#include "minddata/dataset/engine/ir/datasetops/source/cifar10_node.h"
#include "minddata/dataset/engine/ir/datasetops/source/image_folder_node.h"
#include "minddata/dataset/engine/ir/datasetops/source/mnist_node.h"
#include "minddata/dataset/engine/ir/datasetops/source/voc_node.h"

using namespace mindspore::dataset::api;
using mindspore::dataset::BorderType;
using mindspore::dataset::InterpolationMode;
using mindspore::dataset::Tensor;

class MindDataTestPipeline : public UT::DatasetOpTesting {
@@ -44,6 +46,114 @@ class MindDataTestPipeline : public UT::DatasetOpTesting {

// Tests for vision ops (in alphabetical order)

TEST_F(MindDataTestPipeline, TestAutoContrastSuccess1) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestAutoContrastSuccess1.";

// Create an ImageFolder Dataset
std::string folder_path = datasets_root_path_ + "/testPK/data/";
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, true, RandomSampler(false, 5));
EXPECT_NE(ds, nullptr);

// Create a Repeat operation on ds
int32_t repeat_num = 3;
ds = ds->Repeat(repeat_num);
EXPECT_NE(ds, nullptr);

// Create auto contrast object with default values
std::shared_ptr<TensorOperation> auto_contrast = vision::AutoContrast();
EXPECT_NE(auto_contrast, nullptr);

// Create a Map operation on ds
ds = ds->Map({auto_contrast});
EXPECT_NE(ds, nullptr);

// Create a Batch operation on ds
int32_t batch_size = 1;
ds = ds->Batch(batch_size);
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

uint64_t i = 0;
while (row.size() != 0) {
i++;
auto image = row["image"];
MS_LOG(INFO) << "Tensor image shape: " << image->shape();
iter->GetNextRow(&row);
}

EXPECT_EQ(i, 15);

// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestAutoContrastSuccess2) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestAutoContrastSuccess2.";

// Create an ImageFolder Dataset
std::string folder_path = datasets_root_path_ + "/testPK/data/";
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, true, RandomSampler(false, 5));
EXPECT_NE(ds, nullptr);

// Create a Repeat operation on ds
int32_t repeat_num = 3;
ds = ds->Repeat(repeat_num);
EXPECT_NE(ds, nullptr);

// Create auto contrast object
std::shared_ptr<TensorOperation> auto_contrast = vision::AutoContrast(10, {10, 20});
EXPECT_NE(auto_contrast, nullptr);

// Create a Map operation on ds
ds = ds->Map({auto_contrast});
EXPECT_NE(ds, nullptr);

// Create a Batch operation on ds
int32_t batch_size = 1;
ds = ds->Batch(batch_size);
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

uint64_t i = 0;
while (row.size() != 0) {
i++;
auto image = row["image"];
MS_LOG(INFO) << "Tensor image shape: " << image->shape();
iter->GetNextRow(&row);
}

EXPECT_EQ(i, 15);

// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestAutoContrastFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestAutoContrastFail with invalid params.";
// Testing invalid cutoff < 0
std::shared_ptr<TensorOperation> auto_contrast1 = vision::AutoContrast(-1.0);
EXPECT_EQ(auto_contrast1, nullptr);
// Testing invalid cutoff > 100
std::shared_ptr<TensorOperation> auto_contrast2 = vision::AutoContrast(110.0, {10, 20});
EXPECT_EQ(auto_contrast2, nullptr);
}

TEST_F(MindDataTestPipeline, TestCenterCrop) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestCenterCrop with single integer input.";

@@ -535,6 +645,44 @@ TEST_F(MindDataTestPipeline, TestHwcToChw) {
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestInvert) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestInvert.";

// Create an ImageFolder Dataset
std::string folder_path = datasets_root_path_ + "/testPK/data/";
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, true, RandomSampler(false, 20));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> invert_op = vision::Invert();
EXPECT_NE(invert_op, nullptr);

// Create a Map operation on ds
ds = ds->Map({invert_op});
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

uint64_t i = 0;
while (row.size() != 0) {
i++;
auto image = row["image"];
MS_LOG(INFO) << "Tensor image shape: " << image->shape();
iter->GetNextRow(&row);
}
EXPECT_EQ(i, 20);

// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestMixUpBatchFail1) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestMixUpBatchFail1 with negative alpha parameter.";

@@ -947,7 +1095,7 @@ TEST_F(MindDataTestPipeline, TestRandomColor) {

// Failure case: Set invalid negative lower bound
std::shared_ptr<TensorOperation> random_color_op_4 = vision::RandomColor(-0.5, 0.5);
EXPECT_EQ(random_color_op_2, nullptr);
EXPECT_EQ(random_color_op_4, nullptr);

// Create a Map operation on ds
ds = ds->Map({random_color_op_1, random_color_op_3});
@@ -1050,6 +1198,182 @@ TEST_F(MindDataTestPipeline, TestRandomColorAdjust) {
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRandomCropSuccess) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomCropSuccess.";
// Create an VOC Dataset
std::string folder_path = datasets_root_path_ + "/testVOC2012_2";
std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 10));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
// Testing siez of size vector is 1
std::shared_ptr<TensorOperation> random_crop = vision::RandomCrop({20});
EXPECT_NE(random_crop, nullptr);

// Testing siez of size vector is 2
std::shared_ptr<TensorOperation> random_crop1 = vision::RandomCrop({20, 20});
EXPECT_NE(random_crop1, nullptr);

// Testing siez of paddiing vector is 1
std::shared_ptr<TensorOperation> random_crop2 = vision::RandomCrop({20, 20}, {10});
EXPECT_NE(random_crop2, nullptr);

// Testing siez of paddiing vector is 2
std::shared_ptr<TensorOperation> random_crop3 = vision::RandomCrop({20, 20}, {10, 20});
EXPECT_NE(random_crop3, nullptr);

// Testing siez of paddiing vector is 2
std::shared_ptr<TensorOperation> random_crop4 = vision::RandomCrop({20, 20}, {10, 10, 10, 10});
EXPECT_NE(random_crop4, nullptr);

// Testing siez of fill_value vector is 1
std::shared_ptr<TensorOperation> random_crop5 = vision::RandomCrop({20, 20}, {10, 10, 10, 10}, false, {5});
EXPECT_NE(random_crop5, nullptr);

// Testing siez of fill_value vector is 3
std::shared_ptr<TensorOperation> random_crop6 = vision::RandomCrop({20, 20}, {10, 10, 10, 10}, false, {4, 4, 4});
EXPECT_NE(random_crop6, nullptr);

// Create a Map operation on ds
ds = ds->Map({random_crop, random_crop1, random_crop2, random_crop3, random_crop4, random_crop5, random_crop6});
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

uint64_t i = 0;
while (row.size() != 0) {
i++;
auto image = row["image"];
MS_LOG(INFO) << "Tensor image shape: " << image->shape();
iter->GetNextRow(&row);
}

EXPECT_EQ(i, 10);
// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRandomCropFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomCropFail with invalid parameters.";
// Create an VOC Dataset
std::string folder_path = datasets_root_path_ + "/testVOC2012_2";
std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 3));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
// Testing the size parameter is negative.
std::shared_ptr<TensorOperation> random_crop = vision::RandomCrop({-28, 28});
EXPECT_EQ(random_crop, nullptr);
// Testing the size parameter is None.
std::shared_ptr<TensorOperation> random_crop1 = vision::RandomCrop({});
EXPECT_EQ(random_crop1, nullptr);
// Testing the size of size vector is 3.
std::shared_ptr<TensorOperation> random_crop2 = vision::RandomCrop({28, 28, 28});
EXPECT_EQ(random_crop2, nullptr);
// Testing the padding parameter is negative.
std::shared_ptr<TensorOperation> random_crop3 = vision::RandomCrop({28, 28}, {-5});
EXPECT_EQ(random_crop3, nullptr);
// Testing the size of padding vector is empty.
std::shared_ptr<TensorOperation> random_crop4 = vision::RandomCrop({28, 28}, {});
EXPECT_EQ(random_crop4, nullptr);
// Testing the size of padding vector is 3.
std::shared_ptr<TensorOperation> random_crop5 = vision::RandomCrop({28, 28}, {5, 5, 5});
EXPECT_EQ(random_crop5, nullptr);
// Testing the size of padding vector is 5.
std::shared_ptr<TensorOperation> random_crop6 = vision::RandomCrop({28, 28}, {5, 5, 5, 5, 5});
EXPECT_EQ(random_crop6, nullptr);
// Testing the size of fill_value vector is empty.
std::shared_ptr<TensorOperation> random_crop7 = vision::RandomCrop({28, 28}, {0, 0, 0, 0}, false, {});
EXPECT_EQ(random_crop7, nullptr);
// Testing the size of fill_value vector is 2.
std::shared_ptr<TensorOperation> random_crop8 = vision::RandomCrop({28, 28}, {0, 0, 0, 0}, false, {0, 0});
EXPECT_EQ(random_crop8, nullptr);
// Testing the size of fill_value vector is 4.
std::shared_ptr<TensorOperation> random_crop9 = vision::RandomCrop({28, 28}, {0, 0, 0, 0}, false, {0, 0, 0, 0});
EXPECT_EQ(random_crop9, nullptr);
}

TEST_F(MindDataTestPipeline, TestRandomCropWithBboxSuccess) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomCropWithBboxSuccess.";
// Create an VOC Dataset
std::string folder_path = datasets_root_path_ + "/testVOC2012_2";
std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 3));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> random_crop = mindspore::dataset::api::vision::RandomCropWithBBox({128, 128});
EXPECT_NE(random_crop, nullptr);

// Create a Map operation on ds
ds = ds->Map({random_crop}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"});
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

uint64_t i = 0;
while (row.size() != 0) {
i++;
auto image = row["image"];
MS_LOG(INFO) << "Tensor image shape: " << image->shape();
EXPECT_EQ(image->shape()[0], 128);
EXPECT_EQ(image->shape()[1], 128);
iter->GetNextRow(&row);
}

EXPECT_EQ(i, 3);
// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRandomCropWithBboxFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomCropWithBboxFail with invalid parameters.";
// Create an VOC Dataset
std::string folder_path = datasets_root_path_ + "/testVOC2012_2";
std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 3));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
// The size parameter is negative.
std::shared_ptr<TensorOperation> random_crop = vision::RandomCropWithBBox({-10});
EXPECT_EQ(random_crop, nullptr);
// The parameter in the padding vector is negative.
std::shared_ptr<TensorOperation> random_crop1 = vision::RandomCropWithBBox({10, 10}, {-2, 2, 2, 2});
EXPECT_EQ(random_crop1, nullptr);
// The size container is empty.
std::shared_ptr<TensorOperation> random_crop2 = vision::RandomCropWithBBox({});
EXPECT_EQ(random_crop2, nullptr);
// The size of the size container is too large.
std::shared_ptr<TensorOperation> random_crop3 = vision::RandomCropWithBBox({10, 10, 10});
EXPECT_EQ(random_crop3, nullptr);
// The padding container is empty.
std::shared_ptr<TensorOperation> random_crop4 = vision::RandomCropWithBBox({10, 10}, {});
EXPECT_EQ(random_crop4, nullptr);
// The size of the padding container is too large.
std::shared_ptr<TensorOperation> random_crop5 = vision::RandomCropWithBBox({10, 10}, {5, 5, 5, 5, 5});
EXPECT_EQ(random_crop5, nullptr);
// The fill_value container is empty.
std::shared_ptr<TensorOperation> random_crop6 = vision::RandomCropWithBBox({10, 10}, {5, 5, 5, 5}, false, {});
EXPECT_EQ(random_crop6, nullptr);
// The size of the fill_value container is too large.
std::shared_ptr<TensorOperation> random_crop7 =
vision::RandomCropWithBBox({10, 10}, {5, 5, 5, 5}, false, {3, 3, 3, 3});
EXPECT_EQ(random_crop7, nullptr);
}

TEST_F(MindDataTestPipeline, DISABLED_TestRandomHorizontalFlipFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomHorizontalFlipFail with invalid parameters.";

@@ -1062,6 +1386,59 @@ TEST_F(MindDataTestPipeline, DISABLED_TestRandomHorizontalFlipFail) {
EXPECT_EQ(random_horizontal_flip_op, nullptr);
}

TEST_F(MindDataTestPipeline, TestRandomHorizontalFlipWithBBoxSuccess) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomHorizontalFlipWithBBoxSuccess.";
// Create an VOC Dataset
std::string folder_path = datasets_root_path_ + "/testVOC2012_2";
std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 3));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> random_horizontal_flip_op = vision::RandomHorizontalFlipWithBBox(0.5);
EXPECT_NE(random_horizontal_flip_op, nullptr);

// Create a Map operation on ds
ds = ds->Map({random_horizontal_flip_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"});
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

uint64_t i = 0;
while (row.size() != 0) {
i++;
auto image = row["image"];
MS_LOG(INFO) << "Tensor image shape: " << image->shape();
iter->GetNextRow(&row);
}

EXPECT_EQ(i, 3);
// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRandomHorizontalFlipWithBBoxFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomHorizontalFlipWithBBoxFail with invalid parameters.";
// Create an VOC Dataset
std::string folder_path = datasets_root_path_ + "/testVOC2012_2";
std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 3));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
// Incorrect prob parameter.
std::shared_ptr<TensorOperation> random_horizontal_flip_op = vision::RandomHorizontalFlipWithBBox(-1.0);
EXPECT_EQ(random_horizontal_flip_op, nullptr);
// Incorrect prob parameter.
std::shared_ptr<TensorOperation> random_horizontal_flip_op1 = vision::RandomHorizontalFlipWithBBox(2.0);
EXPECT_EQ(random_horizontal_flip_op1, nullptr);
}

TEST_F(MindDataTestPipeline, TestRandomHorizontalAndVerticalFlip) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomHorizontalAndVerticalFlip for horizontal and vertical flips.";

@@ -1371,11 +1748,23 @@ TEST_F(MindDataTestPipeline, TestRandomRotation) {
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> random_rotation_op = vision::RandomRotation({-180, 180});
// Testing the size of degrees is 1
std::shared_ptr<TensorOperation> random_rotation_op = vision::RandomRotation({180});
EXPECT_NE(random_rotation_op, nullptr);
// Testing the size of degrees is 2
std::shared_ptr<TensorOperation> random_rotation_op1 = vision::RandomRotation({-180, 180});
EXPECT_NE(random_rotation_op1, nullptr);
// Testing the size of fill_value is 1
std::shared_ptr<TensorOperation> random_rotation_op2 =
vision::RandomRotation({180}, InterpolationMode::kNearestNeighbour, false, {-1, -1}, {2});
EXPECT_NE(random_rotation_op2, nullptr);
// Testing the size of fill_value is 3
std::shared_ptr<TensorOperation> random_rotation_op3 =
vision::RandomRotation({180}, InterpolationMode::kNearestNeighbour, false, {-1, -1}, {2, 2, 2});
EXPECT_NE(random_rotation_op3, nullptr);

// Create a Map operation on ds
ds = ds->Map({random_rotation_op});
ds = ds->Map({random_rotation_op, random_rotation_op1, random_rotation_op2, random_rotation_op3});
EXPECT_NE(ds, nullptr);

// Create a Batch operation on ds
@@ -1406,6 +1795,42 @@ TEST_F(MindDataTestPipeline, TestRandomRotation) {
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRandomRotationFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomRotationFail with invalid parameters.";

// Create an ImageFolder Dataset
std::string folder_path = datasets_root_path_ + "/testPK/data/";
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, true, RandomSampler(false, 10));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
// Testing the size of degrees vector is 0
std::shared_ptr<TensorOperation> random_rotation_op = vision::RandomRotation({});
EXPECT_EQ(random_rotation_op, nullptr);
// Testing the size of degrees vector is 3
std::shared_ptr<TensorOperation> random_rotation_op1 = vision::RandomRotation({-50.0, 50.0, 100.0});
EXPECT_EQ(random_rotation_op1, nullptr);
// Test the case where the first column value of degrees is greater than the second column value
std::shared_ptr<TensorOperation> random_rotation_op2 = vision::RandomRotation({50.0, -50.0});
EXPECT_EQ(random_rotation_op2, nullptr);
// Testing the size of center vector is 1
std::shared_ptr<TensorOperation> random_rotation_op3 =
vision::RandomRotation({-50.0, 50.0}, InterpolationMode::kNearestNeighbour, false, {-1.0});
EXPECT_EQ(random_rotation_op3, nullptr);
// Testing the size of center vector is 3
std::shared_ptr<TensorOperation> random_rotation_op4 =
vision::RandomRotation({-50.0, 50.0}, InterpolationMode::kNearestNeighbour, false, {-1.0, -1.0, -1.0});
EXPECT_EQ(random_rotation_op4, nullptr);
// Testing the size of fill_value vector is 2
std::shared_ptr<TensorOperation> random_rotation_op5 =
vision::RandomRotation({-50.0, 50.0}, InterpolationMode::kNearestNeighbour, false, {-1.0, -1.0}, {2, 2});
EXPECT_EQ(random_rotation_op5, nullptr);
// Testing the size of fill_value vector is 4
std::shared_ptr<TensorOperation> random_rotation_op6 =
vision::RandomRotation({-50.0, 50.0}, InterpolationMode::kNearestNeighbour, false, {-1.0, -1.0}, {2, 2, 2, 2});
EXPECT_EQ(random_rotation_op6, nullptr);
}

TEST_F(MindDataTestPipeline, TestRandomSharpness) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomSharpness.";

@@ -1592,6 +2017,59 @@ TEST_F(MindDataTestPipeline, TestResizeFail) {
EXPECT_EQ(resize_op, nullptr);
}

TEST_F(MindDataTestPipeline, TestRandomVerticalFlipWithBBoxSuccess) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomVerticalFlipWithBBoxSuccess.";
// Create an VOC Dataset
std::string folder_path = datasets_root_path_ + "/testVOC2012_2";
std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 3));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> random_vertical_flip_op = vision::RandomVerticalFlipWithBBox(0.4);
EXPECT_NE(random_vertical_flip_op, nullptr);

// Create a Map operation on ds
ds = ds->Map({random_vertical_flip_op}, {"image", "bbox"}, {"image", "bbox"}, {"image", "bbox"});
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

uint64_t i = 0;
while (row.size() != 0) {
i++;
auto image = row["image"];
MS_LOG(INFO) << "Tensor image shape: " << image->shape();
iter->GetNextRow(&row);
}

EXPECT_EQ(i, 3);
// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRandomVerticalFlipWithBBoxFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomVerticalFlipWithBBoxFail with invalid parameters.";
// Create an VOC Dataset
std::string folder_path = datasets_root_path_ + "/testVOC2012_2";
std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 3));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
// Incorrect prob parameter.
std::shared_ptr<TensorOperation> random_vertical_flip_op = vision::RandomVerticalFlipWithBBox(-0.5);
EXPECT_EQ(random_vertical_flip_op, nullptr);
// Incorrect prob parameter.
std::shared_ptr<TensorOperation> random_vertical_flip_op1 = vision::RandomVerticalFlipWithBBox(3.0);
EXPECT_EQ(random_vertical_flip_op1, nullptr);
}

TEST_F(MindDataTestPipeline, TestResize1) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestResize1 with single integer input.";
// Create an ImageFolder Dataset
@@ -1640,6 +2118,96 @@ TEST_F(MindDataTestPipeline, TestResize1) {
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRescaleSucess1) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRescaleSucess1.";
// Create an ImageFolder Dataset
std::string folder_path = datasets_root_path_ + "/testPK/data/";
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, true, SequentialSampler(0, 1));
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

auto image = row["image"];

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> rescale = mindspore::dataset::api::vision::Rescale(1.0, 0.0);
EXPECT_NE(rescale, nullptr);

// Convert to the same type
std::shared_ptr<TensorOperation> type_cast = transforms::TypeCast("uint8");
EXPECT_NE(type_cast, nullptr);

ds = ds->Map({rescale, type_cast}, {"image"});
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter1 = ds->CreateIterator();
EXPECT_NE(iter1, nullptr);

// Iterate the dataset and get each row1
std::unordered_map<std::string, std::shared_ptr<Tensor>> row1;
iter1->GetNextRow(&row1);

auto image1 = row1["image"];

EXPECT_EQ(*image, *image1);

// Manually terminate the pipeline
iter1->Stop();
}

TEST_F(MindDataTestPipeline, TestRescaleSucess2) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRescaleSucess2 with different params.";
// Create an ImageFolder Dataset
std::string folder_path = datasets_root_path_ + "/testPK/data/";
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, true, RandomSampler(false, 1));
EXPECT_NE(ds, nullptr);

// Create objects for the tensor ops
std::shared_ptr<TensorOperation> rescale = mindspore::dataset::api::vision::Rescale(1.0 / 255, 1.0);
EXPECT_NE(rescale, nullptr);

ds = ds->Map({rescale}, {"image"});
EXPECT_NE(ds, nullptr);

// Create an iterator over the result of the above dataset
// This will trigger the creation of the Execution Tree and launch it.
std::shared_ptr<Iterator> iter = ds->CreateIterator();
EXPECT_NE(iter, nullptr);

// Iterate the dataset and get each row
std::unordered_map<std::string, std::shared_ptr<Tensor>> row;
iter->GetNextRow(&row);

uint64_t i = 0;
while (row.size() != 0) {
i++;
auto image = row["image"];
MS_LOG(INFO) << "Tensor image shape: " << image->shape();
iter->GetNextRow(&row);
}

EXPECT_EQ(i, 1);

// Manually terminate the pipeline
iter->Stop();
}

TEST_F(MindDataTestPipeline, TestRescaleFail) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRescaleFail with invalid params.";
// incorrect negative rescale parameter
std::shared_ptr<TensorOperation> rescale = mindspore::dataset::api::vision::Rescale(-1.0, 0.0);
EXPECT_EQ(rescale, nullptr);
}

TEST_F(MindDataTestPipeline, DISABLED_TestUniformAugmentFail1) {
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestUniformAugmentFail1 with invalid zero num_ops parameter.";



Loading…
Cancel
Save