加入注释 #21
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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_, °rees));
|
||||
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_, °rees));
|
||||
|
||||
// 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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_, °rees));
|
||||
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_, °rees));
|
||||
|
||||
// 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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> ®ions, 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> ®ions, 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> ®ions,
|
||||
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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()); }
|
||||
|
|
|
|||
Loading…
Reference in New Issue