加入注释 #21

Open
Palette03 wants to merge 2 commits from Palette03/mindspore2022:master into master
75 changed files with 9926 additions and 2773 deletions

View File

@ -14,20 +14,35 @@
* limitations under the License.
*/
// Include the header file for the C function operation in the MindData dataset kernels
#include "minddata/dataset/kernels/c_func_op.h"
// Include the header file for the tensor operation in the MindData dataset kernels
#include "minddata/dataset/kernels/tensor_op.h"
// Include the header file for the status utility in the MindData dataset
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
// Implementation of the Compute function for the CFuncOp class
Status CFuncOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output vectors are valid
IO_CHECK_VECTOR(input, output);
try {
// Call the c_func_ptr_ function with the input vector and assign the result to the output vector
*output = c_func_ptr_(input);
} catch (const std::exception &e) {
// If an exception is caught, return an unexpected status with the error message
RETURN_STATUS_UNEXPECTED("Error raised, " + std::string(e.what()));
}
// Return a status indicating successful computation
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,29 +14,57 @@
* limitations under the License.
*/
// Include the header file "adjust_gamma_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/adjust_gamma_op.h"
// Include the header file for data utilities from the MindData library
#include "minddata/dataset/kernels/data/data_utils.h"
// Include the header file for image utilities from the MindData library
#include "minddata/dataset/kernels/image/image_utils.h"
// Define the namespace "mindspore"
namespace mindspore {
// Define the nested namespace "dataset" within the "mindspore" namespace
namespace dataset {
// Define the constant float variable "kGain" for the class "AdjustGammaOp" and set its value to 1.0
constexpr float AdjustGammaOp::kGain = 1.0;
Status AdjustGammaOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
} // End of namespace "dataset"
} // End of namespace "mindspore"
// typecast
CHECK_FAIL_RETURN_UNEXPECTED(input->type() != DataType::DE_STRING,
"AdjustGamma: input tensor type should be int, float or double, but got: string.");
// Compute function for the AdjustGammaOp class, which adjusts the gamma of an input tensor
// Takes in an input tensor and a pointer to an output tensor
// Returns the status of the computation
if (input->type().IsFloat()) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Check if the input tensor type is not a string
CHECK_FAIL_RETURN_UNEXPECTED(input->type() != DataType::DE_STRING,
"AdjustGamma: input tensor type should be int, float or double, but got: string.");
// Check if the type of the input is float
if (input->type().IsFloat()) {
// Create a shared pointer to a Tensor object
std::shared_ptr<Tensor> input_tensor;
// Call the TypeCast function to convert the input to float32 and store the result in input_tensor
RETURN_IF_NOT_OK(TypeCast(input, &input_tensor, DataType(DataType::DE_FLOAT32)));
// Call the AdjustGamma function with the converted input_tensor, output, gamma_, and gain_ parameters
return AdjustGamma(input_tensor, output, gamma_, gain_);
} else {
} else {
// If the input type is not float, call the AdjustGamma function with the original input, output, gamma_, and gain_ parameters
return AdjustGamma(input, output, gamma_, gain_);
}
}
} // namespace dataset
} // namespace mindspore
// End of the dataset namespace
}
// End of the mindspore namespace

View File

@ -16,84 +16,149 @@
#include <random>
#include <vector>
// Include the header file for the affine operation in the MindData dataset kernels for images
#include "minddata/dataset/kernels/image/affine_op.h"
// Check if the ENABLE_ANDROID macro is defined
#ifndef ENABLE_ANDROID
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for image utilities in the MindData dataset kernels
#include "minddata/dataset/kernels/image/image_utils.h"
// If ENABLE_ANDROID macro is defined
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
// Include the header file for lite image utilities in the MindData dataset kernels
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Include the header file for math utilities in the MindData dataset kernels for images
#include "minddata/dataset/kernels/image/math_utils.h"
// Include the header file for random utilities in the MindData dataset
#include "minddata/dataset/util/random.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Define the default interpolation mode for the AffineOp class as kNearestNeighbour
const InterpolationMode AffineOp::kDefInterpolation = InterpolationMode::kNearestNeighbour;
// Define the default rotation angle for the AffineOp class as 0.0 degrees
const float_t AffineOp::kDegrees = 0.0;
// Define the default translation vector for the AffineOp class as {0.0, 0.0}
const std::vector<float_t> AffineOp::kTranslation = {0.0, 0.0};
// Define the default scale factor for the AffineOp class as 1.0
const float_t AffineOp::kScale = 1.0;
// Define the default shear vector for the AffineOp class as {0.0, 0.0}
const std::vector<float_t> AffineOp::kShear = {0.0, 0.0};
// Define the default fill value for the AffineOp class as {0, 0, 0}
const std::vector<uint8_t> AffineOp::kFillValue = {0, 0, 0};
// Definition of the constructor for the AffineOp class
AffineOp::AffineOp(float_t degrees, const std::vector<float_t> &translation, float_t scale,
const std::vector<float_t> &shear, InterpolationMode interpolation,
const std::vector<uint8_t> &fill_value)
: degrees_(degrees),
translation_(translation),
scale_(scale),
shear_(shear),
interpolation_(interpolation),
fill_value_(fill_value) {}
: degrees_(degrees), // Initialize the degrees_ member variable with the provided degrees value
translation_(translation), // Initialize the translation_ member variable with the provided translation vector
scale_(scale), // Initialize the scale_ member variable with the provided scale value
shear_(shear), // Initialize the shear_ member variable with the provided shear vector
interpolation_(interpolation), // Initialize the interpolation_ member variable with the provided interpolation mode
fill_value_(fill_value) {} // Initialize the fill_value_ member variable with the provided fill value vector
Status AffineOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
CHECK_FAIL_RETURN_UNEXPECTED(translation_.size() >= 2, "AffineOp::Compute translation_ size should >= 2");
float_t translation_x = translation_[0];
float_t translation_y = translation_[1];
float_t degrees = 0.0;
RETURN_IF_NOT_OK(DegreesToRadians(degrees_, &degrees));
CHECK_FAIL_RETURN_UNEXPECTED(shear_.size() >= 2, "AffineOp::Compute shear_ size should >= 2");
float_t shear_x = shear_[0];
float_t shear_y = shear_[1];
RETURN_IF_NOT_OK(DegreesToRadians(shear_x, &shear_x));
RETURN_IF_NOT_OK(DegreesToRadians(-1 * shear_y, &shear_y));
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Apply Affine Transformation
// T is translation matrix: [1, 0, tx | 0, 1, ty | 0, 0, 1]
// C is translation matrix to keep center: [1, 0, cx | 0, 1, cy | 0, 0, 1]
// RSS is rotation with scale and shear matrix
// RSS(a, s, (sx, sy)) =
// = R(a) * S(s) * SHy(sy) * SHx(sx)
// = [ s*cos(a - sy)/cos(sy), s*(-cos(a - sy)*tan(x)/cos(y) - sin(a)), 0 ]
// [ s*sin(a - sy)/cos(sy), s*(-sin(a - sy)*tan(x)/cos(y) + cos(a)), 0 ]
// [ 0 , 0 , 1 ]
//
// where R is a rotation matrix, S is a scaling matrix, and SHx and SHy are the shears:
// SHx(s) = [1, -tan(s)] and SHy(s) = [1 , 0]
// [0, 1 ] [-tan(s), 1]
//
// Thus, the affine matrix is M = T * C * RSS * C^-1
// Check if the size of the translation vector is at least 2
CHECK_FAIL_RETURN_UNEXPECTED(translation_.size() >= 2, "AffineOp::Compute translation_ size should >= 2");
// image is hwc, rows = shape()[0]
CHECK_FAIL_RETURN_UNEXPECTED(input->shape().Size() >= 2, "AffineOp::Compute input->shape() size should >= 2");
float_t cx = ((input->shape()[1] - 1) / 2.0);
float_t cy = ((input->shape()[0] - 1) / 2.0);
// Extract the x and y components of the translation vector
float_t translation_x = translation_[0];
float_t translation_y = translation_[1];
CHECK_FAIL_RETURN_UNEXPECTED(cos(shear_y) != 0.0, "AffineOp: cos(shear_y) should not be zero.");
// Initialize the degrees variable to 0.0
float_t degrees = 0.0;
// Calculate RSS
std::vector<float_t> matrix{
static_cast<float>(scale_ * cos(degrees + shear_y) / cos(shear_y)),
static_cast<float>(scale_ * (-1 * cos(degrees + shear_y) * tan(shear_x) / cos(shear_y) - sin(degrees))),
0,
static_cast<float>(scale_ * sin(degrees + shear_y) / cos(shear_y)),
static_cast<float>(scale_ * (-1 * sin(degrees + shear_y) * tan(shear_x) / cos(shear_y) + cos(degrees))),
0};
// Compute T * C * RSS * C^-1
matrix[2] = (1 - matrix[0]) * cx - matrix[1] * cy + translation_x;
matrix[5] = (1 - matrix[4]) * cy - matrix[3] * cx + translation_y;
RETURN_IF_NOT_OK(Affine(input, output, matrix, interpolation_, fill_value_[0], fill_value_[1], fill_value_[2]));
return Status::OK();
}
// Convert the degrees value to radians
RETURN_IF_NOT_OK(DegreesToRadians(degrees_, &degrees));
// Check if the size of the shear vector is at least 2
CHECK_FAIL_RETURN_UNEXPECTED(shear_.size() >= 2, "AffineOp::Compute shear_ size should >= 2");
// Extract the x and y components of the shear vector
float_t shear_x = shear_[0];
float_t shear_y = shear_[1];
// Convert the shear values from degrees to radians
RETURN_IF_NOT_OK(DegreesToRadians(shear_x, &shear_x));
RETURN_IF_NOT_OK(DegreesToRadians(-1 * shear_y, &shear_y));
// Apply Affine Transformation
// T is the translation matrix: [1, 0, tx | 0, 1, ty | 0, 0, 1]
// C is the translation matrix to keep the center: [1, 0, cx | 0, 1, cy | 0, 0, 1]
// RSS is the rotation with scale and shear matrix
// RSS(a, s, (sx, sy)) =
// = R(a) * S(s) * SHy(sy) * SHx(sx)
// = [ s*cos(a - sy)/cos(sy), s*(-cos(a - sy)*tan(x)/cos(y) - sin(a)), 0 ]
// [ s*sin(a - sy)/cos(sy), s*(-sin(a - sy)*tan(x)/cos(y) + cos(a)), 0 ]
// [ 0 , 0 , 1 ]
//
// where R is a rotation matrix, S is a scaling matrix, and SHx and SHy are the shears:
// SHx(s) = [1, -tan(s)] and SHy(s) = [1 , 0]
// [0, 1 ] [-tan(s), 1]
//
// Thus, the affine matrix is M = T * C * RSS * C^-1
// Check if the input shape has at least 2 dimensions, otherwise return an error message
CHECK_FAIL_RETURN_UNEXPECTED(input->shape().Size() >= 2, "AffineOp::Compute input->shape() size should >= 2");
// Calculate the center coordinates of the image
// The number of rows in the image is equal to the first dimension of the shape
float_t cx = ((input->shape()[1] - 1) / 2.0);
float_t cy = ((input->shape()[0] - 1) / 2.0);
// Check if the cosine of the shear_y angle is not equal to zero
CHECK_FAIL_RETURN_UNEXPECTED(cos(shear_y) != 0.0, "AffineOp: cos(shear_y) should not be zero.");
// Calculate RSS (Rotation, Scale, Shear) matrix
// Create a vector to store the elements of the matrix
std::vector<float_t> matrix{
static_cast<float>(scale_ * cos(degrees + shear_y) / cos(shear_y)), // Element 0
static_cast<float>(scale_ * (-1 * cos(degrees + shear_y) * tan(shear_x) / cos(shear_y) - sin(degrees))), // Element 1
0, // Element 2
static_cast<float>(scale_ * sin(degrees + shear_y) / cos(shear_y)), // Element 3
static_cast<float>(scale_ * (-1 * sin(degrees + shear_y) * tan(shear_x) / cos(shear_y) + cos(degrees))), // Element 4
0 // Element 5
};
// Compute the translation part of the matrix: T * C * RSS * C^-1
matrix[2] = (1 - matrix[0]) * cx - matrix[1] * cy + translation_x; // Update element 2
matrix[5] = (1 - matrix[4]) * cy - matrix[3] * cx + translation_y; // Update element 5
// Apply the affine transformation to the input image using the computed matrix
RETURN_IF_NOT_OK(Affine(input, output, matrix, interpolation_, fill_value_[0], fill_value_[1], fill_value_[2]));
// Return a success status
return Status::OK();
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -14,206 +14,423 @@
* limitations under the License.
*/
// Include the header file "minddata/dataset/kernels/image/auto_augment_op.h"
#include "minddata/dataset/kernels/image/auto_augment_op.h"
// Include the header files for the required image processing operations
#include "minddata/dataset/kernels/image/affine_op.h"
#include "minddata/dataset/kernels/image/auto_contrast_op.h"
#include "minddata/dataset/kernels/image/invert_op.h"
#include "minddata/dataset/kernels/image/posterize_op.h"
#include "minddata/dataset/kernels/image/sharpness_op.h"
#include "minddata/dataset/kernels/image/solarize_op.h"
// Include the header file for the random number generator utility
#include "minddata/dataset/util/random.h"
namespace mindspore {
namespace dataset {
AutoAugmentOp::AutoAugmentOp(AutoAugmentPolicy policy, InterpolationMode interpolation,
const std::vector<uint8_t> &fill_value)
: policy_(policy), interpolation_(interpolation), fill_value_(fill_value) {
rnd_.seed(GetSeed());
transforms_ = GetTransforms(policy);
}
// The code is defining the constructor for the AutoAugmentOp class in the mindspore::dataset namespace.
// The constructor takes in parameters such as policy, interpolation, and fill_value to initialize the object.
// The constructor initializes the member variables policy_, interpolation_, and fill_value_ with the values passed as parameters.
// It also initializes the rnd_ member variable with a random seed obtained from the GetSeed() function.
// The transforms_ member variable is initialized by calling the GetTransforms() function with the policy parameter.
Transforms AutoAugmentOp::GetTransforms(AutoAugmentPolicy policy) {
if (policy == AutoAugmentPolicy::kImageNet) {
return {{{"Posterize", 0.4, 8}, {"Rotate", 0.6, 9}}, {{"Solarize", 0.6, 5}, {"AutoContrast", 0.6, -1}},
{{"Equalize", 0.8, -1}, {"Equalize", 0.6, -1}}, {{"Posterize", 0.6, 7}, {"Posterize", 0.6, 6}},
{{"Equalize", 0.4, -1}, {"Solarize", 0.2, 4}}, {{"Equalize", 0.4, -1}, {"Rotate", 0.8, 8}},
{{"Solarize", 0.6, 3}, {"Equalize", 0.6, -1}}, {{"Posterize", 0.8, 5}, {"Equalize", 1.0, -1}},
{{"Rotate", 0.2, 3}, {"Solarize", 0.6, 8}}, {{"Equalize", 0.6, -1}, {"Posterize", 0.4, 6}},
{{"Rotate", 0.8, 8}, {"Color", 0.4, 0}}, {{"Rotate", 0.4, 9}, {"Equalize", 0.6, -1}},
{{"Equalize", 0.0, -1}, {"Equalize", 0.8, -1}}, {{"Invert", 0.6, -1}, {"Equalize", 1.0, -1}},
{{"Color", 0.6, 4}, {"Contrast", 1.0, 8}}, {{"Rotate", 0.8, 8}, {"Color", 1.0, 2}},
{{"Color", 0.8, 8}, {"Solarize", 0.8, 7}}, {{"Sharpness", 0.4, 7}, {"Invert", 0.6, -1}},
{{"ShearX", 0.6, 5}, {"Equalize", 1.0, -1}}, {{"Color", 0.4, 0}, {"Equalize", 0.6, -1}},
{{"Equalize", 0.4, -1}, {"Solarize", 0.2, 4}}, {{"Solarize", 0.6, 5}, {"AutoContrast", 0.6, -1}},
{{"Invert", 0.6, -1}, {"Equalize", 1.0, -1}}, {{"Color", 0.6, 4}, {"Contrast", 1.0, 8}},
{{"Equalize", 0.8, -1}, {"Equalize", 0.6, -1}}};
// Return the ImageNet policy transforms
return {
{{"Posterize", 0.4, 8}, {"Rotate", 0.6, 9}},
{{"Solarize", 0.6, 5}, {"AutoContrast", 0.6, -1}},
{{"Equalize", 0.8, -1}, {"Equalize", 0.6, -1}},
{{"Posterize", 0.6, 7}, {"Posterize", 0.6, 6}},
{{"Equalize", 0.4, -1}, {"Solarize", 0.2, 4}},
{{"Equalize", 0.4, -1}, {"Rotate", 0.8, 8}},
{{"Solarize", 0.6, 3}, {"Equalize", 0.6, -1}},
{{"Posterize", 0.8, 5}, {"Equalize", 1.0, -1}},
{{"Rotate", 0.2, 3}, {"Solarize", 0.6, 8}},
{{"Equalize", 0.6, -1}, {"Posterize", 0.4, 6}},
{{"Rotate", 0.8, 8}, {"Color", 0.4, 0}},
{{"Rotate", 0.4, 9}, {"Equalize", 0.6, -1}},
{{"Equalize", 0.0, -1}, {"Equalize", 0.8, -1}},
{{"Invert", 0.6, -1}, {"Equalize", 1.0, -1}},
{{"Color", 0.6, 4}, {"Contrast", 1.0, 8}},
{{"Rotate", 0.8, 8}, {"Color", 1.0, 2}},
{{"Color", 0.8, 8}, {"Solarize", 0.8, 7}},
{{"Sharpness", 0.4, 7}, {"Invert", 0.6, -1}},
{{"ShearX", 0.6, 5}, {"Equalize", 1.0, -1}},
{{"Color", 0.4, 0}, {"Equalize", 0.6, -1}},
{{"Equalize", 0.4, -1}, {"Solarize", 0.2, 4}},
{{"Solarize", 0.6, 5}, {"AutoContrast", 0.6, -1}},
{{"Invert", 0.6, -1}, {"Equalize", 1.0, -1}},
{{"Color", 0.6, 4}, {"Contrast", 1.0, 8}},
{{"Equalize", 0.8, -1}, {"Equalize", 0.6, -1}}
};
} else if (policy == AutoAugmentPolicy::kCifar10) {
return {{{"Invert", 0.1, -1}, {"Contrast", 0.2, 6}}, {{"Rotate", 0.7, 2}, {"TranslateX", 0.3, 9}},
{{"Sharpness", 0.8, 1}, {"Sharpness", 0.9, 3}}, {{"ShearY", 0.5, 8}, {"TranslateY", 0.7, 9}},
{{"AutoContrast", 0.5, -1}, {"Equalize", 0.9, -1}}, {{"ShearY", 0.2, 7}, {"Posterize", 0.3, 7}},
{{"Color", 0.4, 3}, {"Brightness", 0.6, 7}}, {{"Sharpness", 0.3, 9}, {"Brightness", 0.7, 9}},
{{"Equalize", 0.6, -1}, {"Equalize", 0.5, -1}}, {{"Contrast", 0.6, 7}, {"Sharpness", 0.6, 5}},
{{"Color", 0.7, 7}, {"TranslateX", 0.5, 8}}, {{"Equalize", 0.3, -1}, {"AutoContrast", 0.4, -1}},
{{"TranslateY", 0.4, 3}, {"Sharpness", 0.2, 6}}, {{"Brightness", 0.9, 6}, {"Color", 0.2, 8}},
{{"Solarize", 0.5, 2}, {"Invert", 0.0, -1}}, {{"Equalize", 0.2, -1}, {"AutoContrast", 0.6, -1}},
{{"Equalize", 0.2, -1}, {"Equalize", 0.6, -1}}, {{"Color", 0.9, 9}, {"Equalize", 0.6, -1}},
{{"AutoContrast", 0.8, -1}, {"Solarize", 0.2, 8}}, {{"Brightness", 0.1, 3}, {"Color", 0.7, 0}},
{{"Solarize", 0.4, 5}, {"AutoContrast", 0.9, -1}}, {{"TranslateY", 0.9, 9}, {"TranslateY", 0.7, 9}},
{{"AutoContrast", 0.9, -1}, {"Solarize", 0.8, 3}}, {{"Equalize", 0.8, -1}, {"Invert", 0.1, -1}},
{{"TranslateY", 0.7, 9}, {"AutoContrast", 0.9, -1}}};
// Return the CIFAR-10 policy transforms
return {
{{"Invert", 0.1, -1}, {"Contrast", 0.2, 6}},
{{"Rotate", 0.7, 2}, {"TranslateX", 0.3, 9}},
{{"Sharpness", 0.8, 1}, {"Sharpness", 0.9, 3}},
{{"ShearY", 0.5, 8}, {"TranslateY", 0.7, 9}},
{{"AutoContrast", 0.5, -1}, {"Equalize", 0.9, -1}},
{{"ShearY", 0.2, 7}, {"Posterize", 0.3, 7}},
{{"Color", 0.4, 3}, {"Brightness", 0.6, 7}},
{{"Sharpness", 0.3, 9}, {"Brightness", 0.7, 9}},
{{"Equalize", 0.6, -1}, {"Equalize", 0.5, -1}},
{{"Contrast", 0.6, 7}, {"Sharpness", 0.6, 5}},
{{"Color", 0.7, 7}, {"TranslateX", 0.5, 8}},
{{"Equalize", 0.3, -1}, {"AutoContrast", 0.4, -1}},
{{"TranslateY", 0.4, 3}, {"Sharpness", 0.2, 6}},
{{"Brightness", 0.9, 6}, {"Color", 0.2, 8}},
{{"Solarize", 0.5, 2}, {"Invert", 0.0, -1}},
{{"Equalize", 0.2, -1}, {"AutoContrast", 0.6, -1}},
{{"Equalize", 0.2, -1}, {"Equalize", 0.6, -1}},
{{"Color", 0.9, 9}, {"Equalize", 0.6, -1}},
{{"AutoContrast", 0.8, -1}, {"Solarize", 0.2, 8}},
{{"Brightness", 0.1, 3}, {"Color", 0.7, 0}},
{{"Solarize", 0.4, 5}, {"AutoContrast", 0.9, -1}},
{{"TranslateY", 0.9, 9}, {"TranslateY", 0.7, 9}},
{{"AutoContrast", 0.9, -1}, {"Solarize", 0.8, 3}},
{{"Equalize", 0.8, -1}, {"Invert", 0.1, -1}},
{{"TranslateY", 0.7, 9}, {"AutoContrast", 0.9, -1}}
};
} else {
return {{{"ShearX", 0.9, 4}, {"Invert", 0.2, -1}}, {{"ShearY", 0.9, 8}, {"Invert", 0.7, -1}},
{{"Equalize", 0.6, -1}, {"Solarize", 0.6, 6}}, {{"Invert", 0.9, -1}, {"Equalize", 0.6, -1}},
{{"Equalize", 0.6, -1}, {"Rotate", 0.9, 3}}, {{"ShearX", 0.9, 4}, {"AutoContrast", 0.8, -1}},
{{"ShearY", 0.9, 8}, {"Invert", 0.4, -1}}, {{"ShearY", 0.9, 5}, {"Solarize", 0.2, 6}},
{{"Invert", 0.9, -1}, {"AutoContrast", 0.8, -1}}, {{"Equalize", 0.6, -1}, {"Rotate", 0.9, 3}},
{{"ShearX", 0.9, 4}, {"Solarize", 0.3, 3}}, {{"ShearY", 0.8, 8}, {"Invert", 0.7, -1}},
{{"Equalize", 0.9, -1}, {"TranslateY", 0.6, 6}}, {{"Invert", 0.9, -1}, {"Equalize", 0.6, -1}},
{{"Contrast", 0.3, 3}, {"Rotate", 0.8, 4}}, {{"Invert", 0.8, -1}, {"TranslateY", 0.0, 2}},
{{"ShearY", 0.7, 6}, {"Solarize", 0.4, 8}}, {{"Invert", 0.6, -1}, {"Rotate", 0.8, 4}},
{{"ShearY", 0.3, 7}, {"TranslateX", 0.9, 3}}, {{"ShearX", 0.1, 6}, {"Invert", 0.6, -1}},
{{"Solarize", 0.7, 2}, {"TranslateY", 0.6, 7}}, {{"ShearY", 0.8, 4}, {"Invert", 0.8, -1}},
{{"ShearX", 0.7, 9}, {"TranslateY", 0.8, 3}}, {{"ShearY", 0.8, 5}, {"AutoContrast", 0.7, -1}},
{{"ShearX", 0.7, 2}, {"Invert", 0.1, -1}}};
// Return the default policy transforms
return {
{{"ShearX", 0.9, 4}, {"Invert", 0.2, -1}},
{{"ShearY", 0.9, 8}, {"Invert", 0.7, -1}},
{{"Equalize", 0.6, -1}, {"Solarize", 0.6, 6}},
{{"Invert", 0.9, -1}, {"Equalize", 0.6, -1}},
{{"Equalize", 0.6, -1}, {"Rotate", 0.9, 3}},
{{"ShearX", 0.9, 4}, {"AutoContrast", 0.8, -1}},
{{"ShearY", 0.9, 8}, {"Invert", 0.4, -1}},
{{"ShearY", 0.9, 5}, {"Solarize", 0.2, 6}},
{{"Invert", 0.9, -1}, {"AutoContrast", 0.8, -1}},
{{"Equalize", 0.6, -1}, {"Rotate", 0.9, 3}},
{{"ShearX", 0.9, 4}, {"Solarize", 0.3, 3}},
{{"ShearY", 0.8, 8}, {"Invert", 0.7, -1}},
{{"Equalize", 0.9, -1}, {"TranslateY", 0.6, 6}},
{{"Invert", 0.9, -1}, {"Equalize", 0.6, -1}},
{{"Contrast", 0.3, 3}, {"Rotate", 0.8, 4}},
{{"Invert", 0.8, -1}, {"TranslateY", 0.0, 2}},
{{"ShearY", 0.7, 6}, {"Solarize", 0.4, 8}},
{{"Invert", 0.6, -1}, {"Rotate", 0.8, 4}},
{{"ShearY", 0.3, 7}, {"TranslateX", 0.9, 3}},
{{"ShearX", 0.1, 6}, {"Invert", 0.6, -1}}
};
}
}
{
{"Solarize", 0.7, 2}, {"TranslateY", 0.6, 7}}, // First pair of transformations
{"ShearY", 0.8, 4}, {"Invert", 0.8, -1}}, // Second pair of transformations
{"ShearX", 0.7, 9}, {"TranslateY", 0.8, 3}}, // Third pair of transformations
{"ShearY", 0.8, 5}, {"AutoContrast", 0.7, -1}}, // Fourth pair of transformations
{"ShearX", 0.7, 2}, {"Invert", 0.1, -1} // Fifth pair of transformations
};
Status AutoAugmentOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
if (input->Rank() != DEFAULT_IMAGE_RANK) {
RETURN_STATUS_UNEXPECTED("AutoAugment: input tensor is not in shape of <H,W,C>, but got rank: " +
std::to_string(input->Rank()));
}
int num_channels = input->shape()[2];
if (num_channels != DEFAULT_IMAGE_CHANNELS) {
RETURN_STATUS_UNEXPECTED("AutoAugment: channel of input image should be 3, but got: " +
std::to_string(num_channels));
}
// Check if the input and output tensors are valid
IO_CHECK(input, output);
int transform_id;
std::vector<float> *probs = new std::vector<float>{0, 0};
std::vector<int32_t> *signs = new std::vector<int32_t>{0, 0};
GetParams(transforms_.size(), &transform_id, probs, signs);
// Check if the input tensor has the correct shape
if (input->Rank() != DEFAULT_IMAGE_RANK) {
// Return an error message if the input tensor does not have the expected shape
RETURN_STATUS_UNEXPECTED("AutoAugment: input tensor is not in shape of <H,W,C>, but got rank: " +
std::to_string(input->Rank()));
}
std::vector<dsize_t> image_size = {input->shape()[0], input->shape()[1]};
std::shared_ptr<Tensor> img = input;
// Get the number of channels in the input tensor
int num_channels = input->shape()[2];
const int num_augments = 2;
for (auto i = 0; i < num_augments; i++) {
std::string op_name = std::get<0>(transforms_[transform_id][i]);
float p = std::get<1>(transforms_[transform_id][i]);
int32_t magnitude_id = std::get<2>(transforms_[transform_id][i]);
if ((*probs)[i] <= p) {
Space space = GetSpace(10, image_size);
std::vector<float> magnitudes = std::get<0>(space[op_name]);
bool sign = std::get<1>(space[op_name]);
float magnitude = 0.0;
if (magnitudes.size() != 1 && magnitude_id != -1) {
magnitude = magnitudes[magnitude_id];
}
if (sign && (*signs)[i] == 0) {
magnitude *= -1.0;
}
RETURN_IF_NOT_OK(ApplyAugment(img, &img, op_name, magnitude));
// Check if the number of channels is correct
if (num_channels != DEFAULT_IMAGE_CHANNELS) {
// Return an error message if the number of channels is not as expected
RETURN_STATUS_UNEXPECTED("AutoAugment: channel of input image should be 3, but got: " +
std::to_string(num_channels));
}
// Declare an integer variable named "transform_id" to store the result of GetParams function
int transform_id;
// Declare a pointer to a dynamically allocated vector of floats named "probs" and initialize it with two elements: 0 and 0
std::vector<float> *probs = new std::vector<float>{0, 0};
// Declare a pointer to a dynamically allocated vector of int32_t named "signs" and initialize it with two elements: 0 and 0
std::vector<int32_t> *signs = new std::vector<int32_t>{0, 0};
// Call the GetParams function passing the size of the "transforms_" vector, the address of "transform_id", "probs" pointer, and "signs" pointer as arguments
GetParams(transforms_.size(), &transform_id, probs, signs);
// Create a vector called "image_size" to store the dimensions of the image
std::vector<dsize_t> image_size = {input->shape()[0], input->shape()[1]};
// Create a shared pointer called "img" and assign it the value of the "input" pointer
std::shared_ptr<Tensor> img = input;
// Define a constant integer variable `num_augments` and set its value to 2
const int num_augments = 2;
// Iterate over the range [0, num_augments) using a for loop
for (auto i = 0; i < num_augments; i++) {
// Get the first element of the tuple at index `i` from the `transforms_` vector and assign it to `op_name`
std::string op_name = std::get<0>(transforms_[transform_id][i]);
// Get the second element of the tuple at index `i` from the `transforms_` vector and assign it to `p`
float p = std::get<1>(transforms_[transform_id][i]);
// Get the third element of the tuple at index `i` from the `transforms_` vector and assign it to `magnitude_id`
int32_t magnitude_id = std::get<2>(transforms_[transform_id][i]);
// Check if the value at index `i` in the `probs` vector is less than or equal to `p`
if ((*probs)[i] <= p) {
// Call the `GetSpace` function with arguments 10 and `image_size` and assign the returned value to `space`
Space space = GetSpace(10, image_size);
// Get the first element of the tuple at key `op_name` from the `space` map and assign it to `magnitudes`
std::vector<float> magnitudes = std::get<0>(space[op_name]);
// Get the second element of the tuple at key `op_name` from the `space` map and assign it to `sign`
bool sign = std::get<1>(space[op_name]);
// Initialize `magnitude` to 0.0
float magnitude = 0.0;
// Check if the size of `magnitudes` is not equal to 1 and `magnitude_id` is not -1
if (magnitudes.size() != 1 && magnitude_id != -1) {
// Assign the value at index `magnitude_id` in `magnitudes` to `magnitude`
magnitude = magnitudes[magnitude_id];
}
// Check if `sign` is true and the value at index `i` in the `signs` vector is 0
if (sign && (*signs)[i] == 0) {
// Multiply `magnitude` by -1.0
magnitude *= -1.0;
}
// Call the `ApplyAugment` function with arguments `img`, `img`, `op_name`, and `magnitude`, and return an error if it fails
RETURN_IF_NOT_OK(ApplyAugment(img, &img, op_name, magnitude));
}
*output = img;
delete probs;
delete signs;
return Status::OK();
}
// Assign the value of `img` to the `output` pointer
*output = img;
// Delete the dynamically allocated `probs` and `signs` vectors
delete probs;
delete signs;
// Return a status indicating successful program execution
return Status::OK();
// A method to get the parameters for the AutoAugment operation
void AutoAugmentOp::GetParams(int transform_num, int *transform_id, std::vector<float> *probs,
std::vector<int32_t> *signs) {
// Create a uniform distribution for generating random transform IDs between 0 and transform_num - 1
std::uniform_int_distribution<int32_t> id_dist(0, transform_num - 1);
// Generate a random transform ID using the distribution and assign it to the transform_id variable
*transform_id = id_dist(rnd_);
// Create a uniform distribution for generating random probabilities between 0 and 1
std::uniform_real_distribution<float> prob_dist(0, 1);
(*probs)[0] = prob_dist(rnd_);
(*probs)[1] = prob_dist(rnd_);
std::uniform_int_distribution<int32_t> sign_dist(0, 1);
(*signs)[0] = sign_dist(rnd_);
(*signs)[1] = sign_dist(rnd_);
// Note: rnd_ is assumed to be an instance of a random number generator
// Generate random probabilities using the distribution and store them in the probs vector
// Note: The size of the probs vector should be equal to the transform_num
for (int i = 0; i < transform_num; i++) {
probs->push_back(prob_dist(rnd_));
}
// The signs vector is not used in this code snippet, so it is left unmodified
}
// Assign the value of the result of calling the prob_dist function with the rnd_ random number generator to the first element of the probs array
(*probs)[0] = prob_dist(rnd_);
// Assign the value of the result of calling the prob_dist function with the rnd_ random number generator to the second element of the probs array
(*probs)[1] = prob_dist(rnd_);
// Create a uniform integer distribution object named "sign_dist" that generates random numbers between 0 and 1 (inclusive)
// Assign the value returned by the sign_dist function to the first element of the signs array
(*signs)[0] = sign_dist(rnd_);
// Assign the value returned by the sign_dist function to the second element of the signs array
(*signs)[1] = sign_dist(rnd_);
// Function to generate a linearly spaced vector of floats
std::vector<float> Linspace(float start, float end, int n, float scale = 1.0, float offset = 0) {
// Create a vector of floats with size n
std::vector<float> linear(n);
// Calculate the step size between each element in the vector
float step = (n == 1) ? 0 : ((end - start) / (n - 1));
// Iterate over each element in the vector
for (auto i = 0; i < linear.size(); ++i) {
// Calculate the value of the current element based on the start, step, scale, and offset
linear[i] = (start + i * step) * scale + offset;
}
// Return the generated linearly spaced vector
return linear;
}
// Define a function named GetSpace that takes in an integer num_bins and a vector of dsize_t named image_size as parameters
Space AutoAugmentOp::GetSpace(int32_t num_bins, const std::vector<dsize_t> &image_size) {
Space space = {{"ShearX", {Linspace(0.0, 0.3, num_bins), true}},
{"ShearY", {Linspace(0.0, 0.3, num_bins), true}},
{"TranslateX", {Linspace(0.0, 150.0 / 331 * image_size[1], num_bins), true}},
{"TranslateY", {Linspace(0.0, 150.0 / 331 * image_size[0], num_bins), true}},
{"Rotate", {Linspace(0.0, 30, num_bins), true}},
{"Brightness", {Linspace(0.0, 0.9, num_bins), true}},
{"Color", {Linspace(0.0, 0.9, num_bins), true}},
{"Contrast", {Linspace(0.0, 0.9, num_bins), true}},
{"Sharpness", {Linspace(0.0, 0.9, num_bins), true}},
{"Posterize", {Linspace(0.0, num_bins - 1, num_bins, -4 / (num_bins - 1), 8), false}},
{"Solarize", {Linspace(256.0, 0.0, num_bins), false}},
{"AutoContrast", {{0}, false}},
{"Equalize", {{0}, false}},
{"Invert", {{0}, false}}};
// Create a variable named space of type Space and initialize it with a set of key-value pairs
Space space = {
{"ShearX", {Linspace(0.0, 0.3, num_bins), true}},
{"ShearY", {Linspace(0.0, 0.3, num_bins), true}},
{"TranslateX", {Linspace(0.0, 150.0 / 331 * image_size[1], num_bins), true}},
{"TranslateY", {Linspace(0.0, 150.0 / 331 * image_size[0], num_bins), true}},
{"Rotate", {Linspace(0.0, 30, num_bins), true}},
{"Brightness", {Linspace(0.0, 0.9, num_bins), true}},
{"Color", {Linspace(0.0, 0.9, num_bins), true}},
{"Contrast", {Linspace(0.0, 0.9, num_bins), true}},
{"Sharpness", {Linspace(0.0, 0.9, num_bins), true}},
{"Posterize", {Linspace(0.0, num_bins - 1, num_bins, -4 / (num_bins - 1), 8), false}},
{"Solarize", {Linspace(256.0, 0.0, num_bins), false}},
{"AutoContrast", {{0}, false}},
{"Equalize", {{0}, false}},
{"Invert", {{0}, false}}
};
// Return the space variable
return space;
}
Status AutoAugmentOp::ApplyAugment(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output,
const std::string &op_name, float magnitude) {
if (op_name == "ShearX") {
// This function applies different image augmentation operations based on the given op_name and magnitude.
// The input image is passed as a shared pointer to a Tensor object, and the augmented image is stored in the output pointer.
// The op_name specifies the type of augmentation to be applied, and the magnitude determines the intensity of the augmentation.
// Check if the op_name is "ShearX"
if (op_name == "ShearX") {
// Calculate the shear angle in degrees from the given magnitude
float_t shear = magnitude * 180 / CV_PI;
// Create an AffineOp object with the shear transformation along the X-axis
AffineOp affine(0.0, {0, 0}, 1.0, {shear, 0.0}, interpolation_, fill_value_);
// Apply the affine transformation to the input image and store the result in the output pointer
RETURN_IF_NOT_OK(affine.Compute(input, output));
} else if (op_name == "ShearY") {
}
// Check if the op_name is "ShearY"
else if (op_name == "ShearY") {
// Calculate the shear angle in degrees from the given magnitude
float_t shear = magnitude * 180 / CV_PI;
// Create an AffineOp object with the shear transformation along the Y-axis
AffineOp affine(0.0, {0, 0}, 1.0, {0.0, shear}, interpolation_, fill_value_);
// Apply the affine transformation to the input image and store the result in the output pointer
RETURN_IF_NOT_OK(affine.Compute(input, output));
} else if (op_name == "TranslateX") {
}
// Check if the op_name is "TranslateX"
else if (op_name == "TranslateX") {
// Convert the magnitude to an integer value for translation
float_t translate = static_cast<int>(magnitude);
// Create an AffineOp object with the translation along the X-axis
AffineOp affine(0.0, {translate, 0}, 1.0, {0.0, 0.0}, interpolation_, fill_value_);
// Apply the affine transformation to the input image and store the result in the output pointer
RETURN_IF_NOT_OK(affine.Compute(input, output));
} else if (op_name == "TranslateY") {
}
// Check if the op_name is "TranslateY"
else if (op_name == "TranslateY") {
// Convert the magnitude to an integer value for translation
float_t translate = static_cast<int>(magnitude);
// Create an AffineOp object with the translation along the Y-axis
AffineOp affine(0.0, {0, translate}, 1.0, {0.0, 0.0}, interpolation_, fill_value_);
// Apply the affine transformation to the input image and store the result in the output pointer
RETURN_IF_NOT_OK(affine.Compute(input, output));
} else if (op_name == "Rotate") {
}
// Check if the op_name is "Rotate"
else if (op_name == "Rotate") {
// Define the indices for the red, blue, and green channels
const int kRIndex = 0;
const int kBIndex = 1;
const int kGIndex = 2;
// Apply the Rotate function to the input image with the given magnitude and other parameters
RETURN_IF_NOT_OK(Rotate(input, output, {}, magnitude, interpolation_, false, fill_value_[kRIndex],
fill_value_[kBIndex], fill_value_[kGIndex]));
} else if (op_name == "Brightness") {
}
// Check if the op_name is "Brightness"
else if (op_name == "Brightness") {
// Adjust the brightness of the input image by adding the magnitude to the pixel values
RETURN_IF_NOT_OK(AdjustBrightness(input, output, 1 + magnitude));
} else if (op_name == "Color") {
}
// Check if the op_name is "Color"
else if (op_name == "Color") {
// Adjust the saturation of the input image by multiplying the pixel values by the magnitude
RETURN_IF_NOT_OK(AdjustSaturation(input, output, 1 + magnitude));
} else if (op_name == "Contrast") {
}
// Check if the op_name is "Contrast"
else if (op_name == "Contrast") {
// Adjust the contrast of the input image by multiplying the pixel values by the magnitude
RETURN_IF_NOT_OK(AdjustContrast(input, output, 1 + magnitude));
} else if (op_name == "Sharpness") {
}
// Check if the op_name is "Sharpness"
else if (op_name == "Sharpness") {
// Create a SharpnessOp object with the given magnitude
SharpnessOp sharpness(1 + magnitude);
// Apply the sharpness operation to the input image and store the result in the output pointer
RETURN_IF_NOT_OK(sharpness.Compute(input, output));
} else if (op_name == "Posterize") {
}
// Check if the op_name is "Posterize"
else if (op_name == "Posterize") {
// Create a PosterizeOp object with the given magnitude
PosterizeOp posterize(static_cast<int>(magnitude));
// Apply the posterize operation to the input image and store the result in the output pointer
RETURN_IF_NOT_OK(posterize.Compute(input, output));
} else if (op_name == "Solarize") {
}
// Check if the op_name is "Solarize"
else if (op_name == "Solarize") {
// Create a SolarizeOp object with the given magnitude and maximum value
SolarizeOp solarize({static_cast<uint8_t>(magnitude), 255});
// Apply the solarize operation to the input image and store the result in the output pointer
RETURN_IF_NOT_OK(solarize.Compute(input, output));
} else if (op_name == "AutoContrast") {
RETURN_IF_NOT_OK(AutoContrast(input, output, 0.0, {}));
} else if (op_name == "Equalize") {
RETURN_IF_NOT_OK(Equalize(input, output));
} else {
InvertOp invert;
RETURN_IF_NOT_OK(invert.Compute(input, output));
}
return Status::OK();
}
// Check if the op_name is "AutoContrast"
else if (op_name == "AutoContrast") {
// ... (code for AutoContrast operation)
}
// If the operation name is "AutoContrast"
if (op_name == "AutoContrast") {
// Call the AutoContrast function with the input and output parameters, along with the specified values
// Return immediately if the function returns a non-ok status
RETURN_IF_NOT_OK(AutoContrast(input, output, 0.0, {}));
}
// If the operation name is "Equalize"
else if (op_name == "Equalize") {
// Call the Equalize function with the input and output parameters
// Return immediately if the function returns a non-ok status
RETURN_IF_NOT_OK(Equalize(input, output));
}
// If the operation name is neither "AutoContrast" nor "Equalize"
else {
// Create an instance of the InvertOp class
InvertOp invert;
// Call the Compute function of the InvertOp instance with the input and output parameters
// Return immediately if the function returns a non-ok status
RETURN_IF_NOT_OK(invert.Compute(input, output));
}
// Return an OK status to indicate successful execution of the function
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,18 +14,42 @@
* limitations under the License.
*/
// Include the header file for the AutoContrastOp class from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/auto_contrast_op.h"
// Include the header file for the ImageUtils class from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Define a constant float variable named kCutOff and initialize it with the value 0.0
const float AutoContrastOp::kCutOff = 0.0;
// Define a constant vector of unsigned integers named kIgnore and initialize it as an empty vector
const std::vector<uint32_t> AutoContrastOp::kIgnore = {};
// Compute function of the AutoContrastOp class
Status AutoContrastOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Call the AutoContrast function with the input, output, cutoff, and ignore parameters
return AutoContrast(input, output, cutoff_, ignore_);
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -14,217 +14,432 @@
* limitations under the License.
*/
#include "minddata/dataset/kernels/image/bounding_box.h"
// Include the header file "minddata/dataset/kernels/image/bounding_box.h" which contains the declarations for the bounding box related functions and classes.
// Include the algorithm header for various algorithms like sorting, searching, etc.
#include <algorithm>
// Include the limits header for numeric limits like minimum and maximum values
#include <limits>
// Include the vector header for using the vector container class
#include <vector>
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
const uint8_t kNumOfCols = 4;
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Declare a constant variable named kNumOfCols of type uint8_t (unsigned 8-bit integer)
// and assign it a value of 4. This variable represents the number of columns in a grid or matrix.
// Definition of the constructor for the BoundingBox class
BoundingBox::BoundingBox(bbox_float x, bbox_float y, bbox_float width, bbox_float height)
: x_(x), y_(y), width_(width), height_(height) {}
Status BoundingBox::ReadFromTensor(const TensorPtr &bbox_tensor, dsize_t index_of_bbox,
std::shared_ptr<BoundingBox> *bbox_out) {
CHECK_FAIL_RETURN_UNEXPECTED(bbox_tensor != nullptr, "BoundingBox: bbox_tensor is null.");
bbox_float x;
bbox_float y;
bbox_float width;
bbox_float height;
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&x, {index_of_bbox, 0}));
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&y, {index_of_bbox, 1}));
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&width, {index_of_bbox, 2}));
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&height, {index_of_bbox, 3}));
*bbox_out = std::make_shared<BoundingBox>(x, y, width, height);
return Status::OK();
}
// This function reads a bounding box from a given tensor and returns it as a shared pointer to a BoundingBox object
// It takes in the following parameters:
// - bbox_tensor: a shared pointer to the tensor containing the bounding box data
// - index_of_bbox: the index of the bounding box to read from the tensor
// - bbox_out: a pointer to a shared pointer to a BoundingBox object, where the resulting bounding box will be stored
// Check if the bbox_tensor is not null, and return an error status if it is
CHECK_FAIL_RETURN_UNEXPECTED(bbox_tensor != nullptr, "BoundingBox: bbox_tensor is null.");
// Declare variables to store the x, y, width, and height values of the bounding box
bbox_float x;
bbox_float y;
bbox_float width;
bbox_float height;
// Get the x value of the bounding box from the tensor at the specified index
// If there is an error getting the value, return the error status
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&x, {index_of_bbox, 0}));
// Get the y value of the bounding box from the tensor at the specified index
// If there is an error getting the value, return the error status
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&y, {index_of_bbox, 1}));
// Get the width value of the bounding box from the tensor at the specified index
// If there is an error getting the value, return the error status
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&width, {index_of_bbox, 2}));
// Get the height value of the bounding box from the tensor at the specified index
// If there is an error getting the value, return the error status
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&height, {index_of_bbox, 3}));
// Create a new BoundingBox object using the x, y, width, and height values
// and assign it to the pointer to shared pointer bbox_out
*bbox_out = std::make_shared<BoundingBox>(x, y, width, height);
// Return a success status
return Status::OK();
// ValidateBoundingBoxes function to validate the input image and bounding box data
Status BoundingBox::ValidateBoundingBoxes(const TensorRow &image_and_bbox) {
// Check if the size of the input data is not equal to 2 (image and bounding box)
if (image_and_bbox.size() != 2) {
// Return an error status with the appropriate error message
return Status(StatusCode::kMDBoundingBoxInvalidShape, __LINE__, __FILE__,
"BoundingBox: invalid input, size of input data should be 2 (including image and bounding box), "
"but got: " +
std::to_string(image_and_bbox.size()));
}
// Check if the shape of the bounding box is less than 2 (should be at least 2-dimensional matrix)
if (image_and_bbox[1]->shape().Size() < 2) {
// Return an error status with the appropriate error message
return Status(StatusCode::kMDBoundingBoxInvalidShape, __LINE__, __FILE__,
"BoundingBox: bounding boxes should have to be two-dimensional matrix at least, but got " +
std::to_string(image_and_bbox[1]->shape().Size()) + " dimension.");
}
// Get the number of features in the bounding box
int64_t num_of_features = image_and_bbox[1]->shape()[1];
// Check if the number of features is less than the required number of columns
if (num_of_features < kNumOfCols) {
// Return an error status with the appropriate error message
return Status(
StatusCode::kMDBoundingBoxInvalidShape, __LINE__, __FILE__,
"BoundingBox: bounding boxes should be have at least 4 features, but got: " + std::to_string(num_of_features));
}
// Create a vector to store shared pointers to BoundingBox objects
std::vector<std::shared_ptr<BoundingBox>> bbox_list;
// Call the GetListOfBoundingBoxes function to populate the bbox_list vector
RETURN_IF_NOT_OK(GetListOfBoundingBoxes(image_and_bbox[1], &bbox_list));
// Get the height and width of the image
int64_t img_h = image_and_bbox[0]->shape()[0];
int64_t img_w = image_and_bbox[0]->shape()[1];
// Iterate over each bounding box in the bbox_list vector
for (auto &bbox : bbox_list) {
// Check if the width of the bounding box is too large (x coordinate exceeds the maximum value of int64)
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<int64_t>::max() - bbox->x()) > bbox->width(),
"BoundingBox: bbox width is too large as coordinate x bigger than max num of int64.");
// Check if the height of the bounding box is too large (y coordinate exceeds the maximum value of int64)
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<int64_t>::max() - bbox->y()) > bbox->height(),
"BoundingBox: bbox height is too large as coordinate y bigger than max num of int64.");
// Check if the bounding box is out of bounds of the image
if ((bbox->x() + bbox->width() > img_w) || (bbox->y() + bbox->height() > img_h)) {
// Return an error status with the appropriate error message
return Status(StatusCode::kMDBoundingBoxOutOfBounds, __LINE__, __FILE__,
"BoundingBox: bounding boxes is out of bounds of the image, as image width: " +
std::to_string(img_w) + ", bbox width coordinate: " + std::to_string(bbox->x() + bbox->width()) +
", and image height: " + std::to_string(img_h) +
", bbox height coordinate: " + std::to_string(bbox->y() + bbox->height()));
}
// Check if the coordinates of the bounding box are negative
if (static_cast<int>(bbox->x()) < 0 || static_cast<int>(bbox->y()) < 0) {
// Return an error status with the appropriate error message
return Status(StatusCode::kMDBoundingBoxOutOfBounds, __LINE__, __FILE__,
"BoundingBox: the coordinates of the bounding boxes has negative value, got: (" +
std::to_string(bbox->x()) + "," + std::to_string(bbox->y()) + ").");
}
}
return Status::OK();
}
// Return the OK status from the Status class
return Status::OK();
Status BoundingBox::WriteToTensor(const TensorPtr &bbox_tensor, dsize_t index_of_bbox) {
CHECK_FAIL_RETURN_UNEXPECTED(bbox_tensor != nullptr, "BoundingBox: bbox_tensor is null.");
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 0}, x_));
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 1}, y_));
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 2}, width_));
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 3}, height_));
return Status::OK();
}
// This function is a member function of the BoundingBox class and is used to write the bounding box coordinates to a given tensor.
// It takes in a reference to a TensorPtr object named bbox_tensor and an index_of_bbox of type dsize_t.
// The function returns a Status object indicating the success or failure of the operation.
Status BoundingBox::GetListOfBoundingBoxes(const TensorPtr &bbox_tensor,
std::vector<std::shared_ptr<BoundingBox>> *bbox_out) {
// Check if the bbox_tensor is not null, if it is null, return an error message using CHECK_FAIL_RETURN_UNEXPECTED macro.
// The macro expands to a check statement that throws an exception with the provided error message if the condition is false.
CHECK_FAIL_RETURN_UNEXPECTED(bbox_tensor != nullptr, "BoundingBox: bbox_tensor is null.");
// Set the x-coordinate of the bounding box at the given index_of_bbox in the bbox_tensor using the SetItemAt function of the TensorPtr object.
// The SetItemAt function takes in a template argument specifying the data type (bbox_float in this case) and a coordinate pair ({index_of_bbox, 0}) indicating the position in the tensor.
// The function returns a Status object indicating the success or failure of the operation.
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 0}, x_));
// Set the y-coordinate of the bounding box at the given index_of_bbox in the bbox_tensor using the SetItemAt function.
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 1}, y_));
// Set the width of the bounding box at the given index_of_bbox in the bbox_tensor using the SetItemAt function.
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 2}, width_));
// Set the height of the bounding box at the given index_of_bbox in the bbox_tensor using the SetItemAt function.
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 3}, height_));
// Return a Status object indicating successful program termination.
return Status::OK();
// This function is a member function of the BoundingBox class.
// It takes a TensorPtr (a smart pointer to a Tensor object) and a pointer to a vector of shared pointers to BoundingBox objects as input.
// It returns a Status object indicating the success or failure of the operation.
Status BoundingBox::GetListOfBoundingBoxes(const TensorPtr &bbox_tensor, std::vector<std::shared_ptr<BoundingBox>> *bbox_out) {
// Check if the bbox_tensor is not null, and return an error message if it is.
CHECK_FAIL_RETURN_UNEXPECTED(bbox_tensor != nullptr, "BoundingBox: bbox_tensor is null.");
// Get the number of boxes from the shape of the bbox_tensor.
dsize_t num_of_boxes = bbox_tensor->shape()[0];
// Iterate over each box.
for (dsize_t i = 0; i < num_of_boxes; i++) {
// Create a shared pointer to a BoundingBox object.
std::shared_ptr<BoundingBox> bbox;
// Read the i-th box from the bbox_tensor and store it in the bbox shared pointer.
RETURN_IF_NOT_OK(ReadFromTensor(bbox_tensor, i, &bbox));
// Add the bbox shared pointer to the bbox_out vector.
bbox_out->push_back(bbox);
}
// Return a Status object indicating success.
return Status::OK();
}
Status BoundingBox::CreateTensorFromBoundingBoxList(const std::vector<std::shared_ptr<BoundingBox>> &bboxes,
TensorPtr *tensor_out) {
// This function takes a vector of shared pointers to BoundingBox objects and creates a tensor from the bounding box data.
// The resulting tensor is stored in the tensor_out pointer.
// Include the necessary headers for the types and functions used in this function
#include <vector>
#include <memory>
#include "BoundingBox.h"
#include "Tensor.h"
#include "Status.h"
// Define the function
Status BoundingBox::CreateTensorFromBoundingBoxList(const std::vector<std::shared_ptr<BoundingBox>>& bboxes, TensorPtr* tensor_out) {
// Get the number of bounding boxes in the input vector
dsize_t num_of_boxes = bboxes.size();
// Create a vector to store the bounding box data for the tensor
std::vector<bbox_float> bboxes_for_tensor;
// Iterate over each bounding box in the input vector
for (dsize_t i = 0; i < num_of_boxes; i++) {
// Create an array to store the bounding box data
bbox_float b_data[kNumOfCols] = {bboxes[i]->x(), bboxes[i]->y(), bboxes[i]->width(), bboxes[i]->height()};
// Insert the bounding box data into the vector
bboxes_for_tensor.insert(bboxes_for_tensor.end(), b_data, b_data + kNumOfCols);
}
// Create a tensor from the bounding box data using the Tensor::CreateFromVector function
RETURN_IF_NOT_OK(Tensor::CreateFromVector(bboxes_for_tensor, TensorShape{num_of_boxes, kNumOfCols}, tensor_out));
// Return a status indicating successful execution of the function
return Status::OK();
}
// Function to pad bounding boxes with given top and left padding values
Status BoundingBox::PadBBoxes(const TensorPtr *bbox_list, size_t bbox_count, int32_t pad_top, int32_t pad_left) {
// Check if the bbox_list pointer is not null, return an error message if it is
CHECK_FAIL_RETURN_UNEXPECTED(bbox_list != nullptr, "BoundingBox: bbox_list ptr is null.");
// Loop through each bounding box in the bbox_list
for (dsize_t i = 0; i < bbox_count; i++) {
// Create a shared pointer to store the current bounding box
std::shared_ptr<BoundingBox> bbox;
// Read the bounding box from the tensor at index i and store it in the bbox pointer
RETURN_IF_NOT_OK(ReadFromTensor(*bbox_list, i, &bbox));
// Check if the sum of the current bounding box's x-coordinate and pad_left exceeds the maximum value of int32_t
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<int32_t>::max() - bbox->x()) > pad_left,
"BoundingBox: pad_left is too large as coordinate x bigger than max num of int64.");
// Add the pad_left value to the x-coordinate of the bounding box
bbox->SetX(bbox->x() + pad_left);
// Check if the sum of the current bounding box's y-coordinate and pad_top exceeds the maximum value of int32_t
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<int32_t>::max() - bbox->y()) > pad_top,
"BoundingBox: pad_top is too large as coordinate y bigger than max num of int64.");
// Add the pad_top value to the y-coordinate of the bounding box
bbox->SetY(bbox->y() + pad_top);
// Write the updated bounding box back to the tensor at index i
RETURN_IF_NOT_OK(bbox->WriteToTensor(*bbox_list, i));
}
// Return OK status to indicate successful execution of the function
return Status::OK();
}
Status BoundingBox::UpdateBBoxesForCrop(TensorPtr *bbox_list, size_t *bbox_count, int32_t CB_Xmin, int32_t CB_Ymin,
int32_t CB_Xmax, int32_t CB_Ymax) {
CHECK_FAIL_RETURN_UNEXPECTED(bbox_list != nullptr, "BoundingBox: bbox_list ptr is null.");
// PASS LIST, COUNT OF BOUNDING BOXES
// Also PAss X/Y Min/Max of image cropped region - normally obtained from 'GetCropBox' functions
std::vector<dsize_t> correct_ind;
std::vector<bbox_float> copyVals;
dsize_t bboxDim = (*bbox_list)->shape()[1];
for (dsize_t i = 0; i < *bbox_count; i++) {
std::shared_ptr<BoundingBox> bbox;
RETURN_IF_NOT_OK(ReadFromTensor(*bbox_list, i, &bbox));
bbox_float bb_Xmax = bbox->x() + bbox->width();
bbox_float bb_Ymax = bbox->y() + bbox->height();
// check for image / BB overlap
if (((bbox->x() > CB_Xmax) || (bbox->y() > CB_Ymax)) || ((bb_Xmax < CB_Xmin) || (bb_Ymax < CB_Ymin))) {
continue; // no overlap found
}
// Update this bbox and select it to move to the final output tensor
correct_ind.push_back(i);
// adjust BBox corners by bringing into new CropBox if beyond
// Also resetting/adjusting for boxes to lie within CropBox instead of Image - subtract CropBox Xmin/YMin
// Check if the pointer to the bbox_list is not null, otherwise return an error message
CHECK_FAIL_RETURN_UNEXPECTED(bbox_list != nullptr, "BoundingBox: bbox_list ptr is null.");
bbox_float bb_Xmin = bbox->x() - std::min(static_cast<bbox_float>(0.0), (bbox->x() - CB_Xmin)) - CB_Xmin;
bbox_float bb_Ymin = bbox->y() - std::min(static_cast<bbox_float>(0.0), (bbox->y() - CB_Ymin)) - CB_Ymin;
bb_Xmax = bb_Xmax - std::max(static_cast<bbox_float>(0.0), (bb_Xmax - CB_Xmax)) - CB_Xmin;
bb_Ymax = bb_Ymax - std::max(static_cast<bbox_float>(0.0), (bb_Ymax - CB_Ymax)) - CB_Ymin;
// Create vectors to store the correct indices and copied values
std::vector<dsize_t> correct_ind;
std::vector<bbox_float> copyVals;
// bound check for float values
bb_Xmin = std::max(bb_Xmin, static_cast<bbox_float>(0));
bb_Ymin = std::max(bb_Ymin, static_cast<bbox_float>(0));
bb_Xmax = std::min(bb_Xmax, static_cast<bbox_float>(CB_Xmax - CB_Xmin)); // find max value relative to new image
bb_Ymax = std::min(bb_Ymax, static_cast<bbox_float>(CB_Ymax - CB_Ymin));
// Get the dimension of the bounding box from the shape of the bbox_list tensor
dsize_t bboxDim = (*bbox_list)->shape()[1];
// reset min values and calculate width/height from Box corners
bbox->SetX(bb_Xmin);
bbox->SetY(bb_Ymin);
bbox->SetWidth(bb_Xmax - bb_Xmin);
bbox->SetHeight(bb_Ymax - bb_Ymin);
RETURN_IF_NOT_OK(bbox->WriteToTensor(*bbox_list, i));
// Iterate through each bounding box
for (dsize_t i = 0; i < *bbox_count; i++) {
// Create a shared pointer to store the current bounding box
std::shared_ptr<BoundingBox> bbox;
// Read the bounding box from the tensor at index i and store it in the bbox pointer
RETURN_IF_NOT_OK(ReadFromTensor(*bbox_list, i, &bbox));
// Calculate the maximum X and Y coordinates of the bounding box
bbox_float bb_Xmax = bbox->x() + bbox->width();
bbox_float bb_Ymax = bbox->y() + bbox->height();
// Check if there is an overlap between the image and the bounding box
if (((bbox->x() > CB_Xmax) || (bbox->y() > CB_Ymax)) || ((bb_Xmax < CB_Xmin) || (bb_Ymax < CB_Ymin))) {
continue; // no overlap found, skip to the next bounding box
}
// create new tensor and copy over bboxes still valid to the image
// bboxes outside of new cropped region are ignored - empty tensor returned in case of none
*bbox_count = correct_ind.size();
bbox_float temp = 0.0;
for (auto slice : correct_ind) { // for every index in the loop
// If there is an overlap, add the index of the bounding box to the correct_ind vector
correct_ind.push_back(i);
// Adjust the corners of the bounding box to fit within the new crop box
// Also adjust the coordinates to be relative to the crop box instead of the image
// Subtract the crop box's Xmin and Ymin from the bounding box's coordinates
// and store the adjusted bounding box in the copyVals vector
}
// Calculate the minimum value for the X-coordinate of the bounding box
bbox_float bb_Xmin = bbox->x() - std::min(static_cast<bbox_float>(0.0), (bbox->x() - CB_Xmin)) - CB_Xmin;
// Calculate the minimum value for the Y-coordinate of the bounding box
bbox_float bb_Ymin = bbox->y() - std::min(static_cast<bbox_float>(0.0), (bbox->y() - CB_Ymin)) - CB_Ymin;
// Calculate the maximum value for the X-coordinate of the bounding box
bb_Xmax = bb_Xmax - std::max(static_cast<bbox_float>(0.0), (bb_Xmax - CB_Xmax)) - CB_Xmin;
// Calculate the maximum value for the Y-coordinate of the bounding box
bb_Ymax = bb_Ymax - std::max(static_cast<bbox_float>(0.0), (bb_Ymax - CB_Ymax)) - CB_Ymin;
// Perform a bound check for the float values
// Ensure that bb_Xmin is not less than 0, if it is, set it to 0
bb_Xmin = std::max(bb_Xmin, static_cast<bbox_float>(0));
// Ensure that bb_Ymin is not less than 0, if it is, set it to 0
bb_Ymin = std::max(bb_Ymin, static_cast<bbox_float>(0));
// Ensure that bb_Xmax is not greater than the difference between CB_Xmax and CB_Xmin, if it is, set it to that difference
bb_Xmax = std::min(bb_Xmax, static_cast<bbox_float>(CB_Xmax - CB_Xmin));
// Ensure that bb_Ymax is not greater than the difference between CB_Ymax and CB_Ymin, if it is, set it to that difference
bb_Ymax = std::min(bb_Ymax, static_cast<bbox_float>(CB_Ymax - CB_Ymin));
// Reset the minimum values and calculate the width and height of the bounding box from its corners
bbox->SetX(bb_Xmin);
bbox->SetY(bb_Ymin);
bbox->SetWidth(bb_Xmax - bb_Xmin);
bbox->SetHeight(bb_Ymax - bb_Ymin);
// Write the bounding box to the tensor and return an error if unsuccessful
RETURN_IF_NOT_OK(bbox->WriteToTensor(*bbox_list, i));
}
// Create a new tensor and copy over the bounding boxes that are still valid within the image
// Bounding boxes outside of the new cropped region are ignored, and an empty tensor is returned if there are none
*bbox_count = correct_ind.size();
bbox_float temp = 0.0;
for (auto slice : correct_ind) { // for every index in the loop
for (dsize_t ix = 0; ix < bboxDim; ix++) {
RETURN_IF_NOT_OK((*bbox_list)->GetItemAt<bbox_float>(&temp, {slice, ix}));
copyVals.push_back(temp);
RETURN_IF_NOT_OK((*bbox_list)->GetItemAt<bbox_float>(&temp, {slice, ix}));
copyVals.push_back(temp);
}
}
std::shared_ptr<Tensor> retV;
RETURN_IF_NOT_OK(
Tensor::CreateFromVector(copyVals, TensorShape({static_cast<dsize_t>(*bbox_count), bboxDim}), &retV));
(*bbox_list) = retV; // reset pointer
return Status::OK();
}
// Create a new tensor from the copied values and return an error if unsuccessful
std::shared_ptr<Tensor> retV;
RETURN_IF_NOT_OK(
Tensor::CreateFromVector(copyVals, TensorShape({static_cast<dsize_t>(*bbox_count), bboxDim}), &retV));
// Reset the pointer to the new tensor
(*bbox_list) = retV;
// Return a status indicating success
return Status::OK();
// Update the bounding boxes for resize based on the given parameters
Status BoundingBox::UpdateBBoxesForResize(const TensorPtr &bbox_list, size_t bbox_count, int32_t target_width,
int32_t target_height, int32_t orig_width, int32_t orig_height) {
// Check if the bbox_list pointer is null, and return an error message if it is
CHECK_FAIL_RETURN_UNEXPECTED(bbox_list != nullptr, "BoundingBox: bbox_list ptr is null.");
// Check if the orig_width is zero, and return an error message if it is
CHECK_FAIL_RETURN_UNEXPECTED(orig_width != 0, "BoundingBox: orig_width is zero.");
// Check if the orig_height is zero, and return an error message if it is
CHECK_FAIL_RETURN_UNEXPECTED(orig_height != 0, "BoundingBox: orig_height is zero.");
}
// cast to float to preserve fractional
// Cast the target width and original width to float to preserve the fractional part
bbox_float W_aspRatio = (target_width * 1.0) / (orig_width * 1.0);
// Cast the target height and original height to float to preserve the fractional part
bbox_float H_aspRatio = (target_height * 1.0) / (orig_height * 1.0);
// Iterate over each bounding box
for (dsize_t i = 0; i < bbox_count; i++) {
// for each bounding box
// Create a shared pointer to a BoundingBox object
std::shared_ptr<BoundingBox> bbox;
// Read the bounding box from the bbox_list tensor at index i and assign it to the bbox pointer
RETURN_IF_NOT_OK(ReadFromTensor(bbox_list, i, &bbox));
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / bbox->x()) > W_aspRatio,
"BoundingBox: Width aspect Ratio is too large as got: " + std::to_string(W_aspRatio));
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / bbox->y()) > H_aspRatio,
"BoundingBox: Height aspect Ratio is too large as got: " + std::to_string(H_aspRatio));
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / bbox->width()) > W_aspRatio,
"BoundingBox: Width aspect Ratio is too large as got: " + std::to_string(W_aspRatio));
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / bbox->height()) > H_aspRatio,
"BoundingBox: Height aspect Ratio is too large as got: " + std::to_string(H_aspRatio));
// Check if the width aspect ratio of the bounding box is too large
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / bbox->x()) > W_aspRatio,
"BoundingBox: Width aspect Ratio is too large as got: " + std::to_string(W_aspRatio));
// update positions and widths
// Check if the height aspect ratio of the bounding box is too large
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / bbox->y()) > H_aspRatio,
"BoundingBox: Height aspect Ratio is too large as got: " + std::to_string(H_aspRatio));
// Check if the width aspect ratio of the bounding box is too large
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / bbox->width()) > W_aspRatio,
"BoundingBox: Width aspect Ratio is too large as got: " + std::to_string(W_aspRatio));
// Check if the height aspect ratio of the bounding box is too large
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / bbox->height()) > H_aspRatio,
"BoundingBox: Height aspect Ratio is too large as got: " + std::to_string(H_aspRatio));
// Update the x and y positions of the bounding box by multiplying them with the width and height aspect ratios respectively
bbox->SetX(bbox->x() * W_aspRatio);
bbox->SetY(bbox->y() * H_aspRatio);
// Update the width and height of the bounding box by multiplying them with the width and height aspect ratios respectively
bbox->SetWidth(bbox->width() * W_aspRatio);
bbox->SetHeight(bbox->height() * H_aspRatio);
// reset bounding box values
// Reset the bounding box values by writing them to the tensor
RETURN_IF_NOT_OK(bbox->WriteToTensor(bbox_list, i));
}
// Return a status indicating successful program execution
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
// Closing braces to end the namespace blocks for "dataset" and "mindspore"

View File

@ -14,63 +14,114 @@
* limitations under the License.
*/
// Include the header file "minddata/dataset/kernels/image/bounding_box_augment_op.h"
#include "minddata/dataset/kernels/image/bounding_box_augment_op.h"
// Include the utility header, which provides various utility functions and classes
#include <utility>
// Include the header file for the cv_tensor module from the minddata/dataset/core directory
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for the bounding_box module from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/bounding_box.h"
// Include the header file for the image_utils module from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the resize_op module from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/resize_op.h"
// Define the namespace "mindspore"
namespace mindspore {
namespace dataset {
const float BoundingBoxAugmentOp::kDefRatio = 0.3;
// Define the nested namespace "dataset"
namespace dataset {
// Define the constant float variable "kDefRatio" with a value of 0.3
const float BoundingBoxAugmentOp::kDefRatio = 0.3;
}
}
// Define the constructor for the BoundingBoxAugmentOp class
BoundingBoxAugmentOp::BoundingBoxAugmentOp(std::shared_ptr<TensorOp> transform, float ratio)
: ratio_(ratio), uniform_(0, 1), transform_(std::move(transform)) {
// Seed the random number generator with a random seed obtained from GetSeed() function
rnd_.seed(GetSeed());
}
// Compute function for the BoundingBoxAugmentOp class
Status BoundingBoxAugmentOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output vectors are valid
IO_CHECK_VECTOR(input, output);
// Validate the bounding boxes in the input
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
// Get the number of boxes from the shape of the second input tensor
uint32_t num_of_boxes = input[1]->shape()[0];
// Declare shared pointers for the crop and result tensors
std::shared_ptr<Tensor> crop_out;
std::shared_ptr<Tensor> res_out;
// Convert the first input tensor to a CVTensor
std::shared_ptr<CVTensor> input_restore = CVTensor::AsCVTensor(input[0]);
// Iterate over each box
for (uint32_t i = 0; i < num_of_boxes; i++) {
// using a uniform distribution to ensure op happens with probability ratio_
// Use a uniform distribution to determine if the operation should be applied based on the probability ratio_
if (uniform_(rnd_) < ratio_) {
// Read the bounding box from the second input tensor
std::shared_ptr<BoundingBox> bbox;
RETURN_IF_NOT_OK(BoundingBox::ReadFromTensor(input[1], i, &bbox));
// Crop the input tensor using the bounding box coordinates
RETURN_IF_NOT_OK(Crop(input_restore, &crop_out, static_cast<int>(bbox->x()), static_cast<int>(bbox->y()),
static_cast<int>(bbox->width()), static_cast<int>(bbox->height())));
// transform the cropped bbox region
// Create tensor rows for the crop output and result output
TensorRow crop_out_row;
TensorRow res_out_row;
crop_out_row.push_back(crop_out);
res_out_row.push_back(res_out);
// Apply the transformation operation to the crop output
RETURN_IF_NOT_OK(transform_->Compute(crop_out_row, &res_out_row));
// place the transformed region back in the restored input
// Get the transformed crop image as a CVTensor
std::shared_ptr<CVTensor> res_img = CVTensor::AsCVTensor(res_out_row[0]);
// check if transformed crop is out of bounds of the box
// Check if the transformed crop is out of bounds of the original bounding box
if (res_img->mat().cols > bbox->width() || res_img->mat().rows > bbox->height() ||
res_img->mat().cols < bbox->width() || res_img->mat().rows < bbox->height()) {
// if so, resize to fit in the box
// If so, resize the transformed crop to fit within the bounding box
std::shared_ptr<TensorOp> resize_op =
std::make_shared<ResizeOp>(static_cast<int32_t>(bbox->height()), static_cast<int32_t>(bbox->width()));
RETURN_IF_NOT_OK(resize_op->Compute(std::static_pointer_cast<Tensor>(res_img), &res_out_row[0]));
res_img = CVTensor::AsCVTensor(res_out_row[0]);
}
// Copy the transformed crop region back into the original input tensor
res_img->mat().copyTo(
input_restore->mat()(cv::Rect(bbox->x(), bbox->y(), res_img->mat().cols, res_img->mat().rows)));
}
}
// Add the input_restore tensor and the second input tensor to the output tensor row
(*output).push_back(std::move(std::static_pointer_cast<Tensor>(input_restore)));
(*output).push_back(input[1]);
// Return OK status to indicate successful computation
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
// Closing braces to end the namespace blocks for "dataset" and "mindspore"

View File

@ -17,72 +17,151 @@
#include <string>
#include "utils/ms_utils.h"
// Check if the ENABLE_ANDROID macro is defined
#ifndef ENABLE_ANDROID
#include "minddata/dataset/kernels/image/image_utils.h"
// If ENABLE_ANDROID is not defined, include the "minddata/dataset/kernels/image/image_utils.h" header file
#include "minddata/dataset/kernels/image/image_utils.h"
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
// If ENABLE_ANDROID is defined, include the "minddata/dataset/kernels/image/lite_image_utils.h" header file
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Include the "status.h" header file from the "minddata/dataset/util" directory
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace
namespace dataset {
// Definition of the static member variable "kDefWidth" of the "CenterCropOp" class
const int32_t CenterCropOp::kDefWidth = 0;
Status CenterCropOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
std::string err_msg;
std::string err_head = "CenterCrop: ";
dsize_t rank = input->shape().Rank();
err_msg +=
(rank < 2 || rank > 3) ? "image shape is not <H,W,C> or <H,W>, but got rank: " + std::to_string(rank) + "\t" : "";
err_msg += (crop_het_ <= 0 || crop_wid_ <= 0)
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Initialize error message string
std::string err_msg;
// Set the error message header
std::string err_head = "CenterCrop: ";
// Get the rank (number of dimensions) of the input tensor
dsize_t rank = input->shape().Rank();
// Check if the rank is not 2 or 3, and append an error message if true
err_msg += (rank < 2 || rank > 3) ? "image shape is not <H,W,C> or <H,W>, but got rank: " + std::to_string(rank) + "\t" : "";
// Check if the crop height or width is less than or equal to 0, and append an error message if true
err_msg += (crop_het_ <= 0 || crop_wid_ <= 0)
? "crop size needs to be positive integers, but got crop height:" + std::to_string(crop_het_) +
", crop width: " + std::to_string(crop_wid_) + "\t"
: "";
CHECK_FAIL_RETURN_SYNTAX_ERROR(err_msg.length() == 0, err_head + err_msg);
// Check if the length of the error message is equal to 0
// If it is not equal to 0, it means there is an error
CHECK_FAIL_RETURN_SYNTAX_ERROR(err_msg.length() == 0, err_head + err_msg);
int32_t top = crop_het_ - input->shape()[0]; // number of pixels to pad (top and bottom)
int32_t left = crop_wid_ - input->shape()[1];
std::shared_ptr<Tensor> pad_image;
// Calculate the number of pixels to pad at the top and bottom of the image
int32_t top = crop_het_ - input->shape()[0];
constexpr int64_t pad_limit = 3;
CHECK_FAIL_RETURN_UNEXPECTED((top < input->shape()[0] * pad_limit && left < input->shape()[1] * pad_limit),
"CenterCrop: CenterCropOp padding size is more than 3 times the original size, got pad"
" top: " +
std::to_string(top) + "pad left: " + std::to_string(left) + ", and original size: " +
std::to_string(input->shape()[0]) + ", " + std::to_string(input->shape()[1]));
// Calculate the number of pixels to pad at the left and right of the image
int32_t left = crop_wid_ - input->shape()[1];
if (top > 0 && left > 0) { // padding only
// Create a shared pointer to a Tensor object named pad_image
// Define a constant integer variable named "pad_limit" with a value of 3
constexpr int64_t pad_limit = 3;
// Check if the condition (top < input->shape()[0] * pad_limit && left < input->shape()[1] * pad_limit) is true
// If the condition is false, execute the following block of code
CHECK_FAIL_RETURN_UNEXPECTED(
(top < input->shape()[0] * pad_limit && left < input->shape()[1] * pad_limit),
"CenterCrop: CenterCropOp padding size is more than 3 times the original size, got pad top: " +
std::to_string(top) + "pad left: " + std::to_string(left) + ", and original size: " +
std::to_string(input->shape()[0]) + ", " + std::to_string(input->shape()[1]));
// The above code checks if the padding size (top and left) is more than 3 times the original size of the input.
// If the condition is true, it throws an error message with the values of top, left, and the original size of the input.
// Check if both top and left padding are greater than 0
if (top > 0 && left > 0) {
// If true, apply padding to the input image using the Pad function
// The padding values are calculated based on the top and left values
// The BorderType is set to kConstant, indicating that the padding should be filled with a constant value
return Pad(input, output, top / 2 + top % 2, top / 2, left / 2 + left % 2, left / 2, BorderType::kConstant);
} else if (top > 0) {
}
// Check if only top padding is greater than 0
else if (top > 0) {
// If true, apply padding to the input image using the Pad function
// The padding values for the top are calculated based on the top value
// The BorderType is set to kConstant, indicating that the padding should be filled with a constant value
RETURN_IF_NOT_OK(Pad(input, &pad_image, top / 2 + top % 2, top / 2, 0, 0, BorderType::kConstant));
// Crop the padded image using the Crop function
// The crop values are calculated based on the crop_wid_ and crop_het_ values
return Crop(pad_image, output, (static_cast<int32_t>(pad_image->shape()[1]) - crop_wid_) / 2,
(static_cast<int32_t>(pad_image->shape()[0]) - crop_het_) / 2, crop_wid_, crop_het_);
} else if (left > 0) {
}
// Check if only left padding is greater than 0
else if (left > 0) {
// If true, apply padding to the input image using the Pad function
// The padding values for the left are calculated based on the left value
// The BorderType is set to kConstant, indicating that the padding should be filled with a constant value
RETURN_IF_NOT_OK(Pad(input, &pad_image, 0, 0, left / 2 + left % 2, left / 2, BorderType::kConstant));
// Crop the padded image using the Crop function
// The crop values are calculated based on the crop_wid_ and crop_het_ values
return Crop(pad_image, output, (static_cast<int32_t>(pad_image->shape()[1]) - crop_wid_) / 2,
(static_cast<int32_t>(pad_image->shape()[0]) - crop_het_) / 2, crop_wid_, crop_het_);
}
return Crop(input, output, (input->shape()[1] - crop_wid_) / 2, (input->shape()[0] - crop_het_) / 2, crop_wid_,
crop_het_);
}
// If none of the above conditions are met, perform cropping on the input image using the Crop function
// The crop values are calculated based on the crop_wid_ and crop_het_ values
return Crop(input, output, (input->shape()[1] - crop_wid_) / 2, (input->shape()[0] - crop_het_) / 2, crop_wid_,
crop_het_);
// Implementation of the Print function for the CenterCropOp class
void CenterCropOp::Print(std::ostream &out) const {
// Print the name of the operation and the values of cropWidth and cropHeight
out << "CenterCropOp: "
<< "cropWidth: " << crop_wid_ << "cropHeight: " << crop_het_ << "\n";
}
// Implementation of the OutputShape function for the CenterCropOp class
Status CenterCropOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Call the OutputShape function of the base class TensorOp and check for any errors
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector
outputs.clear();
// Create a new TensorShape object with dimensions crop_het_ and crop_wid_
TensorShape out = TensorShape{crop_het_, crop_wid_};
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();
// Check the rank of the input tensor
if (inputs[0].Rank() == 2)
// If the rank is 2, append the new TensorShape object to the outputs vector
outputs.emplace_back(out);
if (inputs[0].Rank() == 3)
// If the rank is 3, append the new TensorShape object with an additional dimension to the outputs vector
outputs.emplace_back(out.AppendDim(inputs[0][2]));
// Check if the outputs vector is not empty
if (!outputs.empty())
// If not empty, return OK status
return Status::OK();
// If the outputs vector is empty, return an error status with a descriptive message
return Status(StatusCode::kMDUnexpectedError,
"CenterCrop: invalid input shape, expected 2D or 3D input, but got input dimension is:" +
std::to_string(inputs[0].Rank()));
}
// End of the namespace dataset
} // namespace dataset
} // namespace mindspore
// End of the namespace mindspore
} // namespace mindspore

View File

@ -14,22 +14,57 @@
* limitations under the License.
*/
// Include the string header for string manipulation
#include <string>
// Include the utility header for utility functions
#include <utility>
// Include the cv_tensor header from the minddata/dataset/core directory
#include "minddata/dataset/core/cv_tensor.h"
// Include the image_utils header from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the convert_color_op header from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/convert_color_op.h"
// Include the data_utils header from the minddata/dataset/kernels/data directory
#include "minddata/dataset/kernels/data/data_utils.h"
// Include the random header from the minddata/dataset/util directory
#include "minddata/dataset/util/random.h"
// Include the status header from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace
namespace dataset {
// Definition of the ConvertColorOp constructor, which takes a convert_mode parameter
ConvertColorOp::ConvertColorOp(ConvertMode convert_mode) : convert_mode_(convert_mode) {}
// End of the "dataset" namespace
} // namespace dataset
// End of the "mindspore" namespace
} // namespace mindspore
// The Compute function of the ConvertColorOp class
Status ConvertColorOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Call the ConvertColor function to convert the color of the input tensor and store the result in the output tensor
return ConvertColor(input, output, convert_mode_);
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -15,44 +15,88 @@
*/
#include "minddata/dataset/kernels/image/crop_op.h"
// Check if the ENABLE_ANDROID macro is defined
#ifndef ENABLE_ANDROID
// If ENABLE_ANDROID is not defined, include the image_utils.h header file from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// If ENABLE_ANDROID is defined, include the lite_image_utils.h header file from the minddata/dataset/kernels/image directory
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Include the status.h header file from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
Status CropOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
RETURN_IF_NOT_OK(ValidateImageRank("Crop", input->shape().Size()));
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: Crop height dimension: " + std::to_string(y_ + height_) +
" exceeds image height: " + std::to_string(input_h));
CHECK_FAIL_RETURN_UNEXPECTED(x_ + width_ <= input_w, "Crop: Crop width dimension: " + std::to_string(x_ + width_) +
" exceeds image width: " + std::to_string(input_w));
return Crop(input, output, x_, y_, width_, height_);
}
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// The Compute function of the CropOp class, which performs the actual cropping operation on the input tensor
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Validate the rank of the input tensor to ensure it is an image
RETURN_IF_NOT_OK(ValidateImageRank("Crop", input->shape().Size()));
// Get the height and width of the input tensor
int32_t input_h = static_cast<int>(input->shape()[0]);
int32_t input_w = static_cast<int>(input->shape()[1]);
// Check if the crop region specified by y_, height_, x_, and width_ is within the bounds of the input tensor
CHECK_FAIL_RETURN_UNEXPECTED(y_ + height_ <= input_h, "Crop: Crop height dimension: " + std::to_string(y_ + height_) +
" exceeds image height: " + std::to_string(input_h));
CHECK_FAIL_RETURN_UNEXPECTED(x_ + width_ <= input_w, "Crop: Crop width dimension: " + std::to_string(x_ + width_) +
" exceeds image width: " + std::to_string(input_w));
// Perform the cropping operation on the input tensor and store the result in the output tensor
return Crop(input, output, x_, y_, width_, height_);
// Function to determine the output shape of the CropOp operation
Status CropOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Call the OutputShape function of the base class TensorOp and check for any errors
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector
outputs.clear();
// Create a TensorShape object with the specified height and width
TensorShape out = TensorShape{height_, width_};
// Check if the input tensor has a rank of 2
if (inputs[0].Rank() == 2) {
// Append the out TensorShape object to the outputs vector
(void)outputs.emplace_back(out);
}
// Check if the input tensor has a rank of 3
if (inputs[0].Rank() == 3) {
// Append the out TensorShape object with an additional dimension (third dimension) to the outputs vector
(void)outputs.emplace_back(out.AppendDim(inputs[0][2]));
}
// Check if the outputs vector is not empty
if (!outputs.empty()) {
// Return OK status to indicate successful determination of output shape
return Status::OK();
}
// Return an error status with a message indicating the invalid input shape
return Status(StatusCode::kMDUnexpectedError,
"Crop: invalid input shape, expected 2D or 3D input, but got input dimension is:" +
std::to_string(inputs[0].Rank()));
}
} // namespace dataset
} // namespace mindspore
// End of namespace dataset
} // namespace mindspore

View File

@ -1,54 +1,89 @@
/**
* Copyright 2019 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
// 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
// This is a comment that provides a URL to the Apache License 2.0
// The Apache License 2.0 is a permissive open-source license that allows users to freely use, modify, and distribute the licensed software
// More information about the Apache License 2.0 can be found at the provided URL: http://www.apache.org/licenses/LICENSE-2.0
// This is a comment block that provides information about the license under which the software is distributed
/*
* 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 the header file for the cut_out_op class from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/cut_out_op.h"
// Include the random header, which provides facilities for generating random numbers
#include <random>
// Include the header file for cv_tensor from the minddata/dataset/core directory
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for image_utils from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for random from the minddata/dataset/util directory
#include "minddata/dataset/util/random.h"
// Include the header file for status from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
// The code is defining constants for the CutOutOp class in the mindspore::dataset namespace
// Define a constant boolean variable kDefRandomColor with a default value of false
const bool CutOutOp::kDefRandomColor = false;
// Define a constant unsigned 8-bit integer variable kDefFillR with a default value of 0
const uint8_t CutOutOp::kDefFillR = 0;
// Define a constant unsigned 8-bit integer variable kDefFillG with a default value of 0
const uint8_t CutOutOp::kDefFillG = 0;
// Define a constant unsigned 8-bit integer variable kDefFillB with a default value of 0
const uint8_t CutOutOp::kDefFillB = 0;
// constructor
// Constructor for the CutOutOp class
CutOutOp::CutOutOp(int32_t box_height, int32_t box_width, int32_t num_patches, bool random_color, uint8_t fill_r,
uint8_t fill_g, uint8_t fill_b)
: rnd_(GetSeed()),
box_height_(box_height),
box_width_(box_width),
num_patches_(num_patches),
random_color_(random_color),
fill_r_(fill_r),
fill_g_(fill_g),
fill_b_(fill_b) {}
: rnd_(GetSeed()), // Initialize the random number generator with a seed obtained from GetSeed() function
box_height_(box_height), // Initialize the box_height_ member variable with the provided box_height parameter
box_width_(box_width), // Initialize the box_width_ member variable with the provided box_width parameter
num_patches_(num_patches), // Initialize the num_patches_ member variable with the provided num_patches parameter
random_color_(random_color), // Initialize the random_color_ member variable with the provided random_color parameter
fill_r_(fill_r), // Initialize the fill_r_ member variable with the provided fill_r parameter
fill_g_(fill_g), // Initialize the fill_g_ member variable with the provided fill_g parameter
fill_b_(fill_b) {} // Initialize the fill_b_ member variable with the provided fill_b parameter
// main function call for cut out
Status CutOutOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
std::shared_ptr<CVTensor> inputCV = CVTensor::AsCVTensor(input);
// cut out will clip the erasing area if the box is near the edge of the image and the boxes are black
RETURN_IF_NOT_OK(Erase(inputCV, output, box_height_, box_width_, num_patches_, false, random_color_, &rnd_, fill_r_,
fill_g_, fill_b_));
return Status::OK();
}
// The Compute function of the CutOutOp class is called to perform the cut out operation on the input tensor.
// It takes in a shared pointer to the input tensor and a pointer to the output tensor.
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Convert the input tensor to a CVTensor (OpenCV tensor) for easier manipulation
std::shared_ptr<CVTensor> inputCV = CVTensor::AsCVTensor(input);
// Call the Erase function to perform the cut out operation on the input tensor
// The function will clip the erasing area if the box is near the edge of the image and the boxes are black
// The function also takes in other parameters such as box height, box width, number of patches, random color, etc.
// The function returns a status indicating the success or failure of the operation
RETURN_IF_NOT_OK(Erase(inputCV, output, box_height_, box_width_, num_patches_, false, random_color_, &rnd_, fill_r_,
fill_g_, fill_b_));
// Return a status indicating successful program termination
return Status::OK();
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -14,72 +14,139 @@
* limitations under the License.
*/
// Include the header file "cutmix_batch_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/cutmix_batch_op.h"
// Include the header for numeric limits (provides information about the limits of numeric types)
#include <limits>
// Include the header for string manipulation
#include <string>
// Include the header for utility functions (provides various utility functions)
#include <utility>
// Include the header file for cv_tensor from the minddata/dataset/core directory
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for data_utils from the minddata/dataset/kernels/data directory
#include "minddata/dataset/kernels/data/data_utils.h"
// Include the header file for image_utils from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for random from the minddata/dataset/util directory
#include "minddata/dataset/util/random.h"
// Include the header file for status from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Define a constant variable `kMinLabelShapeSize` with a value of 2
constexpr size_t kMinLabelShapeSize = 2;
// Define a constant variable `kMaxLabelShapeSize` with a value of 3
constexpr size_t kMaxLabelShapeSize = 3;
// Define a constant variable `kExpectedImageShapeSize` with a value of 4
constexpr size_t kExpectedImageShapeSize = 4;
// Define a constant variable `kDimensionOne` with a value of 1
constexpr size_t kDimensionOne = 1;
// Define a constant variable `kDimensionTwo` with a value of 2
constexpr size_t kDimensionTwo = 2;
// Define a constant variable `kDimensionThree` with a value of 3
constexpr size_t kDimensionThree = 3;
// Define a constant variable `kValueOne` with a value of 1
constexpr int64_t kValueOne = 1;
// Define a constant variable `kValueThree` with a value of 3
constexpr int64_t kValueThree = 3;
// Constructor for the CutMixBatchOp class
CutMixBatchOp::CutMixBatchOp(ImageBatchFormat image_batch_format, float alpha, float prob)
: image_batch_format_(image_batch_format), alpha_(alpha), prob_(prob) {
// Initialize the random number generator with a seed obtained from GetSeed()
rnd_.seed(GetSeed());
}
// This function calculates the crop box coordinates and dimensions for the CutMix augmentation technique
void CutMixBatchOp::GetCropBox(int height, int width, float lam, int *x, int *y, int *crop_width, int *crop_height) {
// Calculate the ratio of the area to be cut from the original image
const float cut_ratio = 1 - lam;
// Calculate the width and height of the cut area
int cut_w = static_cast<int>(width * cut_ratio);
int cut_h = static_cast<int>(height * cut_ratio);
// Create uniform distributions for generating random coordinates within the image
std::uniform_int_distribution<int> width_uniform_distribution(0, width);
std::uniform_int_distribution<int> height_uniform_distribution(0, height);
// Generate random coordinates for the center of the crop box
int cx = width_uniform_distribution(rnd_);
int x2, y2;
int cy = height_uniform_distribution(rnd_);
// Calculate the coordinates of the top-left corner of the crop box
constexpr int cut_half = 2;
*x = std::clamp(cx - cut_w / cut_half, 0, width - 1); // horizontal coordinate of left side of crop box
*y = std::clamp(cy - cut_h / cut_half, 0, height - 1); // vertical coordinate of the top side of crop box
// Calculate the coordinates of the bottom-right corner of the crop box
x2 = std::clamp(cx + cut_w / cut_half, 0, width - 1); // horizontal coordinate of right side of crop box
y2 = std::clamp(cy + cut_h / cut_half, 0, height - 1); // vertical coordinate of the bottom side of crop box
// Calculate the width and height of the crop box
*crop_width = std::clamp(x2 - *x, 1, width - 1);
*crop_height = std::clamp(y2 - *y, 1, height - 1);
}
Status CutMixBatchOp::ValidateCutMixBatch(const TensorRow &input) {
// Validate the input by checking if the size of the input is less than the minimum required size
if (input.size() < kMinLabelShapeSize) {
// If the input size is less than the minimum required size, return an error message
RETURN_STATUS_UNEXPECTED(
"CutMixBatch: invalid input, size of input should be 2 (including image and label), but got: " +
std::to_string(input.size()));
}
// Get the shape of the image tensor from the input
std::vector<int64_t> image_shape = input.at(0)->shape().AsVector();
// Get the shape of the label tensor from the input
std::vector<int64_t> label_shape = input.at(1)->shape().AsVector();
// Check inputs
// Check if the shape of the input image is valid
if (image_shape.size() != kExpectedImageShapeSize || image_shape[0] != label_shape[0]) {
RETURN_STATUS_UNEXPECTED(
"CutMixBatch: please make sure images are <H,W,C> or <C,H,W> format, and batched before calling CutMixBatch.");
}
// Check if the type of the labels is valid
if (!input.at(1)->type().IsInt()) {
RETURN_STATUS_UNEXPECTED(
"CutMixBatch: Wrong labels type. The second column (labels) must only include int types, but got:" +
input.at(1)->type().ToString());
}
// Check if the shape of the labels is valid
if (label_shape.size() != kMinLabelShapeSize && label_shape.size() != kMaxLabelShapeSize) {
RETURN_STATUS_UNEXPECTED(
"CutMixBatch: wrong labels shape. "
@ -88,127 +155,220 @@ Status CutMixBatchOp::ValidateCutMixBatch(const TensorRow &input) {
"labels must be in one-hot format and in a batch, but got rank: " +
std::to_string(label_shape.size()));
}
// Create a string to store the shape information of the image
std::string shape_info = "(";
// Iterate over the dimensions of the image shape and append them to the shape_info string
for (auto i : image_shape) {
shape_info = shape_info + std::to_string(i) + ", ";
}
// Replace the last comma with a closing parenthesis
shape_info.replace(shape_info.end() - 1, shape_info.end(), ")");
// Check if the image shape matches the expected format for NCHW
if ((image_shape[kDimensionOne] != kValueOne && image_shape[kDimensionOne] != kValueThree) &&
image_batch_format_ == ImageBatchFormat::kNCHW) {
RETURN_STATUS_UNEXPECTED("CutMixBatch: image doesn't match the <N,C,H,W> format, got shape: " + shape_info);
}
// Check if the image shape matches the expected format for NHWC
if ((image_shape[kDimensionThree] != kValueOne && image_shape[kDimensionThree] != kValueThree) &&
image_batch_format_ == ImageBatchFormat::kNHWC) {
RETURN_STATUS_UNEXPECTED("CutMixBatch: image doesn't match the <N,H,W,C> format, got shape: " + shape_info);
}
return Status::OK();
}
// Return the OK status from the Status class
return Status::OK();
Status CutMixBatchOp::ComputeImage(const TensorRow &input, const int64_t rand_indx_i, const float lam, float *label_lam,
std::shared_ptr<Tensor> *image_i) {
std::vector<int64_t> image_shape = input.at(0)->shape().AsVector();
int x, y, crop_width, crop_height;
// Get a random image
TensorShape remaining({-1});
uchar *start_addr_of_index = nullptr;
std::shared_ptr<Tensor> rand_image;
// ComputeImage function implementation for CutMixBatchOp class
RETURN_IF_NOT_OK(input.at(0)->StartAddrOfIndex({rand_indx_i, 0, 0, 0}, &start_addr_of_index, &remaining));
RETURN_IF_NOT_OK(Tensor::CreateFromMemory(
// Retrieve the shape of the input image tensor
std::vector<int64_t> image_shape = input.at(0)->shape().AsVector();
// Declare variables for x, y, crop_width, and crop_height
int x, y, crop_width, crop_height;
// Declare a TensorShape object for the remaining dimensions
TensorShape remaining({-1});
// Declare a pointer to store the starting address of the random index
uchar *start_addr_of_index = nullptr;
// Declare a shared pointer to store the random image tensor
std::shared_ptr<Tensor> rand_image;
// Call the function `StartAddrOfIndex` on the first element of the `input` vector, passing in the index {rand_indx_i, 0, 0, 0}.
// If the function returns an error code, immediately return that error code.
RETURN_IF_NOT_OK(input.at(0)->StartAddrOfIndex({rand_indx_i, 0, 0, 0}, &start_addr_of_index, &remaining));
// Create a new `Tensor` object called `rand_image` by calling the `CreateFromMemory` function.
// Pass in the following arguments:
// - A `TensorShape` object with dimensions {image_shape[kDimensionOne], image_shape[kDimensionTwo], image_shape[kDimensionThree]}
// - The data type of the first element of the `input` vector
// - The `start_addr_of_index` value obtained from the previous function call
// If the function returns an error code, immediately return that error code.
RETURN_IF_NOT_OK(Tensor::CreateFromMemory(
TensorShape({image_shape[kDimensionOne], image_shape[kDimensionTwo], image_shape[kDimensionThree]}),
input.at(0)->type(), start_addr_of_index, &rand_image));
// Compute image
if (image_batch_format_ == ImageBatchFormat::kNHWC) {
// Compute image
if (image_batch_format_ == ImageBatchFormat::kNHWC) {
// NHWC Format
// Get the crop box coordinates and dimensions based on the image shape and lambda value
GetCropBox(static_cast<int32_t>(image_shape[kDimensionOne]), static_cast<int32_t>(image_shape[kDimensionTwo]), lam,
&x, &y, &crop_width, &crop_height);
// Create a shared pointer to store the cropped image tensor
std::shared_ptr<Tensor> cropped;
// Crop the random image using the computed crop box coordinates and dimensions
RETURN_IF_NOT_OK(Crop(rand_image, &cropped, x, y, crop_width, crop_height));
// Mask the cropped image with the original image at the specified crop box coordinates and dimensions
RETURN_IF_NOT_OK(MaskWithTensor(cropped, image_i, x, y, crop_width, crop_height, ImageFormat::HWC));
// Calculate the label lambda value based on the cropped image dimensions and the original image dimensions
*label_lam = kValueOne - (crop_width * crop_height /
static_cast<float>(image_shape[kDimensionOne] * image_shape[kDimensionTwo]));
} else {
} else {
// NCHW Format
// Get the crop box coordinates and dimensions based on the image shape and lambda value
GetCropBox(static_cast<int32_t>(image_shape[kDimensionTwo]), static_cast<int32_t>(image_shape[kDimensionThree]),
lam, &x, &y, &crop_width, &crop_height);
// Create vectors to store the channels of the CHW image and the cropped channels
std::vector<std::shared_ptr<Tensor>> channels; // A vector holding channels of the CHW image
std::vector<std::shared_ptr<Tensor>> cropped_channels; // A vector holding the channels of the cropped CHW
// Convert the batch tensor to a vector of individual tensors representing each channel
RETURN_IF_NOT_OK(BatchTensorToTensorVector(rand_image, &channels));
// Iterate over each channel and crop it individually
for (auto channel : channels) {
// Call crop for each single channel
std::shared_ptr<Tensor> cropped_channel;
RETURN_IF_NOT_OK(Crop(channel, &cropped_channel, x, y, crop_width, crop_height));
cropped_channels.push_back(cropped_channel);
// Call crop for each single channel
std::shared_ptr<Tensor> cropped_channel;
RETURN_IF_NOT_OK(Crop(channel, &cropped_channel, x, y, crop_width, crop_height));
cropped_channels.push_back(cropped_channel);
}
// Create a shared pointer to store the merged channels as a single tensor
std::shared_ptr<Tensor> cropped;
// Merge channels to a single tensor
// Merge the cropped channels into a single tensor
RETURN_IF_NOT_OK(TensorVectorToBatchTensor(cropped_channels, &cropped));
// Call the function MaskWithTensor with the arguments cropped, image_i, x, y, crop_width, crop_height, and ImageFormat::CHW.
// The function is expected to return an error code, and if it is not OK, the program will return from this point.
RETURN_IF_NOT_OK(MaskWithTensor(cropped, image_i, x, y, crop_width, crop_height, ImageFormat::CHW));
*label_lam = kValueOne - (crop_width * crop_height /
static_cast<float>(image_shape[kDimensionTwo] * image_shape[kDimensionThree]));
// Calculate the value of *label_lam using the formula kValueOne - (crop_width * crop_height / static_cast<float>(image_shape[kDimensionTwo] * image_shape[kDimensionThree])).
// The result will be assigned to *label_lam.
*label_lam = kValueOne - (crop_width * crop_height / static_cast<float>(image_shape[kDimensionTwo] * image_shape[kDimensionThree]));
}
return Status::OK();
}
// Return the OK status from the Status class
return Status::OK();
Status CutMixBatchOp::ComputeLabel(const TensorRow &input, const int64_t rand_indx_i, const int64_t index_i,
const int64_t row_labels, const int64_t num_classes,
const std::size_t label_shape_size, const float label_lam,
std::shared_ptr<Tensor> *out_labels) {
// Compute labels
for (int64_t j = 0; j < row_labels; j++) {
// Compute labels for CutMix augmentation
// Iterate over each row of labels
for (int64_t j = 0; j < row_labels; j++) {
// Iterate over each class
for (int64_t k = 0; k < num_classes; k++) {
std::vector<int64_t> first_index =
label_shape_size == kMaxLabelShapeSize ? std::vector{index_i, j, k} : std::vector{index_i, k};
std::vector<int64_t> second_index =
label_shape_size == kMaxLabelShapeSize ? std::vector{rand_indx_i, j, k} : std::vector{rand_indx_i, k};
if (input.at(1)->type().IsSignedInt()) {
int64_t first_value, second_value;
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&first_value, first_index));
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&second_value, second_index));
RETURN_IF_NOT_OK(
(*out_labels)->SetItemAt(first_index, label_lam * first_value + (1 - label_lam) * second_value));
} else {
uint64_t first_value, second_value;
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&first_value, first_index));
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&second_value, second_index));
RETURN_IF_NOT_OK(
(*out_labels)->SetItemAt(first_index, label_lam * first_value + (1 - label_lam) * second_value));
}
}
}
// Create the first and second index vectors based on the label shape size
std::vector<int64_t> first_index =
label_shape_size == kMaxLabelShapeSize ? std::vector{index_i, j, k} : std::vector{index_i, k};
std::vector<int64_t> second_index =
label_shape_size == kMaxLabelShapeSize ? std::vector{rand_indx_i, j, k} : std::vector{rand_indx_i, k};
return Status::OK();
// Check if the input tensor type is signed integer
if (input.at(1)->type().IsSignedInt()) {
int64_t first_value, second_value;
// Get the values at the first and second indices from the input tensor
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&first_value, first_index));
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&second_value, second_index));
// Compute the label using label_lam and set it at the first index in the output tensor
RETURN_IF_NOT_OK(
(*out_labels)->SetItemAt(first_index, label_lam * first_value + (1 - label_lam) * second_value));
} else {
uint64_t first_value, second_value;
// Get the values at the first and second indices from the input tensor
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&first_value, first_index));
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&second_value, second_index));
// Compute the label using label_lam and set it at the first index in the output tensor
RETURN_IF_NOT_OK(
(*out_labels)->SetItemAt(first_index, label_lam * first_value + (1 - label_lam) * second_value));
}
}
}
Status CutMixBatchOp::Compute(const TensorRow &input, TensorRow *output) {
IO_CHECK_VECTOR(input, output);
RETURN_IF_NOT_OK(ValidateCutMixBatch(input));
std::vector<int64_t> image_shape = input.at(0)->shape().AsVector();
std::vector<int64_t> label_shape = input.at(1)->shape().AsVector();
// Return the OK status from the Status class
return Status::OK();
// Move images into a vector of Tensors
std::vector<std::shared_ptr<Tensor>> images;
RETURN_IF_NOT_OK(BatchTensorToTensorVector(input.at(0), &images));
// Check if the input and output are valid vectors
IO_CHECK_VECTOR(input, output);
// Calculate random labels
std::vector<int64_t> rand_indx;
CHECK_FAIL_RETURN_UNEXPECTED(
// Validate the CutMixBatch operation on the input
RETURN_IF_NOT_OK(ValidateCutMixBatch(input));
// Get the shape of the image tensor from the input
std::vector<int64_t> image_shape = input.at(0)->shape().AsVector();
// Get the shape of the label tensor from the input
std::vector<int64_t> label_shape = input.at(1)->shape().AsVector();
// Create a vector to store shared pointers to Tensor objects
std::vector<std::shared_ptr<Tensor>> images;
// Convert the input batch tensor to a vector of tensors and store them in the 'images' vector
RETURN_IF_NOT_OK(BatchTensorToTensorVector(input.at(0), &images));
// Create an empty vector to store random indices
std::vector<int64_t> rand_indx;
// Check if the size of "images" is within the range of int64_t
CHECK_FAIL_RETURN_UNEXPECTED(
images.size() <= static_cast<size_t>(std::numeric_limits<int64_t>::max()),
"The size of \"images\" must not be more than \"INT64_MAX\", but got: " + std::to_string(images.size()));
for (int64_t idx = 0; idx < static_cast<int64_t>(images.size()); idx++) rand_indx.push_back(idx);
std::shuffle(rand_indx.begin(), rand_indx.end(), rnd_);
std::gamma_distribution<float> gamma_distribution(alpha_, 1);
std::uniform_real_distribution<double> uniform_distribution(0.0, 1.0);
// Tensor holding the output labels
std::shared_ptr<Tensor> out_labels;
RETURN_IF_NOT_OK(TypeCast(std::move(input.at(1)), &out_labels, DataType(DataType::DE_FLOAT32)));
int64_t row_labels = label_shape.size() == kValueThree ? label_shape[kDimensionOne] : kValueOne;
int64_t num_classes = label_shape.size() == kValueThree ? label_shape[kDimensionTwo] : label_shape[kDimensionOne];
// Generate a sequence of indices from 0 to the size of "images" and add them to the vector
for (int64_t idx = 0; idx < static_cast<int64_t>(images.size()); idx++) {
rand_indx.push_back(idx);
}
// Shuffle the vector of indices using the random number generator "rnd_"
std::shuffle(rand_indx.begin(), rand_indx.end(), rnd_);
// Create a gamma distribution object with parameters alpha_ and 1
std::gamma_distribution<float> gamma_distribution(alpha_, 1);
// Create a uniform real distribution object with range [0.0, 1.0]
std::uniform_real_distribution<double> uniform_distribution(0.0, 1.0);
// Create a shared pointer to a Tensor object called "out_labels" to hold the output labels
std::shared_ptr<Tensor> out_labels;
// Use the TypeCast function to convert the input tensor at index 1 to a float32 data type and assign it to "out_labels"
// The TypeCast function returns an error code, so we use the RETURN_IF_NOT_OK macro to check if the conversion was successful
RETURN_IF_NOT_OK(TypeCast(std::move(input.at(1)), &out_labels, DataType(DataType::DE_FLOAT32)));
// Determine the number of rows in the label shape
// If the label shape has a size of 3, assign the value at index 1 to "row_labels"
// Otherwise, assign 1 to "row_labels"
int64_t row_labels = label_shape.size() == kValueThree ? label_shape[kDimensionOne] : kValueOne;
// Determine the number of classes in the label shape
// If the label shape has a size of 3, assign the value at index 2 to "num_classes"
// Otherwise, assign the value at index 1 to "num_classes"
int64_t num_classes = label_shape.size() == kValueThree ? label_shape[kDimensionTwo] : label_shape[kDimensionOne];
// Compute labels and images
for (size_t i = 0; i < static_cast<size_t>(image_shape[0]); i++) {
@ -217,34 +377,54 @@ Status CutMixBatchOp::Compute(const TensorRow &input, TensorRow *output) {
// then x = x1 / (x1+x2) is a random variable from Beta(a1, a2)
float x1 = gamma_distribution(rnd_);
float x2 = gamma_distribution(rnd_);
// Check if x1 and x2 are within the limits of float_t
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() - x1) > x2,
"CutMixBatchOp: gamma_distribution x1 and x2 are too large, got x1: " +
std::to_string(x1) + ", x2:" + std::to_string(x2));
// Calculate lambda
float lam = x1 / (x1 + x2);
// Generate a random number between 0 and 1
double random_number = uniform_distribution(rnd_);
// Check if the random number is less than the probability threshold
if (random_number < prob_) {
float label_lam; // lambda used for labels
// Compute image
RETURN_IF_NOT_OK(ComputeImage(input, rand_indx[i], lam, &label_lam, &images[i]));
// Compute labels
RETURN_IF_NOT_OK(ComputeLabel(input, rand_indx[i], static_cast<int64_t>(i), row_labels, num_classes,
label_shape.size(), label_lam, &out_labels));
}
}
std::shared_ptr<Tensor> out_images;
RETURN_IF_NOT_OK(TensorVectorToBatchTensor(images, &out_images));
// Declare a shared pointer named "out_images" of type "Tensor"
std::shared_ptr<Tensor> out_images;
// Call the function "TensorVectorToBatchTensor" with the "images" vector as input and assign the result to "out_images"
// The function may return an error code, so we use the macro "RETURN_IF_NOT_OK" to check if the function call was successful
RETURN_IF_NOT_OK(TensorVectorToBatchTensor(images, &out_images));
// Move the output into a TensorRow
output->push_back(out_images);
output->push_back(out_labels);
output->push_back(out_images); // Push the 'out_images' tensor into the 'output' TensorRow
output->push_back(out_labels); // Push the 'out_labels' tensor into the 'output' TensorRow
return Status::OK();
}
// Return the OK status from the Status class
return Status::OK();
// Definition of the Print function for the CutMixBatchOp class
void CutMixBatchOp::Print(std::ostream &out) const {
out << "CutMixBatchOp: "
<< "\n";
// Output the class name and a newline character
out << "CutMixBatchOp: " << "\n";
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -15,55 +15,114 @@
*/
#include "minddata/dataset/kernels/image/decode_op.h"
// Check if the ENABLE_ANDROID macro is defined
#ifndef ENABLE_ANDROID
// If ENABLE_ANDROID is not defined, include the image_utils.h header file from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// If ENABLE_ANDROID is defined, include the lite_image_utils.h header file from the minddata/dataset/kernels/image directory
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Include the status.h header file from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Define a constant boolean variable "kDefRgbFormat" with the value true
const bool DecodeOp::kDefRgbFormat = true;
// Constructor for the DecodeOp class, takes a boolean parameter 'rgb' to determine the color mode
DecodeOp::DecodeOp(bool rgb) : is_rgb_format_(rgb) {
if (is_rgb_format_) { // RGB colour mode
// Check if the color mode is RGB
if (is_rgb_format_) {
// If it is RGB, log a debug message indicating the color mode is RGB
MS_LOG(DEBUG) << "Decode colour mode is RGB.";
} else {
// If it is not RGB, log a debug message indicating the color mode is BGR
MS_LOG(DEBUG) << "Decode colour mode is BGR.";
}
}
// The Compute function of the DecodeOp class, responsible for performing the decoding operation
Status DecodeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// check the input tensor shape
// Check the shape of the input tensor
if (input->Rank() != 1) {
// If the input tensor is not 1D, return an error message
RETURN_STATUS_UNEXPECTED("Decode: invalid input shape, only support 1D input, got rank: " +
std::to_string(input->Rank()));
}
if (is_rgb_format_) { // RGB colour mode
// Check if the color mode is RGB
if (is_rgb_format_) {
// If the color mode is RGB, call the Decode function
return Decode(input, output);
} else { // BGR colour mode
} else {
// If the color mode is not RGB, return an error message
RETURN_STATUS_UNEXPECTED(
"Decode: only support Decoded into RGB image, check input parameter 'rgb' first, its value should be 'True'.");
}
}
// This function is used to determine the output shape of the DecodeOp operation.
// It takes in a vector of input tensor shapes and modifies a vector of output tensor shapes.
Status DecodeOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Call the OutputShape function of the base class TensorOp and check for any errors
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector to start fresh
outputs.clear();
TensorShape out({-1, -1, 3}); // we don't know what is output image size, but we know it should be 3 channels
// Create a new TensorShape object with dimensions {-1, -1, 3}
// This indicates that the output image size is unknown, but it will have 3 channels
TensorShape out({-1, -1, 3});
// Check if the rank of the first input tensor is 1
// If it is, add the output shape to the outputs vector
if (inputs[0].Rank() == 1) outputs.emplace_back(out);
// Check if the outputs vector is not empty
// If it is not empty, return OK status
if (!outputs.empty()) return Status::OK();
// If the outputs vector is empty, return an error status
// The error message includes the input shape dimension
return Status(
StatusCode::kMDUnexpectedError,
"Decode: invalid input shape, expected 1D input, but got input dimension is:" + std::to_string(inputs[0].Rank()));
}
// Define the function `OutputType` of the `DecodeOp` class
Status DecodeOp::OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) {
// Call the `OutputType` function of the base class `TensorOp` and check if it returns an error
RETURN_IF_NOT_OK(TensorOp::OutputType(inputs, outputs));
// Set the first element of the `outputs` vector to be of type `DE_UINT8`
outputs[0] = DataType(DataType::DE_UINT8);
// Return a status indicating successful execution of the function
return Status::OK();
}
// End of the `dataset` namespace
} // namespace dataset
} // namespace mindspore
// End of the `mindspore` namespace
} // namespace mindspore

View File

@ -16,14 +16,40 @@
#include "minddata/dataset/kernels/image/equalize_op.h"
#include "minddata/dataset/kernels/image/image_utils.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// only supports RGB images
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
#include <cstdio>
int main(){
std::cout << "Hello World" << std::endl;
return 0;
}
// This code does not have any functionality related to image processing or handling.
// It simply prints "Hello World" to the console and returns 0.
// The Compute function of the EqualizeOp class
Status EqualizeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Call the Equalize function to perform the equalization operation on the input tensor and store the result in the output tensor
return Equalize(input, output);
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -14,133 +14,289 @@
* limitations under the License.
*/
#include "minddata/dataset/kernels/image/exif_utils.h"
// Include the header file "minddata/dataset/kernels/image/exif_utils.h" which contains the necessary functions and definitions for working with EXIF data in image processing.
// Include the algorithm header for using various algorithms like sorting, searching, etc.
#include <algorithm>
// Include the cstdint header for using fixed-width integer types like int32_t, uint64_t, etc.
#include <cstdint>
// Define a constant named UNKNOW_ORIENTATION with a value of 0
#define UNKNOW_ORIENTATION 0
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code for the "mindspore::dataset" namespace goes here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// A template function that takes a pointer to an array of uint8_t (byte) values, along with a boolean flag indicating whether the bytes should be parsed in Intel alignment or not.
// The function returns a value of type T, which is the type specified by the template parameter.
template <typename T>
T parse_bytes(const uint8_t *buf, bool intel_align);
// This is a template specialization for the function `parse_bytes` for the type `uint8_t`
// It takes a pointer to a buffer `buf` and a boolean flag `intel_align` as parameters
// It returns the value pointed to by `buf`, which is of type `uint8_t`
template <>
uint8_t parse_bytes(const uint8_t *buf, bool intel_align) {
// Dereference the pointer `buf` and return the value
return *buf;
}
// Template specialization for parsing bytes as uint16_t
template <>
uint16_t parse_bytes(const uint8_t *buf, bool intel_align) {
// Check if the buffer is null
if (buf == nullptr) {
// If the buffer is null, return 0
return 0;
}
uint16_t res = 0;
if (intel_align) {
res = (static_cast<uint16_t>(buf[1]) << 8) | buf[0];
} else {
res = (static_cast<uint16_t>(buf[0]) << 8) | buf[1];
}
return res;
// If the buffer is not null, continue with the parsing
// (the rest of the code is not provided)
}
// Declare a variable named "res" of type uint16_t and initialize it to 0
uint16_t res = 0;
// Check if the "intel_align" variable is true
if (intel_align) {
// If true, assign the result of the bitwise OR operation between the left-shifted value of buf[1] by 8 bits and buf[0] to "res"
res = (static_cast<uint16_t>(buf[1]) << 8) | buf[0];
} else {
// If false, assign the result of the bitwise OR operation between the left-shifted value of buf[0] by 8 bits and buf[1] to "res"
res = (static_cast<uint16_t>(buf[0]) << 8) | buf[1];
}
// Return the value of "res"
return res;
// Template specialization for parsing bytes as uint32_t
template <>
uint32_t parse_bytes(const uint8_t *buf, bool intel_align) {
// Check if the buffer is null
if (buf == nullptr) {
return 0;
return 0; // Return 0 if the buffer is null
}
uint32_t res = 0;
if (intel_align) {
// Declare a variable 'res' of type uint32_t and initialize it to 0
uint32_t res = 0;
// Check if the 'intel_align' flag is true
if (intel_align) {
// If 'intel_align' is true, perform a bitwise OR operation on the elements of 'buf' to form a 32-bit value
// The elements are cast to uint32_t before shifting and ORing them together
res = (static_cast<uint32_t>(buf[3]) << 24) | (static_cast<uint32_t>(buf[2]) << 16) |
(static_cast<uint32_t>(buf[1]) << 8) | buf[0];
} else {
} else {
// If 'intel_align' is false, perform a bitwise OR operation on the elements of 'buf' in a different order
// The elements are cast to uint32_t before shifting and ORing them together
res = (static_cast<uint32_t>(buf[0]) << 24) | (static_cast<uint32_t>(buf[1]) << 16) |
(static_cast<uint32_t>(buf[2]) << 8) | buf[3];
}
return res;
}
// Return the resulting value 'res'
return res;
// Function to parse Exif data
int parseExif(const uint8_t *buf, uint32_t len) {
// Variable to store the alignment type of the Exif data
bool intel_align = true;
// Variable to store the offset of the Exif data
uint32_t offset = 0;
// Check if the buffer is null or the length is less than 6 bytes
if (!buf || len < 6) {
// Return a constant value indicating unknown orientation
return UNKNOW_ORIENTATION;
}
if (!std::equal(buf, buf + 6, "Exif\0\0")) {
// Check if the first 6 characters in the buffer 'buf' are equal to the string "Exif\0\0"
// If they are not equal, return the value UNKNOW_ORIENTATION
if (!std::equal(buf, buf + 6, "Exif\0\0")) {
return UNKNOW_ORIENTATION;
}
offset += 6;
}
// Increment the value of 'offset' by 6
offset += 6;
// Check if the offset plus 8 is greater than the length of the buffer
if (offset + 8 > len) {
// If it is, return the value UNKNOW_ORIENTATION
return UNKNOW_ORIENTATION;
}
// Check if the characters at the offset and offset + 1 positions in the buffer are 'I' and 'I' respectively
if (buf[offset] == 'I' && buf[offset + 1] == 'I') {
// If they are, set the variable intel_align to true
intel_align = true;
} else if (buf[offset] == 'M' && buf[offset + 1] == 'M') {
}
// If the above condition is not true, check if the characters at the offset and offset + 1 positions in the buffer are 'M' and 'M' respectively
else if (buf[offset] == 'M' && buf[offset + 1] == 'M') {
// If they are, set the variable intel_align to false
intel_align = false;
} else {
}
// If none of the above conditions are true, return the value UNKNOW_ORIENTATION
else {
return UNKNOW_ORIENTATION;
}
// Increase the offset by 2
offset += 2;
// Check if the value at the current offset in the buffer is not equal to 0x2a
if (parse_bytes<uint16_t>(buf + offset, intel_align) != 0x2a) {
return UNKNOW_ORIENTATION;
}
offset += 2;
uint32_t first_ifd_offset = parse_bytes<uint32_t>(buf + offset, intel_align);
offset += first_ifd_offset - 4;
if (offset >= len || offset + 2 > len) {
// If it is not equal, return UNKNOW_ORIENTATION
return UNKNOW_ORIENTATION;
}
int num_entries = parse_bytes<uint16_t>(buf + offset, intel_align);
if (offset + 6 + 12 * num_entries > len) {
// Increase the offset by 2
offset += 2;
// Parse the value at the current offset in the buffer as a uint32_t and assign it to first_ifd_offset
uint32_t first_ifd_offset = parse_bytes<uint32_t>(buf + offset, intel_align);
// Increase the offset by (first_ifd_offset - 4)
offset += first_ifd_offset - 4;
// Check if the offset is greater than or equal to len, or if offset + 2 is greater than len
if (offset >= len || offset + 2 > len) {
// If either condition is true, return UNKNOW_ORIENTATION
return UNKNOW_ORIENTATION;
}
offset += 2;
while (num_entries > 0) {
// Parse the number of entries from the buffer starting at the given offset, using the template function parse_bytes
int num_entries = parse_bytes<uint16_t>(buf + offset, intel_align);
// Check if the total length of the buffer is sufficient to contain all the entries
if (offset + 6 + 12 * num_entries > len) {
// If not, return an unknown orientation value
return UNKNOW_ORIENTATION;
}
// Increment the offset by 2 to skip the number of entries
offset += 2;
// Loop through each entry
while (num_entries > 0) {
// Parse the tag from the buffer at the current offset
uint16_t tag = parse_bytes<uint16_t>(buf + offset, intel_align);
// Check if the tag is equal to 0x112
if (tag == 0x112) {
uint16_t format = parse_bytes<uint16_t>(buf + offset + 2, intel_align);
uint32_t length = parse_bytes<uint32_t>(buf + offset + 4, intel_align);
if (format == 3 && length) {
uint16_t orient = parse_bytes<uint16_t>(buf + offset + 8, intel_align);
return static_cast<int>(orient);
}
// Parse the format, length, and orientation from the buffer at the appropriate offsets
uint16_t format = parse_bytes<uint16_t>(buf + offset + 2, intel_align);
uint32_t length = parse_bytes<uint32_t>(buf + offset + 4, intel_align);
// Check if the format is equal to 3 and the length is non-zero
if (format == 3 && length) {
// Parse the orientation from the buffer at the appropriate offset
uint16_t orient = parse_bytes<uint16_t>(buf + offset + 8, intel_align);
// Return the orientation as an integer
return static_cast<int>(orient);
}
}
// Increment the offset by 12 to skip to the next entry
offset += 12;
// Decrement the number of entries
num_entries--;
}
// If no valid orientation is found, return an unknown orientation value
return UNKNOW_ORIENTATION;
// Function to parse the orientation information from the given data
int ExifInfo::parseOrientation(const unsigned char *data, unsigned len) {
// Check if the data pointer is null or the length is less than 4
if (!data || len < 4)
return UNKNOW_ORIENTATION; // Return the unknown orientation value
// ... (rest of the code)
// Check if the first element of the data array is not equal to 0xFF or the second element is not equal to 0xD8
// If either condition is true, return UNKNOW_ORIENTATION
if (data[0] != 0xFF || data[1] != 0xD8) {
return UNKNOW_ORIENTATION;
}
// Loop while the length of the data is greater than 2
while (len > 2) {
// Check if the last two elements of the data array are equal to 0xD9 and 0xFF respectively
if (data[len - 1] == 0xD9 && data[len - 2] == 0xFF) {
// If the condition is true, break out of the loop
break;
}
// If the condition is false, decrement the length variable by 1
len--;
}
// Check if the length is less than or equal to 2
if (len <= 2) {
// If the condition is true, return the value UNKNOW_ORIENTATION
return UNKNOW_ORIENTATION;
}
// Initialize an unsigned integer variable named "offset" with a value of 0
unsigned int offset = 0;
// Start a for loop that continues until the value of "offset" is less than "len - 1"
for (; offset < len - 1; offset++) {
// Check if the value of "data[offset]" is equal to 0xFF and the value of "data[offset + 1]" is equal to 0xE1
if (data[offset] == 0xFF && data[offset + 1] == 0xE1) {
// If the condition is true, break out of the loop
break;
}
}
// Check if the value of "offset + 4" is greater than "len"
if (offset + 4 > len) {
// If the condition is true, return the value UNKNOW_ORIENTATION
return UNKNOW_ORIENTATION;
}
int ExifInfo::parseOrientation(const unsigned char *data, unsigned len) {
if (!data || len < 4) return UNKNOW_ORIENTATION;
// Increment the value of "offset" by 2
offset += 2;
if (data[0] != 0xFF || data[1] != 0xD8) return UNKNOW_ORIENTATION;
// Parse the next 2 bytes of data starting from the address "data + offset" as a uint16_t and store it in the variable "section_length"
uint16_t section_length = parse_bytes<uint16_t>(data + offset, false);
while (len > 2) {
if (data[len - 1] == 0xD9 && data[len - 2] == 0xFF) break;
len--;
}
if (len <= 2) return UNKNOW_ORIENTATION;
// Check if the value of "offset + section_length" is greater than "len" or if "section_length" is less than 16
if (offset + section_length > len || section_length < 16) {
unsigned int offset = 0;
for (; offset < len - 1; offset++) {
if (data[offset] == 0xFF && data[offset + 1] == 0xE1) break;
}
if (offset + 4 > len) return UNKNOW_ORIENTATION;
offset += 2;
uint16_t section_length = parse_bytes<uint16_t>(data + offset, false);
if (offset + section_length > len || section_length < 16) return UNKNOW_ORIENTATION;
offset += 2;
// If the condition is true, return the value UNKNOW_ORIENTATION
return UNKNOW_ORIENTATION;
}
// Increment the value of "offset" by 2
offset += 2;
// Return the result of calling the parseExif function with the arguments data + offset and len - offset
return parseExif(data + offset, len - offset);
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -15,19 +15,38 @@
*/
#include "minddata/dataset/kernels/image/gaussian_blur_op.h"
// Check if the ENABLE_ANDROID macro is defined
#ifndef ENABLE_ANDROID
// If ENABLE_ANDROID is not defined, include the image_utils.h header file from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// If ENABLE_ANDROID is defined, include the lite_image_utils.h header file from the minddata/dataset/kernels/image directory
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Include the status.h header file from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// The code is inside the "mindspore" namespace
namespace mindspore {
// The code is inside the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Implementation of the Compute function of the GaussianBlurOp class
Status GaussianBlurOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output pointers are valid
IO_CHECK(input, output);
// Validate the rank of the input tensor
RETURN_IF_NOT_OK(ValidateImageRank("GaussianBlur", input->Rank()));
// Call the GaussianBlur function with the specified parameters
return GaussianBlur(input, output, kernel_x_, kernel_y_, sigma_x_, sigma_y_);
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,15 +14,27 @@
* limitations under the License.
*/
// Include the header file "minddata/dataset/kernels/image/horizontal_flip_op.h"
#include "minddata/dataset/kernels/image/horizontal_flip_op.h"
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file "minddata/dataset/kernels/image/image_utils.h" which contains utility functions for image processing in the MindData library.
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Implementation of the Compute function for the HorizontalFlipOp class
Status HorizontalFlipOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output pointers are valid
IO_CHECK(input, output);
// Call the HorizontalFlip function to perform the horizontal flip operation on the input tensor
return HorizontalFlip(input, output);
}
} // namespace dataset
} // namespace mindspore
} // End of the "dataset" namespace
} // End of the "mindspore" namespace

View File

@ -15,36 +15,73 @@
*/
#include "minddata/dataset/kernels/image/hwc_to_chw_op.h"
// Check if the ENABLE_ANDROID macro is defined
#ifndef ENABLE_ANDROID
// If ENABLE_ANDROID is not defined, include the image_utils.h header file from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// If ENABLE_ANDROID is defined, include the lite_image_utils.h header file from the minddata/dataset/kernels/image directory
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Include the status.h header file from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
// Compute function for HwcToChwOp
Status HwcToChwOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if input and output are valid
IO_CHECK(input, output);
// input.shape == HWC
// output.shape == CHW
// input shape is HWC
// output shape is CHW
// Convert input tensor from HWC to CHW format
return HwcToChw(input, output);
}
// OutputShape function for HwcToChwOp
Status HwcToChwOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Call OutputShape function from base class TensorOp
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector
outputs.clear();
// Check if inputs vector has at least one element
CHECK_FAIL_RETURN_UNEXPECTED(inputs.size() > 0, "HwcToChwOp::OutputShape inputs size should > 0");
// Get the shape of the first input tensor
TensorShape in = inputs[0];
// Create the output shape by rearranging the dimensions of the input shape
TensorShape out = TensorShape{in[2], in[0], in[1]};
// If the input tensor has rank 3, add the output shape to the outputs vector
if (inputs[0].Rank() == 3) {
(void)outputs.emplace_back(out);
}
// If outputs vector is not empty, return OK status
if (!outputs.empty()) {
return Status::OK();
}
// Otherwise, return an error status
// (Note: this line is incomplete and should be completed in the actual code)
}
// Return a Status object with StatusCode::kMDUnexpectedError and an error message
// The error message is constructed by concatenating the string "HWC2CHW: invalid input shape, expected 3D input, but got input dimension is:"
// with the string representation of the rank of the first element in the inputs vector
return Status(
StatusCode::kMDUnexpectedError,
"HWC2CHW: invalid input shape, expected 3D input, but got input dimension is:" + std::to_string(inputs[0].Rank()));
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

File diff suppressed because it is too large Load Diff

View File

@ -18,43 +18,85 @@
#include "minddata/dataset/core/cv_tensor.h"
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// only supports RGB images
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
Status InvertOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
#include <cstdio>
int main(){
std::cout << "Hello World" << std::endl;
return 0;
}
// This code does not have any functionality related to image processing or handling.
// It simply prints "Hello World" to the console and returns 0.
// Compute function for the InvertOp class, which takes an input tensor and computes the output tensor
// The function returns a status indicating the success or failure of the computation
// Check if the input and output tensors are valid (non-null)
IO_CHECK(input, output);
try {
// Convert the input tensor to a CVTensor using the AsCVTensor function and store it in a shared_ptr
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input);
// Get the underlying cv::Mat object from the CVTensor
cv::Mat input_img = input_cv->mat();
// Check if the cv::Mat object contains valid data
if (!input_cv->mat().data) {
// If the cv::Mat object does not contain valid data, return an error message
RETURN_STATUS_UNEXPECTED("[Internal ERROR] Invert: load image failed.");
}
// Check if the rank of the input tensor is not equal to 3
if (input_cv->Rank() != 3) {
// If the rank is not 3, return an error message with the current rank
RETURN_STATUS_UNEXPECTED("Invert: image shape is not <H,W,C>, got rank: " + std::to_string(input_cv->Rank()));
}
// Get the number of channels from the shape of the input tensor
int num_channels = input_cv->shape()[2];
// Check if the number of channels is not equal to 3
if (num_channels != 3) {
// If the number of channels is not 3, return an error message with the current number of channels
RETURN_STATUS_UNEXPECTED(
"Invert: image shape is incorrect, expected num of channels is 3, "
"but got:" +
std::to_string(num_channels));
}
// Create an empty CVTensor with the same shape and type as the input tensor
std::shared_ptr<CVTensor> output_cv;
RETURN_IF_NOT_OK(CVTensor::CreateEmpty(input_cv->shape(), input_cv->type(), &output_cv));
// Check if the output CVTensor is null
RETURN_UNEXPECTED_IF_NULL(output_cv);
output_cv->mat() = cv::Scalar::all(255) - input_img;
*output = std::static_pointer_cast<Tensor>(output_cv);
}
// Assign the value of all elements in the output_cv matrix to 255 minus the corresponding element in the input_img matrix
output_cv->mat() = cv::Scalar::all(255) - input_img;
// Cast the output_cv matrix to a shared pointer of type Tensor and assign it to the output pointer
*output = std::static_pointer_cast<Tensor>(output_cv);
catch (const cv::Exception &e) {
// Catch any OpenCV exceptions that occur during the execution of the code
// Concatenate the error message from the exception with the string "Invert: " and return it as an error message
RETURN_STATUS_UNEXPECTED("Invert: " + std::string(e.what()));
}
// Return a status indicating successful execution of the code
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,216 +14,428 @@
* limitations under the License.
*/
// Include the math library header file for using mathematical functions and constants in the code
#include <cmath>
// Include the header file "lite_mat.h" from the "lite_cv" library
#include "lite_cv/lite_mat.h"
// Include the header file "image_process.h" from the "lite_cv" library
#include "lite_cv/image_process.h"
// Check if the ENABLE_ANDROID macro is defined
#ifdef ENABLE_ANDROID
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
#define USE_NEON
#include <arm_neon.h>
#endif
// Check if any of the ARM-related macros are defined
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
// Define the USE_NEON macro
#define USE_NEON
// Include the ARM NEON header file
#include <arm_neon.h>
// End of ARM-related macro check
#endif
// End of ENABLE_ANDROID macro check
#endif
// Define a constant variable `kAngle22_5` with a value of 0.39269908169872414
constexpr float kAngle22_5 = 0.39269908169872414;
// Define a constant variable `kAngle67_5` with a value of 1.1780972450961724
constexpr float kAngle67_5 = 1.1780972450961724;
// Define a constant variable `kCertainBorder` with a value of 2
constexpr int kCertainBorder = 2;
// Define a constant variable `kUncertainBorder` with a value of 1
constexpr int kUncertainBorder = 1;
// Define a constant variable `kNotBorder` with a value of 0
constexpr int kNotBorder = 0;
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace, a sub-namespace of "mindspore"
namespace dataset {
// Definition of the static function "GetSobelKernel"
static void GetSobelKernel(float *kernel, int flag, int ksize, double scale) {
// Create a vector of floats named "buffer" with size "ksize + 1"
std::vector<float> buffer(ksize + 1);
// Check if the kernel size is 1
if (ksize == 1) {
// If so, set the first element of the buffer to 1
buffer[0] = 1;
} else if (ksize == 3) {
}
// Check if the kernel size is 3
else if (ksize == 3) {
// Check the value of the flag
if (flag == 0) {
// If flag is 0, set the elements of the buffer to 1, 2, and 1 respectively
buffer[0] = 1, buffer[1] = 2, buffer[2] = 1;
} else if (flag == 1) {
// If flag is 1, set the elements of the buffer to -1, 0, and 1 respectively
buffer[0] = -1, buffer[1] = 0, buffer[2] = 1;
} else {
// If flag is neither 0 nor 1, set the elements of the buffer to 1, -2, and 1 respectively
buffer[0] = 1, buffer[1] = -2, buffer[2] = 1;
}
} else {
}
// If the kernel size is neither 1 nor 3
else {
// Declare variables to store the previous and current values
float old, now;
// Set the first element of the buffer to 1
buffer[0] = 1;
// Set the remaining elements of the buffer to 0
for (int i = 0; i < ksize; i++) {
buffer[i + 1] = 0;
}
// Perform calculations for ksize - flag - 1 iterations
for (int i = 0; i < ksize - flag - 1; i++) {
// Store the value of the first element in the buffer
old = buffer[0];
// Perform calculations for each element in the buffer
for (int j = 1; j <= ksize; j++) {
// Calculate the current value by adding the current element and the previous element
now = buffer[j] + buffer[j - 1];
// Update the previous element with the stored value
buffer[j - 1] = old;
// Update the stored value with the current value
old = now;
}
}
// Perform calculations for flag iterations
for (int i = 0; i < flag; i++) {
// Store the negative value of the first element in the buffer
old = -buffer[0];
// Perform calculations for each element in the buffer
for (int j = 1; j <= ksize; j++) {
// Calculate the current value by subtracting the current element from the previous element
now = buffer[j - 1] - buffer[j];
// Update the previous element with the stored value
buffer[j - 1] = old;
// Update the stored value with the current value
old = now;
}
}
}
scale = flag == 0 ? scale : 1.0;
for (int i = 0; i < ksize; i++) {
// Set the value of scale to either scale or 1.0 based on the condition flag == 0
// If flag is equal to 0, then scale remains unchanged, otherwise scale is set to 1.0
scale = flag == 0 ? scale : 1.0;
// Iterate over the elements of the kernel array from index 0 to ksize-1
for (int i = 0; i < ksize; i++) {
// Multiply the value of buffer[i] by the value of scale and assign the result to kernel[i]
kernel[i] = buffer[i] * scale;
}
}
// Function to apply Sobel filter on an input image
bool Sobel(const LiteMat &src, LiteMat &dst, int flag_x, int flag_y, int ksize, double scale, // NOLINT
PaddBorderType pad_type) {
// Check if the input image is empty or not of type UINT8
if (src.IsEmpty() || src.data_type_ != LDataType::UINT8) {
return false;
}
// Check if the flag values are within valid range
if (flag_x < 0 || flag_y < 0 || flag_x + flag_y <= 0 || flag_x >= ksize || flag_y >= ksize) {
return false;
}
// Rest of the code for applying the Sobel filter goes here...
}
// Check if the destination image is empty or if its width, height, channel, or data type is different from the source image
if (dst.IsEmpty() || dst.width_ != src.width_ || dst.height_ != src.height_ || dst.channel_ != src.channel_ ||
dst.data_type_ != LDataType::FLOAT32) {
// If any of the above conditions are true, initialize the destination image with the same width, height, channel, and data type as the source image
dst.Init(src.width_, src.height_, src.channel_, LDataType::FLOAT32);
}
LiteMat kx, ky;
kx.Init(ksize, 1, 1, LDataType::FLOAT32);
ky.Init(1, ksize, 1, LDataType::FLOAT32);
// Declare two instances of the LiteMat class named kx and ky
LiteMat kx, ky;
GetSobelKernel(kx, flag_x, ksize, scale);
GetSobelKernel(ky, flag_y, ksize, scale);
// Initialize the kx object with the specified parameters: ksize, 1, 1, and LDataType::FLOAT32
kx.Init(ksize, 1, 1, LDataType::FLOAT32);
return ConvRowCol(src, kx, ky, dst, LDataType::FLOAT32, pad_type);
}
// Initialize the ky object with the specified parameters: 1, ksize, 1, and LDataType::FLOAT32
ky.Init(1, ksize, 1, LDataType::FLOAT32);
// Call the function GetSobelKernel with the arguments kx, flag_x, ksize, and scale
GetSobelKernel(kx, flag_x, ksize, scale);
// Call the function GetSobelKernel with the arguments ky, flag_y, ksize, and scale
GetSobelKernel(ky, flag_y, ksize, scale);
// Return the result of calling the function ConvRowCol with the provided arguments:
// - src: the source image
// - kx: the kernel size in the x-direction
// - ky: the kernel size in the y-direction
// - dst: the destination image
// - LDataType::FLOAT32: the data type of the destination image (float32)
// - pad_type: the padding type used in the convolution operation
// A static function that returns the value of an element in a 2D grid represented by a 1D vector
// The function takes in the vector, the width and height of the grid, and the x and y coordinates of the element
static float GetEdge(const std::vector<float> &temp, int width, int height, int x, int y) {
// Check if the given coordinates are within the bounds of the grid
if (x >= 0 && y >= 0 && x < width && y < height) {
// If the coordinates are valid, calculate the index of the element in the 1D vector using the formula y * width + x
// and return the value at that index
return temp[y * width + x];
} else {
// If the coordinates are out of bounds, return -1.0f to indicate an invalid value
return -1.0f;
}
}
// A function to round a floating-point value to the nearest integer
static float Round(float value) {
// rounding if the result is even
// eg. 1.5 -> 2, 2.5 -> 2
// Calculate the rounded value using the round function from the math library
float rnd = round(value);
// Calculate the floor and ceiling values of the input
float rnd_l = floor(value);
float rnd_h = ceil(value);
// Check if the difference between the input and the floor value is exactly 0.5
if (value - rnd_l == 0.5) {
// If the rounded value is even, return the rounded value
if (fmod(rnd, 2) == 0) {
return rnd;
} else if (value > 0) {
}
// If the input is positive, return the floor value
else if (value > 0) {
return rnd_l;
} else {
}
// If the input is negative, return the ceiling value
else {
return rnd_h;
}
}
// If the difference is not exactly 0.5, return the rounded value
return rnd;
}
// A static function named NonMaximumSuppression is defined here
// It takes three parameters: gx, gy, and edges, all of type LiteMat
// The fourth parameter, L2gradient, is a boolean flag
static void NonMaximumSuppression(const LiteMat &gx, const LiteMat &gy, LiteMat &edges, bool L2gradient) { // NOLINT
// Initialize the edges LiteMat object with the same dimensions and data type as gx
edges.Init(gx.width_, gx.height_, gx.channel_, gx.data_type_);
const float *gx_ptr = gx;
const float *gy_ptr = gy;
float *edges_ptr = edges;
int size = gx.height_ * gx.width_;
std::vector<float> temp(size);
for (int i = 0; i < size; i++) {
float gx_value = Round(gx_ptr[i]);
float gy_value = Round(gy_ptr[i]);
if (L2gradient) {
temp[i] = sqrt(gx_value * gx_value + gy_value * gy_value);
} else {
temp[i] = abs(gx_value) + abs(gy_value);
}
}
for (int y = 0; y < gx.height_; y++) {
for (int x = 0; x < gx.width_; x++) {
float gx_value = Round(gx_ptr[y * gx.width_ + x]);
float gy_value = Round(gy_ptr[y * gx.width_ + x]);
float gx_value_abs = std::abs(gx_value);
float gy_value_abs = std::abs(gy_value);
float angle_value = atan2(gy_value_abs, gx_value_abs);
float edge_value = temp[y * gx.width_ + x];
float edge_pre, edge_nex;
if (angle_value < kAngle22_5 || angle_value > kAngle67_5) {
if (angle_value < kAngle22_5) {
edge_pre = GetEdge(temp, gx.width_, gx.height_, x - 1, y);
edge_nex = GetEdge(temp, gx.width_, gx.height_, x + 1, y);
} else {
edge_pre = GetEdge(temp, gx.width_, gx.height_, x, y - 1);
edge_nex = GetEdge(temp, gx.width_, gx.height_, x, y + 1);
}
if (edge_value > edge_pre && edge_value >= edge_nex) {
edges_ptr[y * gx.width_ + x] = temp[y * gx.width_ + x];
} else {
edges_ptr[y * gx.width_ + x] = 0.f;
}
} else {
if (gx_value * gy_value < 0) {
edge_pre = GetEdge(temp, gx.width_, gx.height_, x + 1, y - 1);
edge_nex = GetEdge(temp, gx.width_, gx.height_, x - 1, y + 1);
} else {
edge_pre = GetEdge(temp, gx.width_, gx.height_, x - 1, y - 1);
edge_nex = GetEdge(temp, gx.width_, gx.height_, x + 1, y + 1);
}
if (edge_value > edge_pre && edge_value > edge_nex) {
edges_ptr[y * gx.width_ + x] = temp[y * gx.width_ + x];
} else {
edges_ptr[y * gx.width_ + x] = 0.f;
}
}
}
}
}
static void Hysteresis(const LiteMat &edges, uint8_t *dst, double low_thresh, double high_thresh) {
const float *edges_ptr = edges;
// Create a constant pointer to a float variable named gx_ptr and initialize it with the address of gx
const float *gx_ptr = gx;
int size = edges.height_ * edges.width_;
std::vector<int> stack;
std::vector<int> buffer(size);
int buffer_step = edges.width_;
for (int y = 0; y < edges.height_; y++) {
for (int x = 0; x < edges.width_; x++) {
int pos = y * edges.width_ + x;
float edge_value = edges_ptr[pos];
if (edge_value > high_thresh) {
buffer[pos] = kCertainBorder;
stack.push_back(pos);
} else if (edge_value <= low_thresh) {
buffer[pos] = kNotBorder;
} else {
buffer[pos] = kUncertainBorder;
}
// Create a constant pointer to a float variable named gy_ptr and initialize it with the address of gy
const float *gy_ptr = gy;
// Create a pointer to a float variable named edges_ptr and initialize it with the address of edges
// Calculate the total number of elements in the grid by multiplying the height and width
int size = gx.height_ * gx.width_;
// Create a temporary vector of floats with size equal to the total number of elements
std::vector<float> temp(size);
// Iterate over each element in the grid
for (int i = 0; i < size; i++) {
// Round the values of gx and gy to the nearest integer
float gx_value = Round(gx_ptr[i]);
float gy_value = Round(gy_ptr[i]);
// Check if L2gradient flag is set
if (L2gradient) {
// Calculate the magnitude of the gradient using the Euclidean distance formula
temp[i] = sqrt(gx_value * gx_value + gy_value * gy_value);
} else {
// Calculate the magnitude of the gradient using the sum of absolute values
temp[i] = abs(gx_value) + abs(gy_value);
}
}
// Iterate over each row of the gx and gy matrices
for (int y = 0; y < gx.height_; y++) {
// Iterate over each column of the gx and gy matrices
for (int x = 0; x < gx.width_; x++) {
// Calculate the index of the current element in the gx and gy matrices
int index = y * gx.width_ + x;
// Round the gx and gy values at the current index
float gx_value = Round(gx_ptr[index]);
float gy_value = Round(gy_ptr[index]);
// Calculate the absolute values of gx_value and gy_value
float gx_value_abs = std::abs(gx_value);
float gy_value_abs = std::abs(gy_value);
// Calculate the angle value using atan2 function
float angle_value = atan2(gy_value_abs, gx_value_abs);
// Get the edge value at the current position
float edge_value = temp[y * gx.width_ + x];
// Declare variables for storing edge values of neighboring pixels
float edge_pre, edge_nex;
// Check the angle value to determine the direction of neighboring pixels
if (angle_value < kAngle22_5 || angle_value > kAngle67_5) {
// If the angle is less than kAngle22_5 or greater than kAngle67_5
if (angle_value < kAngle22_5) {
// If the angle is less than kAngle22_5, get the edge values of the left and right neighboring pixels
edge_pre = GetEdge(temp, gx.width_, gx.height_, x - 1, y);
edge_nex = GetEdge(temp, gx.width_, gx.height_, x + 1, y);
} else {
// If the angle is greater than kAngle67_5, get the edge values of the top and bottom neighboring pixels
edge_pre = GetEdge(temp, gx.width_, gx.height_, x, y - 1);
edge_nex = GetEdge(temp, gx.width_, gx.height_, x, y + 1);
}
// Compare the edge value with the neighboring edge values and update the edges_ptr accordingly
if (edge_value > edge_pre && edge_value >= edge_nex) {
edges_ptr[y * gx.width_ + x] = temp[y * gx.width_ + x];
} else {
edges_ptr[y * gx.width_ + x] = 0.f;
}
} else {
// If the angle is between kAngle22_5 and kAngle67_5
if (gx_value * gy_value < 0) {
// If the product of gx_value and gy_value is negative, get the edge values of the top-right and bottom-left neighboring pixels
edge_pre = GetEdge(temp, gx.width_, gx.height_, x + 1, y - 1);
edge_nex = GetEdge(temp, gx.width_, gx.height_, x - 1, y + 1);
} else {
// If the product of gx_value and gy_value is positive, get the edge values of the top-left and bottom-right neighboring pixels
edge_pre = GetEdge(temp, gx.width_, gx.height_, x - 1, y - 1);
edge_nex = GetEdge(temp, gx.width_, gx.height_, x + 1, y + 1);
}
// Compare the edge value with the neighboring edge values and update the edges_ptr accordingly
if (edge_value > edge_pre && edge_value > edge_nex) {
edges_ptr[y * gx.width_ + x] = temp[y * gx.width_ + x];
} else {
edges_ptr[y * gx.width_ + x] = 0.f;
}
}
}
}
}
// A static function named "Hysteresis" that takes in a LiteMat object called "edges", a pointer to a uint8_t called "dst",
// and two double values called "low_thresh" and "high_thresh"
static void Hysteresis(const LiteMat &edges, uint8_t *dst, double low_thresh, double high_thresh) {
// Create a constant pointer to a float called "edges_ptr" and initialize it with the data from the "edges" LiteMat object
const float *edges_ptr = edges;
}
// Calculate the total number of elements in the edges matrix
int size = edges.height_ * edges.width_;
// Create an empty stack to store positions of certain border pixels
std::vector<int> stack;
// Create a buffer vector with the same size as the edges matrix
std::vector<int> buffer(size);
// Calculate the step size for accessing elements in the buffer vector
int buffer_step = edges.width_;
// Iterate over each pixel in the edges matrix
for (int y = 0; y < edges.height_; y++) {
for (int x = 0; x < edges.width_; x++) {
// Calculate the position of the current pixel in the edges matrix
int pos = y * edges.width_ + x;
// Get the edge value of the current pixel
float edge_value = edges_ptr[pos];
// Check if the edge value is greater than the high threshold
if (edge_value > high_thresh) {
// Set the buffer value at the current position to indicate a certain border pixel
buffer[pos] = kCertainBorder;
// Add the current position to the stack
stack.push_back(pos);
}
// Check if the edge value is less than or equal to the low threshold
else if (edge_value <= low_thresh) {
// Set the buffer value at the current position to indicate a non-border pixel
buffer[pos] = kNotBorder;
}
// If the edge value is between the low and high thresholds
else {
// Set the buffer value at the current position to indicate an uncertain border pixel
buffer[pos] = kUncertainBorder;
}
}
}
// While the stack is not empty
while (!stack.empty()) {
// Get the last element from the stack
int pos = stack.back();
stack.pop_back();
// Calculate the y and x coordinates from the position
int y = static_cast<int>(pos / buffer_step);
int x = pos % buffer_step;
// Iterate over the neighboring cells
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
// Calculate the coordinates of the next cell
int next_y = y + i;
int next_x = x + j;
// Check if the next cell is out of bounds or the same as the current cell
if (next_y < 0 || next_x < 0 || next_y >= edges.height_ || next_x >= edges.width_ ||
(next_y == y && next_x == x)) {
// Continue to the next iteration of the inner loop
continue;
}
// Calculate the position of the next cell in the buffer
int next = next_y * buffer_step + next_x;
// Check if the next cell is an uncertain border
if (buffer[next] == kUncertainBorder) {
// Set the next cell as a certain border and add it to the stack
buffer[next] = kCertainBorder;
stack.push_back(next);
}
@ -231,44 +443,90 @@ static void Hysteresis(const LiteMat &edges, uint8_t *dst, double low_thresh, do
}
}
// Iterate over the elements of the buffer array
for (int i = 0; i < size; i++) {
// Check if the current element of the buffer array is equal to kCertainBorder
if (buffer[i] == kCertainBorder) {
// If the condition is true, set the corresponding element of the dst array to 255
dst[i] = 255;
} else {
// If the condition is false, set the corresponding element of the dst array to 0
dst[i] = 0;
}
}
}
bool Canny(const LiteMat &src, LiteMat &dst, double low_thresh, double high_thresh, int ksize, // NOLINT
bool L2gradient) {
// Function to apply Canny edge detection on an input image
bool Canny(const LiteMat &src, LiteMat &dst, double low_thresh, double high_thresh, int ksize, bool L2gradient) {
// Check if the input image is empty or not of the correct type and channel count
if (src.IsEmpty() || src.data_type_ != LDataType::UINT8 || src.channel_ != 1) {
return false;
}
// Check if the threshold values are valid
if (low_thresh < 0 || high_thresh < 0 || low_thresh > high_thresh) {
return false;
}
// Check if the kernel size is valid
if (ksize % 2 == 0 || ksize < 3 || ksize > 7) {
return false;
}
// Check if the destination image is empty or not of the same size, channel count, and data type as the source image
if (dst.IsEmpty() || dst.width_ != src.width_ || dst.height_ != src.height_ || dst.channel_ != src.channel_ ||
dst.data_type_ != src.data_type_) {
// Initialize the destination image with the same size, channel count, and data type as the source image
dst.Init(src.width_, src.height_, src.channel_, src.data_type_);
}
double scale = ksize == 7 ? 1 / 16.0 : 1.0;
low_thresh *= scale;
high_thresh *= scale;
LiteMat gx, gy;
Sobel(src, gx, 1, 0, ksize, scale, PaddBorderType::PADD_BORDER_REPLICATE);
Sobel(src, gy, 0, 1, ksize, scale, PaddBorderType::PADD_BORDER_REPLICATE);
LiteMat edges;
NonMaximumSuppression(gx, gy, edges, L2gradient);
Hysteresis(edges, dst, low_thresh, high_thresh);
return true;
}
// Declare a variable named "scale" of type double and initialize it with the value 1/16.0 if the value of "ksize" is equal to 7, otherwise initialize it with the value 1.0
double scale = ksize == 7 ? 1 / 16.0 : 1.0;
// Multiply the value of "low_thresh" by the value of "scale"
low_thresh *= scale;
// Multiply the value of "high_thresh" by the value of "scale"
high_thresh *= scale;
// Declare two LiteMat objects named gx and gy
LiteMat gx, gy;
// Apply the Sobel operator to the source image 'src' in the x-direction (1, 0)
// The result will be stored in the gx LiteMat object
// The Sobel operator is applied with a kernel size of 'ksize'
// The scale parameter is used to scale the computed gradients
// The PaddBorderType::PADD_BORDER_REPLICATE option is used to handle border pixels
Sobel(src, gx, 1, 0, ksize, scale, PaddBorderType::PADD_BORDER_REPLICATE);
// Apply the Sobel operator to the source image 'src' in the y-direction (0, 1)
// The result will be stored in the gy LiteMat object
// The Sobel operator is applied with a kernel size of 'ksize'
// The scale parameter is used to scale the computed gradients
// The PaddBorderType::PADD_BORDER_REPLICATE option is used to handle border pixels
Sobel(src, gy, 0, 1, ksize, scale, PaddBorderType::PADD_BORDER_REPLICATE);
// Declare a variable named "edges" of type LiteMat
LiteMat edges;
// Call the NonMaximumSuppression function with the parameters gx, gy, edges, and L2gradient
NonMaximumSuppression(gx, gy, edges, L2gradient);
// Call the Hysteresis function with the provided parameters: edges, dst, low_thresh, high_thresh
Hysteresis(edges, dst, low_thresh, high_thresh);
// Return true to indicate successful execution of the function
return true;
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -14,74 +14,163 @@
* limitations under the License.
*/
// Include the math library header file for using mathematical functions and constants in the code
#include <cmath>
// Include the header file "lite_mat.h" from the "lite_cv" library
#include "lite_cv/lite_mat.h"
// Include the header file "image_process.h" from the "lite_cv" library
#include "lite_cv/image_process.h"
// Check if the ENABLE_ANDROID macro is defined
#ifdef ENABLE_ANDROID
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
#define USE_NEON
#include <arm_neon.h>
#endif
// Check if any of the ARM-related macros are defined
#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64)
// Define the USE_NEON macro
#define USE_NEON
// Include the ARM NEON header file
#include <arm_neon.h>
// End of ARM-related macro check
#endif
// End of ENABLE_ANDROID macro check
#endif
// Define the namespace "mindspore"
namespace mindspore {
namespace dataset {
static void GetGaussianKernel(float *kernel, int size, double sigma) {
int n = (size - 1) / 2;
std::vector<float> buffer(n);
float sum = 0;
for (int i = 0; i < n; i++) {
int x = i - n;
float g = exp(-0.5 * x * x / (sigma * sigma));
buffer[i] = g;
sum += g;
}
sum = sum * 2 + 1;
if (size % 2 == 0) {
sum += 1;
}
const float scale = 1. / sum;
for (int i = 0; i < n; i++) {
float g = buffer[i] * scale;
kernel[i] = g;
kernel[size - 1 - i] = g;
}
kernel[n] = scale;
if (size % 2 == 0) {
kernel[n + 1] = scale;
// Define the namespace "dataset" within the "mindspore" namespace
namespace dataset {
// Define a static function "GetGaussianKernel" that takes in a float array "kernel", an integer "size", and a double "sigma"
static void GetGaussianKernel(float *kernel, int size, double sigma) {
// Calculate the value of "n" by subtracting 1 from "size" and dividing the result by 2
int n = (size - 1) / 2;
// Create a vector "buffer" of floats with size "n"
std::vector<float> buffer(n);
// Initialize the variable "sum" to 0
float sum = 0;
// Iterate from 0 to "n" (exclusive)
for (int i = 0; i < n; i++) {
// Calculate the value of "x" by subtracting "n" from "i"
int x = i - n;
// Calculate the value of "g" using the Gaussian function formula
float g = exp(-0.5 * x * x / (sigma * sigma));
// Store the value of "g" in the "buffer" vector at index "i"
buffer[i] = g;
// Add the value of "g" to the variable "sum"
sum += g;
}
// Multiply the value of "sum" by 2 and add 1 to it
sum = sum * 2 + 1;
// Check if "size" is even
if (size % 2 == 0) {
// If "size" is even, add 1 to the value of "sum"
sum += 1;
}
}
}
}
bool GaussianBlur(const LiteMat &src, LiteMat &dst, const std::vector<int> &ksize, double sigmaX, // NOLINT
double sigmaY, PaddBorderType pad_type) {
// Calculate the scaling factor by dividing 1 by the sum
const float scale = 1. / sum;
// Iterate over the elements of the buffer array
for (int i = 0; i < n; i++) {
// Multiply each element of the buffer array by the scaling factor
float g = buffer[i] * scale;
// Assign the scaled value to the corresponding element in the kernel array
kernel[i] = g;
// Assign the scaled value to the mirrored element in the kernel array
kernel[size - 1 - i] = g;
}
// Assign the scaling factor to the last element of the kernel array
kernel[n] = scale;
// Check if the size of the kernel array is even
if (size % 2 == 0) {
// If the size is even, assign the scaling factor to the second last element of the kernel array
kernel[n + 1] = scale;
}
// Function to apply Gaussian blur to an input image
bool GaussianBlur(const LiteMat &src, LiteMat &dst, const std::vector<int> &ksize, double sigmaX, double sigmaY, PaddBorderType pad_type) {
// Check if the input image is empty or not of type UINT8
if (src.IsEmpty() || src.data_type_ != LDataType::UINT8) {
return false;
}
// Check if the kernel size is valid (2D, odd dimensions, and positive values)
if (ksize.size() != 2 || ksize[0] <= 0 || ksize[1] <= 0 || ksize[0] % 2 != 1 || ksize[1] % 2 != 1) {
return false;
}
// Check if the sigmaX value is valid (positive)
if (sigmaX <= 0) {
return false;
}
// Check if the sigmaY value is valid (positive), if not, set it equal to sigmaX
if (sigmaY <= 0) {
sigmaY = sigmaX;
}
// Check if the kernel size is 1x1, if so, assign the input image to the output image and return true
if (ksize[0] == 1 && ksize[1] == 1) {
dst = src;
return true;
}
}
LiteMat kx, ky;
kx.Init(ksize[0], 1, 1, LDataType::FLOAT32);
ky.Init(1, ksize[1], 1, LDataType::FLOAT32);
// Declare two LiteMat objects named kx and ky
LiteMat kx, ky;
GetGaussianKernel(kx, ksize[0], sigmaX);
GetGaussianKernel(ky, ksize[1], sigmaY);
// Initialize the kx object with the specified parameters:
// - Width: ksize[0]
// - Height: 1
// - Channel: 1
// - Data type: FLOAT32
kx.Init(ksize[0], 1, 1, LDataType::FLOAT32);
// Initialize the ky object with the specified parameters:
// - Width: 1
// - Height: ksize[1]
// - Channel: 1
// - Data type: FLOAT32
ky.Init(1, ksize[1], 1, LDataType::FLOAT32);
// Call the function GetGaussianKernel with the parameters kx, ksize[0], and sigmaX
GetGaussianKernel(kx, ksize[0], sigmaX);
// Call the function GetGaussianKernel with the parameters ky, ksize[1], and sigmaY
GetGaussianKernel(ky, ksize[1], sigmaY);
// Return the result of calling the ConvRowCol function with the provided arguments
return ConvRowCol(src, kx, ky, dst, src.data_type_, pad_type);
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,22 +14,39 @@
* limitations under the License.
*/
// Include the header file "math_utils.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/math_utils.h"
// Include the algorithm header for using various algorithms like sorting, searching, etc.
#include <algorithm>
// Include the string header for using string-related functions and classes
#include <string>
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace
namespace dataset {
// Function to compute the upper and lower percentiles of a histogram
Status ComputeUpperAndLowerPercentiles(std::vector<int32_t> *hist, int32_t hi_p, int32_t low_p, int32_t *hi,
int32_t *lo) {
// Check if the input parameters are valid
CHECK_FAIL_RETURN_UNEXPECTED(hist != nullptr, "hist is nullptr");
CHECK_FAIL_RETURN_UNEXPECTED(hi != nullptr, "hi is nullptr");
CHECK_FAIL_RETURN_UNEXPECTED(lo != nullptr, "lo is nullptr");
try {
// Compute the total count of values in the histogram
int32_t n = std::accumulate(hist->begin(), hist->end(), 0);
// Define the maximum percentile value
constexpr float kMaxPerc = 100.0;
// Compute the cut value for the lower percentile
int32_t cut = static_cast<int32_t>((low_p / kMaxPerc) * n);
// Iterate through the histogram from the lower bound and subtract the cut value from each bin until cut becomes 0
for (int32_t lb = 0; lb < static_cast<int32_t>(hist->size()) && cut > 0; lb++) {
if (cut > (*hist)[lb]) {
cut -= (*hist)[lb];
@ -39,7 +56,11 @@ Status ComputeUpperAndLowerPercentiles(std::vector<int32_t> *hist, int32_t hi_p,
cut = 0;
}
}
// Compute the cut value for the upper percentile
cut = static_cast<int32_t>((hi_p / kMaxPerc) * n);
// Iterate through the histogram from the upper bound and subtract the cut value from each bin until cut becomes 0
for (auto ub_iter = hist->end() - 1; ub_iter >= hist->begin() && cut > 0; ub_iter--) {
if (cut > *ub_iter) {
cut -= *ub_iter;
@ -49,39 +70,90 @@ Status ComputeUpperAndLowerPercentiles(std::vector<int32_t> *hist, int32_t hi_p,
cut = 0;
}
}
// Initialize the lower and upper bounds
*lo = 0;
*hi = hist->size() - 1;
// Find the first non-zero bin from the lower bound
for (; (*lo) < (*hi) && !(*hist)[*lo]; (*lo)++) {
}
// Find the first non-zero bin from the upper bound
for (; (*hi) >= 0 && !(*hist)[*hi]; (*hi)--) {
}
} catch (const std::exception &e) {
// If an exception occurs, create an error message and return an unexpected status
std::string err_message = "AutoContrast: ComputeUpperAndLowerPercentiles failed: ";
err_message += e.what();
RETURN_STATUS_UNEXPECTED(err_message);
}
// Return success status
return Status::OK();
}
Status DegreesToRadians(float_t degrees, float_t *radians_target) {
CHECK_FAIL_RETURN_UNEXPECTED(radians_target != nullptr, "radians_target is nullptr");
*radians_target = CV_PI * degrees / 180.0;
// End of the "dataset" namespace
} // namespace dataset
// End of the "mindspore" namespace
} // namespace mindspore
}
// Return the OK status to indicate successful program termination
return Status::OK();
}
// Function to convert degrees to radians
// Takes a float value representing degrees and a pointer to a float value representing the target radians
Status DegreesToRadians(float_t degrees, float_t *radians_target) {
// Check if the pointer to the target radians is not nullptr
CHECK_FAIL_RETURN_UNEXPECTED(radians_target != nullptr, "radians_target is nullptr");
// Convert degrees to radians using the formula: radians = (pi * degrees) / 180.0
*radians_target = CV_PI * degrees / 180.0;
// Return OK status to indicate successful conversion
return Status::OK();
}
// Function to generate a random real number within a given range
// Parameters:
// - a: lower bound of the range
// - b: upper bound of the range
// - rnd: pointer to an instance of std::mt19937, a random number generator
// - result: pointer to a float_t variable where the generated number will be stored
// Returns:
// - Status: indicates the success or failure of the function
Status GenerateRealNumber(float_t a, float_t b, std::mt19937 *rnd, float_t *result) {
// Check if the rnd pointer is not null
CHECK_FAIL_RETURN_UNEXPECTED(rnd != nullptr, "rnd is nullptr");
// Check if the result pointer is not null
CHECK_FAIL_RETURN_UNEXPECTED(result != nullptr, "result is nullptr");
try {
// Create a uniform real distribution with the given range
std::uniform_real_distribution<float_t> distribution{a, b};
// Generate a random number using the distribution and the random number generator
*result = distribution(*rnd);
} catch (const std::exception &e) {
// If an exception occurs, create an error message with the exception details
std::string err_message = "RandomAffine: GenerateRealNumber failed: ";
err_message += e.what();
// Return the error message as a Status object
RETURN_STATUS_UNEXPECTED(err_message);
}
// Return a Status object indicating success
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
// Closing braces to end the namespace blocks for "dataset" and "mindspore"

View File

@ -14,95 +14,199 @@
* limitations under the License.
*/
#include "minddata/dataset/kernels/image/mixup_batch_op.h"
// Include the header file "minddata/dataset/kernels/image/mixup_batch_op.h" which contains the declaration of the MixupBatchOp class and its associated functions and variables.
// Include the header for numeric limits (provides information about the limits of numeric types)
#include <limits>
// Include the header for string manipulation
#include <string>
// Include the header for utility functions (provides various utility functions)
#include <utility>
// Include the header file for cv_tensor from the minddata/dataset/core directory
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for data_utils from the minddata/dataset/kernels/data directory
#include "minddata/dataset/kernels/data/data_utils.h"
// Include the header file for random from the minddata/dataset/util directory
#include "minddata/dataset/util/random.h"
// Include the header file for status from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Define a constant variable `kExpectedImageShapeSize` with a value of 4
constexpr size_t kExpectedImageShapeSize = 4;
// Define a constant variable `kMaxLabelShapeSize` with a value of 3
constexpr size_t kMaxLabelShapeSize = 3;
// Define a constant variable `kMinLabelShapeSize` with a value of 2
constexpr size_t kMinLabelShapeSize = 2;
// Define a constant variable `dimension_one` with a value of 1
constexpr size_t dimension_one = 1;
// Define a constant variable `dimension_two` with a value of 2
constexpr size_t dimension_two = 2;
// Define a constant variable `dimension_three` with a value of 3
constexpr size_t dimension_three = 3;
// Define a constant variable `value_one` with a value of 1
constexpr int64_t value_one = 1;
// Define a constant variable `value_three` with a value of 3
constexpr int64_t value_three = 3;
MixUpBatchOp::MixUpBatchOp(float alpha) : alpha_(alpha) { rnd_.seed(GetSeed()); }
// Define the constructor for the MixUpBatchOp class, which takes a float parameter alpha
MixUpBatchOp::MixUpBatchOp(float alpha) : alpha_(alpha) {
Status MixUpBatchOp::ComputeLabels(const TensorRow &input, std::shared_ptr<Tensor> *out_labels,
std::vector<int64_t> *rand_indx, const std::vector<int64_t> &label_shape,
const float lam, const size_t images_size) {
CHECK_FAIL_RETURN_UNEXPECTED(
images_size <= static_cast<size_t>(std::numeric_limits<int64_t>::max()),
"The \'images_size\' must not be more than \'INT64_MAX\', but got: " + std::to_string(images_size));
for (int64_t i = 0; i < static_cast<int64_t>(images_size); i++) {
rand_indx->push_back(i);
}
std::shuffle(rand_indx->begin(), rand_indx->end(), rnd_);
// Initialize the random number generator with a seed obtained from GetSeed() function
rnd_.seed(GetSeed());
}
RETURN_IF_NOT_OK(TypeCast(std::move(input.at(1)), out_labels, DataType(DataType::DE_FLOAT32)));
// ComputeLabels function to generate labels for a batch of input data
// Parameters:
// - input: the input data in the form of a TensorRow
// - out_labels: a pointer to a shared_ptr of Tensor, which will store the generated labels
// - rand_indx: a pointer to a vector of int64_t, which will store the randomly shuffled indices
// - label_shape: a vector of int64_t, specifying the shape of the labels
// - lam: a float value representing the lambda parameter
// - images_size: the size of the input images
int64_t row_labels = label_shape.size() == kMaxLabelShapeSize ? label_shape[1] : 1;
int64_t num_classes = label_shape.size() == kMaxLabelShapeSize ? label_shape[dimension_two] : label_shape[1];
// Check if images_size is within the range of int64_t
CHECK_FAIL_RETURN_UNEXPECTED(
images_size <= static_cast<size_t>(std::numeric_limits<int64_t>::max()),
"The 'images_size' must not be more than 'INT64_MAX', but got: " + std::to_string(images_size));
// Iterate over the range of images_size and push each index into the rand_indx vector
for (int64_t i = 0; i < static_cast<int64_t>(images_size); i++) {
rand_indx->push_back(i);
}
// Shuffle the elements in the rand_indx vector using the rnd_ random number generator
std::shuffle(rand_indx->begin(), rand_indx->end(), rnd_);
// Call the TypeCast function with the second element of the input vector as the argument
// Use std::move to transfer ownership of the element to the function
// The result of the TypeCast function is then passed as an argument to the RETURN_IF_NOT_OK macro
// The macro checks if the result is an OK status, and if not, returns the error status
// The TypeCast function converts the input element to the DataType DE_FLOAT32 and stores the result in out_labels
// Check if the size of label_shape is equal to kMaxLabelShapeSize
// If it is, assign the value at index 1 of label_shape to row_labels
// Otherwise, assign 1 to row_labels
int64_t row_labels = label_shape.size() == kMaxLabelShapeSize ? label_shape[1] : 1;
// Check if the size of label_shape is equal to kMaxLabelShapeSize
// If it is, assign the value at index dimension_two of label_shape to num_classes
// Otherwise, assign the value at index 1 of label_shape to num_classes
int64_t num_classes = label_shape.size() == kMaxLabelShapeSize ? label_shape[dimension_two] : label_shape[1];
for (int64_t i = 0; i < label_shape[0]; i++) {
// Iterate over the first dimension of the label shape
for (int64_t j = 0; j < row_labels; j++) {
// Iterate over the row labels
for (int64_t k = 0; k < num_classes; k++) {
// Iterate over the number of classes
std::vector<int64_t> first_index =
label_shape.size() == kMaxLabelShapeSize ? std::vector{i, j, k} : std::vector{i, k};
// Create a vector to store the first index based on the size of the label shape
std::vector<int64_t> second_index = label_shape.size() == kMaxLabelShapeSize
? std::vector{(*rand_indx)[static_cast<size_t>(i)], j, k}
: std::vector{(*rand_indx)[static_cast<size_t>(i)], k};
// Create a vector to store the second index based on the size of the label shape and the random index
if (input.at(1)->type().IsSignedInt()) {
// Check if the type of the input tensor at index 1 is a signed integer
int64_t first_value, second_value;
// Declare variables to store the first and second values
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&first_value, first_index));
// Get the value at the first index from the input tensor and store it in first_value
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&second_value, second_index));
// Get the value at the second index from the input tensor and store it in second_value
RETURN_IF_NOT_OK((*out_labels)->SetItemAt(first_index, lam * first_value + (1 - lam) * second_value));
// Set the value at the first index in the output labels tensor to the linear combination of first_value and second_value
} else {
// If the type of the input tensor at index 1 is not a signed integer
uint64_t first_value, second_value;
// Declare variables to store the first and second values
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&first_value, first_index));
// Get the value at the first index from the input tensor and store it in first_value
RETURN_IF_NOT_OK(input.at(1)->GetItemAt(&second_value, second_index));
// Get the value at the second index from the input tensor and store it in second_value
RETURN_IF_NOT_OK((*out_labels)->SetItemAt(first_index, lam * first_value + (1 - lam) * second_value));
// Set the value at the first index in the output labels tensor to the linear combination of first_value and second_value
}
}
}
}
// Return Status::OK() to indicate successful execution of the function
return Status::OK();
}
Status MixUpBatchOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the size of the input data is less than 2
if (input.size() < 2) {
// If the size is less than 2, return an error message with the size of the input data
RETURN_STATUS_UNEXPECTED("MixUpBatch: size of input data should be 2 (including images or labels), but got: " +
std::to_string(input.size()) + ", check 'input_columns' when call this operator.");
}
std::vector<std::shared_ptr<CVTensor>> images;
std::vector<int64_t> image_shape = input.at(0)->shape().AsVector();
std::vector<int64_t> label_shape = input.at(1)->shape().AsVector();
// Declare a vector named "images" that stores shared pointers to CVTensor objects
std::vector<std::shared_ptr<CVTensor>> images;
// Check inputs
// Declare a vector named "image_shape" and initialize it with the shape of the first element in the "input" vector
std::vector<int64_t> image_shape = input.at(0)->shape().AsVector();
// Declare a vector named "label_shape" and initialize it with the shape of the second element in the "input" vector
std::vector<int64_t> label_shape = input.at(1)->shape().AsVector();
// Check if the size of the image shape is not equal to the expected size or if the first element of the image shape is not equal to the first element of the label shape
if (image_shape.size() != kExpectedImageShapeSize || image_shape[0] != label_shape[0]) {
// Return an error message indicating the expected and actual sizes of the image shape and label shape
RETURN_STATUS_UNEXPECTED("MixUpBatch: rank of image shape should be: " + std::to_string(kExpectedImageShapeSize) +
", but got: " + std::to_string(image_shape.size()) +
", make sure image shape are <H,W,C> or <C,H,W> and batched before calling MixUpBatch.");
}
// Check if the type of the second input column (labels) is not an integer type
if (!input.at(1)->type().IsInt()) {
// Return an error message indicating that the labels must only include int types and the actual type of the second input column
RETURN_STATUS_UNEXPECTED(
"MixUpBatch: wrong labels type. The second column (labels) must only include int types, but got: " +
input.at(1)->type().ToString());
}
// Check if the size of the label shape is not equal to the minimum label shape size and not equal to the maximum label shape size
if (label_shape.size() != kMinLabelShapeSize && label_shape.size() != kMaxLabelShapeSize) {
// Return an unexpected status with an error message explaining the expected label shape
RETURN_STATUS_UNEXPECTED(
"MixUpBatch: wrong labels shape. "
"The second column (labels) must have a shape of NC or NLC where N is the batch size, "
@ -110,66 +214,131 @@ Status MixUpBatchOp::Compute(const TensorRow &input, TensorRow *output) {
"labels must be in one-hot format and in a batch, but got rank: " +
std::to_string(label_shape.size()));
}
// Check if the image shape does not match the expected dimensions
if ((image_shape[dimension_one] != value_one && image_shape[dimension_one] != value_three) &&
(image_shape[dimension_three] != value_one && image_shape[dimension_three] != value_three)) {
// Return an unexpected status with an error message explaining the expected image shape
RETURN_STATUS_UNEXPECTED("MixUpBatch: images shape should in <N,H,W,C> or <N,C,H,W>, got shape:" +
input.at(0)->shape().ToString());
}
// Move images into a vector of CVTensors
RETURN_IF_NOT_OK(BatchTensorToCVTensorVector(input.at(0), &images));
// Move images into a vector of CVTensors
RETURN_IF_NOT_OK(BatchTensorToCVTensorVector(input.at(0), &images));
// Calculating lambda
// If x1 is a random variable from Gamma(a1, 1) and x2 is a random variable from Gamma(a2, 1)
// If x1 is a random variable from Gamma(a1, 1) and x2 is a random variable from Gamma(a2, 1),
// then x = x1 / (x1+x2) is a random variable from Beta(a1, a2)
// Create a gamma distribution with shape parameter alpha_ and scale parameter 1
std::gamma_distribution<float> distribution(alpha_, 1);
// Generate random variables x1 and x2 from the gamma distribution
float x1 = distribution(rnd_);
float x2 = distribution(rnd_);
// Check if the multiplication of x1 and x2 is within the bounds of float_t
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() - x1) > x2,
"multiplication out of bounds, with multipliers: " + std::to_string(x1) + " and " +
std::to_string(x2) +
", which result in the out of bounds product:" + std::to_string(x1 * x2));
// Check if the sum of x1 and x2 is not equal to 0
CHECK_FAIL_RETURN_UNEXPECTED(x1 + x2 != 0.0, "addition of variable(x1 and x2) of Gamma should not be 0.");
// Calculate lambda by dividing x1 by the sum of x1 and x2
float lam = x1 / (x1 + x2);
// Calculate random labels
std::vector<int64_t> rand_indx;
std::shared_ptr<Tensor> out_labels;
// Create an empty vector to store random indices
std::vector<int64_t> rand_indx;
// Compute labels
RETURN_IF_NOT_OK(ComputeLabels(input, &out_labels, &rand_indx, label_shape, lam, images.size()));
// Create a shared pointer to a Tensor object called out_labels
std::shared_ptr<Tensor> out_labels;
// Compute labels
// Call the function ComputeLabels with the following parameters:
// - input: the input data
// - out_labels: the output labels
// - rand_indx: the random index
// - label_shape: the shape of the labels
// - lam: the lambda value
// - images.size(): the size of the images
RETURN_IF_NOT_OK(ComputeLabels(input, &out_labels, &rand_indx, label_shape, lam, images.size()));
// Compute images
// Iterate over the images vector using an int64_t index variable i
for (int64_t i = 0; i < images.size(); i++) {
// Create a TensorShape object called remaining with a single dimension of -1
TensorShape remaining({-1});
// Declare a pointer to uchar called start_addr_of_index and initialize it to nullptr
uchar *start_addr_of_index = nullptr;
// Declare a shared pointer to Tensor called out
std::shared_ptr<Tensor> out;
// Call the StartAddrOfIndex function on the first element of the input vector, passing in the index {rand_indx[i], 0, 0, 0}
// and the addresses of start_addr_of_index and remaining as output parameters
RETURN_IF_NOT_OK(input.at(0)->StartAddrOfIndex({rand_indx[i], 0, 0, 0}, &start_addr_of_index, &remaining));
// Call the CreateFromMemory function on the first element of the input vector, passing in the image shape and type,
// start_addr_of_index, and the address of out as an output parameter
RETURN_IF_NOT_OK(input.at(0)->CreateFromMemory(
TensorShape({image_shape[dimension_one], image_shape[dimension_two], image_shape[dimension_three]}),
input.at(0)->type(), start_addr_of_index, &out));
// Convert the shared pointer to Tensor out to a shared pointer to CVTensor called rand_image
std::shared_ptr<CVTensor> rand_image = CVTensor::AsCVTensor(std::move(out));
// Check if the data pointer of the mat member of rand_image is null
if (!rand_image->mat().data) {
// If it is null, return an unexpected status with an error message
RETURN_STATUS_UNEXPECTED("[Internal ERROR] MixUpBatch: allocate memory failed.");
}
// Update the mat member of the i-th element of the images vector by performing a linear combination of the original image
// and the rand_image, using the mixing coefficient lam
images[i]->mat() = lam * images[i]->mat() + (1 - lam) * rand_image->mat();
}
// Move the output into a TensorRow
// Create a shared pointer to a Tensor object called output_image
std::shared_ptr<Tensor> output_image;
// Create an empty Tensor with the same shape and data type as the first input Tensor
// and assign it to the output_image pointer
RETURN_IF_NOT_OK(Tensor::CreateEmpty(input.at(0)->shape(), input.at(0)->type(), &output_image));
// Iterate over the images vector
for (int64_t i = 0; i < images.size(); i++) {
// Insert each image Tensor from the images vector into the output_image Tensor
RETURN_IF_NOT_OK(output_image->InsertTensor({i}, images[i]));
}
// Push the output_image Tensor into the output vector
output->push_back(output_image);
// Push the out_labels Tensor into the output vector
output->push_back(out_labels);
return Status::OK();
}
// Return the OK status from the Status class
return Status::OK();
// Define the Print function of the MixUpBatchOp class
void MixUpBatchOp::Print(std::ostream &out) const {
// Use the provided output stream to print the MixUpBatchOp information
out << "MixUpBatchOp: "
<< "alpha: " << alpha_ << "\n";
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -15,41 +15,79 @@
*/
#include "minddata/dataset/kernels/image/normalize_op.h"
// Include the random header for generating random numbers
#include <random>
// Include the vector header for using the vector container
#include <vector>
// Check if the ENABLE_ANDROID macro is defined
#ifndef ENABLE_ANDROID
// If ENABLE_ANDROID is not defined, include the image_utils.h header file from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// If ENABLE_ANDROID is defined, include the lite_image_utils.h header file from the minddata/dataset/kernels/image directory
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Include the status.h header file from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace
namespace dataset {
// Definition of the constructor for the NormalizeOp class, taking in two vectors of floats as parameters
NormalizeOp::NormalizeOp(const std::vector<float> &mean, const std::vector<float> &std) : mean_(mean), std_(std) {
// pre-calculate normalized mean to be used later in each Compute
// Pre-calculate the normalized mean to be used later in each Compute
for (int64_t i = 0; i < mean.size(); i++) {
mean_[i] = mean_[i] / std_[i];
}
}
// Compute function for the NormalizeOp class
Status NormalizeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output pointers are valid
IO_CHECK(input, output);
// Doing the Normalization
// Call the Normalize function to perform the normalization
// Pass the input, output, mean, and std as arguments
return Normalize(input, output, mean_, std_);
}
// Definition of the Print function for the NormalizeOp class
void NormalizeOp::Print(std::ostream &out) const {
// Print the initial part of the output message
out << "NormalizeOp, mean: ";
// Iterate over each element in the mean_ vector and print it followed by a comma
for (const auto &m : mean_) {
out << m << ", ";
}
// Print the closing brace for the mean_ vector and start a new line
out << "}" << std::endl << "std: ";
// Iterate over each element in the std_ vector and print it followed by a comma
for (const auto &s : std_) {
out << s << ", ";
}
// Print the closing brace for the std_ vector and start a new line
out << "}" << std::endl;
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -15,36 +15,80 @@
*/
#include "minddata/dataset/kernels/image/normalize_pad_op.h"
// Include the random header, which provides facilities for generating random numbers
#include <random>
// Include the header file for image utilities from the MindData dataset library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility from the MindData dataset library
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace
namespace dataset {
// Definition of the constructor for the NormalizePadOp class
NormalizePadOp::NormalizePadOp(float mean_r, float mean_g, float mean_b, float std_r, float std_g, float std_b,
std::string dtype) {
// Create a Tensor object from the mean values
Status s = Tensor::CreateFromVector<float>({mean_r, mean_g, mean_b}, &mean_);
// Check if there was an error creating the Tensor
if (s.IsError()) {
// Log an error message with the invalid mean values
MS_LOG(ERROR) << "NormalizePad: invalid mean value, got: (" + std::to_string(mean_r) + std::to_string(mean_g) +
std::to_string(mean_b) + ").";
}
// Create a Tensor object from the standard deviation values
s = Tensor::CreateFromVector<float>({std_r, std_g, std_b}, &std_);
// Check if there was an error creating the Tensor
if (s.IsError()) {
// Log an error message with the invalid standard deviation values
MS_LOG(ERROR) << "NormalizePad: invalid std value, got: (" + std::to_string(std_r) + std::to_string(std_g) +
std::to_string(std_b) + ").";
}
// Store the dtype value
dtype_ = dtype;
}
// End of the "dataset" namespace
} // namespace dataset
// End of the "mindspore" namespace
} // namespace mindspore
// Compute function for the NormalizePadOp class
Status NormalizePadOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Doing the Normalization + pad
// Call the NormalizePad function to perform normalization and padding
// Pass the input tensor, output tensor, mean, standard deviation, and data type as arguments
return NormalizePad(input, output, mean_, std_, dtype_);
}
// Definition of the Print function for the NormalizePadOp class
void NormalizePadOp::Print(std::ostream &out) const {
out << "NormalizeOp, mean: " << *(mean_.get()) << std::endl << "std: " << *(std_.get()) << std::endl;
// Output the string "NormalizeOp, mean: " followed by the value of the mean_ variable
out << "NormalizeOp, mean: " << *(mean_.get()) << std::endl;
// Output the string "std: " followed by the value of the std_ variable
out << "std: " << *(std_.get()) << std::endl;
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -15,42 +15,82 @@
*/
#include "minddata/dataset/kernels/image/pad_op.h"
// Include the header file for image utilities from the MindData library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for dataset constants from the MindData library
#include "minddata/dataset/include/dataset/constants.h"
// Include the header file for status utilities from the MindData library
#include "minddata/dataset/util/status.h"
// Define the namespace "mindspore"
namespace mindspore {
namespace dataset {
const BorderType PadOp::kDefBorderType = BorderType::kConstant;
const uint8_t PadOp::kDefFillR = 0;
const uint8_t PadOp::kDefFillG = 0;
const uint8_t PadOp::kDefFillB = 0;
// Define the nested namespace "dataset"
namespace dataset {
// Define the constant variable "kDefBorderType" of type BorderType and initialize it with BorderType::kConstant
const BorderType PadOp::kDefBorderType = BorderType::kConstant;
// Define the constant variable "kDefFillR" of type uint8_t and initialize it with 0
const uint8_t PadOp::kDefFillR = 0;
// Define the constant variable "kDefFillG" of type uint8_t and initialize it with 0
const uint8_t PadOp::kDefFillG = 0;
// Define the constant variable "kDefFillB" of type uint8_t and initialize it with 0
const uint8_t PadOp::kDefFillB = 0;
}
}
// Define the constructor for the PadOp class, which takes in several parameters to initialize the object
PadOp::PadOp(int32_t pad_top, int32_t pad_bottom, int32_t pad_left, int32_t pad_right, BorderType padding_mode,
uint8_t fill_r, uint8_t fill_g, uint8_t fill_b)
: pad_top_(pad_top),
pad_bottom_(pad_bottom),
pad_left_(pad_left),
pad_right_(pad_right),
boarder_type_(padding_mode),
fill_r_(fill_r),
fill_g_(fill_g),
fill_b_(fill_b) {}
: pad_top_(pad_top), // Initialize the pad_top_ member variable with the value of the pad_top parameter
pad_bottom_(pad_bottom), // Initialize the pad_bottom_ member variable with the value of the pad_bottom parameter
pad_left_(pad_left), // Initialize the pad_left_ member variable with the value of the pad_left parameter
pad_right_(pad_right), // Initialize the pad_right_ member variable with the value of the pad_right parameter
boarder_type_(padding_mode), // Initialize the boarder_type_ member variable with the value of the padding_mode parameter
fill_r_(fill_r), // Initialize the fill_r_ member variable with the value of the fill_r parameter
fill_g_(fill_g), // Initialize the fill_g_ member variable with the value of the fill_g parameter
fill_b_(fill_b) {} // Initialize the fill_b_ member variable with the value of the fill_b parameter
// The Compute function of the PadOp class
Status PadOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Call the Pad function to perform padding on the input tensor
// Pass the input tensor, output tensor, padding values, border type, and fill color
return Pad(input, output, pad_top_, pad_bottom_, pad_left_, pad_right_, boarder_type_, fill_r_, fill_g_, fill_b_);
}
// Function to determine the output shape of the PadOp operation
Status PadOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Call the OutputShape function of the base class TensorOp and check for any errors
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector
outputs.clear();
TensorShape out({-1, -1, 3}); // we don't know what is output image size, but we know it should be 3 channels
// Create a TensorShape object with dimensions {-1, -1, 3}
// The actual values of the first two dimensions are unknown, but we know the output should have 3 channels
TensorShape out({-1, -1, 3});
// If the input has a rank of 1, add the output shape to the outputs vector
if (inputs[0].Rank() == 1) outputs.emplace_back(out);
// If the outputs vector is not empty, return OK status
if (!outputs.empty()) return Status::OK();
// If the outputs vector is empty, return an error status with a message
return Status(
StatusCode::kMDUnexpectedError,
"Pad: invalid input shape, expected 1D input, but got input dimension is:" + std::to_string(inputs[0].Rank()));
}
} // namespace dataset
} // namespace mindspore
// End of namespace dataset
} // namespace mindspore

View File

@ -14,44 +14,91 @@
* limitations under the License.
*/
// Include the header file "posterize_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/posterize_op.h"
// Include the OpenCV image codecs header file, which provides functions for reading and writing images
#include <opencv2/imgcodecs.hpp>
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code for the "mindspore::dataset" namespace goes here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Define a constant variable named "kBit" of type uint8_t (unsigned 8-bit integer)
// This variable is a member of the PosterizeOp class
const uint8_t PosterizeOp::kBit = 8;
// Define the constructor for the PosterizeOp class, which takes a parameter of type uint8_t named bit
PosterizeOp::PosterizeOp(uint8_t bit) : bit_(bit) {}
Status PosterizeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
uint8_t mask_value = ~((uint8_t)(1 << (8 - bit_)) - 1);
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input);
if (!input_cv->mat().data) {
RETURN_STATUS_UNEXPECTED("[Internal ERROR] Posterize: load image failed.");
}
if (input_cv->Rank() != 3 && input_cv->Rank() != 2) {
RETURN_STATUS_UNEXPECTED("Posterize: input image is not in shape of <H,W,C> or <H,W>, but got rank: " +
std::to_string(input_cv->Rank()));
}
std::vector<uint8_t> lut_vector;
for (std::size_t i = 0; i < 256; i++) {
lut_vector.push_back(i & mask_value);
}
cv::Mat in_image = input_cv->mat();
// Compute function for the PosterizeOp class, which takes an input tensor and produces an output tensor
// The function returns a status indicating success or failure
cv::Mat output_img;
CHECK_FAIL_RETURN_UNEXPECTED(in_image.depth() == CV_8U || in_image.depth() == CV_8S,
"Posterize: data type of input image should be int, "
"but got " +
input->type().ToString());
cv::LUT(in_image, lut_vector, output_img);
std::shared_ptr<CVTensor> result_tensor;
// Calculate the mask value based on the number of bits specified by the 'bit_' variable
uint8_t mask_value = ~((uint8_t)(1 << (8 - bit_)) - 1);
RETURN_IF_NOT_OK(CVTensor::CreateFromMat(output_img, input_cv->Rank(), &result_tensor));
*output = std::static_pointer_cast<Tensor>(result_tensor);
return Status::OK();
// Convert the input tensor to a CVTensor for easier manipulation
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input);
// Check if the input CVTensor has valid data
if (!input_cv->mat().data) {
// If the input CVTensor does not have valid data, return an error status
RETURN_STATUS_UNEXPECTED("[Internal ERROR] Posterize: load image failed.");
}
// Check if the input CVTensor has a valid rank (either 2 or 3)
if (input_cv->Rank() != 3 && input_cv->Rank() != 2) {
// If the input CVTensor does not have a valid rank, return an error status with the rank information
RETURN_STATUS_UNEXPECTED("Posterize: input image is not in shape of <H,W,C> or <H,W>, but got rank: " +
std::to_string(input_cv->Rank()));
}
// Create a vector to store the lookup table values
std::vector<uint8_t> lut_vector;
// Generate the lookup table by applying the mask value to each possible pixel value (0-255)
for (std::size_t i = 0; i < 256; i++) {
lut_vector.push_back(i & mask_value);
}
// Get the OpenCV matrix representation of the input CVTensor
cv::Mat in_image = input_cv->mat();
// Declare a variable named "output_img" of type cv::Mat, which will hold the output image
cv::Mat output_img;
// Check if the depth of the input image is either CV_8U (unsigned 8-bit integer) or CV_8S (signed 8-bit integer)
// If the depth is not one of these types, return an error message indicating the expected data type
CHECK_FAIL_RETURN_UNEXPECTED(in_image.depth() == CV_8U || in_image.depth() == CV_8S,
"Posterize: data type of input image should be int, "
"but got " +
input->type().ToString());
// Apply a look-up table transformation to the input image using the lut_vector and store the result in output_img
cv::LUT(in_image, lut_vector, output_img);
// Declare a shared pointer named "result_tensor" of type CVTensor, which will hold the final result
std::shared_ptr<CVTensor> result_tensor;
// Call the CVTensor::CreateFromMat function to create a CVTensor object from the output_img and assign the result to result_tensor
RETURN_IF_NOT_OK(CVTensor::CreateFromMat(output_img, input_cv->Rank(), &result_tensor));
// Cast the result_tensor to a shared pointer of Tensor and assign it to the output pointer
*output = std::static_pointer_cast<Tensor>(result_tensor);
// Return a Status object indicating that the operation was successful
return Status::OK();
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -14,20 +14,45 @@
* limitations under the License.
*/
// Include the header file "random_adjust_sharpness_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/random_adjust_sharpness_op.h"
// Define the namespace "mindspore"
namespace mindspore {
namespace dataset {
const float RandomAdjustSharpnessOp::kDefProbability = 0.5;
Status RandomAdjustSharpnessOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// Define the nested namespace "dataset"
namespace dataset {
if (distribution_(rnd_)) {
return SharpnessOp::Compute(input, output);
}
*output = input;
return Status::OK();
// Define the constant float variable "kDefProbability" for the class "RandomAdjustSharpnessOp"
const float RandomAdjustSharpnessOp::kDefProbability = 0.5;
}
}
// Compute function for the RandomAdjustSharpnessOp class
// Takes in an input tensor and a pointer to an output tensor
// IO_CHECK is a macro that checks if the input and output tensors are valid
Status RandomAdjustSharpnessOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid using the IO_CHECK macro
IO_CHECK(input, output);
// ...
}
// Check if the result of the distribution function is true
if (distribution_(rnd_)) {
// If true, call the Compute function of the SharpnessOp class with input and output as parameters and return the result
return SharpnessOp::Compute(input, output);
}
// If the result of the distribution function is false, assign the value of input to output
*output = input;
// Return a Status object indicating successful program execution
return Status::OK();
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -14,80 +14,165 @@
* limitations under the License.
*/
// Include the header file "random_affine_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/random_affine_op.h"
// Include the math header for mathematical functions like sqrt, sin, etc.
#include <cmath>
// Include the limits header for numeric limits like maximum and minimum values of data types
#include <limits>
// Include the header file for math utilities related to image processing from the MindData library
#include "minddata/dataset/kernels/image/math_utils.h"
// Include the header file for random number generation utilities from the MindData library
#include "minddata/dataset/util/random.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Define the static member variable kDegreesRange of type std::vector<float_t> and initialize it with {0.0, 0.0}
const std::vector<float_t> RandomAffineOp::kDegreesRange = {0.0, 0.0};
// Define the static member variable kTranslationPercentages of type std::vector<float_t> and initialize it with {0.0, 0.0, 0.0, 0.0}
const std::vector<float_t> RandomAffineOp::kTranslationPercentages = {0.0, 0.0, 0.0, 0.0};
// Define the static member variable kScaleRange of type std::vector<float_t> and initialize it with {1.0, 1.0}
const std::vector<float_t> RandomAffineOp::kScaleRange = {1.0, 1.0};
// Define the static member variable kShearRanges of type std::vector<float_t> and initialize it with {0.0, 0.0, 0.0, 0.0}
const std::vector<float_t> RandomAffineOp::kShearRanges = {0.0, 0.0, 0.0, 0.0};
// Define the static member variable kDefInterpolation of type InterpolationMode and initialize it with InterpolationMode::kNearestNeighbour
const InterpolationMode RandomAffineOp::kDefInterpolation = InterpolationMode::kNearestNeighbour;
// Define the static member variable kFillValue of type std::vector<uint8_t> and initialize it with {0, 0, 0}
const std::vector<uint8_t> RandomAffineOp::kFillValue = {0, 0, 0};
// Constructor for the RandomAffineOp class
RandomAffineOp::RandomAffineOp(std::vector<float_t> degrees, std::vector<float_t> translate_range,
std::vector<float_t> scale_range, std::vector<float_t> shear_ranges,
InterpolationMode interpolation, std::vector<uint8_t> fill_value)
: AffineOp(0.0),
degrees_range_(degrees),
translate_range_(translate_range),
scale_range_(scale_range),
shear_ranges_(shear_ranges) {
interpolation_ = interpolation;
fill_value_ = fill_value;
rnd_.seed(GetSeed());
is_deterministic_ = false;
: AffineOp(0.0), // Call the constructor of the base class AffineOp with a default value of 0.0
degrees_range_(degrees), // Initialize the degrees_range_ member variable with the provided degrees vector
translate_range_(translate_range), // Initialize the translate_range_ member variable with the provided translate_range vector
scale_range_(scale_range), // Initialize the scale_range_ member variable with the provided scale_range vector
shear_ranges_(shear_ranges) { // Initialize the shear_ranges_ member variable with the provided shear_ranges vector
interpolation_ = interpolation; // Assign the provided interpolation value to the interpolation_ member variable
fill_value_ = fill_value; // Assign the provided fill_value vector to the fill_value_ member variable
rnd_.seed(GetSeed()); // Seed the random number generator with a seed obtained from GetSeed() function
is_deterministic_ = false; // Set the is_deterministic_ member variable to false
}
Status RandomAffineOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// Compute function for the RandomAffineOp class, which takes an input tensor and computes the output tensor
// The function returns a status indicating the success or failure of the computation
CHECK_FAIL_RETURN_UNEXPECTED(translate_range_.size() == 4, "RandomAffine: the translate range size is not 4.");
CHECK_FAIL_RETURN_UNEXPECTED(degrees_range_.size() == 2, "RandomAffine: the degrees range size is not 2.");
CHECK_FAIL_RETURN_UNEXPECTED(scale_range_.size() == 2, "RandomAffine: the scale range size is not 2.");
CHECK_FAIL_RETURN_UNEXPECTED(shear_ranges_.size() == 4, "RandomAffine: the shear ranges size is not 4.");
// Check if the input and output tensors are valid (non-null)
IO_CHECK(input, output);
dsize_t height = input->shape()[0];
dsize_t width = input->shape()[1];
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / std::abs(translate_range_[0])) > width,
"RandomAffineOp: multiplication out of bounds.");
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / std::abs(translate_range_[1])) > width,
"RandomAffineOp: multiplication out of bounds.");
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / std::abs(translate_range_[2])) > height,
"RandomAffineOp: multiplication out of bounds.");
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / std::abs(translate_range_[3])) > height,
"RandomAffineOp: multiplication out of bounds.");
float_t min_dx = translate_range_[0] * width;
float_t max_dx = translate_range_[1] * width;
float_t min_dy = translate_range_[2] * height;
float_t max_dy = translate_range_[3] * height;
float_t degrees = 0.0;
RETURN_IF_NOT_OK(GenerateRealNumber(degrees_range_[0], degrees_range_[1], &rnd_, &degrees));
float_t translation_x = 0.0;
RETURN_IF_NOT_OK(GenerateRealNumber(min_dx, max_dx, &rnd_, &translation_x));
float_t translation_y = 0.0;
RETURN_IF_NOT_OK(GenerateRealNumber(min_dy, max_dy, &rnd_, &translation_y));
float_t scale = 1.0;
RETURN_IF_NOT_OK(GenerateRealNumber(scale_range_[0], scale_range_[1], &rnd_, &scale));
float_t shear_x = 0.0;
RETURN_IF_NOT_OK(GenerateRealNumber(shear_ranges_[0], shear_ranges_[1], &rnd_, &shear_x));
float_t shear_y = 0.0;
RETURN_IF_NOT_OK(GenerateRealNumber(shear_ranges_[2], shear_ranges_[3], &rnd_, &shear_y));
// assign to base class variables
degrees_ = fmod(degrees, 360.0);
scale_ = scale;
translation_[0] = translation_x;
translation_[1] = translation_y;
shear_[0] = shear_x;
shear_[1] = shear_y;
return AffineOp::Compute(input, output);
}
} // namespace dataset
} // namespace mindspore
// Check if the size of the translate range is 4, if not, return an error message
CHECK_FAIL_RETURN_UNEXPECTED(translate_range_.size() == 4, "RandomAffine: the translate range size is not 4.");
// Check if the size of the degrees range is 2, if not, return an error message
CHECK_FAIL_RETURN_UNEXPECTED(degrees_range_.size() == 2, "RandomAffine: the degrees range size is not 2.");
// Check if the size of the scale range is 2, if not, return an error message
CHECK_FAIL_RETURN_UNEXPECTED(scale_range_.size() == 2, "RandomAffine: the scale range size is not 2.");
// Check if the size of the shear ranges is 4, if not, return an error message
CHECK_FAIL_RETURN_UNEXPECTED(shear_ranges_.size() == 4, "RandomAffine: the shear ranges size is not 4.");
// Get the height and width of the input shape
dsize_t height = input->shape()[0];
dsize_t width = input->shape()[1];
// Check if the multiplication of the translate range and width is within the bounds of float_t
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / std::abs(translate_range_[0])) > width,
"RandomAffineOp: multiplication out of bounds.");
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / std::abs(translate_range_[1])) > width,
"RandomAffineOp: multiplication out of bounds.");
// Check if the multiplication of the translate range and height is within the bounds of float_t
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / std::abs(translate_range_[2])) > height,
"RandomAffineOp: multiplication out of bounds.");
CHECK_FAIL_RETURN_UNEXPECTED((std::numeric_limits<float_t>::max() / std::abs(translate_range_[3])) > height,
"RandomAffineOp: multiplication out of bounds.");
// Calculate the minimum and maximum values for translation in the x and y directions
float_t min_dx = translate_range_[0] * width;
float_t max_dx = translate_range_[1] * width;
float_t min_dy = translate_range_[2] * height;
float_t max_dy = translate_range_[3] * height;
// Initialize degrees to 0.0
float_t degrees = 0.0;
// Generate a random real number within the specified range for degrees
RETURN_IF_NOT_OK(GenerateRealNumber(degrees_range_[0], degrees_range_[1], &rnd_, &degrees));
// Initialize translation_x and translation_y to 0.0
float_t translation_x = 0.0;
float_t translation_y = 0.0;
// Generate random real numbers within the specified range for translation in the x and y directions
RETURN_IF_NOT_OK(GenerateRealNumber(min_dx, max_dx, &rnd_, &translation_x));
RETURN_IF_NOT_OK(GenerateRealNumber(min_dy, max_dy, &rnd_, &translation_y));
// Declare and initialize a variable `scale` of type `float_t` with a value of 1.0
float_t scale = 1.0;
// Call the function `GenerateRealNumber` with arguments `scale_range_[0]`, `scale_range_[1]`, `&rnd_`, and `&scale`
// The function generates a random real number within the specified range and assigns it to the variable `scale`
RETURN_IF_NOT_OK(GenerateRealNumber(scale_range_[0], scale_range_[1], &rnd_, &scale));
// Declare and initialize a variable `shear_x` of type `float_t` with a value of 0.0
float_t shear_x = 0.0;
// Call the function `GenerateRealNumber` with arguments `shear_ranges_[0]`, `shear_ranges_[1]`, `&rnd_`, and `&shear_x`
// The function generates a random real number within the specified range and assigns it to the variable `shear_x`
RETURN_IF_NOT_OK(GenerateRealNumber(shear_ranges_[0], shear_ranges_[1], &rnd_, &shear_x));
// Declare and initialize a variable `shear_y` of type `float_t` with a value of 0.0
float_t shear_y = 0.0;
// Call the function `GenerateRealNumber` with arguments `shear_ranges_[2]`, `shear_ranges_[3]`, `&rnd_`, and `&shear_y`
// The function generates a random real number within the specified range and assigns it to the variable `shear_y`
RETURN_IF_NOT_OK(GenerateRealNumber(shear_ranges_[2], shear_ranges_[3], &rnd_, &shear_y));
// Assign the value of `degrees` modulo 360.0 to the variable `degrees_`
degrees_ = fmod(degrees, 360.0);
// Assign the value of `scale` to the variable `scale_`
scale_ = scale;
// Assign the value of `translation_x` to the first element of the array `translation_`
translation_[0] = translation_x;
// Assign the value of `translation_y` to the second element of the array `translation_`
translation_[1] = translation_y;
// Assign the value of `shear_x` to the first element of the array `shear_`
shear_[0] = shear_x;
// Assign the value of `shear_y` to the second element of the array `shear_`
shear_[1] = shear_y;
// Call the `Compute` function of the `AffineOp` class with arguments `input` and `output`
// Return the result of the `Compute` function
return AffineOp::Compute(input, output);
// End of the `dataset` namespace
}
// End of the `mindspore` namespace

View File

@ -14,37 +14,60 @@
* limitations under the License.
*/
// Include the header file "random_auto_contrast_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/random_auto_contrast_op.h"
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file "minddata/dataset/kernels/image/image_utils.h" which contains utility functions for image processing in the MindData library.
// Define the namespace "mindspore"
namespace mindspore {
// Define the nested namespace "dataset"
namespace dataset {
// Define the constant variable "kCutOff" with a value of 0.0
const float RandomAutoContrastOp::kCutOff = 0.0;
// Define the constant vector "kIgnore" with an empty initializer list
const std::vector<uint32_t> RandomAutoContrastOp::kIgnore = {};
// Define the constant variable "kDefProbability" with a value of 0.5
const float RandomAutoContrastOp::kDefProbability = 0.5;
// The Compute function of the RandomAutoContrastOp class
Status RandomAutoContrastOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// Check input
IO_CHECK(input, output); // Check if input and output are valid
// Check input shape
if (input->Rank() != DEFAULT_IMAGE_RANK) {
RETURN_STATUS_UNEXPECTED("RandomAutoContrast: image shape is not <H,W,C>, got rank: " +
std::to_string(input->Rank()));
}
// Check number of channels in input shape
if (input->shape()[CHANNEL_INDEX] != DEFAULT_IMAGE_CHANNELS) {
RETURN_STATUS_UNEXPECTED(
"RandomAutoContrast: image shape is incorrect, expected num of channels is 3, "
"but got:" +
std::to_string(input->shape()[CHANNEL_INDEX]));
}
// Check if input type is supported
CHECK_FAIL_RETURN_UNEXPECTED(input->type().AsCVType() != kCVInvalidType,
"RandomAutoContrast: Cannot convert from OpenCV type, unknown CV type. Currently "
"supported data type: [int8, uint8, int16, uint16, int32, float16, float32, float64].");
// Apply AutoContrast if the random distribution condition is met
if (distribution_(rnd_)) {
return AutoContrast(input, output, cutoff_, ignore_);
}
// If the random distribution condition is not met, assign input to output
*output = input;
// Return OK status to indicate successful computation
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
// End of namespace dataset
} // namespace mindspore

View File

@ -15,14 +15,25 @@
*/
#include "minddata/dataset/kernels/image/random_color_adjust_op.h"
// Include the random header, which provides facilities for generating random numbers
#include <random>
// Include the header file for image utilities from the MindData library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for random number generation utilities from the MindData library
#include "minddata/dataset/util/random.h"
// Include the header file for status utilities from the MindData library
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace
namespace dataset {
// Definition of the constructor for the RandomColorAdjustOp class
RandomColorAdjustOp::RandomColorAdjustOp(float s_bright_factor, float e_bright_factor, float s_contrast_factor,
float e_contrast_factor, float s_saturation_factor, float e_saturation_factor,
float s_hue_factor, float e_hue_factor)
@ -34,17 +45,33 @@ RandomColorAdjustOp::RandomColorAdjustOp(float s_bright_factor, float e_bright_f
saturation_factor_end_(e_saturation_factor),
hue_factor_start_(s_hue_factor),
hue_factor_end_(e_hue_factor) {
// Seed the random number generator with a random seed
rnd_.seed(GetSeed());
// Set the flag for determinism to false
is_deterministic_ = false;
}
Status RandomColorAdjustOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// End of the "dataset" namespace
} // namespace dataset
// randomly select an augmentation to apply to the input image until all the transformations run
std::vector<std::string> params_vector = {"brightness", "contrast", "saturation", "hue"};
// End of the "mindspore" namespace
} // namespace mindspore
std::shuffle(params_vector.begin(), params_vector.end(), rnd_);
// The Compute function of the RandomColorAdjustOp class takes in a shared pointer to a Tensor object as input and a pointer to a shared pointer to a Tensor object as output
// It returns a status indicating the success or failure of the computation
// Check if the input and output pointers are valid using the IO_CHECK macro
// Create a vector named "params_vector" to store a list of augmentation parameters
std::vector<std::string> params_vector = {"brightness", "contrast", "saturation", "hue"};
// The vector contains the following augmentation parameters: brightness, contrast, saturation, hue
// These parameters will be randomly selected and applied to the input image until all transformations have been run
// Shuffle the elements in the params_vector using the random number generator rnd_
std::shuffle(params_vector.begin(), params_vector.end(), rnd_);
*output = std::static_pointer_cast<Tensor>(input);
// determine if certain augmentation needs to be executed:
@ -52,40 +79,45 @@ Status RandomColorAdjustOp::Compute(const std::shared_ptr<Tensor> &input, std::s
// case switch
if (param == "brightness") {
if (CmpFloat(bright_factor_start_, bright_factor_end_) && CmpFloat(bright_factor_start_, 1.0f)) {
// If the brightness factor is not within the desired range and is equal to 1.0, skip the brightness adjustment
MS_LOG(DEBUG) << "Not running brightness.";
} else {
// adjust the brightness of an image
// Adjust the brightness of the image by generating a random factor within the specified range
float random_factor = std::uniform_real_distribution<float>(bright_factor_start_, bright_factor_end_)(rnd_);
RETURN_IF_NOT_OK(AdjustBrightness(*output, output, random_factor));
}
} else if (param == "contrast") {
if (CmpFloat(contrast_factor_start_, contrast_factor_end_) && CmpFloat(contrast_factor_start_, 1.0f)) {
// If the contrast factor is not within the desired range and is equal to 1.0, skip the contrast adjustment
MS_LOG(DEBUG) << "Not running contrast.";
} else {
// Adjust the contrast of the image by generating a random factor within the specified range
float random_factor = std::uniform_real_distribution<float>(contrast_factor_start_, contrast_factor_end_)(rnd_);
RETURN_IF_NOT_OK(AdjustContrast(*output, output, random_factor));
}
} else if (param == "saturation") {
// adjust the Saturation of an image
if (CmpFloat(saturation_factor_start_, saturation_factor_end_) && CmpFloat(saturation_factor_start_, 1.0f)) {
// If the saturation factor is not within the desired range and is equal to 1.0, skip the saturation adjustment
MS_LOG(DEBUG) << "Not running saturation.";
} else {
// Adjust the saturation of the image by generating a random factor within the specified range
float random_factor =
std::uniform_real_distribution<float>(saturation_factor_start_, saturation_factor_end_)(rnd_);
RETURN_IF_NOT_OK(AdjustSaturation(*output, output, random_factor));
}
} else if (param == "hue") {
if (CmpFloat(hue_factor_start_, hue_factor_end_) && CmpFloat(hue_factor_start_, 0.0f)) {
// If the hue factor is not within the desired range and is equal to 0.0, skip the hue adjustment
MS_LOG(DEBUG) << "Not running hue.";
} else {
// adjust the Hue of an image
// Adjust the hue of the image by generating a random factor within the specified range
float random_factor = std::uniform_real_distribution<float>(hue_factor_start_, hue_factor_end_)(rnd_);
RETURN_IF_NOT_OK(AdjustHue(*output, output, random_factor));
}
}
}
// now after we do all the transformations, the last one is fine
// After all the transformations are done, return OK status
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,55 +14,104 @@
* limitations under the License.
*/
// Include the header file for the RandomColorOp class from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/random_color_op.h"
// Include the header file for the ImageUtils class from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the CvTensor class from the minddata/dataset/core directory
#include "minddata/dataset/core/cv_tensor.h"
// Start of the mindspore namespace
namespace mindspore {
namespace dataset {
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
RandomColorOp::RandomColorOp(float t_lb, float t_ub) : rnd_(GetSeed()), dist_(t_lb, t_ub), t_lb_(t_lb), t_ub_(t_ub) {
is_deterministic_ = false;
// Define the constructor for the RandomColorOp class, taking in a lower bound (t_lb) and an upper bound (t_ub) as parameters
RandomColorOp::RandomColorOp(float t_lb, float t_ub) :
// Initialize the rnd_ member variable with a random seed obtained from the GetSeed() function
rnd_(GetSeed()),
// Initialize the dist_ member variable with the lower bound (t_lb) and upper bound (t_ub) parameters
dist_(t_lb, t_ub),
// Initialize the t_lb_ member variable with the lower bound (t_lb) parameter
t_lb_(t_lb),
// Initialize the t_ub_ member variable with the upper bound (t_ub) parameter
t_ub_(t_ub) {
// Set the is_deterministic_ member variable to false
is_deterministic_ = false;
}
// The Compute function of the RandomColorOp class
Status RandomColorOp::Compute(const std::shared_ptr<Tensor> &in, std::shared_ptr<Tensor> *out) {
// Check if the input and output tensors are valid
IO_CHECK(in, out);
// Check if the input tensor has the correct shape
if (in->Rank() != 3 || in->shape()[2] != 3) {
// If the shape is not <H,W,C> or the channel is not 3, return an error message
RETURN_STATUS_UNEXPECTED("RandomColor: image shape is not <H,W,C> or channel is not 3, got rank: " +
std::to_string(in->Rank()) + ", and channel: " + std::to_string(in->shape()[2]));
}
// 0.5 pixel precision assuming an 8 bit image
// Define the pixel precision assuming an 8-bit image
const auto eps = 0.00195;
// Generate a random number between 0 and 1
const auto t = dist_(rnd_);
// Check if the random number is close to 1.0
if (abs(t - 1.0) < eps) {
// Just return input? Can we do it given that input would otherwise get consumed in CVTensor constructor anyway?
// If it is, just return the input tensor as the output
*out = in;
return Status::OK();
}
// Convert the input tensor to a CVTensor
auto cvt_in = CVTensor::AsCVTensor(in);
auto m1 = cvt_in->mat();
// Convert the image to grayscale
cv::Mat gray;
// gray is allocated without using the allocator
cv::cvtColor(m1, gray, cv::COLOR_RGB2GRAY);
// luminosity is not preserved, consider using weights.
// Create a new 3-channel image with all channels set to the grayscale image
cv::Mat temp[3] = {gray, gray, gray};
cv::Mat cv_out;
cv::merge(temp, 3, cv_out);
// Create a new CVTensor from the merged image
std::shared_ptr<CVTensor> cvt_out;
RETURN_IF_NOT_OK(CVTensor::CreateFromMat(cv_out, cvt_in->Rank(), &cvt_out));
// Check if the random number is close to 0.0
if (abs(t - 0.0) < eps) {
// return grayscale
// If it is, return the grayscale image as the output
*out = std::static_pointer_cast<Tensor>(cvt_out);
return Status::OK();
}
try {
// return blended image. addWeighted takes care of overflow for uint8_t
// Blend the original image and the merged image using the random number as the weight
cv::addWeighted(m1, t, cvt_out->mat(), 1 - t, 0, cvt_out->mat());
} catch (const cv::Exception &e) {
// If an exception occurs during blending, return an error message
RETURN_STATUS_UNEXPECTED("RandomColorOp: cv::addWeighted " + std::string(e.what()));
}
// Set the blended image as the output
*out = std::static_pointer_cast<Tensor>(cvt_out);
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
// Closing braces to end the namespace blocks for "dataset" and "mindspore"

View File

@ -17,154 +17,266 @@
#include <limits>
#include <random>
// Include the header file for image utilities from the MindData dataset library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for random number generation utilities from the MindData dataset library
#include "minddata/dataset/util/random.h"
// Include the header file for status utilities from the MindData dataset library
#include "minddata/dataset/util/status.h"
// Define the namespace "mindspore" for the code
namespace mindspore {
namespace dataset {
const float RandomCropAndResizeOp::kDefScaleLb = 0.08;
const float RandomCropAndResizeOp::kDefScaleUb = 1.0;
const float RandomCropAndResizeOp::kDefAspectLb = 0.75;
const float RandomCropAndResizeOp::kDefAspectUb = 1.333333;
const InterpolationMode RandomCropAndResizeOp::kDefInterpolation = InterpolationMode::kLinear;
const int32_t RandomCropAndResizeOp::kDefMaxIter = 10;
// Define the nested namespace "dataset" within the "mindspore" namespace
namespace dataset {
// Define the constant float values for the default scale lower bound and upper bound
const float RandomCropAndResizeOp::kDefScaleLb = 0.08;
const float RandomCropAndResizeOp::kDefScaleUb = 1.0;
// Define the constant float values for the default aspect ratio lower bound and upper bound
const float RandomCropAndResizeOp::kDefAspectLb = 0.75;
const float RandomCropAndResizeOp::kDefAspectUb = 1.333333;
// Define the constant InterpolationMode value for the default interpolation mode
const InterpolationMode RandomCropAndResizeOp::kDefInterpolation = InterpolationMode::kLinear;
// Define the constant int32_t value for the default maximum iterations
const int32_t RandomCropAndResizeOp::kDefMaxIter = 10;
} // End of namespace dataset
} // End of namespace mindspore
// Constructor for the RandomCropAndResizeOp class
RandomCropAndResizeOp::RandomCropAndResizeOp(int32_t target_height, int32_t target_width, float scale_lb,
float scale_ub, float aspect_lb, float aspect_ub,
InterpolationMode interpolation, int32_t max_attempts)
: target_height_(target_height),
target_width_(target_width),
rnd_scale_(scale_lb, scale_ub),
rnd_aspect_(log(aspect_lb), log(aspect_ub)),
interpolation_(interpolation),
aspect_lb_(aspect_lb),
aspect_ub_(aspect_ub),
max_iter_(max_attempts) {
rnd_.seed(GetSeed());
is_deterministic_ = false;
: target_height_(target_height), // Initialize the target height member variable with the provided value
target_width_(target_width), // Initialize the target width member variable with the provided value
rnd_scale_(scale_lb, scale_ub), // Initialize the random scale generator with the provided lower and upper bounds
rnd_aspect_(log(aspect_lb), log(aspect_ub)), // Initialize the random aspect generator with the logarithm of the provided lower and upper bounds
interpolation_(interpolation), // Initialize the interpolation mode member variable with the provided value
aspect_lb_(aspect_lb), // Initialize the aspect lower bound member variable with the provided value
aspect_ub_(aspect_ub), // Initialize the aspect upper bound member variable with the provided value
max_iter_(max_attempts) { // Initialize the maximum number of attempts member variable with the provided value
rnd_.seed(GetSeed()); // Seed the random number generator with a random seed
is_deterministic_ = false; // Set the deterministic flag to false
}
Status RandomCropAndResizeOp::Compute(const TensorRow &input, TensorRow *output) {
IO_CHECK_VECTOR(input, output);
if (input.size() != 1) {
for (size_t i = 0; i < input.size() - 1; i++) {
if (input[i]->Rank() != 2 && input[i]->Rank() != 3) {
std::string err_msg = "RandomCropAndResizeOp: image shape is not <H,W,C> or <H, W>, but got rank:" +
std::to_string(input[i]->Rank());
RETURN_STATUS_UNEXPECTED(err_msg);
}
if (input[i]->shape()[0] != input[i + 1]->shape()[0] || input[i]->shape()[1] != input[i + 1]->shape()[1]) {
RETURN_STATUS_UNEXPECTED(
"RandomCropAndResizeOp: Input images in different column of each row must have the same size.");
}
// Check if the input and output vectors are valid
IO_CHECK_VECTOR(input, output);
// Check if the size of the input vector is not equal to 1
if (input.size() != 1) {
// Iterate through the input vector (except the last element)
for (size_t i = 0; i < input.size() - 1; i++) {
// Check if the rank of the current input tensor is not 2 or 3
if (input[i]->Rank() != 2 && input[i]->Rank() != 3) {
// Create an error message indicating that the image shape is not <H,W,C> or <H, W>
std::string err_msg = "RandomCropAndResizeOp: image shape is not <H,W,C> or <H, W>, but got rank:" +
std::to_string(input[i]->Rank());
// Return an unexpected status with the error message
RETURN_STATUS_UNEXPECTED(err_msg);
}
// Check if the height and width of the current input tensor is not equal to the next input tensor
if (input[i]->shape()[0] != input[i + 1]->shape()[0] || input[i]->shape()[1] != input[i + 1]->shape()[1]) {
// Return an unexpected status indicating that input images in different columns of each row must have the same size
RETURN_STATUS_UNEXPECTED(
"RandomCropAndResizeOp: Input images in different column of each row must have the same size.");
}
}
output->resize(input.size());
int x = 0;
int y = 0;
int crop_height = 0;
int crop_width = 0;
for (size_t i = 0; i < input.size(); i++) {
RETURN_IF_NOT_OK(ValidateImageRank("RandomCropAndResize", static_cast<int32_t>(input[i]->shape().Size())));
int h_in = static_cast<int>(input[i]->shape()[0]);
int w_in = static_cast<int>(input[i]->shape()[1]);
if (i == 0) {
RETURN_IF_NOT_OK(GetCropBox(h_in, w_in, &x, &y, &crop_height, &crop_width));
}
RETURN_IF_NOT_OK(CropAndResize(input[i], &(*output)[i], x, y, crop_height, crop_width, target_height_,
target_width_, interpolation_));
}
return Status::OK();
}
// Resize the output vector to match the size of the input vector
output->resize(input.size());
// Initialize variables for crop coordinates and dimensions
int x = 0;
int y = 0;
int crop_height = 0;
int crop_width = 0;
// Iterate through the input vector
for (size_t i = 0; i < input.size(); i++) {
// Validate the rank of the current input tensor
RETURN_IF_NOT_OK(ValidateImageRank("RandomCropAndResize", static_cast<int32_t>(input[i]->shape().Size())));
// Get the height and width of the current input tensor
int h_in = static_cast<int>(input[i]->shape()[0]);
int w_in = static_cast<int>(input[i]->shape()[1]);
// If it's the first input tensor, calculate the crop box coordinates and dimensions
if (i == 0) {
RETURN_IF_NOT_OK(GetCropBox(h_in, w_in, &x, &y, &crop_height, &crop_width));
}
// Crop and resize the current input tensor and store the result in the corresponding output tensor
RETURN_IF_NOT_OK(CropAndResize(input[i], &(*output)[i], x, y, crop_height, crop_width, target_height_,
target_width_, interpolation_));
}
// Return a status indicating successful computation
return Status::OK();
// This function calculates the output shape of the RandomCropAndResize operation based on the input shape.
Status RandomCropAndResizeOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Call the OutputShape function of the base class TensorOp to perform basic shape validation
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector
outputs.clear();
// Create a TensorShape object representing the desired output shape
TensorShape out = TensorShape{target_height_, target_width_};
// Check if the input tensor has rank 2
if (inputs[0].Rank() == 2) {
// Append the desired output shape to the outputs vector
(void)outputs.emplace_back(out);
}
// Check if the input tensor has rank 3
if (inputs[0].Rank() == 3) {
// Append the desired output shape with an additional dimension representing the number of channels
(void)outputs.emplace_back(out.AppendDim(inputs[0][2]));
}
// Check if the outputs vector is not empty
if (!outputs.empty()) {
// Return OK status to indicate successful output shape calculation
return Status::OK();
}
// Return an error status with a descriptive error message if the input shape is invalid
return Status(StatusCode::kMDUnexpectedError,
"RandomCropAndResize: invalid input shape, expected 2D or 3D input, but got input dimension is: " +
std::to_string(inputs[0].Rank()));
}
// This function calculates the crop box parameters for the RandomCropAndResize operation
Status RandomCropAndResizeOp::GetCropBox(int h_in, int w_in, int *x, int *y, int *crop_height, int *crop_width) {
// Check if crop_height is nullptr
CHECK_FAIL_RETURN_UNEXPECTED(crop_height != nullptr, "crop_height is nullptr.");
// Check if crop_width is nullptr
CHECK_FAIL_RETURN_UNEXPECTED(crop_width != nullptr, "crop_width is nullptr.");
// Set crop_width to the width of the input tensor
*crop_width = w_in;
// Set crop_height to the height of the input tensor
*crop_height = h_in;
// Check if the width of the input tensor is not 0
CHECK_FAIL_RETURN_UNEXPECTED(w_in != 0, "RandomCropAndResize: Width of input cannot be 0.");
// Check if the height of the input tensor is not 0
CHECK_FAIL_RETURN_UNEXPECTED(h_in != 0, "RandomCropAndResize: Height of input cannot be 0.");
// Check if aspect_lb_ is greater than 0
CHECK_FAIL_RETURN_UNEXPECTED(
aspect_lb_ > 0,
"RandomCropAndResize: 'ratio'(aspect) lower bound must be greater than 0, but got:" + std::to_string(aspect_lb_));
// Iterate for max_iter_ number of times
for (int32_t i = 0; i < max_iter_; i++) {
// Generate a random scale value using rnd_scale_
double const sample_scale = rnd_scale_(rnd_);
// In case of non-symmetrical aspect ratios, use uniform distribution on a logarithmic sample_scale.
// Note rnd_aspect_ is already a random distribution of the input aspect ratio in logarithmic sample_scale.
// Generate a random aspect value using rnd_aspect_ and convert it to linear scale using exp
double const sample_aspect = exp(rnd_aspect_(rnd_));
// ... (additional code not provided)
}
}
// Check if the multiplication of the maximum value of int32_t divided by h_in is greater than w_in
// If it is not, then it means the multiplication is out of bounds and we need to check the image width and height
CHECK_FAIL_RETURN_UNEXPECTED(
(std::numeric_limits<int32_t>::max() / h_in) > w_in,
"RandomCropAndResizeOp: multiplication out of bounds, check image width and image height first.");
// Check if the multiplication of the maximum value of int32_t divided by h_in divided by w_in is greater than sample_scale
// If it is not, then it means the multiplication is out of bounds and we need to check the image width, height, and sample scale
CHECK_FAIL_RETURN_UNEXPECTED(
static_cast<double>((std::numeric_limits<int32_t>::max() / h_in) / w_in) > sample_scale,
"RandomCropAndResizeOp: multiplication out of bounds, check image width, image height and sample scale first.");
// Check if the multiplication of the maximum value of int32_t divided by h_in divided by w_in divided by sample_scale is greater than sample_aspect
// If it is not, then it means the multiplication is out of bounds and we need to check the image width, height, sample scale, and sample aspect
CHECK_FAIL_RETURN_UNEXPECTED(
(static_cast<double>((std::numeric_limits<int32_t>::max() / h_in) / w_in) / sample_scale) > sample_aspect,
"RandomCropAndResizeOp: multiplication out of bounds, check image width, image "
"height, sample scale and sample aspect first.");
"RandomCropAndResizeOp: multiplication out of bounds, check image width, image height, sample scale and sample aspect first.");
// Calculate the crop width by rounding the square root of the multiplication of h_in, w_in, sample_scale, and sample_aspect
*crop_width = static_cast<int32_t>(std::round(std::sqrt(h_in * w_in * sample_scale * sample_aspect)));
// Calculate the crop height by dividing the crop width by the sample aspect ratio and rounding the result
*crop_height = static_cast<int32_t>(std::round(*crop_width / sample_aspect));
// forbidden crop_width or crop_height is zero
// Check if crop_width is less than or equal to zero
if (*crop_width <= 0) {
// If so, set crop_width to 1
*crop_width = 1;
}
// Check if crop_height is less than or equal to zero
if (*crop_height <= 0) {
// If so, set crop_height to 1
*crop_height = 1;
}
if (*crop_width <= w_in && *crop_height <= h_in) {
std::uniform_int_distribution<> rd_x(0, w_in - *crop_width);
std::uniform_int_distribution<> rd_y(0, h_in - *crop_height);
*x = rd_x(rnd_);
*y = rd_y(rnd_);
return Status::OK();
// If the desired crop width and height are smaller than or equal to the input width and height,
// generate random x and y coordinates within the valid range
std::uniform_int_distribution<> rd_x(0, w_in - *crop_width);
std::uniform_int_distribution<> rd_y(0, h_in - *crop_height);
*x = rd_x(rnd_);
*y = rd_y(rnd_);
return Status::OK();
}
}
double const img_aspect = static_cast<double>(w_in) / h_in;
if (img_aspect < aspect_lb_) {
}
// Calculate the aspect ratio of the image
double const img_aspect = static_cast<double>(w_in) / h_in;
// Check if the image aspect ratio is less than the lower bound aspect ratio
if (img_aspect < aspect_lb_) {
// If so, set the crop width to the input width and calculate the crop height based on the lower bound aspect ratio
*crop_width = w_in;
*crop_height = static_cast<int32_t>(std::round(*crop_width / static_cast<double>(aspect_lb_)));
} else {
} else {
// If the image aspect ratio is not less than the lower bound aspect ratio,
// check if it is greater than the upper bound aspect ratio
if (img_aspect > aspect_ub_) {
*crop_height = h_in;
*crop_width = static_cast<int32_t>(std::round(*crop_height * static_cast<double>(aspect_ub_)));
// If so, set the crop height to the input height and calculate the crop width based on the upper bound aspect ratio
*crop_height = h_in;
*crop_width = static_cast<int32_t>(std::round(*crop_height * static_cast<double>(aspect_ub_)));
} else {
*crop_width = w_in;
*crop_height = h_in;
// If the image aspect ratio is within the valid range, set the crop width and height to the input width and height
*crop_width = w_in;
*crop_height = h_in;
}
}
constexpr float crop_ratio = 2.0;
// forbidden crop_width or crop_height is zero
if (*crop_width <= 0) {
*crop_width = 1;
}
if (*crop_height <= 0) {
*crop_height = 1;
}
*x = static_cast<int32_t>(std::round((w_in - *crop_width) / crop_ratio));
*y = static_cast<int32_t>(std::round((h_in - *crop_height) / crop_ratio));
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
// Set a constant crop ratio
constexpr float crop_ratio = 2.0;
// Check if the crop width is zero, and if so, set it to 1
if (*crop_width <= 0) {
*crop_width = 1;
}
// Check if the crop height is zero, and if so, set it to 1
if (*crop_height <= 0) {
*crop_height = 1;
}
*x = static_cast<int32_t>(std::round((w_in - *crop_width) / crop_ratio)); // Calculate the value of x by subtracting crop_width from w_in, dividing the result by crop_ratio, and rounding it to the nearest integer. Store the result in the memory location pointed to by x.
*y = static_cast<int32_t>(std::round((h_in - *crop_height) / crop_ratio)); // Calculate the value of y by subtracting crop_height from h_in, dividing the result by crop_ratio, and rounding it to the nearest integer. Store the result in the memory location pointed to by y.
return Status::OK(); // Return a Status object indicating that the function execution was successful.
}
} // namespace dataset // End of the dataset namespace
} // namespace mindspore // End of the mindspore namespace

View File

@ -14,46 +14,93 @@
* limitations under the License.
*/
// Include the header file "random_crop_and_resize_with_bbox_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/random_crop_and_resize_with_bbox_op.h"
// Include the utility header, which provides various utility components and functions
#include <utility>
// Include the header file for the bounding box operations in the MindData dataset kernels
#include "minddata/dataset/kernels/image/bounding_box.h"
// Include the header file for the image utility functions in the MindData dataset kernels
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility functions in the MindData dataset
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
Status RandomCropAndResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
IO_CHECK_VECTOR(input, output);
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
RETURN_IF_NOT_OK(ValidateImageRank("RandomCropAndResizeWithBBox", static_cast<int32_t>(input[0]->shape().Size())));
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
const int output_count = 2;
output->resize(output_count);
(*output)[1] = std::move(input[1]); // move boxes over to output
// Code specific to the "dataset" namespace can be written here
size_t bboxCount = input[1]->shape()[0]; // number of rows in bbox tensor
int h_in = input[0]->shape()[0];
int w_in = input[0]->shape()[1];
int x = 0;
int y = 0;
int crop_height = 0;
int crop_width = 0;
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Check if the input and output are vectors
IO_CHECK_VECTOR(input, output);
// Validate the bounding boxes in the input
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
// Validate the rank of the input image tensor
RETURN_IF_NOT_OK(ValidateImageRank("RandomCropAndResizeWithBBox", static_cast<int32_t>(input[0]->shape().Size())));
// Define a constant integer variable named "output_count" and assign it the value 2
const int output_count = 2;
// Resize the "output" vector to have a size of "output_count"
output->resize(output_count);
// Move the value at index 1 of the "input" vector to index 1 of the "output" vector
(*output)[1] = std::move(input[1]); // move boxes over to output
// Get the number of rows in the bbox tensor and store it in the variable bboxCount
size_t bboxCount = input[1]->shape()[0];
// Get the height and width of the input tensor and store them in the variables h_in and w_in respectively
int h_in = input[0]->shape()[0];
int w_in = input[0]->shape()[1];
// Initialize the variables x, y, crop_height, and crop_width to 0
int x = 0;
int y = 0;
int crop_height = 0;
int crop_width = 0;
// Call the GetCropBox function of the RandomCropAndResizeOp class to obtain the crop box coordinates and dimensions
// Pass the input height (h_in), input width (w_in), and pointers to variables x, y, crop_height, and crop_width
// The function will modify the values of x, y, crop_height, and crop_width based on the input dimensions
// If the function returns an error code, immediately return that error code
RETURN_IF_NOT_OK(RandomCropAndResizeOp::GetCropBox(h_in, w_in, &x, &y, &crop_height, &crop_width));
int maxX = x + crop_width; // max dims of selected CropBox on image
int maxY = y + crop_height;
// Calculate the maximum x-coordinate of the selected CropBox on the image
int maxX = x + crop_width;
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForCrop(&(*output)[1], &bboxCount, x, y, maxX, maxY)); // IMAGE_UTIL
RETURN_IF_NOT_OK(CropAndResize(input[0], &(*output)[0], x, y, crop_height, crop_width, target_height_, target_width_,
interpolation_));
// Calculate the maximum y-coordinate of the selected CropBox on the image
int maxY = y + crop_height;
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForResize((*output)[1], bboxCount, target_width_, target_height_,
// Call the UpdateBBoxesForCrop function from the BoundingBox class to update the bounding boxes for the cropped image
// Pass the address of the second element of the output vector, the address of the bboxCount variable, and the x, y, maxX, maxY values as arguments
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForCrop(&(*output)[1], &bboxCount, x, y, maxX, maxY)); // IMAGE_UTIL
// Call the CropAndResize function to crop and resize the input image
// Pass the first element of the input vector, the address of the first element of the output vector, x, y, crop_height, crop_width, target_height_, target_width_, and interpolation_ as arguments
RETURN_IF_NOT_OK(CropAndResize(input[0], &(*output)[0], x, y, crop_height, crop_width, target_height_, target_width_, interpolation_));
// Check if the return value of the function call to UpdateBBoxesForResize is not OK, and return immediately if it is not OK
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForResize((*output)[1], bboxCount, target_width_, target_height_,
crop_width, crop_height));
return Status::OK();
}
// Return a Status object indicating that the function execution was successful
return Status::OK();
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -19,45 +19,93 @@
#include "minddata/dataset/core/config_manager.h"
#include "minddata/dataset/kernels/image/decode_op.h"
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace
namespace dataset {
// Implementation of the constructor for the RandomCropDecodeResizeOp class
RandomCropDecodeResizeOp::RandomCropDecodeResizeOp(int32_t target_height, int32_t target_width, float scale_lb,
float scale_ub, float aspect_lb, float aspect_ub,
InterpolationMode interpolation, int32_t max_attempts)
// Call the constructor of the base class RandomCropAndResizeOp with the provided arguments
: RandomCropAndResizeOp(target_height, target_width, scale_lb, scale_ub, aspect_lb, aspect_ub, interpolation,
max_attempts) {}
// End of the "dataset" namespace
} // namespace dataset
// End of the "mindspore" namespace
} // namespace mindspore
// The Compute function of the RandomCropDecodeResizeOp class
Status RandomCropDecodeResizeOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output vectors are valid
IO_CHECK_VECTOR(input, output);
// Get the number of elements in the input vector
const auto output_count = input.size();
// Resize the output vector to match the size of the input vector
output->resize(output_count);
// Initialize variables for crop coordinates and dimensions
int x = 0;
int y = 0;
int crop_height = 0;
int crop_width = 0;
// Create a TensorRow to store the decoded images
TensorRow decoded;
decoded.resize(output_count);
// Iterate over each element in the input vector
for (size_t i = 0; i < input.size(); i++) {
// Check if the input image is empty (nullptr)
if (input[i] == nullptr) {
RETURN_STATUS_UNEXPECTED("RandomCropDecodeResize: input image is empty since got nullptr.");
}
// Check if the input image is a non-empty JPEG image
if (!IsNonEmptyJPEG(input[i])) {
// Create a DecodeOp object and compute the decoding operation on the input image
DecodeOp op(true);
RETURN_IF_NOT_OK(op.Compute(input[i], &decoded[i]));
// Compute the random crop and resize operation on the decoded image
RETURN_IF_NOT_OK(RandomCropAndResizeOp::Compute(decoded, output));
} else {
// Get the width and height of the JPEG image
int h_in = 0;
int w_in = 0;
RETURN_IF_NOT_OK(GetJpegImageInfo(input[i], &w_in, &h_in));
// If this is the first image, compute the crop box coordinates and dimensions
if (i == 0) {
RETURN_IF_NOT_OK(GetCropBox(h_in, w_in, &x, &y, &crop_height, &crop_width));
}
// Create a shared pointer to store the decoded tensor
std::shared_ptr<Tensor> decoded_tensor = nullptr;
// Crop and decode the JPEG image using the specified crop coordinates and dimensions
RETURN_IF_NOT_OK(JpegCropAndDecode(input[i], &decoded_tensor, x, y, crop_width, crop_height));
// Resize the decoded tensor to the target height and width using the specified interpolation method
RETURN_IF_NOT_OK(Resize(decoded_tensor, &(*output)[i], target_height_, target_width_, 0.0, 0.0, interpolation_));
}
}
// Return OK status to indicate successful computation
return Status::OK();
}
// Close the namespace blocks for dataset and mindspore
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -20,61 +20,93 @@
#include "minddata/dataset/util/random.h"
#include "minddata/dataset/util/status.h"
// Define the namespace "mindspore" for the code
namespace mindspore {
namespace dataset {
const int32_t RandomCropOp::kDefPadTop = 0;
const int32_t RandomCropOp::kDefPadBottom = 0;
const int32_t RandomCropOp::kDefPadLeft = 0;
const int32_t RandomCropOp::kDefPadRight = 0;
const BorderType RandomCropOp::kDefBorderType = BorderType::kConstant;
const bool RandomCropOp::kDefPadIfNeeded = false;
const uint8_t RandomCropOp::kDefFillR = 0;
const uint8_t RandomCropOp::kDefFillG = 0;
const uint8_t RandomCropOp::kDefFillB = 0;
// Define the nested namespace "dataset" for the code
namespace dataset {
// Define the constant integer variables for the default padding values of the RandomCropOp class
const int32_t RandomCropOp::kDefPadTop = 0;
const int32_t RandomCropOp::kDefPadBottom = 0;
const int32_t RandomCropOp::kDefPadLeft = 0;
const int32_t RandomCropOp::kDefPadRight = 0;
// Define the constant BorderType variable for the default border type of the RandomCropOp class
const BorderType RandomCropOp::kDefBorderType = BorderType::kConstant;
// Define the constant boolean variable for the default padIfNeeded value of the RandomCropOp class
const bool RandomCropOp::kDefPadIfNeeded = false;
// Define the constant unsigned integer variables for the default fill values of the RandomCropOp class
const uint8_t RandomCropOp::kDefFillR = 0;
const uint8_t RandomCropOp::kDefFillG = 0;
const uint8_t RandomCropOp::kDefFillB = 0;
}
}
// Constructor for the RandomCropOp class
RandomCropOp::RandomCropOp(int32_t crop_height, int32_t crop_width, int32_t pad_top, int32_t pad_bottom,
int32_t pad_left, int32_t pad_right, bool pad_if_needed, BorderType padding_mode,
uint8_t fill_r, uint8_t fill_g, uint8_t fill_b)
: crop_height_(crop_height),
crop_width_(crop_width),
pad_top_(pad_top),
pad_bottom_(pad_bottom),
pad_left_(pad_left),
pad_right_(pad_right),
pad_if_needed_(pad_if_needed),
border_type_(padding_mode),
fill_r_(fill_r),
fill_g_(fill_g),
fill_b_(fill_b) {
rnd_.seed(GetSeed());
is_deterministic_ = false;
: crop_height_(crop_height), // Initialize the crop height member variable with the provided value
crop_width_(crop_width), // Initialize the crop width member variable with the provided value
pad_top_(pad_top), // Initialize the pad top member variable with the provided value
pad_bottom_(pad_bottom), // Initialize the pad bottom member variable with the provided value
pad_left_(pad_left), // Initialize the pad left member variable with the provided value
pad_right_(pad_right), // Initialize the pad right member variable with the provided value
pad_if_needed_(pad_if_needed), // Initialize the pad if needed member variable with the provided value
border_type_(padding_mode), // Initialize the border type member variable with the provided value
fill_r_(fill_r), // Initialize the fill red member variable with the provided value
fill_g_(fill_g), // Initialize the fill green member variable with the provided value
fill_b_(fill_b) { // Initialize the fill blue member variable with the provided value
rnd_.seed(GetSeed()); // Seed the random number generator with a random seed
is_deterministic_ = false; // Set the deterministic flag to false
}
Status RandomCropOp::ImagePadding(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *pad_image,
int32_t *t_pad_top, int32_t *t_pad_bottom, int32_t *t_pad_left, int32_t *t_pad_right,
int32_t *padded_image_w, int32_t *padded_image_h, bool *crop_further) {
// Set the value of t_pad_top to the value of pad_top_
*t_pad_top = pad_top_;
// Set the value of t_pad_bottom to the value of pad_bottom_
*t_pad_bottom = pad_bottom_;
// Set the value of t_pad_left to the value of pad_left_
*t_pad_left = pad_left_;
// Set the value of t_pad_right to the value of pad_right_
*t_pad_right = pad_right_;
constexpr int64_t max_ratio = 3;
CHECK_FAIL_RETURN_UNEXPECTED(
pad_top_ < input->shape()[0] * max_ratio && pad_bottom_ < input->shape()[0] * max_ratio &&
pad_left_ < input->shape()[1] * max_ratio && pad_right_ < input->shape()[1] * max_ratio,
"Pad: padding size is three times bigger than the image size, padding top: " + std::to_string(pad_top_) +
", padding bottom: " + std::to_string(pad_bottom_) + ", padding pad_left_: " + std::to_string(pad_left_) +
", padding padding right:" + std::to_string(pad_right_) + ", image shape: " + std::to_string(input->shape()[0]) +
", " + std::to_string(input->shape()[1]));
// Define a constant variable `max_ratio` with a value of 3
constexpr int64_t max_ratio = 3;
// Check if the padding values are within the allowed range, which is three times the size of the input image
// If any of the padding values exceed the allowed range, return an error message
CHECK_FAIL_RETURN_UNEXPECTED(
pad_top_ < input->shape()[0] * max_ratio && pad_bottom_ < input->shape()[0] * max_ratio &&
pad_left_ < input->shape()[1] * max_ratio && pad_right_ < input->shape()[1] * max_ratio,
"Pad: padding size is three times bigger than the image size, padding top: " + std::to_string(pad_top_) +
", padding bottom: " + std::to_string(pad_bottom_) + ", padding pad_left_: " + std::to_string(pad_left_) +
", padding padding right:" + std::to_string(pad_right_) + ", image shape: " + std::to_string(input->shape()[0]) +
", " + std::to_string(input->shape()[1]));
// The error message includes the values of the padding variables (pad_top_, pad_bottom_, pad_left_, pad_right_)
// as well as the shape of the input image (input->shape()[0], input->shape()[1])
// Call the Pad function with the provided parameters and check if it returns OK. If not, return immediately.
RETURN_IF_NOT_OK(
Pad(input, pad_image, pad_top_, pad_bottom_, pad_left_, pad_right_, border_type_, fill_r_, fill_g_, fill_b_));
// Check if the size of the image after padding is at least 2. If not, return an error message.
CHECK_FAIL_RETURN_UNEXPECTED(
(*pad_image)->shape().Size() >= 2,
"RandomCrop: invalid shape of image after pad, got rank: " + std::to_string((*pad_image)->shape().Size()));
*padded_image_h = (*pad_image)->shape()[0];
*padded_image_w = (*pad_image)->shape()[1];
// Dereference the pointer to get the shape of the padded image and assign the first dimension to padded_image_h
*padded_image_h = (*pad_image)->shape()[0];
// Dereference the pointer to get the shape of the padded image and assign the second dimension to padded_image_w
*padded_image_w = (*pad_image)->shape()[1];
if (*padded_image_h == crop_height_ && *padded_image_w == crop_width_) {
*crop_further = false; // no need for further crop
@ -82,103 +114,174 @@ Status RandomCropOp::ImagePadding(const std::shared_ptr<Tensor> &input, std::sha
} else if (pad_if_needed_) {
// check the dimensions of the image for padding, if we do need padding, then we change the pad values
if (*padded_image_h < crop_height_) {
// Call the Pad function to pad the image with the required dimensions
RETURN_IF_NOT_OK(Pad(*pad_image, pad_image, crop_height_ - *padded_image_h, crop_height_ - *padded_image_h, 0, 0,
border_type_, fill_r_, fill_g_, fill_b_));
// update pad total above/below
t_pad_top += ((ptrdiff_t)crop_height_ - *padded_image_h);
t_pad_bottom += ((ptrdiff_t)crop_height_ - *padded_image_h);
// Continue with the execution if the padding is successful
// Otherwise, return the error status
// Note: RETURN_IF_NOT_OK is a macro that checks the status and returns if it is not OK
// It is used here to handle the error condition and return the error status immediately
// without executing the remaining code in the function
// The Pad function is expected to return a Status object indicating the success or failure of the operation
// The arguments passed to the Pad function specify the amount of padding required in each dimension,
// the border type, and the fill color for the padded pixels
// The pad_image is passed as both the input and output image, indicating that it will be modified in-place
}
if (*padded_image_w < crop_width_) {
RETURN_IF_NOT_OK(Pad(*pad_image, pad_image, 0, 0, crop_width_ - *padded_image_w, crop_width_ - *padded_image_w,
border_type_, fill_r_, fill_g_, fill_b_));
// update pad total left/right
t_pad_left += ((ptrdiff_t)crop_width_ - *padded_image_w);
t_pad_right += ((ptrdiff_t)crop_width_ - *padded_image_w);
}
*padded_image_h = (*pad_image)->shape()[0];
*padded_image_w = (*pad_image)->shape()[1];
}
// If the width of the padded image is smaller than the desired crop width
if (*padded_image_w < crop_width_) {
// Pad the image on the left and right sides to match the crop width
RETURN_IF_NOT_OK(Pad(*pad_image, pad_image, 0, 0, crop_width_ - *padded_image_w, crop_width_ - *padded_image_w,
border_type_, fill_r_, fill_g_, fill_b_));
// Update the total padding on the left and right sides
t_pad_left += ((ptrdiff_t)crop_width_ - *padded_image_w);
t_pad_right += ((ptrdiff_t)crop_width_ - *padded_image_w);
}
// Update the height and width of the padded image
*padded_image_h = (*pad_image)->shape()[0];
*padded_image_w = (*pad_image)->shape()[1];
}
// Check if crop height or crop width is zero
if (crop_height_ == 0 || crop_width_ == 0) {
// Return an error status with a message indicating that crop size cannot be zero
return Status(StatusCode::kMDShapeMisMatch, __LINE__, __FILE__,
"RandomCrop: invalid crop size, crop width or crop height is not allowed to be zero.");
}
// Check if crop size is bigger than the image dimensions
if (*padded_image_h < crop_height_ || *padded_image_w < crop_width_ || crop_height_ == 0 || crop_width_ == 0) {
// Return an error status with a message indicating the invalid crop size
return Status(StatusCode::kMDShapeMisMatch, __LINE__, __FILE__,
"RandomCrop: invalid crop size, crop size is bigger than the image dimensions, got crop height: " +
std::to_string(crop_height_) + ", crop width: " + std::to_string(crop_width_));
}
return Status::OK();
}
// Return a success status
return Status::OK();
// This function generates random x and y coordinates for cropping an image
void RandomCropOp::GenRandomXY(int *x, int *y, const int32_t &padded_image_w, const int32_t &padded_image_h) {
// GenCropPoints for cropping
// Generate a random x coordinate within the range [0, padded_image_w - crop_width_]
*x = std::uniform_int_distribution<int>(0, padded_image_w - crop_width_)(rnd_);
// Generate a random y coordinate within the range [0, padded_image_h - crop_height_]
*y = std::uniform_int_distribution<int>(0, padded_image_h - crop_height_)(rnd_);
}
Status RandomCropOp::Compute(const TensorRow &input, TensorRow *output) {
IO_CHECK_VECTOR(input, output);
if (input.size() > 1) {
for (size_t i = 0; i < input.size() - 1; i++) {
if (input[i]->Rank() != 2 && input[i]->Rank() != 3) {
std::string err_msg =
"RandomCropOp: image shape is not <H,W,C> or <H, W>, but got rank:" + std::to_string(input[i]->Rank());
RETURN_STATUS_UNEXPECTED(err_msg);
}
if (input[i]->shape()[0] != input[i + 1]->shape()[0] || input[i]->shape()[1] != input[i + 1]->shape()[1]) {
RETURN_STATUS_UNEXPECTED(
"RandomCropOp: Input images in different column must have the same shape, check the output shape in "
"specified 'input_columns' before call this operation.");
}
}
}
int x = 0;
int y = 0;
const auto output_count = input.size();
output->resize(output_count);
for (size_t i = 0; i < input.size(); i++) {
RETURN_IF_NOT_OK(ValidateImageRank("RandomCrop", static_cast<int32_t>(input[i]->shape().Size())));
std::shared_ptr<Tensor> pad_image = nullptr;
int32_t t_pad_top = 0;
int32_t t_pad_bottom = 0;
int32_t t_pad_left = 0;
int32_t t_pad_right = 0;
int32_t padded_image_w = 0;
int32_t padded_image_h = 0;
bool crop_further = true; // whether image needs further cropping based on new size & requirements
// Check if the input and output vectors are valid
IO_CHECK_VECTOR(input, output);
RETURN_IF_NOT_OK( // error code sent back directly
ImagePadding(input[i], &pad_image, &t_pad_top, &t_pad_bottom, &t_pad_left, &t_pad_right, &padded_image_w,
&padded_image_h, &crop_further));
if (!crop_further) {
(*output)[i] = pad_image;
continue;
// If there is more than one input tensor
if (input.size() > 1) {
// Iterate through each input tensor except the last one
for (size_t i = 0; i < input.size() - 1; i++) {
// Check if the rank of the input tensor is not 2 or 3
if (input[i]->Rank() != 2 && input[i]->Rank() != 3) {
// Create an error message indicating the incorrect rank of the input tensor
std::string err_msg = "RandomCropOp: image shape is not <H,W,C> or <H, W>, but got rank:" + std::to_string(input[i]->Rank());
// Return an unexpected status with the error message
RETURN_STATUS_UNEXPECTED(err_msg);
}
if (i == 0) {
GenRandomXY(&x, &y, padded_image_w, padded_image_h);
// Check if the shape of the current input tensor is different from the shape of the next input tensor
if (input[i]->shape()[0] != input[i + 1]->shape()[0] || input[i]->shape()[1] != input[i + 1]->shape()[1]) {
// Return an unexpected status indicating that input images in different columns must have the same shape
RETURN_STATUS_UNEXPECTED("RandomCropOp: Input images in different column must have the same shape, check the output shape in specified 'input_columns' before call this operation.");
}
RETURN_IF_NOT_OK(Crop(pad_image, &(*output)[i], x, y, crop_width_, crop_height_));
}
return Status::OK();
}
// Initialize variables for x and y coordinates
int x = 0;
int y = 0;
// Get the number of output tensors
const auto output_count = input.size();
// Resize the output vector to match the number of output tensors
output->resize(output_count);
// Iterate through each input tensor
for (size_t i = 0; i < input.size(); i++) {
// Validate the rank of the input tensor
RETURN_IF_NOT_OK(ValidateImageRank("RandomCrop", static_cast<int32_t>(input[i]->shape().Size())));
// Create a shared pointer for the padded image
std::shared_ptr<Tensor> pad_image = nullptr;
// Initialize variables for padding
int32_t t_pad_top = 0;
int32_t t_pad_bottom = 0;
int32_t t_pad_left = 0;
int32_t t_pad_right = 0;
int32_t padded_image_w = 0;
int32_t padded_image_h = 0;
// Initialize a boolean variable to determine if further cropping is needed
bool crop_further = true;
// ...
}
RETURN_IF_NOT_OK( // error code sent back directly
ImagePadding(input[i], &pad_image, &t_pad_top, &t_pad_bottom, &t_pad_left, &t_pad_right, &padded_image_w,
&padded_image_h, &crop_further));
// If crop_further is false, assign pad_image to the corresponding element in the output vector and continue to the next iteration
if (!crop_further) {
(*output)[i] = pad_image;
continue;
}
// If i is 0, generate random x and y coordinates within the bounds of the padded image
if (i == 0) {
GenRandomXY(&x, &y, padded_image_w, padded_image_h);
}
// Crop the pad_image using the generated x and y coordinates, crop_width_, and crop_height_, and assign the result to the corresponding element in the output vector
RETURN_IF_NOT_OK(Crop(pad_image, &(*output)[i], x, y, crop_width_, crop_height_));
}
// Return a Status object indicating successful program termination
return Status::OK();
// Define the function OutputShape for the RandomCropOp class
Status RandomCropOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Call the OutputShape function of the base class TensorOp and check for any errors
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector
outputs.clear();
// Create a TensorShape object with the specified crop height and width
TensorShape out = TensorShape{crop_height_, crop_width_};
// Check if the rank of the input tensor is 2
if (inputs[0].Rank() == 2) {
// Append the specified crop height and width to the output shape
(void)outputs.emplace_back(out);
} else if (inputs[0].Rank() == 3) {
}
// Check if the rank of the input tensor is 3
else if (inputs[0].Rank() == 3) {
// Append the specified crop height, width, and the third dimension of the input tensor to the output shape
(void)outputs.emplace_back(out.AppendDim(inputs[0][2]));
}
// Check if the outputs vector is not empty
if (!outputs.empty()) {
// Return OK status to indicate successful output shape calculation
return Status::OK();
}
// Return an error status with a message indicating the invalid input shape
return Status(StatusCode::kMDUnexpectedError,
"RandomCrop: invalid input shape, expected 2D or 3D input, but got input dimension is:" +
std::to_string(inputs[0].Rank()));
}
// Close the namespace for the dataset
} // namespace dataset
} // namespace mindspore
// Close the namespace for the mindspore
} // namespace mindspore

View File

@ -14,55 +14,101 @@
* limitations under the License.
*/
// Include the header file "random_crop_with_bbox_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/random_crop_with_bbox_op.h"
// Include the utility header, which provides various utility functions and classes
#include <utility>
// Include the header file for the bounding box operations in the MindData dataset kernels
#include "minddata/dataset/kernels/image/bounding_box.h"
// Include the header file for the image utility functions in the MindData dataset kernels
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility functions in the MindData dataset
#include "minddata/dataset/util/status.h"
// Start of the namespace "mindspore"
namespace mindspore {
namespace dataset {
Status RandomCropWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
IO_CHECK_VECTOR(input, output);
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
// Start of the namespace "dataset"
namespace dataset {
// Implementation of the Compute function of the RandomCropWithBBoxOp class
Status RandomCropWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output are vectors
IO_CHECK_VECTOR(input, output);
// Validate the bounding boxes in the input
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
// Rest of the function implementation goes here
} // End of the Compute function
} // End of the namespace "dataset"
} // End of the namespace "mindspore"
std::shared_ptr<Tensor> pad_image = nullptr;
int32_t t_pad_top = 0;
int32_t t_pad_bottom = 0;
int32_t t_pad_left = 0;
int32_t t_pad_right = 0;
size_t boxCount = input[1]->shape()[0]; // number of rows
// Declare a shared pointer named "pad_image" of type "Tensor" and initialize it to nullptr
std::shared_ptr<Tensor> pad_image = nullptr;
int32_t padded_image_h = 0;
int32_t padded_image_w = 0;
const int output_count = 2;
output->resize(output_count);
(*output)[1] = std::move(input[1]); // since some boxes may be removed
// Declare four integer variables named "t_pad_top", "t_pad_bottom", "t_pad_left", and "t_pad_right" and initialize them to 0
int32_t t_pad_top = 0;
int32_t t_pad_bottom = 0;
int32_t t_pad_left = 0;
int32_t t_pad_right = 0;
bool crop_further = true; // Whether further cropping will be required or not, true unless required size matches
RETURN_IF_NOT_OK( // Error passed back to caller
RandomCropOp::ImagePadding(input[0], &pad_image, &t_pad_top, &t_pad_bottom, &t_pad_left, &t_pad_right,
// Declare a size_t variable named "boxCount" and assign it the value of the number of rows in the shape of the "input[1]" tensor
size_t boxCount = input[1]->shape()[0];
// Declare and initialize variables for the height and width of the padded image
int32_t padded_image_h = 0;
int32_t padded_image_w = 0;
// Declare a constant variable for the number of outputs
const int output_count = 2;
// Resize the output vector to have a size of output_count
output->resize(output_count);
// Move the second element of the input vector to the second element of the output vector
(*output)[1] = std::move(input[1]); // since some boxes may be removed
// A boolean variable to determine whether further cropping will be required or not
bool crop_further = true;
// Call the ImagePadding function from the RandomCropOp class to calculate the padding values and determine if further cropping is needed
// The function takes the input image and several output parameters to store the padded image, padding values, and dimensions of the padded image
// The function also updates the crop_further variable based on whether the required size matches or not
RETURN_IF_NOT_OK(RandomCropOp::ImagePadding(input[0], &pad_image, &t_pad_top, &t_pad_bottom, &t_pad_left, &t_pad_right,
&padded_image_w, &padded_image_h, &crop_further));
// update bounding boxes with new values based on relevant image padding
// If there is padding on the left or top of the image, update the bounding boxes
// by padding them with the corresponding values
if (t_pad_left || t_pad_top) {
// Call the PadBBoxes function to update the bounding boxes
RETURN_IF_NOT_OK(BoundingBox::PadBBoxes(&(*output)[1], boxCount, t_pad_top, t_pad_left));
}
// If no further cropping is required
if (!crop_further) {
// no further cropping required
// Set the first element of the output vector to the padded image
(*output)[0] = pad_image;
// Move the second element of the input vector to the second element of the output vector
(*output)[1] = std::move(input[1]);
// Return OK status to indicate successful execution
return Status::OK();
}
int x, y;
RandomCropOp::GenRandomXY(&x, &y, padded_image_w, padded_image_h);
int maxX = x + RandomCropOp::crop_width_; // max dims of selected CropBox on image
int maxY = y + RandomCropOp::crop_height_;
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForCrop(&(*output)[1], &boxCount, x, y, maxX, maxY));
return Crop(pad_image, &(*output)[0], x, y, RandomCropOp::crop_width_, RandomCropOp::crop_height_);
int x, y; // Declare variables x and y to store the random coordinates
RandomCropOp::GenRandomXY(&x, &y, padded_image_w, padded_image_h); // Generate random x and y coordinates within the padded image dimensions
int maxX = x + RandomCropOp::crop_width_; // Calculate the maximum x coordinate of the selected CropBox on the image
int maxY = y + RandomCropOp::crop_height_; // Calculate the maximum y coordinate of the selected CropBox on the image
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForCrop(&(*output)[1], &boxCount, x, y, maxX, maxY)); // Update the bounding boxes for the crop operation
return Crop(pad_image, &(*output)[0], x, y, RandomCropOp::crop_width_, RandomCropOp::crop_height_); // Perform the crop operation on the padded image and store the result in the output variable
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -15,20 +15,42 @@
*/
#include "minddata/dataset/kernels/image/random_equalize_op.h"
// Include the header file for image utilities from the MindData library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility from the MindData library
#include "minddata/dataset/util/status.h"
// The code is defining a namespace called "mindspore" which contains another namespace called "dataset"
namespace mindspore {
namespace dataset {
// The code is defining a constant float variable called "kDefProbability" and initializing it with the value 0.5
const float RandomEqualizeOp::kDefProbability = 0.5;
// Implementation of the Compute function for the RandomEqualizeOp class
// Include the necessary headers
// Define the Compute function
Status RandomEqualizeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Generate a random number using the distribution and random number generator
if (distribution_(rnd_)) {
// If the random number satisfies the condition, call the Equalize function
return Equalize(input, output);
}
// If the random number does not satisfy the condition, assign the input tensor to the output tensor
*output = input;
// Return OK status to indicate successful computation
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
// End of namespace dataset
} // namespace mindspore

View File

@ -15,25 +15,63 @@
*/
#include "minddata/dataset/kernels/image/random_horizontal_flip_op.h"
// Include the header file for image utilities from the MindData library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility from the MindData library
#include "minddata/dataset/util/status.h"
// Define the namespace "mindspore" for encapsulating related code
namespace mindspore {
// Define the nested namespace "dataset" for encapsulating dataset-related code
namespace dataset {
// Define the constant float variable "kDefProbability" with a default value of 0.5
const float RandomHorizontalFlipOp::kDefProbability = 0.5;
// Define the implementation of the Compute function for the RandomHorizontalFlipOp class
// Include the necessary headers for the required types and functions
#include <mindspore/dataset/engine/datasetops/source/sampler/random_horizontal_flip_op.h>
#include <mindspore/dataset/util/status.h>
namespace mindspore {
namespace dataset {
const float RandomHorizontalFlipOp::kDefProbability = 0.5;
// Compute function implementation
Status RandomHorizontalFlipOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output vectors are valid
IO_CHECK_VECTOR(input, output);
// Get the size of the input vector
const auto output_count = input.size();
// Resize the output vector to match the size of the input vector
output->resize(output_count);
// Check if the random number generated by the distribution is within the desired range
if (distribution_(rnd_)) {
// Iterate over each element in the input vector
for (size_t i = 0; i < input.size(); i++) {
// Call the HorizontalFlip function to perform the horizontal flip operation on the input tensor
RETURN_IF_NOT_OK(HorizontalFlip(input[i], &(*output)[i]));
}
// Return OK status to indicate successful operation
return Status::OK();
}
// If the random number generated by the distribution is not within the desired range,
// simply assign the input vector to the output vector
*output = input;
// Return OK status to indicate successful operation
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,46 +14,85 @@
* limitations under the License.
*/
#include "minddata/dataset/kernels/image/random_horizontal_flip_with_bbox_op.h"
// Include the header file "random_horizontal_flip_with_bbox_op.h" from the "minddata/dataset/kernels/image" directory.
// Include the utility header, which provides various utility components and functions
#include <utility>
// Include the header file for the cv_tensor module from the minddata/dataset/core directory
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for the bounding_box module from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/bounding_box.h"
// Include the header file for the image_utils module from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status module from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Define the namespace "mindspore"
namespace mindspore {
namespace dataset {
const float RandomHorizontalFlipWithBBoxOp::kDefProbability = 0.5;
// Define the nested namespace "dataset"
namespace dataset {
// Define the constant float variable "kDefProbability" and set its value to 0.5
const float RandomHorizontalFlipWithBBoxOp::kDefProbability = 0.5;
}
}
// The Compute function of the RandomHorizontalFlipWithBBoxOp class
Status RandomHorizontalFlipWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output are vectors
IO_CHECK_VECTOR(input, output);
// Validate the bounding boxes in the input
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
// Check if the random number generated by the distribution is within the desired range
if (distribution_(rnd_)) {
// To test bounding boxes algorithm, create random bboxes from image dims
size_t num_of_boxes = input[1]->shape()[0]; // set to give number of bboxes
float img_center = (input[0]->shape()[1] / 2.); // get the center of the image
// To test the bounding boxes algorithm, create random bounding boxes from image dimensions
size_t num_of_boxes = input[1]->shape()[0]; // Get the number of bounding boxes
float img_center = (input[0]->shape()[1] / 2.); // Get the center of the image
// Iterate over each bounding box
for (int i = 0; i < num_of_boxes; i++) {
// Read the bounding box from the input tensor
std::shared_ptr<BoundingBox> bbox;
RETURN_IF_NOT_OK(BoundingBox::ReadFromTensor(input[1], i, &bbox));
// do the flip
BoundingBox::bbox_float diff = img_center - bbox->x(); // get distance from min_x to center
BoundingBox::bbox_float refl_min_x = diff + img_center; // get reflection of min_x
BoundingBox::bbox_float new_min_x =
refl_min_x - bbox->width(); // subtract from the reflected min_x to get the new one
// Perform the horizontal flip
BoundingBox::bbox_float diff = img_center - bbox->x(); // Get the distance from min_x to center
BoundingBox::bbox_float refl_min_x = diff + img_center; // Get the reflection of min_x
BoundingBox::bbox_float new_min_x = refl_min_x - bbox->width(); // Subtract from the reflected min_x to get the new one
bbox->SetX(new_min_x);
// Write the modified bounding box back to the input tensor
RETURN_IF_NOT_OK(bbox->WriteToTensor(input[1], i));
}
// Resize the output tensor row to accommodate the modified bounding boxes
(*output).resize(2);
// move input to output pointer of bounding boxes
// Move the input tensor containing the bounding boxes to the output tensor row
(*output)[1] = std::move(input[1]);
// perform HorizontalFlip on the image
// Perform horizontal flip on the image
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(std::move(input[0]));
return HorizontalFlip(std::static_pointer_cast<Tensor>(input_cv), &(*output)[0]);
}
// If the random number generated by the distribution is not within the desired range,
// simply copy the input tensor row to the output tensor row
*output = input;
// Return OK status to indicate successful computation
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
// End of namespace dataset
} // namespace mindspore

View File

@ -14,34 +14,56 @@
* limitations under the License.
*/
// Include the header file "random_invert_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/random_invert_op.h"
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file "minddata/dataset/kernels/image/image_utils.h" which contains utility functions for image processing in the MindData library.
// Define the namespace "mindspore"
namespace mindspore {
namespace dataset {
const float RandomInvertOp::kDefProbability = 0.5;
Status RandomInvertOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// check input
if (input->Rank() != DEFAULT_IMAGE_RANK) {
RETURN_STATUS_UNEXPECTED("RandomInvert: image shape is not <H,W,C>, got rank: " + std::to_string(input->Rank()));
}
if (input->shape()[CHANNEL_INDEX] != DEFAULT_IMAGE_CHANNELS) {
RETURN_STATUS_UNEXPECTED(
"RandomInvert: image shape is incorrect, expected num of channels is 3, "
"but got:" +
std::to_string(input->shape()[CHANNEL_INDEX]));
}
CHECK_FAIL_RETURN_UNEXPECTED(input->type().AsCVType() != kCVInvalidType,
"RandomInvert: Cannot convert from OpenCV type, unknown CV type. Currently "
"supported data type: [int8, uint8, int16, uint16, int32, float16, float32, float64].");
if (distribution_(rnd_)) {
return InvertOp::Compute(input, output);
}
*output = input;
return Status::OK();
// Define the nested namespace "dataset"
namespace dataset {
// Define the constant float variable "kDefProbability" with a default value of 0.5
const float RandomInvertOp::kDefProbability = 0.5;
}
}
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Check the shape of the input tensor
if (input->Rank() != DEFAULT_IMAGE_RANK) {
// If the rank of the input tensor is not equal to DEFAULT_IMAGE_RANK, return an error message
RETURN_STATUS_UNEXPECTED("RandomInvert: image shape is not <H,W,C>, got rank: " + std::to_string(input->Rank()));
}
// Check the number of channels in the input tensor
if (input->shape()[CHANNEL_INDEX] != DEFAULT_IMAGE_CHANNELS) {
// If the number of channels is not equal to DEFAULT_IMAGE_CHANNELS, return an error message
RETURN_STATUS_UNEXPECTED(
"RandomInvert: image shape is incorrect, expected num of channels is 3, "
"but got:" +
std::to_string(input->shape()[CHANNEL_INDEX]));
}
// Check if the input tensor has a valid CV type
CHECK_FAIL_RETURN_UNEXPECTED(input->type().AsCVType() != kCVInvalidType,
"RandomInvert: Cannot convert from OpenCV type, unknown CV type. Currently "
"supported data type: [int8, uint8, int16, uint16, int32, float16, float32, float64].");
// Generate a random number using the distribution and random number generator
if (distribution_(rnd_)) {
// If the generated random number satisfies the condition, call the Compute function of the InvertOp class
return InvertOp::Compute(input, output);
}
// If the generated random number does not satisfy the condition, assign the input tensor to the output tensor
*output = input;
// Return OK status to indicate successful computation
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,21 +14,41 @@
* limitations under the License.
*/
// Include the header file "random_lighting_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/random_lighting_op.h"
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file "minddata/dataset/kernels/image/image_utils.h" which contains utility functions for image processing in the MindData library.
// Define the namespace "mindspore"
namespace mindspore {
namespace dataset {
const float RandomLightingOp::kAlpha = 0.05;
// Define the nested namespace "dataset" within the "mindspore" namespace
namespace dataset {
// Define the constant float variable "kAlpha" for the RandomLightingOp class
const float RandomLightingOp::kAlpha = 0.05;
}
}
// Compute function for the RandomLightingOp class
// Takes in an input tensor and a pointer to an output tensor
// Uses IO_CHECK macro to check if the input and output are valid
Status RandomLightingOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// Rest of the code goes here
}
// Generate random values for red, green, and blue channels using the distribution object rnd_rgb_
float rnd_r = dist_(rnd_rgb_);
float rnd_g = dist_(rnd_rgb_);
float rnd_b = dist_(rnd_rgb_);
// Call the RandomLighting function with the input, output, and random values for red, green, and blue channels
return RandomLighting(input, output, rnd_r, rnd_g, rnd_b);
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -14,28 +14,55 @@
* limitations under the License.
*/
#include "minddata/dataset/kernels/image/random_posterize_op.h"
// Include the header file "random_posterize_op.h" from the "minddata/dataset/kernels/image" directory.
// Include the OpenCV image codecs header file, which provides functions for reading and writing images
#include <opencv2/imgcodecs.hpp>
// Include the "random.h" header file from the "minddata/dataset/util" directory
#include "minddata/dataset/util/random.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Define a constant vector of unsigned 8-bit integers named kBitRange
const std::vector<uint8_t> RandomPosterizeOp::kBitRange = {4, 8};
// Define the constructor for the RandomPosterizeOp class, which takes a vector of uint8_t values as input
RandomPosterizeOp::RandomPosterizeOp(const std::vector<uint8_t> &bit_range)
: PosterizeOp(bit_range[0]), bit_range_(bit_range) {
// Seed the random number generator with a random seed obtained from the GetSeed() function
rnd_.seed(GetSeed());
// Set the is_deterministic_ flag to false, indicating that the operation is not deterministic
is_deterministic_ = false;
}
// Define the Compute function for the RandomPosterizeOp class
Status RandomPosterizeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input tensor is not null, if it is null, return an error message
CHECK_FAIL_RETURN_UNEXPECTED(input != nullptr, "RandomPosterizeOp: parameter input is nullptr");
// Determine the bit value for posterization based on the bit range
// If the lower and upper bounds of the bit range are the same, use that value as the bit value
// Otherwise, generate a random bit value within the range using a uniform distribution and the random number generator
bit_ = (bit_range_[0] == bit_range_[1]) ? bit_range_[0]
: std::uniform_int_distribution<uint8_t>(bit_range_[0], bit_range_[1])(rnd_);
// Call the Compute function of the PosterizeOp class to perform the posterization operation
return PosterizeOp::Compute(input, output);
}
} // namespace dataset
} // namespace mindspore
// End of namespace dataset
} // namespace mindspore

View File

@ -15,26 +15,53 @@
*/
#include "minddata/dataset/kernels/image/random_resize_op.h"
// Include the random header, which provides facilities for generating random numbers
#include <random>
// Include the header file for the ConfigManager class from the minddata::dataset::core namespace
#include "minddata/dataset/core/config_manager.h"
// Include the header file for the CvTensor class from the minddata::dataset::core namespace
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for the Status class from the minddata::dataset::util namespace
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
const int32_t RandomResizeOp::kDefTargetWidth = 0;
// The code is defining a constant integer variable named "kDefTargetWidth" inside the "RandomResizeOp" class in the "dataset" namespace of the "mindspore" namespace.
// The constant is initialized with the value 0.
// Define the Compute function for the RandomResizeOp class
Status RandomResizeOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output vectors are valid
IO_CHECK_VECTOR(input, output);
// Get the size of the input vector
const auto output_count = input.size();
// Resize the output vector to match the size of the input vector
output->resize(output_count);
// Generate a random interpolation mode using the distribution and random generator
InterpolationMode interpolation_random_resize = static_cast<InterpolationMode>(distribution_(random_generator_));
// Create a shared pointer to a ResizeOp object with the specified size and interpolation mode
std::shared_ptr<TensorOp> resize_op = std::make_shared<ResizeOp>(size1_, size2_, interpolation_random_resize);
// Iterate over each element in the input vector
for (size_t i = 0; i < input.size(); i++) {
// Compute the resize operation on the current input element and store the result in the corresponding output element
RETURN_IF_NOT_OK(resize_op->Compute(input[i], &(*output)[i]));
}
// Return a status indicating successful computation
return Status::OK();
}
// Close the dataset namespace
} // namespace dataset
} // namespace mindspore
// Close the mindspore namespace
} // namespace mindspore

View File

@ -14,20 +14,31 @@
* limitations under the License.
*/
// Include the header file for the "random_resize_with_bbox_op" kernel from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/random_resize_with_bbox_op.h"
// Include the header file for the "resize_with_bbox_op" kernel from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/resize_with_bbox_op.h"
// Include the header file for the "status" utility from the "minddata/dataset/util" directory
#include "minddata/dataset/util/status.h"
namespace mindspore {
namespace dataset {
const int32_t RandomResizeWithBBoxOp::kDefTargetWidth = 0;
// The code is defining a constant integer variable named "kDefTargetWidth" inside the "RandomResizeWithBBoxOp" class in the "dataset" namespace of the "mindspore" namespace.
Status RandomResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
// Randomly selects from the following four interpolation methods
// 0-bilinear, 1-nearest_neighbor, 2-bicubic, 3-area
interpolation_ = static_cast<InterpolationMode>(distribution_(random_generator_));
RETURN_IF_NOT_OK(ResizeWithBBoxOp::Compute(input, output));
return Status::OK();
}
// The constant is initialized with the value 0.
namespace dataset {
// Compute function for the RandomResizeWithBBoxOp class
Status RandomResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
// Randomly selects from the following four interpolation methods
// 0-bilinear, 1-nearest_neighbor, 2-bicubic, 3-area
interpolation_ = static_cast<InterpolationMode>(distribution_(random_generator_));
// Call the Compute function of the parent ResizeWithBBoxOp class
RETURN_IF_NOT_OK(ResizeWithBBoxOp::Compute(input, output));
// Return OK status to indicate successful computation
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -15,73 +15,129 @@
*/
#include "minddata/dataset/kernels/image/random_rotation_op.h"
// Include the random header, which provides facilities for generating random numbers
#include <random>
// Include the header file for cv_tensor from the minddata/dataset/core directory
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for image_utils from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for random from the minddata/dataset/util directory
#include "minddata/dataset/util/random.h"
// Include the header file for status from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Define the namespace "mindspore"
namespace mindspore {
namespace dataset {
const std::vector<float> RandomRotationOp::kDefCenter = {};
const InterpolationMode RandomRotationOp::kDefInterpolation = InterpolationMode::kNearestNeighbour;
const bool RandomRotationOp::kDefExpand = false;
const uint8_t RandomRotationOp::kDefFillR = 0;
const uint8_t RandomRotationOp::kDefFillG = 0;
const uint8_t RandomRotationOp::kDefFillB = 0;
// constructor
// Define the namespace "dataset" within the "mindspore" namespace
namespace dataset {
// Define the constant static member variable "kDefCenter" of type std::vector<float> in the "RandomRotationOp" class
const std::vector<float> RandomRotationOp::kDefCenter = {};
// Define the constant static member variable "kDefInterpolation" of type InterpolationMode in the "RandomRotationOp" class
const InterpolationMode RandomRotationOp::kDefInterpolation = InterpolationMode::kNearestNeighbour;
// Define the constant static member variable "kDefExpand" of type bool in the "RandomRotationOp" class
const bool RandomRotationOp::kDefExpand = false;
// Define the constant static member variable "kDefFillR" of type uint8_t in the "RandomRotationOp" class
const uint8_t RandomRotationOp::kDefFillR = 0;
// Define the constant static member variable "kDefFillG" of type uint8_t in the "RandomRotationOp" class
const uint8_t RandomRotationOp::kDefFillG = 0;
// Define the constant static member variable "kDefFillB" of type uint8_t in the "RandomRotationOp" class
const uint8_t RandomRotationOp::kDefFillB = 0;
}
}
// Constructor for the RandomRotationOp class
RandomRotationOp::RandomRotationOp(float start_degree, float end_degree, InterpolationMode resample, bool expand,
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_(center),
interpolation_(resample),
expand_(expand),
fill_r_(fill_r),
fill_g_(fill_g),
fill_b_(fill_b) {
: degree_start_(start_degree), // Initialize the member variable degree_start_ with the value of start_degree
degree_end_(end_degree), // Initialize the member variable degree_end_ with the value of end_degree
center_(center), // Initialize the member variable center_ with the value of center
interpolation_(resample), // Initialize the member variable interpolation_ with the value of resample
expand_(expand), // Initialize the member variable expand_ with the value of expand
fill_r_(fill_r), // Initialize the member variable fill_r_ with the value of fill_r
fill_g_(fill_g), // Initialize the member variable fill_g_ with the value of fill_g
fill_b_(fill_b) { // Initialize the member variable fill_b_ with the value of fill_b
// Seed the random number generator with a random seed obtained from GetSeed() function
rnd_.seed(GetSeed());
// Set the is_deterministic_ flag to false, indicating that the operation is not deterministic
is_deterministic_ = false;
}
// main function call for random rotation : Generate the random degrees
// Check if the input and output tensors are valid
Status RandomRotationOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// Generate a random double value using the distribution and random number generator
float random_double = distribution_(rnd_);
// get the degree rotation range, mod by 360 because full rotation doesn't affect
// the way this op works (uniform distribution)
// assumption here is that mDegreesEnd > mDegreeStart so we always get positive number
// Note: the range technically is greater than 360 degrees, but will be halved
// Calculate the degree rotation range by subtracting the start degree from the end degree and dividing by 2
// This is done to ensure a uniform distribution of degrees within the range
float degree_range = (degree_end_ - degree_start_) / 2;
// Calculate the midpoint of the degree range by adding the start degree to the end degree and dividing by 2
float mid = (degree_end_ + degree_start_) / 2;
// Calculate the final degree by adding the midpoint to the product of the random double and the degree range
float degree = mid + random_double * degree_range;
return Rotate(input, output, center_, degree, interpolation_, expand_, fill_r_, fill_g_, fill_b_);
}
// Return the result of calling the Rotate function with the provided arguments
return Rotate(input, output, center_, degree, interpolation_, expand_, fill_r_, fill_g_, fill_b_);
// Define the function OutputShape for the RandomRotationOp class
Status RandomRotationOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Call the OutputShape function of the base class TensorOp and check for any errors
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector
outputs.clear();
// Initialize variables to store the output height and width
int32_t outputH = -1, outputW = -1;
// if expand_, then we cannot know the shape. We need the input image to find the output shape --> set it to
// <-1,-1[,3]>
// Check if the expand_ flag is set to true
// If expand_ is true, we cannot determine the output shape without the input image
// In this case, set the output shape to <-1, -1[, 3]>
CHECK_FAIL_RETURN_UNEXPECTED(inputs.size() > 0 && inputs[0].Size() >= 2,
"RandomRotationOp: invalid input shape, expected 2D or 3D input, but got input"
" dimension is: " +
std::to_string(inputs[0].Rank()));
if (!expand_) {
// If expand_ is false, we can determine the output shape based on the input shape
// Set the output height and width to the values from the input shape
outputH = inputs[0][0];
outputW = inputs[0][1];
}
// Create a TensorShape object with the output height and width
TensorShape out = TensorShape{outputH, outputW};
// Check the rank of the input shape
// If the rank is 2, append the output shape to the outputs vector
if (inputs[0].Rank() == 2) outputs.emplace_back(out);
// If the rank is 3, append the output shape with an additional dimension for the channel
if (inputs[0].Rank() == 3) outputs.emplace_back(out.AppendDim(inputs[0][2]));
// If the outputs vector is not empty, return OK status
if (!outputs.empty()) return Status::OK();
// If the outputs vector is empty, return an error status with a message indicating the invalid input shape
return Status(StatusCode::kMDUnexpectedError,
"RandomRotation: invalid input shape, expected 2D or 3D input, but got input dimension is:" +
std::to_string(inputs[0].Rank()));
}
} // namespace dataset
} // namespace mindspore
// Close the namespace blocks for dataset and mindspore

View File

@ -15,84 +15,163 @@
*/
#include "minddata/dataset/kernels/image/random_select_subpolicy_op.h"
// Include the header file for the Tensor class from the minddata/dataset/core directory
#include "minddata/dataset/core/tensor.h"
// Include the header file for the TensorOp class from the minddata/dataset/kernels directory
#include "minddata/dataset/kernels/tensor_op.h"
// Include the header file for the Status class from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Compute function for the RandomSelectSubpolicyOp class
Status RandomSelectSubpolicyOp::Compute(const TensorRow &input, TensorRow *output) {
// Create a copy of the input TensorRow
TensorRow in_row = input;
// Generate a random number using the rand_int_ generator
size_t rand_num = rand_int_(gen_);
// Check if the random number is within the range of the policy size
CHECK_FAIL_RETURN_UNEXPECTED(rand_num < policy_.size(),
"RandomSelectSubpolicy: "
"get rand number failed:" +
std::to_string(rand_num));
// Iterate over each subpolicy in the selected policy
for (auto &sub : policy_[rand_num]) {
// Check if a random double generated using the rand_double_ generator is less than or equal to the subpolicy's second value
if (rand_double_(gen_) <= sub.second) {
// Compute the subpolicy using the input TensorRow and store the result in the output TensorRow
RETURN_IF_NOT_OK(sub.first->Compute(in_row, output));
// Move the output TensorRow to the input TensorRow for the next iteration
in_row = std::move(*output);
}
}
// Move the final input TensorRow to the output TensorRow
*output = std::move(in_row);
// Return a Status object indicating successful computation
return Status::OK();
}
// This function returns the number of inputs for the RandomSelectSubpolicyOp class.
uint32_t RandomSelectSubpolicyOp::NumInput() {
// Get the number of inputs for the first subpolicy
uint32_t num_in = policy_.front().front().first->NumInput();
// Iterate over each subpolicy
for (auto &sub : policy_) {
// Iterate over each policy in the subpolicy
for (auto &p : sub) {
// Check if the number of inputs for the current policy is different from the first subpolicy
if (num_in != p.first->NumInput()) {
// If so, log a warning message and return 0
MS_LOG(WARNING) << "Unable to determine numInput.";
return 0;
}
}
}
// If all subpolicies have the same number of inputs, return the number of inputs for the first subpolicy
return num_in;
}
// Function to determine the number of outputs for the RandomSelectSubpolicyOp class
uint32_t RandomSelectSubpolicyOp::NumOutput() {
// Get the number of outputs from the first subpolicy
uint32_t num_out = policy_.front().front().first->NumOutput();
// Iterate through each subpolicy and check if the number of outputs is consistent
for (auto &sub : policy_) {
for (auto &p : sub) {
// If the number of outputs is not consistent, log a warning and return 0
if (num_out != p.first->NumOutput()) {
MS_LOG(WARNING) << "Unable to determine numInput.";
return 0;
}
}
}
// Return the number of outputs
return num_out;
}
// Define the function OutputShape for the RandomSelectSubpolicyOp class
Status RandomSelectSubpolicyOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Clear the outputs vector to remove any existing shapes
outputs.clear();
// Resize the outputs vector to have a size equal to the number of output tensors
// Each output tensor is initialized with an unknown rank shape
outputs.resize(NumOutput(), TensorShape::CreateUnknownRankShape());
// Return a status indicating that the function executed successfully
return Status::OK();
}
// Function to determine the output type of the RandomSelectSubpolicyOp
Status RandomSelectSubpolicyOp::OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) {
// Check the output type of the first subpolicy and return if it is not okay
RETURN_IF_NOT_OK(policy_.front().front().first->OutputType(inputs, outputs));
// Iterate through each subpolicy and its operations
for (auto &sub : policy_) {
for (auto &p : sub) {
// Create a temporary vector to store the output types of the current operation
std::vector<DataType> tmp_types;
// Get the output type of the current operation and return if it is not okay
RETURN_IF_NOT_OK(p.first->OutputType(inputs, tmp_types));
// Check if the output types of the current operation match the existing output types
if (outputs != tmp_types) {
// If the output types do not match, clear the existing output types and resize it to the correct size
outputs.clear();
outputs.resize(NumOutput(), DataType(DataType::DE_UNKNOWN));
// Return OK status to indicate successful program termination
return Status::OK();
}
}
}
// Return OK status to indicate successful program termination
return Status::OK();
}
// Constructor for the RandomSelectSubpolicyOp class
RandomSelectSubpolicyOp::RandomSelectSubpolicyOp(const std::vector<Subpolicy> &policy)
: gen_(GetSeed()), policy_(policy), rand_int_(0, policy.size() - 1), rand_double_(0, 1) {
// Check if the input policy is empty and log an error message if it is
if (policy_.empty()) {
MS_LOG(ERROR) << "RandomSelectSubpolicy: input 'policy' in RandomSelectSubpolicy is empty, check input parameter.";
}
// Set the is_deterministic_ flag to false
is_deterministic_ = false;
}
} // namespace dataset
} // namespace mindspore
// Closing braces to end the namespace blocks for "dataset" and "mindspore"

View File

@ -14,37 +14,67 @@
* limitations under the License.
*/
// Include the header file for the random sharpness operation in the MindData dataset kernels image module
#include "minddata/dataset/kernels/image/random_sharpness_op.h"
// Include the header file for the sharpness operation in the MindData dataset kernels image module
#include "minddata/dataset/kernels/image/sharpness_op.h"
// Include the header file for the OpenCV tensor in the MindData dataset core module
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for the random number generator in the MindData dataset util module
#include "minddata/dataset/util/random.h"
// Include the header file for the status in the MindData dataset util module
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Define a constant float variable named kDefStartDegree and assign it the value 0.1
const float RandomSharpnessOp::kDefStartDegree = 0.1;
// Define a constant float variable named kDefEndDegree and assign it the value 1.9
const float RandomSharpnessOp::kDefEndDegree = 1.9;
/// constructor
// Constructor for the RandomSharpnessOp class
RandomSharpnessOp::RandomSharpnessOp(float start_degree, float end_degree)
: start_degree_(start_degree), end_degree_(end_degree) {
// Seed the random number generator with a random seed
rnd_.seed(GetSeed());
// Set the flag for determinism to false
is_deterministic_ = false;
}
/// main function call for random sharpness : Generate the random degrees
Status RandomSharpnessOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
float random_double = distribution_(rnd_);
/// get the degree sharpness range
/// the way this op works (uniform distribution)
/// assumption here is that mDegreesEnd > mDegreeStart so we always get positive number
float degree_range = (end_degree_ - start_degree_) / 2;
float mid = (end_degree_ + start_degree_) / 2;
alpha_ = mid + random_double * degree_range;
/// Check if the input and output tensors are valid
IO_CHECK(input, output);
return SharpnessOp::Compute(input, output);
}
} // namespace dataset
} // namespace mindspore
/// Generate a random double value using the specified distribution and random number generator
float random_double = distribution_(rnd_);
/// Calculate the range of degrees of sharpness
/// The assumption here is that the end degree is greater than the start degree, so we always get a positive number
float degree_range = (end_degree_ - start_degree_) / 2;
/// Calculate the midpoint of the degree range
float mid = (end_degree_ + start_degree_) / 2;
/// Calculate the alpha value using the random double and degree range
alpha_ = mid + random_double * degree_range;
// Return the result of calling the Compute function of the SharpnessOp class, passing in the input and output parameters
return SharpnessOp::Compute(input, output);
} // End of the dataset namespace
} // End of the mindspore namespace

View File

@ -14,34 +14,73 @@
* limitations under the License.
*/
// Include the header file for the random solarize operation in the MindData dataset kernels image module
#include "minddata/dataset/kernels/image/random_solarize_op.h"
// Include the header file for the solarize operation in the MindData dataset kernels image module
#include "minddata/dataset/kernels/image/solarize_op.h"
// Include the header file for the CV tensor in the MindData dataset core module
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for the status utility in the MindData dataset util module
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Compute function for the RandomSolarizeOp class
// Takes an input tensor and a pointer to an output tensor as arguments
// Uses IO_CHECK macro to check if the input and output tensors are valid
Status RandomSolarizeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// Rest of the code for the Compute function goes here
}
uint8_t threshold_min_ = threshold_[0], threshold_max_ = threshold_[1];
// Declare two variables of type uint8_t named threshold_min_ and threshold_max_
// Initialize threshold_min_ with the value at index 0 of the array threshold_
// Initialize threshold_max_ with the value at index 1 of the array threshold_
uint8_t threshold_min_ = threshold_[0], threshold_max_ = threshold_[1];
CHECK_FAIL_RETURN_UNEXPECTED(threshold_min_ <= threshold_max_,
"RandomSolarize: min of threshold: " + std::to_string(threshold_min_) +
" is greater than max of threshold: " + std::to_string(threshold_max_));
// Check if the minimum threshold value is less than or equal to the maximum threshold value
CHECK_FAIL_RETURN_UNEXPECTED(threshold_min_ <= threshold_max_,
"RandomSolarize: min of threshold: " + std::to_string(threshold_min_) +
" is greater than max of threshold: " + std::to_string(threshold_max_));
uint8_t threshold_min = std::uniform_int_distribution(threshold_min_, threshold_max_)(rnd_);
uint8_t threshold_max = std::uniform_int_distribution(threshold_min_, threshold_max_)(rnd_);
// Declare a variable named threshold_min of type uint8_t
// Assign it the result of generating a random number between threshold_min_ and threshold_max_ using the rnd_ random number generator
uint8_t threshold_min = std::uniform_int_distribution(threshold_min_, threshold_max_)(rnd_);
// Declare a variable named threshold_max of type uint8_t
// Assign it the result of generating a random number between threshold_min_ and threshold_max_ using the rnd_ random number generator
uint8_t threshold_max = std::uniform_int_distribution(threshold_min_, threshold_max_)(rnd_);
// Check if the maximum threshold is less than the minimum threshold
if (threshold_max < threshold_min) {
// If so, swap the values of the minimum and maximum thresholds using a temporary variable
uint8_t temp = threshold_min;
threshold_min = threshold_max;
threshold_max = temp;
}
// Create a vector of uint8_t values and initialize it with the minimum and maximum thresholds
std::vector<uint8_t> inputs = {threshold_min, threshold_max};
// Create a unique pointer to a SolarizeOp object using the inputs vector
std::unique_ptr<SolarizeOp> op = std::make_unique<SolarizeOp>(inputs);
// Call the Compute function of the SolarizeOp object, passing the input and output parameters
// and return the result
return op->Compute(input, output);
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,27 +14,66 @@
* limitations under the License.
*/
// Include the header file "random_vertical_flip_op.h" from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/random_vertical_flip_op.h"
// Include the header file for image utilities from the MindData library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility from the MindData library
#include "minddata/dataset/util/status.h"
// Define the namespace "mindspore"
namespace mindspore {
// Define the nested namespace "dataset"
namespace dataset {
// Define the constant float variable "kDefProbability" with a value of 0.5
const float RandomVerticalFlipOp::kDefProbability = 0.5;
// Define the implementation of the Compute function for the RandomVerticalFlipOp class
// Include the necessary headers for the required types and functions
#include <mindspore/dataset/engine/datasetops/source/sampler/random_vertical_flip_op.h>
#include <mindspore/dataset/util/status.h>
namespace mindspore {
namespace dataset {
const float RandomVerticalFlipOp::kDefProbability = 0.5;
// Compute function definition
Status RandomVerticalFlipOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output vectors are valid
IO_CHECK_VECTOR(input, output);
// Get the size of the input vector
const auto output_count = input.size();
// Resize the output vector to match the size of the input vector
output->resize(output_count);
// Check if the random number generated by the distribution is within the desired range
if (distribution_(rnd_)) {
// Iterate over each element in the input vector
for (size_t i = 0; i < input.size(); i++) {
// Call the VerticalFlip function to perform the vertical flip operation on the input tensor
RETURN_IF_NOT_OK(VerticalFlip(input[i], &(*output)[i]));
}
// Return OK status to indicate successful execution
return Status::OK();
}
// If the random number generated by the distribution is not within the desired range,
// simply assign the input vector to the output vector
*output = input;
// Return OK status to indicate successful execution
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,41 +14,83 @@
* limitations under the License.
*/
// Include the necessary header files for the code to work correctly
#include "minddata/dataset/util/status.h"
#include "minddata/dataset/kernels/image/bounding_box.h"
#include "minddata/dataset/kernels/image/image_utils.h"
#include "minddata/dataset/kernels/image/random_vertical_flip_with_bbox_op.h"
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace
namespace dataset {
// Define the default probability for random vertical flip
const float RandomVerticalFlipWithBBoxOp::kDefProbability = 0.5;
// Implementation of the Compute function for RandomVerticalFlipWithBBoxOp
Status RandomVerticalFlipWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output are vectors
IO_CHECK_VECTOR(input, output);
// Validate the bounding boxes in the input TensorRow
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
// ... (rest of the code)
// Check if the random number generated by distribution_ is true
if (distribution_(rnd_)) {
// Get the height of the input tensor and assign it to imHeight
dsize_t imHeight = input[0]->shape()[0];
size_t boxCount = input[1]->shape()[0]; // number of rows in tensor
// one time allocation -> updated in the loop
// type defined based on VOC test dataset
for (int i = 0; i < boxCount; i++) {
std::shared_ptr<BoundingBox> bbox;
RETURN_IF_NOT_OK(BoundingBox::ReadFromTensor(input[1], i, &bbox));
// Get the number of rows in the input tensor and assign it to boxCount
size_t boxCount = input[1]->shape()[0];
}
// subtract (curCorner + height) from (max) for new Corner position
// One-time allocation for a shared pointer to a BoundingBox object
// This shared pointer will be updated in the loop
// The type of the shared pointer is defined based on the VOC test dataset
for (int i = 0; i < boxCount; i++) {
// Create a new shared pointer to a BoundingBox object
std::shared_ptr<BoundingBox> bbox;
// Read the BoundingBox object from a tensor at index i and assign it to the shared pointer
// The ReadFromTensor function returns an error code, so we check if it is not OK
RETURN_IF_NOT_OK(BoundingBox::ReadFromTensor(input[1], i, &bbox));
// Calculate the new y-coordinate for the bounding box corner by subtracting the sum of the current y-coordinate and height from the maximum y-coordinate
BoundingBox::bbox_float newBoxCorner_y = (imHeight - 1.0) - ((bbox->y() + bbox->height()) - 1.0);
// Set the new y-coordinate for the bounding box
bbox->SetY(newBoxCorner_y);
// Write the updated bounding box to the tensor at index i in the input vector
RETURN_IF_NOT_OK(bbox->WriteToTensor(input[1], i));
}
// Define the number of outputs
const int output_count = 2;
// Resize the output vector to hold the specified number of outputs
output->resize(output_count);
// Assign the second element of the input vector to the second element of the output vector
(*output)[1] = input[1];
// Return the result of calling the VerticalFlip function with the first element of the input vector and the address of the first element of the output vector
return VerticalFlip(input[0], &(*output)[0]);
}
// If the input and output vectors are the same, assign the input vector to the output vector
*output = input;
// Return a Status object indicating that the operation was successful
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -15,19 +15,37 @@
*/
#include "minddata/dataset/kernels/image/rescale_op.h"
// Include the header file for image utilities from the MindData dataset library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility from the MindData dataset library
#include "minddata/dataset/util/status.h"
// The code is defining functions and methods within the "mindspore" and "dataset" namespaces
namespace mindspore {
namespace dataset {
// Implementation of the Compute method for the RescaleOp class
Status RescaleOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output pointers are valid
IO_CHECK(input, output);
// Call the Rescale function with the input, output, rescale_, and shift_ parameters
return Rescale(input, output, rescale_, shift_);
}
// Implementation of the OutputType method for the RescaleOp class
Status RescaleOp::OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) {
// Call the OutputType method of the base class TensorOp
RETURN_IF_NOT_OK(TensorOp::OutputType(inputs, outputs));
// Set the output data type to DE_FLOAT32
outputs[0] = DataType(DataType::DE_FLOAT32);
// Return a success status
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -15,82 +15,142 @@
*/
#include "minddata/dataset/kernels/image/resize_cubic_op.h"
namespace mindspore {
namespace dataset {
// using 8 bits for result
constexpr uint8_t PrecisionBits = 22;
// using 16 bit for clip8 table capacity
constexpr uint16_t Clip8TableCapacity = 640;
// The code is defining two constants within the "mindspore::dataset" namespace.
// construct lookup table
// The first constant is named "PrecisionBits" and has a value of 22. It is declared as a constexpr uint8_t, which means it is a compile-time constant of type unsigned 8-bit integer. This constant is used to specify the number of bits used for the result.
// The second constant is named "Clip8TableCapacity" and has a value of 640. It is declared as a constexpr uint16_t, which means it is a compile-time constant of type unsigned 16-bit integer. This constant is used to specify the capacity of a table.
// Create a static lookup table named _clip8_table using a lambda function
static const std::vector<uint8_t> _clip8_table = []() {
// Create two vectors, v1 and v2, with initial sizes of 896 and 384 respectively
std::vector<uint8_t> v1(896, 0);
std::vector<uint8_t> v2(384, 255);
// Fill v1 with values from 0 to 255 starting from index Clip8TableCapacity
for (int i = 0; i < 256; i++) {
v1[i + Clip8TableCapacity] = i;
}
// Append the elements of v2 to the end of v1
v1.insert(v1.end(), v2.begin(), v2.end());
// Return the resulting vector v1 as the value of the lambda function
return v1;
}();
// Declare a static constant pointer to an unsigned 8-bit integer, named clip8_table
// The pointer is initialized with the address of the element at index Clip8TableCapacity in the _clip8_table array
static const uint8_t *clip8_table = &_clip8_table[Clip8TableCapacity];
// A static inline function that takes an unsigned integer as input and returns an 8-bit unsigned integer
static inline uint8_t clip8(unsigned int input) {
// Calculate the index by right-shifting the input by the number of PrecisionBits
uint16_t index = input >> PrecisionBits;
// Check if the index is greater than or equal to the Clip8TableCapacity
if (index >= Clip8TableCapacity) {
// If the index is greater than or equal to the Clip8TableCapacity, return 0
return 0;
}
// Return the value at the index in the clip8_table
return clip8_table[index];
}
// A static inline function that performs cubic interpolation on a given input value x
static inline double cubic_interp(double x) {
// Define a constant coefficient a as -0.5
double a = -0.5;
// If x is negative, make it positive
if (x < 0.0) {
x = -x;
}
// If x is less than 1.0, perform the first cubic interpolation equation
if (x < 1.0) {
return ((a + 2.0) * x - (a + 3.0)) * x * x + 1;
}
// If x is less than 2.0, perform the second cubic interpolation equation
if (x < 2.0) {
return (((x - 5) * x + 8) * x - 4) * a;
}
// If x is greater than or equal to 2.0, return 0.0
return 0.0;
}
struct interpolation {
double (*interpolation)(double x);
double threshold;
};
// Define a struct named "interpolation" that contains two members
int calc_coeff(int input_size, int out_size, int input0, int input1, const struct interpolation *interp,
std::vector<int> &regions, std::vector<double> &coeffs_interp) {
double threshold, scale, interp_scale;
int kernel_size;
// Member 1: A function pointer named "interpolation" that points to a function taking a double argument and returning a double
double (*interpolation)(double x);
// Member 2: A double variable named "threshold"
double threshold;
// Function to calculate coefficients for interpolation
// Parameters:
// - input_size: size of the input data
// - out_size: size of the output data
// - input0: starting index of the input data
// - input1: ending index of the input data
// - interp: pointer to a struct containing interpolation information
// - regions: reference to a vector to store the regions
// - coeffs_interp: reference to a vector to store the interpolation coefficients
// Declare variables
double threshold, scale, interp_scale;
int kernel_size;
// Check if out_size is equal to 0
if (out_size == 0) {
// If so, log an error message and return 0
MS_LOG(ERROR) << "out_size can not be zero.";
return 0;
}
// Calculate the scale as the difference between input1 and input0 divided by out_size
scale = static_cast<double>((input1 - input0)) / out_size;
// Check if the scale is less than 1.0
if (scale < 1.0) {
// If so, set interp_scale to 1.0
interp_scale = 1.0;
} else {
// Otherwise, set interp_scale to the calculated scale
interp_scale = scale;
}
// obtain size
threshold = interp->threshold * interp_scale;
// Obtain the size by multiplying the threshold value with the interpolation scale
// coefficients number
kernel_size = static_cast<int>(ceil(threshold)) * 2 + 1;
if (out_size > INT_MAX / (kernel_size * static_cast<int>(sizeof(double)))) {
MS_LOG(WARNING) << "Unable to allocator memory as output Image size is so large.";
// Calculate the kernel size based on the threshold value
kernel_size = static_cast<int>(ceil(threshold)) * 2 + 1;
// Check if the output size is too large to allocate memory
if (out_size > INT_MAX / (kernel_size * static_cast<int>(sizeof(double)))) {
// Log a warning message indicating that memory allocation is not possible due to the large output image size
MS_LOG(WARNING) << "Unable to allocate memory as output Image size is so large.";
// Return 0 to indicate failure
return 0;
}
}
// coefficient array
std::vector<double> coeffs(out_size * kernel_size, 0.0);
std::vector<int> region(out_size * 2, 0);
// Create a vector named "coeffs" to store the coefficients
// The size of the vector is calculated by multiplying "out_size" and "kernel_size"
// Initialize all elements of the vector to 0.0
std::vector<double> coeffs(out_size * kernel_size, 0.0);
// Create a vector named "region" to store the region values
// The size of the vector is calculated by multiplying "out_size" and 2
// Initialize all elements of the vector to 0
std::vector<int> region(out_size * 2, 0);
for (int xx = 0; xx < out_size; xx++) {
double center = input0 + (xx + 0.5) * scale;
@ -109,191 +169,366 @@ int calc_coeff(int input_size, int out_size, int input0, int input1, const struc
x_max -= x_min;
double *coeff = &coeffs[xx * kernel_size];
for (x = 0; x < x_max; x++) {
// Calculate the interpolation value for the current x position
double m = interp->interpolation(((x + x_min) - center + 0.5) * ss);
coeff[x] = m;
mm += m;
}
// ...
}
}
// Iterate over the values of x from 0 to x_max
for (x = 0; x < x_max; x++) {
// Check if mm is not equal to 0.0
if (mm != 0.0) {
// Divide the value of coeff[x] by mm
coeff[x] /= mm;
}
}
// Remaining values should stay empty if they are used despite of x_max.
// Iterate over the values of x from the current value of x to kernel_size
for (; x < kernel_size; x++) {
// Set the value of coeff[x] to 0
coeff[x] = 0;
}
// Set the value of region[xx * 2] to x_min
region[xx * 2] = x_min;
// Set the value of region[xx * 2 + 1] to x_max
region[xx * 2 + 1] = x_max;
}
regions = std::move(region);
coeffs_interp = std::move(coeffs);
return kernel_size;
}
// Move the contents of the 'region' object to the 'regions' object
regions = std::move(region);
// Move the contents of the 'coeffs' object to the 'coeffs_interp' object
coeffs_interp = std::move(coeffs);
// Return the value of 'kernel_size' variable
return kernel_size;
// A function to normalize the coefficients of a kernel
void normalize_coeff(int out_size, int kernel_size, const std::vector<double> &prekk, std::vector<int> &kk) {
// Iterate over each element in the output size times kernel size
for (int x = 0; x < out_size * kernel_size; x++) {
// If the value at prekk[x] is less than 0
if (prekk[x] < 0) {
// Normalize the value by multiplying it with (1 << PrecisionBits) and subtracting 0.5
kk[x] = static_cast<int>((-0.5 + prekk[x] * (1 << PrecisionBits)));
} else {
// Normalize the value by multiplying it with (1 << PrecisionBits) and adding 0.5
kk[x] = static_cast<int>((0.5 + prekk[x] * (1 << PrecisionBits)));
}
}
}
Status ImagingHorizontalInterp(LiteMat &output, LiteMat input, int offset, int kernel_size,
const std::vector<int> &regions, const std::vector<double> &prekk) {
int ss0, ss1, ss2;
int32_t *k = nullptr;
// Function to perform horizontal interpolation on an input image and store the result in the output image
// Parameters:
// - output: reference to the output image
// - input: input image to be interpolated
// - offset: offset value for interpolation
// - kernel_size: size of the interpolation kernel
// - regions: vector of regions for interpolation
// - prekk: vector of precomputed values for interpolation
// normalize previous calculated coefficients
std::vector<int> kk(prekk.begin(), prekk.end());
normalize_coeff(output.width_, kernel_size, prekk, kk);
uint8_t *input_ptr = input;
uint8_t *output_ptr = output;
int32_t input_width = input.width_ * 3;
int32_t output_width = output.width_ * 3;
// Declare variables to store the size of the input image
int ss0, ss1, ss2;
for (int yy = 0; yy < output.height_; yy++) {
// obtain the ptr of output, and put calculated value into it
// Declare a pointer to an int32_t variable and initialize it to nullptr
int32_t *k = nullptr;
// Create a new vector kk and copy the elements from prekk vector
std::vector<int> kk(prekk.begin(), prekk.end());
// Normalize the coefficients in kk vector using the normalize_coeff function
normalize_coeff(output.width_, kernel_size, prekk, kk);
// Create pointers to the input and output arrays
uint8_t *input_ptr = input;
uint8_t *output_ptr = output;
// Calculate the width of the input and output arrays
int32_t input_width = input.width_ * 3;
int32_t output_width = output.width_ * 3;
// Iterate over each row of the output image
for (int yy = 0; yy < output.height_; yy++) {
// Obtain a pointer to the current row of the output image
uint8_t *bgr_buf = output_ptr;
// Iterate over each pixel in the current row
for (int xx = 0; xx < output.width_; xx++) {
int x_min = regions[xx * 2];
int x_max = regions[xx * 2 + 1];
k = &kk[xx * kernel_size];
ss0 = ss1 = ss2 = 1 << (PrecisionBits - 1);
for (int x = 0; x < x_max; x++) {
ss0 += (input_ptr[(yy + offset) * input_width + (x + x_min) * 3]) * k[x];
ss1 += (input_ptr[(yy + offset) * input_width + (x + x_min) * 3 + 1]) * k[x];
ss2 += (input_ptr[(yy + offset) * input_width + (x + x_min) * 3 + 2]) * k[x];
}
bgr_buf[0] = clip8(ss0);
bgr_buf[1] = clip8(ss1);
bgr_buf[2] = clip8(ss2);
bgr_buf += 3;
// Get the minimum and maximum x values for the current pixel
int x_min = regions[xx * 2];
int x_max = regions[xx * 2 + 1];
// Get the pointer to the current kernel
k = &kk[xx * kernel_size];
// Initialize the sums for each color channel
ss0 = ss1 = ss2 = 1 << (PrecisionBits - 1);
// Iterate over each x value within the range of the current pixel
for (int x = 0; x < x_max; x++) {
// Calculate the sum for each color channel using the input image and the kernel
ss0 += (input_ptr[(yy + offset) * input_width + (x + x_min) * 3]) * k[x];
ss1 += (input_ptr[(yy + offset) * input_width + (x + x_min) * 3 + 1]) * k[x];
ss2 += (input_ptr[(yy + offset) * input_width + (x + x_min) * 3 + 2]) * k[x];
}
// Clip the sums to the range of 0-255 and store them in the output image buffer
bgr_buf[0] = clip8(ss0);
bgr_buf[1] = clip8(ss1);
bgr_buf[2] = clip8(ss2);
// Move the output image buffer pointer to the next pixel
bgr_buf += 3;
}
// Move the output image pointer to the next row
output_ptr += output_width;
}
return Status::OK();
}
// Return the OK status from the Status class
return Status::OK();
Status ImagingVerticalInterp(LiteMat &output, LiteMat input, int kernel_size, const std::vector<int> &regions,
const std::vector<double> &prekk) {
int ss0, ss1, ss2;
// Function to perform vertical interpolation on an input image and store the result in the output image
// Parameters:
// - output: reference to the output image where the interpolated result will be stored
// - input: input image on which interpolation will be performed
// - kernel_size: size of the interpolation kernel
// - regions: vector containing the regions of interest for interpolation
// - prekk: vector containing precomputed values for interpolation
// normalize previous calculated coefficients
std::vector<int> kk(prekk.begin(), prekk.end());
normalize_coeff(output.height_, kernel_size, prekk, kk);
uint8_t *input_ptr = input;
uint8_t *output_ptr = output;
const int32_t input_width = input.width_ * 3;
const int32_t output_width = output.width_ * 3;
// Declare variables to store the size of the input image
int ss0, ss1, ss2;
for (int yy = 0; yy < output.height_; yy++) {
// obtain the ptr of output, and put calculated value into it
// Create a new vector kk and copy the elements from prekk vector
std::vector<int> kk(prekk.begin(), prekk.end());
// Normalize the coefficients in kk vector based on the height of the output image and the kernel size
normalize_coeff(output.height_, kernel_size, prekk, kk);
// Create pointers to the input and output arrays
uint8_t *input_ptr = input;
uint8_t *output_ptr = output;
// Calculate the width of the input and output images by multiplying the width by 3 (assuming RGB color channels)
const int32_t input_width = input.width_ * 3;
const int32_t output_width = output.width_ * 3;
// Iterate over each row of the output image
for (int yy = 0; yy < output.height_; yy++) {
// Get a pointer to the current row of the output image
uint8_t *bgr_buf = output_ptr;
// Get a pointer to the current row of the kernel
int32_t *k = &kk[yy * kernel_size];
// Get the minimum and maximum y-coordinates for the current row
int y_min = regions[yy * 2];
int y_max = regions[yy * 2 + 1];
for (int xx = 0; xx < output.width_; xx++) {
ss0 = ss1 = ss2 = 1 << (PrecisionBits - 1);
for (int y = 0; y < y_max; y++) {
ss0 += (input_ptr[(y + y_min) * input_width + xx * 3]) * k[y];
ss1 += (input_ptr[(y + y_min) * input_width + xx * 3 + 1]) * k[y];
ss2 += (input_ptr[(y + y_min) * input_width + xx * 3 + 2]) * k[y];
}
bgr_buf[0] = clip8(ss0);
bgr_buf[1] = clip8(ss1);
bgr_buf[2] = clip8(ss2);
bgr_buf += 3;
}
output_ptr += output_width;
}
return Status::OK();
}
// Iterate over each column of the output image
for (int xx = 0; xx < output.width_; xx++) {
// Initialize the sum variables for each color channel
ss0 = ss1 = ss2 = 1 << (PrecisionBits - 1);
// Iterate over each y-coordinate within the specified range
for (int y = 0; y < y_max; y++) {
// Calculate the weighted sum for each color channel
ss0 += (input_ptr[(y + y_min) * input_width + xx * 3]) * k[y];
ss1 += (input_ptr[(y + y_min) * input_width + xx * 3 + 1]) * k[y];
ss2 += (input_ptr[(y + y_min) * input_width + xx * 3 + 2]) * k[y];
}
// Clip the calculated values to the range [0, 255] and store them in the output buffer
bgr_buf[0] = clip8(ss0);
bgr_buf[1] = clip8(ss1);
bgr_buf[2] = clip8(ss2);
// Move the output buffer pointer to the next pixel
bgr_buf += 3;
}
// Move the output pointer to the next row
output_ptr += output_width;
}
// Return the OK status from the Status class
return Status::OK();
// Function to perform image interpolation
bool ImageInterpolation(LiteMat input, LiteMat &output, int x_size, int y_size, struct interpolation *interp,
const int rect[4]) {
// Variables for interpolation
int horizontal_interp, vertical_interp, horiz_kernel, vert_kernel, rect_y0, rect_y1;
// Vectors to store interpolation regions and coefficients
std::vector<int> horiz_region, vert_region;
std::vector<double> horiz_coeff, vert_coeff;
// Temporary LiteMat to store intermediate results
LiteMat temp;
horizontal_interp = x_size != input.width_ || rect[2] != x_size || rect[0];
vertical_interp = y_size != input.height_ || rect[3] != y_size || rect[1];
// Check if the x_size is not equal to the width of the input image or if rect[2] is not equal to x_size or if rect[0] is true
horizontal_interp = x_size != input.width_ || rect[2] != x_size || rect[0];
horiz_kernel = calc_coeff(input.width_, x_size, rect[0], rect[2], interp, horiz_region, horiz_coeff);
if (!horiz_kernel) {
// Check if the y_size is not equal to the height of the input image or if rect[3] is not equal to y_size or if rect[1] is true
vertical_interp = y_size != input.height_ || rect[3] != y_size || rect[1];
// Calculate the horizontal kernel coefficients using the calc_coeff function, passing in the width of the input, the x size, the left and right coordinates of the rectangle, the interpolation method, the horizontal region, and the horizontal coefficient
horiz_kernel = calc_coeff(input.width_, x_size, rect[0], rect[2], interp, horiz_region, horiz_coeff);
// Check if the horizontal kernel calculation was successful
if (!horiz_kernel) {
// If not, return false to indicate failure
return false;
}
// Calculate the vertical kernel coefficients using the calc_coeff function, passing in the height of the input image, y_size, and the y-coordinates of the rectangle, rect[1] and rect[3]. Also pass in the interpolation method, interp, the vertical region, vert_region, and the vertical coefficient, vert_coeff.
vert_kernel = calc_coeff(input.height_, y_size, rect[1], rect[3], interp, vert_region, vert_coeff);
// Check if the vertical kernel calculation was successful by checking if vert_kernel is false (0 or NULL).
if (!vert_kernel) {
// If the vertical kernel calculation failed, return false to indicate failure.
return false;
}
// Assign the first row of the input image to the variable rect_y0
rect_y0 = vert_region[0];
// Assign the last row of the input image to the variable rect_y1
// The last row is calculated by adding the second-to-last row and the last row of the vert_region array
rect_y1 = vert_region[y_size * 2 - 1] + vert_region[y_size * 2 - 2];
// Check if horizontal interpolation is enabled
if (horizontal_interp) {
// Shift the region for vertical resize
for (int i = 0; i < y_size; i++) {
vert_region[i * 2] -= rect_y0;
}
vert_kernel = calc_coeff(input.height_, y_size, rect[1], rect[3], interp, vert_region, vert_coeff);
if (!vert_kernel) {
return false;
}
// first and last used row in the input image
rect_y0 = vert_region[0];
rect_y1 = vert_region[y_size * 2 - 1] + vert_region[y_size * 2 - 2];
// two-direction resize, horizontal resize
if (horizontal_interp) {
// Shift region for vertical resize
for (int i = 0; i < y_size; i++) {
vert_region[i * 2] -= rect_y0;
}
temp.Init(x_size, rect_y1 - rect_y0, 3, LDataType::UINT8, false);
// Initialize a temporary image with the new dimensions
temp.Init(x_size, rect_y1 - rect_y0, 3, LDataType::UINT8, false);
}
// Call the ImagingHorizontalInterp function and store the result in the variable rc
auto rc = ImagingHorizontalInterp(temp, input, rect_y0, horiz_kernel, horiz_region, horiz_coeff);
// Check if rc indicates an error
if (rc.IsError()) {
// Print an error message using MS_LOG(ERROR) and the error message from rc
MS_LOG(ERROR) << "Image horizontal resize failed, error msg is " << rc;
// Return false to indicate that the image horizontal resize failed
return false;
}
// Check if the temp variable is empty
if (temp.IsEmpty()) {
// Return false to indicate that the temp variable is empty
return false;
}
// Assign the value of temp to both input and output variables
output = input = temp;
}
/* vertical resize */
// Check if vertical interpolation is enabled
if (vertical_interp) {
// Initialize the output image with the same width as the input image, but with a resized height
output.Init(input.width_, y_size, 3, LDataType::UINT8, false);
// Check if the output image is not empty
if (!output.IsEmpty()) {
// Perform vertical interpolation on the output image using the specified kernel, region, and coefficients
auto rc = ImagingVerticalInterp(output, input, vert_kernel, vert_region, vert_coeff);
// Check if any error occurred during vertical interpolation
if (rc.IsError()) {
// Print the error message and return false to indicate failure
MS_LOG(ERROR) << "Image vertical resize failed, error msg is " << rc;
return false;
}
}
// Check if the output image is empty after vertical interpolation
if (output.IsEmpty()) {
// Return false to indicate failure
return false;
}
}
// Check if both horizontal and vertical interpolation are disabled
if (!horizontal_interp && !vertical_interp) {
// Set the output image to be the same as the input image
output = input;
}
// Return true to indicate success
return true;
}
// Function to resize an image using cubic interpolation
bool ResizeCubic(const LiteMat &input, const LiteMat &dst, int dst_w, int dst_h) {
// Check if the input image has the correct data type and number of channels
if (input.data_type_ != LDataType::UINT8 || input.channel_ != 3) {
// Log an error message indicating the unsupported data type and number of channels
MS_LOG(ERROR) << "Unsupported data type, only support input image of uint8 dtype and 3 channel, got channel: " +
std::to_string(input.channel_);
// Return false to indicate failure
return false;
}
// Initialize variables for the size of the destination image
int x_size = dst_w, y_size = dst_h;
// Create a rectangle with the dimensions of the input image
int rect[4] = {0, 0, input.width_, input.height_};
// Create an output LiteMat object for the resized image
LiteMat output;
struct interpolation interp = {cubic_interp, 2.0};
bool res = ImageInterpolation(input, output, x_size, y_size, &interp, rect);
// Declare a struct variable named "interp" of type "interpolation" and initialize it with the values {cubic_interp, 2.0}
struct interpolation interp = {cubic_interp, 2.0};
// Declare a boolean variable named "res" and call the function "ImageInterpolation" with the arguments "input", "output", "x_size", "y_size", "&interp", and "rect"
// Store the return value of the function in "res"
bool res = ImageInterpolation(input, output, x_size, y_size, &interp, rect);
// Use the memcpy_s function to copy the data from the output tensor to the destination tensor
auto ret_code = memcpy_s(dst.data_ptr_, output.size_, output.data_ptr_, output.size_);
// Check if the memcpy_s function returned an error code
if (ret_code != 0) {
// If an error occurred, log an error message and return false
MS_LOG(ERROR) << "memcpy_s failed when copying tensor.";
return false;
}
// Return the result of the operation
return res;
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -15,65 +15,130 @@
*/
#include "minddata/dataset/kernels/image/resize_op.h"
// Check if the ENABLE_ANDROID macro is defined
#ifndef ENABLE_ANDROID
// If ENABLE_ANDROID is not defined, include the image_utils.h header file from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/image_utils.h"
// If ENABLE_ANDROID is defined, include the lite_image_utils.h header file from the minddata/dataset/kernels/image directory
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Include the status.h header file from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Define the namespace "mindspore" for encapsulating related code
namespace mindspore {
// Define the nested namespace "dataset" for encapsulating dataset-related code
namespace dataset {
// Define the constant integer variable "kDefWidth" with a default value of 0
const int32_t ResizeOp::kDefWidth = 0;
// Define the constant enumeration variable "kDefInterpolation" with a default value of InterpolationMode::kLinear
const InterpolationMode ResizeOp::kDefInterpolation = InterpolationMode::kLinear;
Status ResizeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
RETURN_IF_NOT_OK(ValidateImageRank("Resize", static_cast<int32_t>(input->shape().Size())));
int32_t output_h = 0;
int32_t output_w = 0;
int32_t input_h = static_cast<int>(input->shape()[0]);
int32_t input_w = static_cast<int>(input->shape()[1]);
if (size2_ == 0) {
if (input_h < input_w) {
CHECK_FAIL_RETURN_UNEXPECTED(input_h != 0, "Resize: the input height cannot be 0.");
output_h = size1_;
output_w = static_cast<int>(std::lround((static_cast<float>(input_w) / input_h) * output_h));
} else {
CHECK_FAIL_RETURN_UNEXPECTED(input_w != 0, "Resize: the input width cannot be 0.");
output_w = size1_;
output_h = static_cast<int>(std::lround((static_cast<float>(input_h) / input_w) * output_w));
}
} else {
// The code snippet provided does not contain the complete definition of the ResizeOp class.
// It only defines the default values for the static member variables "kDefWidth" and "kDefInterpolation".
// The complete definition of the ResizeOp class should be present elsewhere in the code.
// The ResizeOp class likely contains member functions and other member variables that are not shown here.
// The purpose of this code is to initialize the default values for the static member variables of the ResizeOp class.
} // end of namespace dataset
} // end of namespace mindspore
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Validate the rank of the input tensor to ensure it is an image
RETURN_IF_NOT_OK(ValidateImageRank("Resize", static_cast<int32_t>(input->shape().Size())));
// Initialize variables for the output height and width
int32_t output_h = 0;
int32_t output_w = 0;
// Get the input height and width from the shape of the input tensor
int32_t input_h = static_cast<int>(input->shape()[0]);
int32_t input_w = static_cast<int>(input->shape()[1]);
// Check if size2_ is 0, which means only one dimension is specified for resizing
if (size2_ == 0) {
// If the input height is smaller than the input width
if (input_h < input_w) {
// Check if the input height is not 0
CHECK_FAIL_RETURN_UNEXPECTED(input_h != 0, "Resize: the input height cannot be 0.");
// Calculate the output height based on the specified size1_ and the aspect ratio of the input image
output_h = size1_;
output_w = size2_;
output_w = static_cast<int>(std::lround((static_cast<float>(input_w) / input_h) * output_h));
} else {
// Check if the input width is not 0
CHECK_FAIL_RETURN_UNEXPECTED(input_w != 0, "Resize: the input width cannot be 0.");
// Calculate the output width based on the specified size1_ and the aspect ratio of the input image
output_w = size1_;
output_h = static_cast<int>(std::lround((static_cast<float>(input_h) / input_w) * output_w));
}
} else {
// If both dimensions are specified for resizing, use the specified size1_ and size2_
output_h = size1_;
output_w = size2_;
}
// Return the result of calling the Resize function with the provided arguments
// The Resize function is expected to take an input image, an output image, and the desired output dimensions
// The last three arguments are the starting point for cropping the input image (0, 0 in this case)
// The last argument is the interpolation method to be used (interpolation_ in this case)
return Resize(input, output, output_h, output_w, 0, 0, interpolation_);
}
// Check if the input shape is valid and calculate the output shape for the Resize operation
Status ResizeOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Call the OutputShape function of the base class TensorOp and check if it returns an error
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector to ensure it is empty before calculating the output shape
outputs.clear();
// Initialize variables to store the output height and width
int32_t outputH = -1, outputW = -1;
// if size2_ == 0, then we cannot know the shape. We need the input image to find the output shape --> set it to
// <-1,-1[,3]>
// If size2_ is not equal to 0, we can determine the output shape based on the provided size1_ and size2_
if (size2_ != 0) {
outputH = size1_;
outputW = size2_;
}
// Create a TensorShape object with the calculated output height and width
TensorShape out = TensorShape{outputH, outputW};
// Check the rank of the input shape
if (inputs[0].Rank() == 2) {
// If the input shape has rank 2, append the output shape to the outputs vector
(void)outputs.emplace_back(out);
}
if (inputs[0].Rank() == 3) {
// If the input shape has rank 3, append the output shape with an additional dimension for the channel
(void)outputs.emplace_back(out.AppendDim(inputs[0][2]));
}
// Check if the outputs vector is not empty
if (!outputs.empty()) {
// Return OK status to indicate successful calculation of the output shape
return Status::OK();
}
return Status(StatusCode::kMDUnexpectedError,
"Resize: invalid input shape, expected 2D or 3D input, but got input dimension is:" +
std::to_string(inputs[0].Rank()));
}
// Return a Status object with an error code and error message
return Status(StatusCode::kMDUnexpectedError,
"Resize: invalid input shape, expected 2D or 3D input, but got input dimension is:" +
std::to_string(inputs[0].Rank()));
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -16,24 +16,44 @@
#include "minddata/dataset/kernels/image/resize_preserve_ar_op.h"
#ifdef ENABLE_ANDROID
// If the ENABLE_ANDROID macro is defined, include the "lite_image_utils.h" header file from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Include the "status.h" header file from the "minddata/dataset/util" directory
#include "minddata/dataset/util/status.h"
// The code is defining a constant integer variable named "kDefImgOrientation" inside the "ResizePreserveAROp" class in the "dataset" namespace of the "mindspore" namespace.
namespace mindspore {
namespace dataset {
// Define the default value for the image orientation constant
const int32_t ResizePreserveAROp::kDefImgOrientation = 0;
// Define the constructor for the ResizePreserveAROp class
ResizePreserveAROp::ResizePreserveAROp(int32_t height, int32_t width, int32_t img_orientation)
: height_(height), width_(width), img_orientation_(img_orientation) {}
// The Compute function of the ResizePreserveAROp class
Status ResizePreserveAROp::Compute(const TensorRow &inputs, TensorRow *outputs) {
// Check if the inputs and outputs are vectors
IO_CHECK_VECTOR(inputs, outputs);
// Conditional compilation for Android platform
#ifdef ENABLE_ANDROID
// Call the ResizePreserve function with the provided inputs, height, width, image orientation, and outputs
return ResizePreserve(inputs, height_, width_, img_orientation_, outputs);
#endif
// Return a Status object indicating that the computation was successful
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
// Closing braces to end the namespace blocks for "dataset" and "mindspore"

View File

@ -14,39 +14,94 @@
* limitations under the License.
*/
// Include the header file for the "resize_with_bbox_op" class from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/resize_with_bbox_op.h"
// Include the "utility" header file for the utility functions and classes
#include <utility>
// Include the "memory" header file for the smart pointers
#include <memory>
// Include the header file for the "resize_op" class from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/resize_op.h"
// Include the header file for the "bounding_box" class from the "minddata/dataset/kernels/image" directory
#include "minddata/dataset/kernels/image/bounding_box.h"
// Include the header file for the "cv_tensor" class from the "minddata/dataset/core" directory
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for the "tensor" class from the "minddata/dataset/core" directory
#include "minddata/dataset/core/tensor.h"
// Include the header file for the "tensor_op" class from the "minddata/dataset/kernels" directory
#include "minddata/dataset/kernels/tensor_op.h"
// Include the header file for the "status" class from the "minddata/dataset/util" directory
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Compute function for the ResizeWithBBoxOp class
Status ResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output are vectors
IO_CHECK_VECTOR(input, output);
// Validate the bounding boxes in the input
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
int32_t input_h = input[0]->shape()[0];
int32_t input_w = input[0]->shape()[1];
output->resize(2);
(*output)[1] = input[1]; // move boxes over to output
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input[0]);
RETURN_IF_NOT_OK(ResizeOp::Compute(std::static_pointer_cast<Tensor>(input_cv), &(*output)[0]));
int32_t output_h = (*output)[0]->shape()[0]; // output height if ResizeWithBBox
int32_t output_w = (*output)[0]->shape()[1]; // output width if ResizeWithBBox
size_t bboxCount = input[1]->shape()[0]; // number of rows in bbox tensor
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForResize((*output)[1], bboxCount, output_w, output_h, input_w, input_h));
return Status::OK();
// Continue with the rest of the function...
}
// Declare and initialize an int32_t variable named input_h, which will store the value of the first dimension of the input tensor
int32_t input_h = input[0]->shape()[0];
// Declare and initialize an int32_t variable named input_w, which will store the value of the second dimension of the input tensor
int32_t input_w = input[0]->shape()[1];
// Resize the output vector to have a size of 2
output->resize(2);
// Move the value at index 1 of the input vector to index 1 of the output vector
(*output)[1] = input[1];
// Create a shared pointer named "input_cv" of type "CVTensor" and initialize it with the result of calling the static member function "AsCVTensor" of the "CVTensor" class, passing "input[0]" as the argument.
// Call the Compute function of the ResizeOp class, passing in the input_cv tensor and the address of the first element of the output tensor
// Use std::static_pointer_cast to cast the input_cv tensor to a std::shared_ptr<Tensor> before passing it to the Compute function
// Use the dereference operator (*) to get the value at the address of the first element of the output tensor
// Return the result of the Compute function, which is a status code indicating success or failure
// Get the height of the output tensor by accessing the first element of the vector `output` and calling the `shape()` function, followed by accessing the first element of the resulting shape vector
int32_t output_h = (*output)[0]->shape()[0];
// Get the width of the output tensor by accessing the first element of the vector `output` and calling the `shape()` function, followed by accessing the second element of the resulting shape vector
int32_t output_w = (*output)[0]->shape()[1];
// Declare a variable `bboxCount` of type `size_t` to store the number of rows in the `bbox` tensor
size_t bboxCount = input[1]->shape()[0];
// Call the `UpdateBBoxesForResize` function from the `BoundingBox` class to update the bounding boxes for resize
// Pass the `(*output)[1]` tensor, `bboxCount`, `output_w`, `output_h`, `input_w`, and `input_h` as arguments
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForResize((*output)[1], bboxCount, output_w, output_h, input_w, input_h));
// Return a `Status::OK()` to indicate successful execution of the function
return Status::OK();
}
// End of the `dataset` namespace
} // namespace dataset
} // namespace mindspore
// End of the `mindspore` namespace

View File

@ -18,18 +18,40 @@
#include "minddata/dataset/kernels/image/image_utils.h"
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// The #endif directive is used to end a conditional compilation block started by #ifdef or #ifndef
// Since there is no corresponding #ifdef or #ifndef in the provided code, this #endif is unnecessary
// It can be safely removed from the code
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
Status RgbToBgrOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
auto input_type = input->type();
CHECK_FAIL_RETURN_UNEXPECTED(input_type != DataType::DE_UINT32 && input_type != DataType::DE_UINT64 &&
input_type != DataType::DE_INT64 && input_type != DataType::DE_STRING,
"RgbToBgr: Input includes unsupported data type in [uint32, int64, uint64, string].");
// Start of the "dataset" namespace
namespace dataset {
// Implementation of the Compute function for the RgbToBgrOp class
Status RgbToBgrOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output pointers are valid
IO_CHECK(input, output);
// Get the data type of the input tensor
auto input_type = input->type();
// Check if the input data type is unsupported (uint32, int64, uint64, string)
CHECK_FAIL_RETURN_UNEXPECTED(input_type != DataType::DE_UINT32 && input_type != DataType::DE_UINT64 &&
input_type != DataType::DE_INT64 && input_type != DataType::DE_STRING,
"RgbToBgr: Input includes unsupported data type in [uint32, int64, uint64, string].");
// Rest of the function implementation...
} // End of the Compute function
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Return the result of calling the RgbToBgr function with the input and output parameters
return RgbToBgr(input, output);
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -20,13 +20,29 @@
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// The Compute function of the RgbToGrayOp class takes in a shared pointer to an input tensor and a pointer to an output tensor
Status RgbToGrayOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Call the RgbToGray function to convert the input tensor to grayscale and store the result in the output tensor
return RgbToGray(input, output);
}
} // namespace dataset
} // namespace mindspore
// Closing braces to end the namespace blocks for "dataset" and "mindspore"

View File

@ -15,15 +15,36 @@
*/
#include "minddata/dataset/kernels/image/rgba_to_bgr_op.h"
// Include the header file for image utilities from the MindData library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility from the MindData library
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// The Compute function of the RgbaToBgrOp class
Status RgbaToBgrOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Call the RgbaToBgr function to convert the input tensor from RGBA to BGR format
return RgbaToBgr(input, output);
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -15,15 +15,36 @@
*/
#include "minddata/dataset/kernels/image/rgba_to_rgb_op.h"
// Include the header file for image utilities from the MindData library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility from the MindData library
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// The Compute function of the RgbaToRgbOp class
Status RgbaToRgbOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Call the RgbaToRgb function to convert the input tensor from RGBA to RGB
return RgbaToRgb(input, output);
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -14,80 +14,153 @@
* limitations under the License.
*/
// Include the rotate_op.h header file from the minddata/dataset/kernels/image directory
#include "minddata/dataset/kernels/image/rotate_op.h"
// Check if the ENABLE_ANDROID macro is defined
#ifndef ENABLE_ANDROID
#include "minddata/dataset/kernels/image/image_utils.h"
// If ENABLE_ANDROID is not defined, include the "minddata/dataset/kernels/image/image_utils.h" header file
#include "minddata/dataset/kernels/image/image_utils.h"
#else
#include "minddata/dataset/kernels/image/lite_image_utils.h"
// If ENABLE_ANDROID is defined, include the "minddata/dataset/kernels/image/lite_image_utils.h" header file
#include "minddata/dataset/kernels/image/lite_image_utils.h"
#endif
// Define the namespace "mindspore"
namespace mindspore {
namespace dataset {
const std::vector<float> RotateOp::kDefCenter = {};
const InterpolationMode RotateOp::kDefInterpolation = InterpolationMode::kNearestNeighbour;
const bool RotateOp::kDefExpand = false;
const uint8_t RotateOp::kDefFillR = 0;
const uint8_t RotateOp::kDefFillG = 0;
const uint8_t RotateOp::kDefFillB = 0;
// Define the namespace "dataset" within the "mindspore" namespace
namespace dataset {
// Define the constant static member variable "kDefCenter" of type std::vector<float> in the RotateOp class
const std::vector<float> RotateOp::kDefCenter = {};
// Define the constant static member variable "kDefInterpolation" of type InterpolationMode in the RotateOp class
const InterpolationMode RotateOp::kDefInterpolation = InterpolationMode::kNearestNeighbour;
// Define the constant static member variable "kDefExpand" of type bool in the RotateOp class
const bool RotateOp::kDefExpand = false;
// Define the constant static member variable "kDefFillR" of type uint8_t in the RotateOp class
const uint8_t RotateOp::kDefFillR = 0;
// Define the constant static member variable "kDefFillG" of type uint8_t in the RotateOp class
const uint8_t RotateOp::kDefFillG = 0;
// Define the constant static member variable "kDefFillB" of type uint8_t in the RotateOp class
const uint8_t RotateOp::kDefFillB = 0;
}
}
// Definition of the constructor for the RotateOp class, taking an angle_id as a parameter
RotateOp::RotateOp(int angle_id)
: angle_id_(angle_id),
degrees_(0),
center_({}),
interpolation_(InterpolationMode::kLinear),
expand_(false),
fill_r_(0),
fill_g_(0),
fill_b_(0) {}
: angle_id_(angle_id), // Initialize the angle_id_ member variable with the value passed as a parameter
degrees_(0), // Initialize the degrees_ member variable with the value 0
center_({}), // Initialize the center_ member variable with an empty initializer list
interpolation_(InterpolationMode::kLinear), // Initialize the interpolation_ member variable with the value InterpolationMode::kLinear
expand_(false), // Initialize the expand_ member variable with the value false
fill_r_(0), // Initialize the fill_r_ member variable with the value 0
fill_g_(0), // Initialize the fill_g_ member variable with the value 0
fill_b_(0) {} // Initialize the fill_b_ member variable with the value 0
// Definition of the constructor for the RotateOp class
RotateOp::RotateOp(float degrees, InterpolationMode resample, bool expand, std::vector<float> center, uint8_t fill_r,
uint8_t fill_g, uint8_t fill_b)
: angle_id_(0),
degrees_(degrees),
center_(center),
interpolation_(resample),
expand_(expand),
fill_r_(fill_r),
fill_g_(fill_g),
fill_b_(fill_b) {}
: angle_id_(0), // Initialize the angle_id_ member variable to 0
degrees_(degrees), // Initialize the degrees_ member variable with the provided degrees value
center_(center), // Initialize the center_ member variable with the provided center vector
interpolation_(resample), // Initialize the interpolation_ member variable with the provided resample value
expand_(expand), // Initialize the expand_ member variable with the provided expand value
fill_r_(fill_r), // Initialize the fill_r_ member variable with the provided fill_r value
fill_g_(fill_g), // Initialize the fill_g_ member variable with the provided fill_g value
fill_b_(fill_b) {} // Initialize the fill_b_ member variable with the provided fill_b value
// The Compute function of the RotateOp class
Status RotateOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Validate the rank of the input tensor
RETURN_IF_NOT_OK(ValidateImageRank("Rotate", static_cast<int32_t>(input->shape().Size())));
// Check if the code is being compiled for Android
#ifndef ENABLE_ANDROID
// Call the Rotate function with the specified parameters
return Rotate(input, output, center_, degrees_, interpolation_, expand_, fill_r_, fill_g_, fill_b_);
#else
// Call the Rotate function with the specified parameters for Android
return Rotate(input, output, angle_id_);
#endif
}
Status RotateOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Check if the code is being compiled for Android
#ifndef ENABLE_ANDROID
// Call the OutputShape function of the base class TensorOp and store the result in outputs
RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs));
// Clear the outputs vector
outputs.clear();
// Initialize outputH and outputW to -1
int32_t outputH = -1, outputW = -1;
// if expand_, then we cannot know the shape. We need the input image to find the output shape --> set it to
// <-1,-1[,3]>
// Check if expand_ is false
// If expand_ is true, we cannot determine the output shape and set it to <-1,-1[,3]>
if (!expand_) {
// Set outputH and outputW to the values of the first two dimensions of the input shape
outputH = inputs[0][0];
outputW = inputs[0][1];
}
// Create a TensorShape object out with dimensions outputH and outputW
TensorShape out = TensorShape{outputH, outputW};
// Check if the rank of the input shape is 2
// If it is, append out to outputs
if (inputs[0].Rank() == 2) outputs.emplace_back(out);
// Check if the rank of the input shape is 3
// If it is, append out with an additional dimension equal to the third dimension of the input shape to outputs
if (inputs[0].Rank() == 3) outputs.emplace_back(out.AppendDim(inputs[0][2]));
// Check if outputs is not empty
// If it is not empty, return Status::OK()
if (!outputs.empty()) return Status::OK();
// Return an error status with a message indicating that the input shape is invalid
return Status(StatusCode::kMDUnexpectedError,
"Rotate: invalid input shape, expected 2D or 3D input, but got input dimension is:" +
std::to_string(inputs[0].Rank()));
#else
// Check if the size of the inputs vector is not equal to the number of inputs expected by the operator
// If it is not equal, return an error status with a message indicating the mismatch
if (inputs.size() != NumInput())
return Status(StatusCode::kMDUnexpectedError,
"The size of the input argument vector: " + std::to_string(inputs.size()) +
", does not match the number of inputs: " + std::to_string(NumInput()));
// Set outputs to be equal to inputs
outputs = inputs;
// Return Status::OK()
return Status::OK();
#endif
}
// Close the namespace dataset
} // namespace dataset
} // namespace mindspore
// Close the namespace mindspore
} // namespace mindspore

View File

@ -14,67 +14,148 @@
* limitations under the License.
*/
// Include the header file for the sharpness operation in the MindData dataset kernels for images
#include "minddata/dataset/kernels/image/sharpness_op.h"
// Include the header file for image utilities in the MindData dataset kernels
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the CVTensor class in the MindData dataset core
#include "minddata/dataset/core/cv_tensor.h"
// Include the header file for the Status class in the MindData dataset utilities
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code specific to the "dataset" namespace can be written here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// Define a constant float variable named kDefAlpha and assign it the value 1.0
const float SharpnessOp::kDefAlpha = 1.0;
Status SharpnessOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// Compute function for the SharpnessOp class, which takes an input tensor and produces an output tensor
// The function returns a status indicating the success or failure of the computation
// Check if the input and output tensors are valid (non-null)
IO_CHECK(input, output);
try {
// Convert the input tensor to a CVTensor using the AsCVTensor function
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input);
// Get the OpenCV Mat object from the CVTensor
cv::Mat input_img = input_cv->mat();
// Check if the Mat object contains valid data
if (!input_cv->mat().data) {
// If the Mat object does not contain valid data, return an error message
RETURN_STATUS_UNEXPECTED("[Internal ERROR] Sharpness: load image failed.");
}
// Check if the rank of the input tensor is equal to 1 or if the number of dimensions in the input matrix is greater than 2
if (input_cv->Rank() == 1 || input_cv->mat().dims > 2) {
RETURN_STATUS_UNEXPECTED("Sharpness: shape of input is not <H,W,C> or <H,W>, but got rank: " +
std::to_string(input_cv->Rank()));
// If the condition is true, return an error message indicating that the shape of the input is not <H,W,C> or <H,W>,
// and also include the rank of the input tensor in the error message
RETURN_STATUS_UNEXPECTED("Sharpness: shape of input is not <H,W,C> or <H,W>, but got rank: " +
std::to_string(input_cv->Rank()));
}
/// creating a smoothing filter. 1, 1, 1,
/// 1, 5, 1,
/// 1, 1, 1
// Creating a smoothing filter with the following pattern:
// 1, 1, 1,
// 1, 5, 1,
// 1, 1, 1
const float filterMid = 5.0;
const float filterSum = 13.0;
cv::Mat filter = cv::Mat(3, 3, CV_32F, cv::Scalar::all(1.0 / filterSum));
filter.at<float>(1, 1) = filterMid / filterSum;
// Define a constant float variable named filterMid and assign it the value 5.0
const float filterMid = 5.0;
/// applying filter on channels
cv::Mat result = cv::Mat();
cv::filter2D(input_img, result, -1, filter);
// Define a constant float variable named filterSum and assign it the value 13.0
const float filterSum = 13.0;
int height = input_cv->shape()[0];
int width = input_cv->shape()[1];
// Create a cv::Mat object named filter with dimensions 3x3, data type CV_32F, and initialize all elements with the value 1.0 divided by filterSum
cv::Mat filter = cv::Mat(3, 3, CV_32F, cv::Scalar::all(1.0 / filterSum));
/// restoring the edges
input_img.row(0).copyTo(result.row(0));
input_img.row(height - 1).copyTo(result.row(height - 1));
input_img.col(0).copyTo(result.col(0));
input_img.col(width - 1).copyTo(result.col(width - 1));
// Set the element at row 1, column 1 of the filter matrix to the value of filterMid divided by filterSum
filter.at<float>(1, 1) = filterMid / filterSum;
/// blend based on alpha : (alpha_ *input_img) + ((1.0-alpha_) * result);
cv::addWeighted(input_img, alpha_, result, 1.0 - alpha_, 0.0, result);
// Apply a filter on the channels of an image
std::shared_ptr<CVTensor> output_cv;
RETURN_IF_NOT_OK(CVTensor::CreateFromMat(result, input_cv->Rank(), &output_cv));
RETURN_UNEXPECTED_IF_NULL(output_cv);
// Create an empty matrix to store the result
cv::Mat result = cv::Mat();
*output = std::static_pointer_cast<Tensor>(output_cv);
}
// Apply the filter using the filter2D function
// input_img: the input image to apply the filter on
// result: the output matrix to store the filtered image
// -1: the desired depth of the output image, -1 means the same depth as the input image
// filter: the filter to apply on the image
cv::filter2D(input_img, result, -1, filter);
// Declare and initialize an integer variable named "height" with the value of the first dimension of the "input_cv" shape
int height = input_cv->shape()[0];
// Declare and initialize an integer variable named "width" with the value of the second dimension of the "input_cv" shape
int width = input_cv->shape()[1];
// Restoring the edges of the image
// Copy the first row of the input image to the corresponding row of the result image
input_img.row(0).copyTo(result.row(0));
// Copy the last row of the input image to the corresponding row of the result image
input_img.row(height - 1).copyTo(result.row(height - 1));
// Copy the first column of the input image to the corresponding column of the result image
input_img.col(0).copyTo(result.col(0));
// Copy the last column of the input image to the corresponding column of the result image
input_img.col(width - 1).copyTo(result.col(width - 1));
// Blend the input image and the result image based on the alpha value
// The formula used is: (alpha_ * input_img) + ((1.0 - alpha_) * result)
// Use the OpenCV function addWeighted to perform the blending
// Parameters:
// - input_img: the input image to be blended
// - alpha_: the weight for the input image
// - result: the result image
// - 1.0 - alpha_: the weight for the result image
// - 0.0: the scalar value to be added to the blended images (not used in this case)
// - result: the output image after blending
cv::addWeighted(input_img, alpha_, result, 1.0 - alpha_, 0.0, result);
// Declare a shared pointer named "output_cv" of type CVTensor
std::shared_ptr<CVTensor> output_cv;
// Call the CreateFromMat function of the CVTensor class to create a new CVTensor object from the "result" matrix
// Pass the rank of the "input_cv" object as a parameter to the CreateFromMat function
// Store the created CVTensor object in the "output_cv" shared pointer
RETURN_IF_NOT_OK(CVTensor::CreateFromMat(result, input_cv->Rank(), &output_cv));
// Check if the "output_cv" shared pointer is null
// If it is null, return an unexpected error
RETURN_UNEXPECTED_IF_NULL(output_cv);
// Cast the output_cv variable to the type Tensor using std::static_pointer_cast
// Assign the result of the cast to the output variable
*output = std::static_pointer_cast<Tensor>(output_cv);
}
catch (const cv::Exception &e) {
// Catch any OpenCV exceptions that occur and handle them
// Return an error message with the exception's what() message appended
RETURN_STATUS_UNEXPECTED("Sharpness: " + std::string(e.what()));
}
// Return a Status object indicating successful program termination
return Status::OK();
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace

View File

@ -17,35 +17,80 @@
#include "minddata/dataset/kernels/image/image_utils.h"
#include "minddata/dataset/util/status.h"
// Define the namespace "mindspore"
namespace mindspore {
// Define the nested namespace "dataset"
namespace dataset {
// Define the constant integer variable "kDefNumH" and initialize it with the value 1
const int32_t SlicePatchesOp::kDefNumH = 1;
// Define the constant integer variable "kDefNumW" and initialize it with the value 1
const int32_t SlicePatchesOp::kDefNumW = 1;
// Define the constant unsigned integer variable "kDefFillV" and initialize it with the value 0
const uint8_t SlicePatchesOp::kDefFillV = 0;
// Define the constant enum variable "kDefSliceMode" and initialize it with the value SliceMode::kPad
const SliceMode SlicePatchesOp::kDefSliceMode = SliceMode::kPad;
} // End of namespace dataset
} // End of namespace mindspore
// Define the constructor for the SlicePatchesOp class, which takes in four parameters: num_height, num_width, slice_mode, and fill_value
SlicePatchesOp::SlicePatchesOp(int32_t num_height, int32_t num_width, SliceMode slice_mode, uint8_t fill_value)
: num_height_(num_height), num_width_(num_width), slice_mode_(slice_mode), fill_value_(fill_value) {}
// Compute function for the SlicePatchesOp class, which takes an input TensorRow and produces an output TensorRow
Status SlicePatchesOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output vectors have the same size
IO_CHECK_VECTOR(input, output);
// Check if the size of the input vector is 1
CHECK_FAIL_RETURN_UNEXPECTED(
input.size() == 1,
"size of input should be 1, which means 'input_columns' should be 1 when call this operator, but got:" +
"size of input should be 1, which means 'input_columns' should be 1 when calling this operator, but got:" +
std::to_string(input.size()));
auto in_tensor = input[0];
auto in_type = in_tensor->type();
auto in_shape = in_tensor->shape();
CHECK_FAIL_RETURN_UNEXPECTED(in_type.IsNumeric(), "Input Tensor type should be numeric, got type is non-numeric.");
CHECK_FAIL_RETURN_UNEXPECTED(
in_shape.Rank() >= 2, "Rank of input data should be greater than 2, but got:" + std::to_string(in_shape.Rank()));
std::vector<std::shared_ptr<Tensor>> out;
RETURN_IF_NOT_OK(SlicePatches(in_tensor, &out, num_height_, num_width_, slice_mode_, fill_value_));
(void)std::copy(out.begin(), out.end(), std::back_inserter(*output));
return Status::OK();
// Rest of the code for the Compute function goes here...
}
} // namespace dataset
} // namespace mindspore
// Declare a variable "in_tensor" and assign it the value of the first element in the "input" array
auto in_tensor = input[0];
// Declare a variable "in_type" and assign it the type of "in_tensor"
auto in_type = in_tensor->type();
// Declare a variable "in_shape" and assign it the shape of "in_tensor"
auto in_shape = in_tensor->shape();
// Check if the input tensor type is numeric
CHECK_FAIL_RETURN_UNEXPECTED(in_type.IsNumeric(), "Input Tensor type should be numeric, got type is non-numeric.");
// Check if the rank of the input data is greater than or equal to 2
CHECK_FAIL_RETURN_UNEXPECTED(in_shape.Rank() >= 2, "Rank of input data should be greater than 2, but got:" + std::to_string(in_shape.Rank()));
// Include the necessary headers for the code
#include <vector>
#include <memory>
#include <algorithm>
// Start of the namespace "mindspore"
namespace mindspore {
namespace dataset {
// Function to slice patches from an input tensor and store them in the "out" vector
std::vector<std::shared_ptr<Tensor>> out;
RETURN_IF_NOT_OK(SlicePatches(in_tensor, &out, num_height_, num_width_, slice_mode_, fill_value_));
// Copy the elements from the "out" vector to the "output" vector using std::copy and std::back_inserter
(void)std::copy(out.begin(), out.end(), std::back_inserter(*output));
// Return a status indicating successful program termination
return Status::OK();
// End of the namespace "dataset"
}
}

View File

@ -18,59 +18,119 @@
#include "minddata/dataset/core/cv_tensor.h"
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// only supports RGB images
const uint8_t kPixelValue = 255;
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
Status SolarizeOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
// Code for the "mindspore::dataset" namespace goes here
uint8_t threshold_min_ = threshold_[0], threshold_max_ = threshold_[1];
} // End of the "dataset" namespace
CHECK_FAIL_RETURN_UNEXPECTED(
} // End of the "mindspore" namespace
// Define a constant variable kPixelValue with a value of 255
// This variable represents the maximum pixel value for RGB images, indicating full intensity for each color channel (red, green, and blue)
// Compute function for the SolarizeOp class, which takes an input tensor and computes the solarized version of it
// The solarized version is stored in the output tensor
// Check if the input and output tensors are valid (not null)
IO_CHECK(input, output);
// Declare two variables of type uint8_t named threshold_min_ and threshold_max_
// Initialize threshold_min_ with the value at index 0 of the array threshold_
// Initialize threshold_max_ with the value at index 1 of the array threshold_
uint8_t threshold_min_ = threshold_[0], threshold_max_ = threshold_[1];
// Check if the minimum threshold is less than or equal to the maximum threshold
CHECK_FAIL_RETURN_UNEXPECTED(
threshold_min_ <= threshold_max_,
"Solarize: threshold[0] must be smaller or equal to threshold[1], got 'threshold' value: (" +
std::to_string(threshold_min_) + "," + std::to_string(threshold_max_) + ").");
std::to_string(threshold_min_) + "," + std::to_string(threshold_max_) + ").");
// If the check fails, return an unexpected error message with the values of threshold_min_ and threshold_max_
try {
// Convert the input tensor to a CVTensor using the AsCVTensor function and store it in a shared_ptr
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input);
// Get the underlying cv::Mat object from the CVTensor
cv::Mat input_img = input_cv->mat();
// Check if the cv::Mat object contains valid data
if (!input_cv->mat().data) {
// If the cv::Mat object does not contain valid data, return an error message
RETURN_STATUS_UNEXPECTED("Solarize: load image failed.");
}
std::shared_ptr<CVTensor> mask_mat_tensor;
std::shared_ptr<CVTensor> output_cv_tensor;
RETURN_IF_NOT_OK(CVTensor::CreateFromMat(input_img, input_cv->Rank(), &mask_mat_tensor));
// Declare a shared pointer named `mask_mat_tensor` of type `CVTensor`
std::shared_ptr<CVTensor> mask_mat_tensor;
RETURN_IF_NOT_OK(CVTensor::CreateEmpty(input_cv->shape(), input_cv->type(), &output_cv_tensor));
RETURN_UNEXPECTED_IF_NULL(mask_mat_tensor);
RETURN_UNEXPECTED_IF_NULL(output_cv_tensor);
// Declare a shared pointer named `output_cv_tensor` of type `CVTensor`
std::shared_ptr<CVTensor> output_cv_tensor;
// Call the `CreateFromMat` function of the `CVTensor` class to create a `CVTensor` object from `input_img`
// Pass the `input_cv->Rank()` as the second argument and assign the result to `mask_mat_tensor`
RETURN_IF_NOT_OK(CVTensor::CreateFromMat(input_img, input_cv->Rank(), &mask_mat_tensor));
// Create an empty CVTensor with the same shape and type as the input CVTensor, and assign it to the output_cv_tensor variable. If the creation fails, return an error code.
RETURN_IF_NOT_OK(CVTensor::CreateEmpty(input_cv->shape(), input_cv->type(), &output_cv_tensor));
// Check if the mask_mat_tensor is null. If it is null, return an error code.
RETURN_UNEXPECTED_IF_NULL(mask_mat_tensor);
// Check if the output_cv_tensor is null. If it is null, return an error code.
RETURN_UNEXPECTED_IF_NULL(output_cv_tensor);
// Check if the minimum threshold is equal to the maximum threshold
if (threshold_min_ == threshold_max_) {
// If they are equal, set all elements in the mask matrix to 0 except for the elements greater than or equal to the minimum threshold
mask_mat_tensor->mat().setTo(0, ~(input_cv->mat() >= threshold_min_));
} else {
// If they are not equal, set all elements in the mask matrix to 0 except for the elements that are both greater than or equal to the minimum threshold and less than or equal to the maximum threshold
mask_mat_tensor->mat().setTo(0, ~((input_cv->mat() >= threshold_min_) & (input_cv->mat() <= threshold_max_)));
}
// solarize desired portion
constexpr int max_size = 255;
output_cv_tensor->mat() = cv::Scalar::all(max_size) - mask_mat_tensor->mat();
input_cv->mat().copyTo(output_cv_tensor->mat(), mask_mat_tensor->mat() == 0);
input_cv->mat().copyTo(output_cv_tensor->mat(), input_cv->mat() < threshold_min_);
// Define a constant integer variable named "max_size" with a value of 255
constexpr int max_size = 255;
*output = std::static_pointer_cast<Tensor>(output_cv_tensor);
}
// Set the matrix of the "output_cv_tensor" to be the result of subtracting "mask_mat_tensor" from a matrix filled with "max_size"
output_cv_tensor->mat() = cv::Scalar::all(max_size) - mask_mat_tensor->mat();
// Copy the matrix of "input_cv" to the matrix of "output_cv_tensor" where the corresponding element in "mask_mat_tensor" is equal to 0
input_cv->mat().copyTo(output_cv_tensor->mat(), mask_mat_tensor->mat() == 0);
// Copy the matrix of "input_cv" to the matrix of "output_cv_tensor" where the corresponding element in "input_cv" is less than "threshold_min_"
input_cv->mat().copyTo(output_cv_tensor->mat(), input_cv->mat() < threshold_min_);
// Cast the output_cv_tensor to the type Tensor using std::static_pointer_cast
// Assign the result of the cast to the variable output
*output = std::static_pointer_cast<Tensor>(output_cv_tensor);
}
catch (const cv::Exception &e) {
// Catch any OpenCV exceptions that may occur during execution
const std::string cv_err_msg(e.what());
// Create a string to store the error message
std::string err_message = "Solarize: ";
// Append the OpenCV error message to the error message string
err_message += cv_err_msg;
// Return an unexpected status with the error message
RETURN_STATUS_UNEXPECTED(err_message);
}
// Return a status indicating successful execution
return Status::OK();
}
// Close the dataset namespace
} // namespace dataset
} // namespace mindspore
// Close the mindspore namespace
} // namespace mindspore

View File

@ -15,15 +15,36 @@
*/
#include "minddata/dataset/kernels/image/swap_red_blue_op.h"
// Include the header file for image utilities from the MindData library
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file for the status utility from the MindData library
#include "minddata/dataset/util/status.h"
// Start of the "mindspore" namespace
namespace mindspore {
namespace dataset {
// Start of the "dataset" namespace, which is a sub-namespace of "mindspore"
namespace dataset {
// Code for the "mindspore::dataset" namespace goes here
} // End of the "dataset" namespace
} // End of the "mindspore" namespace
// The Compute function of the SwapRedBlueOp class
Status SwapRedBlueOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output tensors are valid
IO_CHECK(input, output);
// Call the SwapRedAndBlue function to perform the red and blue channel swapping
return SwapRedAndBlue(input, output);
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -1,63 +1,87 @@
/**
* 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
// 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
// This is a comment that provides a URL to the Apache License 2.0
// The Apache License 2.0 is a permissive open-source license that allows users to freely use, modify, and distribute the licensed software
// More information about the Apache License 2.0 can be found at the provided URL: 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.
*/
// This comment block appears to be a license statement, indicating the terms under which the software is distributed.
// It states that unless required by applicable law or agreed to in writing, the software is distributed under the License.
// The software is distributed on an "AS IS" BASIS, meaning there are no warranties or conditions of any kind, either express or implied.
// The License should be consulted for more details on the specific terms and limitations.
// Include the header file "minddata/dataset/kernels/image/uniform_aug_op.h"
#include "minddata/dataset/kernels/image/uniform_aug_op.h"
// Include the utility header, which provides various utility functions and classes
#include <utility>
// Include the "random.h" header file from the "minddata/dataset/util" directory
#include "minddata/dataset/util/random.h"
// Define the namespace "mindspore" for encapsulating related code
namespace mindspore {
// Define the nested namespace "dataset" for encapsulating dataset-related code
namespace dataset {
// Define a constant integer variable "kDefNumOps" with a value of 2 for the UniformAugOp class
const int UniformAugOp::kDefNumOps = 2;
// Define the constructor for the UniformAugOp class
UniformAugOp::UniformAugOp(std::vector<std::shared_ptr<TensorOp>> op_list, int32_t num_ops)
: tensor_op_list_(std::move(op_list)), num_ops_(num_ops) {
// Seed the random number generator with a seed obtained from the GetSeed() function
rnd_.seed(GetSeed());
}
// compute method to apply uniformly random selected augmentations from a list
Status UniformAugOp::Compute(const TensorRow &input, TensorRow *output) {
IO_CHECK_VECTOR(input, output);
// The Compute method of the UniformAugOp class is used to apply uniformly randomly selected augmentations from a list to the input tensor row and store the result in the output tensor row.
// randomly select ops to be applied
std::vector<std::shared_ptr<TensorOp>> selected_tensor_ops;
std::sample(tensor_op_list_.begin(), tensor_op_list_.end(), std::back_inserter(selected_tensor_ops), num_ops_, rnd_);
// Check if the input and output tensor rows are valid vectors
IO_CHECK_VECTOR(input, output);
bool first = true;
for (const auto &tensor_op : selected_tensor_ops) {
// Do NOT apply the op, if second random generator returned zero
if (std::uniform_int_distribution<int>(0, 1)(rnd_)) {
continue;
// Create a vector to store the selected tensor operations
std::vector<std::shared_ptr<TensorOp>> selected_tensor_ops;
// Randomly select a specified number of tensor operations from the tensor_op_list_
// and store them in the selected_tensor_ops vector
std::sample(tensor_op_list_.begin(), tensor_op_list_.end(), std::back_inserter(selected_tensor_ops), num_ops_, rnd_);
bool first = true; // A boolean variable to keep track of whether we are applying the first tensor operation or not
// Iterate over each tensor operation in the selected_tensor_ops container
for (const auto &tensor_op : selected_tensor_ops) {
// Check if the second random generator returned zero
if (std::uniform_int_distribution<int>(0, 1)(rnd_) == 0) {
continue; // If it returned zero, skip applying the current tensor operation and continue to the next one
}
// apply C++ ops (note: python OPs are not accepted)
// Apply C++ operations (Python operations are not accepted)
if (first) {
RETURN_IF_NOT_OK(tensor_op->Compute(input, output));
first = false;
// If this is the first tensor operation, compute it using the input tensor and store the result in the output tensor
RETURN_IF_NOT_OK(tensor_op->Compute(input, output));
first = false; // Set first to false to indicate that the first tensor operation has been applied
} else {
RETURN_IF_NOT_OK(tensor_op->Compute(std::move(*output), output));
// If this is not the first tensor operation, compute it using the moved output tensor (as input) and store the result in the output tensor
RETURN_IF_NOT_OK(tensor_op->Compute(std::move(*output), output));
}
}
}
// The case where no tensor op is applied.
// Check if the output tensor is empty
if (output->empty()) {
// If it is empty, assign the input tensor to the output tensor
*output = input;
}
// Return the OK status from the Status namespace
return Status::OK();
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -14,15 +14,25 @@
* limitations under the License.
*/
// Include the header file "minddata/dataset/kernels/image/vertical_flip_op.h"
#include "minddata/dataset/kernels/image/vertical_flip_op.h"
#include "minddata/dataset/kernels/image/image_utils.h"
// Include the header file "minddata/dataset/kernels/image/image_utils.h" which contains utility functions for image processing in the MindData library.
// The code is defining a namespace called "mindspore" which contains another namespace called "dataset"
namespace mindspore {
namespace dataset {
// The Compute function of the VerticalFlipOp class is being defined here
Status VerticalFlipOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output pointers are valid
IO_CHECK(input, output);
// Call the VerticalFlip function with the input and output pointers
return VerticalFlip(input, output);
}
} // namespace dataset
} // namespace mindspore
} // namespace mindspore

View File

@ -15,80 +15,193 @@
*/
#include "minddata/dataset/kernels/plugin_op.h"
// Include the header file for the Tensor class from the minddata/dataset/core directory
#include "minddata/dataset/core/tensor.h"
// Include the header file for the PluginLoader class from the minddata/dataset/plugin directory
#include "minddata/dataset/plugin/plugin_loader.h"
// Start of the "mindspore" namespace
namespace mindspore {
// Start of the "dataset" namespace
namespace dataset {
// Implementation of the PluginOp::PluginToTensorRow function
Status PluginOp::PluginToTensorRow(const std::vector<plugin::Tensor> &in_row, TensorRow *out_row) {
// Check if the out_row pointer is not null and if it is empty
CHECK_FAIL_RETURN_UNEXPECTED(out_row != nullptr && out_row->empty(), "null/empty out_row received!");
// Reserve memory in the out_row vector to avoid reallocations
out_row->reserve(in_row.size());
// Iterate over each tensor in the in_row vector
for (const auto &tensor : in_row) {
// Create a shared pointer to a Tensor object
std::shared_ptr<Tensor> output;
// Get the data type of the tensor
DataType tp = DataType(tensor.type_);
// Check if the data type is numeric and not unknown
CHECK_FAIL_RETURN_UNEXPECTED(tp.IsNumeric() && tp != DataType::DE_UNKNOWN,
"Input datatype should be numeric, got Unsupported type: " + tensor.type_);
// Create a Tensor object from the tensor data and shape
RETURN_IF_NOT_OK(Tensor::CreateFromMemory(TensorShape(tensor.shape_), tp, tensor.buffer_.data(), &output));
// Add the created Tensor object to the out_row vector
out_row->emplace_back(output);
}
// Return a Status object indicating successful execution
return Status::OK();
}
// End of the "dataset" namespace
}
// End of the "mindspore" namespace
}
// Convert a TensorRow to a vector of plugin::Tensor objects
Status PluginOp::TensorRowToPlugin(const TensorRow &in_row, std::vector<plugin::Tensor> *out_row) {
// Check if the output vector is not null and empty
CHECK_FAIL_RETURN_UNEXPECTED(out_row != nullptr && out_row->empty(), "null/empty out_row received!");
// Resize the output vector to match the size of the input TensorRow
out_row->resize(in_row.size());
// Iterate over each element in the input TensorRow
for (size_t ind = 0; ind < in_row.size(); ind++) {
// Get a reference to the current plugin::Tensor object
plugin::Tensor &tensor = (*out_row)[ind];
// Check if the current tensor is of numeric type
if (in_row[ind]->type().IsNumeric()) {
// Get the size of the buffer needed to store the tensor data
dsize_t buffer_size = in_row[ind]->SizeInBytes();
// Resize the buffer of the plugin::Tensor object to match the buffer size
tensor.buffer_.resize(buffer_size);
// Check if the buffer size is less than SECUREC_MEM_MAX_LEN
if (buffer_size < SECUREC_MEM_MAX_LEN) {
// Copy the data from the input tensor to the plugin::Tensor buffer using memcpy_s
int ret_code = memcpy_s(tensor.buffer_.data(), tensor.buffer_.size(), in_row[ind]->GetBuffer(), buffer_size);
// Check if the memcpy_s operation was successful
CHECK_FAIL_RETURN_UNEXPECTED(ret_code == 0, "Failed to copy data into plugin tensor.");
} else {
// Copy the data from the input tensor to the plugin::Tensor buffer using memcpy_s
int ret_code = memcpy_s(tensor.buffer_.data(), buffer_size, in_row[ind]->GetBuffer(), buffer_size);
// Check if the memcpy_s operation was successful
CHECK_FAIL_RETURN_UNEXPECTED(ret_code == 0, "Failed to copy data into plugin tensor.");
}
} else { // string tensor, for now, only tensor with 1 string is supported!
// Check if the string tensor has more than 1 element
CHECK_FAIL_RETURN_UNEXPECTED(in_row[ind]->shape().NumOfElements() == 1,
"String tensor with more than 1 element is not yet supported.");
// get the first and only string in this tensor
// Get the first and only string in this tensor
std::string str1(*(in_row[ind]->begin<std::string_view>()));
tensor.buffer_.resize(str1.size());
auto ret_code = memcpy_s(tensor.buffer_.data(), tensor.buffer_.size(), str1.data(), str1.size());
CHECK_FAIL_RETURN_UNEXPECTED(ret_code == 0, "memcpy_s failed when copying string tensor.");
}
}
}
// Resize the buffer of the tensor to match the size of the input string
tensor.buffer_.resize(str1.size());
// Use the memcpy_s function to copy the data from the input string to the tensor buffer
auto ret_code = memcpy_s(tensor.buffer_.data(), tensor.buffer_.size(), str1.data(), str1.size());
// Check if the memcpy_s function returned a success code (0) and return an error message if it failed
CHECK_FAIL_RETURN_UNEXPECTED(ret_code == 0, "memcpy_s failed when copying string tensor.");
}
// Set the shape of the tensor to match the shape of the input row
tensor.shape_ = in_row[ind]->shape().AsVector();
// Set the type of the tensor to match the type of the input row
tensor.type_ = in_row[ind]->type().ToString();
}
// Return a status indicating that the function executed successfully
return Status::OK();
}
// The Compute function of the PluginOp class, which takes an input TensorRow and produces an output TensorRow
Status PluginOp::Compute(const TensorRow &input, TensorRow *output) {
// Compute should quit if init fails. Error code has already been logged, no need to repeat
// Check if the initialization code has failed, and return if it has
RETURN_IF_NOT_OK(init_code_);
// Create vectors to hold the input and output plugin Tensors
std::vector<plugin::Tensor> in_row, out_row;
// Convert the input TensorRow to plugin Tensors and store them in the in_row vector
RETURN_IF_NOT_OK(TensorRowToPlugin(input, &in_row));
// Call the Compute function of the plugin_op_ object, passing in the input and output vectors
plugin::Status rc = plugin_op_->Compute(&in_row, &out_row);
// Check if the Compute function returned an error status, and log the error message if it did
CHECK_FAIL_RETURN_UNEXPECTED(rc.IsOk(), rc.ToString());
// Convert the output plugin Tensors to a TensorRow and store it in the output parameter
RETURN_IF_NOT_OK(PluginToTensorRow(out_row, output));
// Return a success status
return Status::OK();
}
// Constructor for the PluginOp class
PluginOp::PluginOp(const std::string &lib_path, const std::string &func_name, const std::string &user_args)
: plugin_op_(nullptr), lib_path_(lib_path), func_name_(func_name), user_args_(user_args) {
// Call the Init() function and assign its return value to the init_code_ member variable
init_code_ = Init();
}
// Initialize the PluginOp function
Status PluginOp::Init() {
// Create a pointer to the PluginManagerBase class and initialize it to nullptr
plugin::PluginManagerBase *plugin = nullptr;
// Load the plugin using the PluginLoader singleton instance and the provided library path
// The loaded plugin is stored in the 'plugin' pointer
RETURN_IF_NOT_OK(PluginLoader::GetInstance()->LoadPlugin(lib_path_, &plugin));
// casting a void pointer to specific type
// Cast the void pointer 'plugin' to the specific type 'plugin::TensorOp' and assign it to 'plugin_op_'
plugin_op_ = dynamic_cast<plugin::TensorOp *>(plugin->GetModule(func_name_));
// Return an error if the cast failed (i.e., 'plugin_op_' is nullptr)
RETURN_UNEXPECTED_IF_NULL(plugin_op_);
// Parse the serialized arguments 'user_args_' using the 'plugin_op_' object
plugin::Status rc = plugin_op_->ParseSerializedArgs(user_args_);
// Check if the parsing was successful, otherwise return an error with the error message
CHECK_FAIL_RETURN_UNEXPECTED(rc.IsOk(), rc.ToString());
// Return a success status
return Status::OK();
}
// End of the 'dataset' namespace
} // namespace dataset
} // namespace mindspore
// End of the 'mindspore' namespace
} // namespace mindspore

View File

@ -15,149 +15,264 @@
*/
#include "minddata/dataset/kernels/py_func_op.h"
// Include the memory header for smart pointers and dynamic memory management
#include <memory>
// Include the vector header for dynamic arrays
#include <vector>
// Include the header file for the Tensor class from the minddata/dataset/core directory
#include "minddata/dataset/core/tensor.h"
// Include the header file for the transforms_ir.h file from the minddata/dataset/kernels/ir/data directory
#include "minddata/dataset/kernels/ir/data/transforms_ir.h"
// Include the header file for the TensorOp class from the minddata/dataset/kernels directory
#include "minddata/dataset/kernels/tensor_op.h"
// Include the header file for the Status class from the minddata/dataset/util directory
#include "minddata/dataset/util/status.h"
// Include the header file for the validators class from the minddata/dataset/util directory
#include "minddata/dataset/util/validators.h"
namespace mindspore {
namespace dataset {
// Compute function of PyFuncOp class, takes input tensor row and output tensor row as parameters
Status PyFuncOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if input and output vectors are valid
IO_CHECK_VECTOR(input, output);
// Create a Status object with success status and a message
Status ret = Status(StatusCode::kSuccess, "PyFunc Call Succeed");
// Start a new block
{
// Acquire Python GIL
// Acquire the Python Global Interpreter Lock (GIL)
py::gil_scoped_acquire gil_acquire;
// Check if the Python interpreter is initialized
if (Py_IsInitialized() == 0) {
// If not initialized, set the Status object with failure status and a message
ret = Status(StatusCode::kMDPythonInterpreterFailure, "Python Interpreter is finalized");
// Jump to the ComputeReturn label to return the Status object
goto ComputeReturn;
}
try {
// Transform input tensor vector into numpy array vector
// Create a Python tuple with the same size as the input tensor row
py::tuple input_args(input.size());
// Create a Python object to store the return value
py::object ret_py_obj;
// Check if the input tensor row is not empty
if (input.size() > 0) {
// Iterate over each tensor in the input tensor row
for (size_t i = 0; i < input.size(); i++) {
// Create a new numpy array to store the data of the current tensor
py::array new_data;
// Call the GetDataAsNumpy function of the current tensor to get its data as a numpy array
RETURN_IF_NOT_OK(input.at(i)->GetDataAsNumpy(&new_data));
// possible memcpy here
// Assign the new_data value to the input_args array at index i
input_args[i] = new_data;
}
// Invoke python function
// Invoke the python function
// Call the stored python function pointer with the input_args array as arguments
ret_py_obj = this->py_func_ptr_(*input_args);
} else {
// If the python function does not take any arguments
// Call the stored python function pointer without any arguments
ret_py_obj = this->py_func_ptr_();
}
if (output_type_ != DataType::DE_UNKNOWN) {
// If the output type is known
// Cast the return value of the python function to the specified output type
RETURN_IF_NOT_OK(CastOutput(ret_py_obj, output));
} else {
if (py::isinstance<py::tuple>(ret_py_obj)) {
// In case of a n-m mapping, the return value will be a tuple of numpy arrays
// If the return value of the python function is a tuple
// Cast the return value to a py::tuple object
py::tuple ret_py_tuple = ret_py_obj.cast<py::tuple>();
// Iterate over two containers simultaneously for memory copy
// Iterate over the elements of the tuple
for (size_t i = 0; i < ret_py_tuple.size(); i++) {
// Get the i-th element of the tuple
py::object ret_py_ele = ret_py_tuple[i];
// Object is none if pyfunc timeout
// Check if the element is None
if (ret_py_ele.is_none()) {
// Log a message indicating that the expected return value is a numpy array but got None
MS_LOG(INFO) << "Expected that PyFunc should return numpy array, got None. If python_multiprocessing is "
"True, PyFunc may execute time out.";
goto TimeoutError;
}
if (!py::isinstance<py::array>(ret_py_ele)) {
goto ShapeMisMatch;
}
std::shared_ptr<Tensor> out;
RETURN_IF_NOT_OK(Tensor::CreateFromNpArray(ret_py_ele.cast<py::array>(), &out));
output->push_back(out);
}
} else if (py::isinstance<py::array>(ret_py_obj)) {
// In case of a n-1 mapping, the return value will be a numpy array
std::shared_ptr<Tensor> out;
RETURN_IF_NOT_OK(Tensor::CreateFromNpArray(ret_py_obj.cast<py::array>(), &out));
output->push_back(out);
} else {
goto TimeoutError;
}
// Check if the return value is a numpy array
if (!py::isinstance<py::array>(ret_py_ele)) {
goto ShapeMisMatch;
}
// Create a shared pointer to a Tensor object and initialize it with the numpy array
std::shared_ptr<Tensor> out;
RETURN_IF_NOT_OK(Tensor::CreateFromNpArray(ret_py_ele.cast<py::array>(), &out));
// Add the Tensor object to the output vector
output->push_back(out);
}
} catch (const py::error_already_set &e) {
} else if (py::isinstance<py::array>(ret_py_obj)) {
// In case of a n-1 mapping, the return value will be a numpy array
// Create a shared pointer to a Tensor object and initialize it with the numpy array
std::shared_ptr<Tensor> out;
RETURN_IF_NOT_OK(Tensor::CreateFromNpArray(ret_py_obj.cast<py::array>(), &out));
// Add the Tensor object to the output vector
output->push_back(out);
} else {
goto ShapeMisMatch;
}
}
} catch (const py::error_already_set &e) {
ret = Status(StatusCode::kMDPyFuncException, e.what());
}
}
ComputeReturn:
return ret;
// Return the value of the variable 'ret' from the function
return ret;
ShapeMisMatch:
ret = Status(StatusCode::kMDShapeMisMatch, __LINE__, __FILE__,
"PyFunc should return a numpy array or a numpy array tuple, check data type of return value in user "
"defined python function.");
goto ComputeReturn;
// Create a Status object with the error code StatusCode::kMDShapeMisMatch
// The error message is "PyFunc should return a numpy array or a numpy array tuple, check data type of return value in user defined python function."
// The error location is the current line number (__LINE__) and file name (__FILE__)
ret = Status(StatusCode::kMDShapeMisMatch, __LINE__, __FILE__,
"PyFunc should return a numpy array or a numpy array tuple, check data type of return value in user defined python function.");
TimeoutError:
ret = Status(StatusCode::kMDTimeOut, __LINE__, __FILE__,
"Expected that PyFunc should return numpy array, got None. If \'python_multiprocessing\' is True, "
"PyFunc may execute time out.");
goto ComputeReturn;
}
// Jump to the label "ComputeReturn" to handle the error and return from the function
goto ComputeReturn;
// Set the return status to indicate a timeout error
ret = Status(StatusCode::kMDTimeOut, __LINE__, __FILE__,
"Expected that PyFunc should return numpy array, got None. If 'python_multiprocessing' is True, "
"PyFunc may execute time out.");
// Jump to the label "ComputeReturn" to handle the return value
goto ComputeReturn;
// Function to cast the output of a PyFuncOp to a specified data type
Status PyFuncOp::CastOutput(const py::object &ret_py_obj, TensorRow *output) {
try {
std::shared_ptr<Tensor> out;
// Switch statement to handle different data types
switch (output_type_) {
case DataType::DE_INT32:
// Create an empty tensor of shape {1} and data type int32
RETURN_IF_NOT_OK(Tensor::CreateEmpty(TensorShape({1}), DataType(DataType::DE_INT32), &out));
// Set the value at index {0} of the tensor to the casted value of ret_py_obj
RETURN_IF_NOT_OK(out->SetItemAt({0}, ret_py_obj.cast<int32_t>()));
break;
case DataType::DE_BOOL:
// Create a scalar tensor with the value casted from ret_py_obj
RETURN_IF_NOT_OK(Tensor::CreateScalar(ret_py_obj.cast<bool>(), &out));
break;
default:
// If the specified data type is not supported, return an error
RETURN_STATUS_UNEXPECTED("No cast for the specified DataType was found.");
}
// Add the created tensor to the output TensorRow
output->push_back(out);
} catch (const std::exception &e) {
// If an exception occurs during the casting process, return an error with the exception message
return Status(StatusCode::kMDUnexpectedError, e.what());
}
// Return OK status to indicate successful casting
return Status::OK();
}
// Define the implementation of the `to_json` function for the `PyFuncOp` class
Status PyFuncOp::to_json(nlohmann::json *out_json) {
// Create a JSON object to store the arguments
nlohmann::json args;
{
// Acquire the Global Interpreter Lock (GIL) to safely execute Python code
py::gil_scoped_acquire gil_acquire;
// Check if the `to_json` attribute exists in the `py_func_ptr_` object
if (py_func_ptr_.attr("to_json")) {
// Call the `to_json` method and parse the returned JSON string into a JSON object
args = nlohmann::json::parse(py_func_ptr_.attr("to_json")().cast<std::string>());
}
}
// Assign the `args` JSON object to the `out_json` pointer
*out_json = args;
// Return a `Status` object indicating successful execution
return Status::OK();
}
// Implementation of the `from_json` function for the PyFuncOp class
Status PyFuncOp::from_json(nlohmann::json json_obj, std::vector<std::shared_ptr<TensorOperation>> *result) {
// Create a vector to store the output tensor operations
std::vector<std::shared_ptr<TensorOperation>> output;
// Validate the "tensor_op_name" parameter in the JSON object
RETURN_IF_NOT_OK(ValidateParamInJson(json_obj, "tensor_op_name", kPyFuncOp));
// Validate the "tensor_op_params" parameter in the JSON object
RETURN_IF_NOT_OK(ValidateParamInJson(json_obj, "tensor_op_params", kPyFuncOp));
// Get the value of the "tensor_op_name" parameter
std::string op_name = json_obj["tensor_op_name"];
// Get the value of the "tensor_op_params" parameter
nlohmann::json op_params = json_obj["tensor_op_params"];
// Get the value of the "python_module" parameter
std::string python_module = json_obj["python_module"];
// Create a null pointer for the tensor operation
std::shared_ptr<TensorOperation> operation = nullptr;
py::function py_func =
py::module::import(python_module.c_str()).attr(op_name.c_str()).attr("from_json")(op_params.dump());
// Import the Python module and call the `from_json` function of the specified operation
py::function py_func = py::module::import(python_module.c_str()).attr(op_name.c_str()).attr("from_json")(op_params.dump());
// Create a pre-built operation using the PyFuncOp and the imported Python function
operation = std::make_shared<transforms::PreBuiltOperation>(std::make_shared<PyFuncOp>(py_func));
// Add the operation to the output vector
output.push_back(operation);
// Assign the output vector to the result pointer
*result = output;
// Return OK status to indicate successful execution
return Status::OK();
}
// Check if the PyFuncOp is random or not
bool PyFuncOp::IsRandom() {
// Initialize the random flag as true
bool random = true;
// Check if the py_func_ptr_ has the attribute "random" and if its value is false
if (py::hasattr(py_func_ptr_, "random") && py::reinterpret_borrow<py::bool_>(py_func_ptr_.attr("random")) == false)
random = false;
// Return the value of the random flag
return random;
}
// End of the dataset namespace
} // namespace dataset
} // namespace mindspore
// End of the mindspore namespace
} // namespace mindspore

View File

@ -19,61 +19,105 @@
namespace mindspore {
namespace dataset {
// Name: Compute()
// Description: This Compute() take 1 Tensor and produce 1 Tensor.
// The derived class should override this function otherwise error.
Status TensorOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
IO_CHECK(input, output);
if (!OneToOne()) {
return Status(StatusCode::kMDUnexpectedError, "Wrong Compute() function is called. This is not 1-1 TensorOp.");
} else {
return Status(StatusCode::kMDUnexpectedError,
"Is this TensorOp 1-1? If yes, please implement this Compute() in the derived class.");
}
}
// Name: Compute()
// Description: This Compute() take multiple Tensors from different columns and produce multiple Tensors too.
// The derived class should override this function otherwise error.
// Description: This Compute() function takes 1 Tensor as input and produces 1 Tensor as output.
// The derived class should override this function, otherwise an error will occur.
Status TensorOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
// Check if the input and output pointers are valid
IO_CHECK(input, output);
// If the TensorOp is not a one-to-one operation, return an error
if (!OneToOne()) {
return Status(StatusCode::kMDUnexpectedError, "Wrong Compute() function is called. This is not a 1-1 TensorOp.");
} else {
// If the TensorOp is a one-to-one operation, return an error message indicating that the derived class should implement the Compute() function
return Status(StatusCode::kMDUnexpectedError, "Is this TensorOp 1-1? If yes, please implement this Compute() in the derived class.");
}
}
} // namespace dataset
} // namespace mindspore
// Name: Compute()
// Description: This function is used to compute the output Tensors based on the input Tensors.
// It takes multiple Tensors from different columns as input and produces multiple Tensors as output.
// The derived class should override this function, otherwise an error will occur.
Status TensorOp::Compute(const TensorRow &input, TensorRow *output) {
// Check if the input and output are vectors
IO_CHECK_VECTOR(input, output);
// If the op is OneToOne, it can only accept one tensor as input
if (OneToOne()) {
CHECK_FAIL_RETURN_UNEXPECTED(input.size() == 1, "The op is OneToOne, can only accept one tensor as input.");
// Resize the output vector to hold one tensor
output->resize(1);
// Call the Compute function with the first input tensor and store the result in the first output tensor
return Compute(input[0], &(*output)[0]);
}
// ... (rest of the code)
return Status(StatusCode::kMDUnexpectedError,
"Is this TensorOp oneToOne? If no, please implement this Compute() in the derived class.");
}
// Return a Status object with an unexpected error code and an error message
return Status(StatusCode::kMDUnexpectedError, "Is this TensorOp oneToOne? If no, please implement this Compute() in the derived class.");
// The Compute function of the TensorOp class
Status TensorOp::Compute(const std::shared_ptr<DeviceTensor> &input, std::shared_ptr<DeviceTensor> *output) {
// Check if the input and output pointers are valid
IO_CHECK(input, output);
// Return a Status object with an error code and a message indicating that the wrong Compute() function is called
// This message suggests that the function should be implemented in the derived class if the operator can be executed on different devices
return Status(StatusCode::kMDUnexpectedError,
"Wrong Compute() function is called. This is a function for operators which can be executed by"
"different device. If so, please implement it in the derived class.");
}
// Function to determine the output shape of a tensor operation
Status TensorOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) {
// Check if the number of input shapes matches the expected number of inputs for this operation
if (inputs.size() != NumInput())
return Status(StatusCode::kMDUnexpectedError,
"The size of the input argument vector does not match the number of inputs");
// Set the output shapes to be the same as the input shapes
outputs = inputs;
// Return a status indicating successful execution of the function
return Status::OK();
}
// Implementation of the OutputType function in the TensorOp class
// This function takes in a vector of input data types and a reference to a vector of output data types
Status TensorOp::OutputType(const std::vector<DataType> &inputs, std::vector<DataType> &outputs) {
// Check if the size of the input vector matches the expected number of inputs for this operation
if (inputs.size() != NumInput())
return Status(StatusCode::kMDUnexpectedError,
"The size of the input argument vector does not match the number of inputs");
// Set the output vector to be the same as the input vector
outputs = inputs;
// Return a status indicating successful execution of the function
return Status::OK();
}
// SetAscendResource function implementation for the TensorOp class
// Takes a shared pointer to a DeviceResource object as input
Status TensorOp::SetAscendResource(const std::shared_ptr<DeviceResource> &resource) {
// Return a Status object with a specific error code and error message
return Status(StatusCode::kMDUnexpectedError,
"This is a CPU operator which doesn't have Ascend Resource. Please verify your context");
}
} // namespace dataset
} // namespace mindspore
// Closing braces to end the "dataset" and "mindspore" namespaces

View File

@ -16,27 +16,51 @@
#include "minddata/dataset/plugin/plugin_loader.h"
// Include the algorithm header for various algorithms like sorting, searching, etc.
#include <algorithm>
// Include the numeric header for numeric algorithms like accumulate, inner_product, etc.
#include <numeric>
// Include the set header for the set container class
#include <set>
// Include the vector header for the vector container class
#include <vector>
// Include the header file for the MindSpore log adapter utility
#include "mindspore/core/utils/log_adapter.h"
// Include the header file for the MindData dataset plugin shared library utility
#include "minddata/dataset/plugin/shared_lib_util.h"
// Start of the namespace "mindspore"
namespace mindspore {
// Start of the namespace "dataset"
namespace dataset {
// Definition of the static member function "GetInstance" of the class "PluginLoader"
PluginLoader *PluginLoader::GetInstance() noexcept {
// Create a static instance of the class "PluginLoader" named "pl"
static PluginLoader pl;
// Return the address of the static instance "pl"
return &pl;
}
// Destructor for the PluginLoader class
PluginLoader::~PluginLoader() {
// Create a vector to store the keys from the plugins map
std::vector<std::string> keys;
// get the keys from map, this is to avoid concurrent iteration and delete
// Get the keys from the plugins map using std::transform
// This is done to avoid concurrent iteration and deletion
std::transform(plugins_.begin(), plugins_.end(), std::back_inserter(keys), [](const auto &p) { return p.first; });
// Iterate over the keys vector and unload each plugin
for (std::string &key : keys) {
// Call the UnloadPlugin function for the current key
Status rc = UnloadPlugin(key);
// Log an error message if the return code indicates an error
MSLOG_IF(ERROR, rc.IsError(), mindspore::NoExceptionType) << rc.ToString();
}
}

View File

@ -15,11 +15,17 @@
*/
#include "minddata/dataset/plugin/shared_lib_util.h"
// Check if the current platform is Linux and include the necessary header file
#ifdef __linux__
#include <dlfcn.h>
#endif
// Start of the namespace for the MindSpore dataset
namespace mindspore {
namespace dataset {
// Implementation of the Load function for loading a shared library
#ifdef __linux__
void *SharedLibUtil::Load(const std::string &name) { return dlopen(name.c_str(), RTLD_LAZY); }
void *SharedLibUtil::FindSym(void *handle, const std::string &name) { return dlsym(handle, name.c_str()); }