forked from mindspore-Ecosystem/mindspore
[feat][assistant][I3CEGM] add op adjust gamma
This commit is contained in:
parent
84c9082468
commit
4191dde45f
|
@ -18,6 +18,7 @@
|
||||||
#include "minddata/dataset/api/python/pybind_register.h"
|
#include "minddata/dataset/api/python/pybind_register.h"
|
||||||
#include "minddata/dataset/include/dataset/transforms.h"
|
#include "minddata/dataset/include/dataset/transforms.h"
|
||||||
|
|
||||||
|
#include "minddata/dataset/kernels/ir/vision/adjust_gamma_ir.h"
|
||||||
#include "minddata/dataset/kernels/ir/vision/auto_contrast_ir.h"
|
#include "minddata/dataset/kernels/ir/vision/auto_contrast_ir.h"
|
||||||
#include "minddata/dataset/kernels/ir/vision/bounding_box_augment_ir.h"
|
#include "minddata/dataset/kernels/ir/vision/bounding_box_augment_ir.h"
|
||||||
#include "minddata/dataset/kernels/ir/vision/center_crop_ir.h"
|
#include "minddata/dataset/kernels/ir/vision/center_crop_ir.h"
|
||||||
|
@ -67,6 +68,17 @@
|
||||||
namespace mindspore {
|
namespace mindspore {
|
||||||
namespace dataset {
|
namespace dataset {
|
||||||
|
|
||||||
|
PYBIND_REGISTER(
|
||||||
|
AdjustGammaOperation, 1, ([](const py::module *m) {
|
||||||
|
(void)py::class_<vision::AdjustGammaOperation, TensorOperation, std::shared_ptr<vision::AdjustGammaOperation>>(
|
||||||
|
*m, "AdjustGammaOperation")
|
||||||
|
.def(py::init([](float gamma, float gain) {
|
||||||
|
auto ajust_gamma = std::make_shared<vision::AdjustGammaOperation>(gamma, gain);
|
||||||
|
THROW_IF_ERROR(ajust_gamma->ValidateParams());
|
||||||
|
return ajust_gamma;
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
|
||||||
PYBIND_REGISTER(
|
PYBIND_REGISTER(
|
||||||
AutoContrastOperation, 1, ([](const py::module *m) {
|
AutoContrastOperation, 1, ([](const py::module *m) {
|
||||||
(void)py::class_<vision::AutoContrastOperation, TensorOperation, std::shared_ptr<vision::AutoContrastOperation>>(
|
(void)py::class_<vision::AutoContrastOperation, TensorOperation, std::shared_ptr<vision::AutoContrastOperation>>(
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "minddata/dataset/include/dataset/transforms.h"
|
#include "minddata/dataset/include/dataset/transforms.h"
|
||||||
|
#include "minddata/dataset/kernels/ir/vision/adjust_gamma_ir.h"
|
||||||
#include "minddata/dataset/kernels/ir/vision/affine_ir.h"
|
#include "minddata/dataset/kernels/ir/vision/affine_ir.h"
|
||||||
#include "minddata/dataset/kernels/ir/vision/auto_contrast_ir.h"
|
#include "minddata/dataset/kernels/ir/vision/auto_contrast_ir.h"
|
||||||
#include "minddata/dataset/kernels/ir/vision/bounding_box_augment_ir.h"
|
#include "minddata/dataset/kernels/ir/vision/bounding_box_augment_ir.h"
|
||||||
|
@ -118,6 +119,19 @@ std::shared_ptr<TensorOperation> Affine::Parse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ENABLE_ANDROID
|
#ifndef ENABLE_ANDROID
|
||||||
|
// AdjustGamma Transform Operation.
|
||||||
|
struct AdjustGamma::Data {
|
||||||
|
Data(float gamma, float gain) : gamma_(gamma), gain_(gain) {}
|
||||||
|
float gamma_;
|
||||||
|
float gain_;
|
||||||
|
};
|
||||||
|
|
||||||
|
AdjustGamma::AdjustGamma(float gamma, float gain) : data_(std::make_shared<Data>(gamma, gain)) {}
|
||||||
|
|
||||||
|
std::shared_ptr<TensorOperation> AdjustGamma::Parse() {
|
||||||
|
return std::make_shared<AdjustGammaOperation>(data_->gamma_, data_->gain_);
|
||||||
|
}
|
||||||
|
|
||||||
// AutoContrast Transform Operation.
|
// AutoContrast Transform Operation.
|
||||||
struct AutoContrast::Data {
|
struct AutoContrast::Data {
|
||||||
Data(float cutoff, const std::vector<uint32_t> &ignore) : cutoff_(cutoff), ignore_(ignore) {}
|
Data(float cutoff, const std::vector<uint32_t> &ignore) : cutoff_(cutoff), ignore_(ignore) {}
|
||||||
|
|
|
@ -57,7 +57,31 @@ class AutoContrast final : public TensorTransform {
|
||||||
std::shared_ptr<Data> data_;
|
std::shared_ptr<Data> data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Apply a given image transform on a random selection of bounding box regions of a given image.
|
/// \brief AdjustGamma TensorTransform.
|
||||||
|
/// \notes Apply gamma correction on input image.
|
||||||
|
class AdjustGamma final : public TensorTransform {
|
||||||
|
public:
|
||||||
|
/// \brief Constructor.
|
||||||
|
/// \param[in] gamma Non negative real number, which makes the output image pixel value
|
||||||
|
/// exponential in relation to the input image pixel value.
|
||||||
|
/// \param[in] gain The constant multiplier.
|
||||||
|
explicit AdjustGamma(float gamma, float gain = 1);
|
||||||
|
|
||||||
|
/// \brief Destructor.
|
||||||
|
~AdjustGamma() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// \brief Function to convert TensorTransform object into a TensorOperation object.
|
||||||
|
/// \return Shared pointer to TensorOperation object.
|
||||||
|
std::shared_ptr<TensorOperation> Parse() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Data;
|
||||||
|
std::shared_ptr<Data> data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief BoundingBoxAugment TensorTransform.
|
||||||
|
/// \note Apply a given image transform on a random selection of bounding box regions of a given image.
|
||||||
class BoundingBoxAugment final : public TensorTransform {
|
class BoundingBoxAugment final : public TensorTransform {
|
||||||
public:
|
public:
|
||||||
/// \brief Constructor.
|
/// \brief Constructor.
|
||||||
|
|
|
@ -6,6 +6,7 @@ if(ENABLE_ACL)
|
||||||
add_subdirectory(dvpp)
|
add_subdirectory(dvpp)
|
||||||
endif()
|
endif()
|
||||||
add_library(kernels-image OBJECT
|
add_library(kernels-image OBJECT
|
||||||
|
adjust_gamma_op.cc
|
||||||
affine_op.cc
|
affine_op.cc
|
||||||
auto_contrast_op.cc
|
auto_contrast_op.cc
|
||||||
bounding_box.cc
|
bounding_box.cc
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2021 Huawei Technologies Co., Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "minddata/dataset/kernels/image/adjust_gamma_op.h"
|
||||||
|
#include <memory>
|
||||||
|
#include "minddata/dataset/kernels/data/data_utils.h"
|
||||||
|
#include "minddata/dataset/kernels/image/image_utils.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace dataset {
|
||||||
|
|
||||||
|
const float AdjustGammaOp::kGain = 1.0;
|
||||||
|
|
||||||
|
Status AdjustGammaOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
|
||||||
|
IO_CHECK(input, output);
|
||||||
|
|
||||||
|
// typecast
|
||||||
|
CHECK_FAIL_RETURN_UNEXPECTED(input->type() != DataType::DE_STRING,
|
||||||
|
"AdjustGamma: input tensor type should be [int, float, double], but got string.");
|
||||||
|
|
||||||
|
if (input->type().IsFloat()) {
|
||||||
|
std::shared_ptr<Tensor> input_tensor;
|
||||||
|
RETURN_IF_NOT_OK(TypeCast(input, &input_tensor, DataType(DataType::DE_FLOAT32)));
|
||||||
|
return AdjustGamma(input_tensor, output, gamma_, gain_);
|
||||||
|
} else {
|
||||||
|
return AdjustGamma(input, output, gamma_, gain_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace dataset
|
||||||
|
} // namespace mindspore
|
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2021 Huawei Technologies Co., Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_ADJUST_GAMMA_OP_H_
|
||||||
|
#define MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_ADJUST_GAMMA_OP_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "minddata/dataset/core/tensor.h"
|
||||||
|
#include "minddata/dataset/core/cv_tensor.h"
|
||||||
|
#include "minddata/dataset/kernels/tensor_op.h"
|
||||||
|
#include "minddata/dataset/util/status.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace dataset {
|
||||||
|
class AdjustGammaOp : public TensorOp {
|
||||||
|
public:
|
||||||
|
/// Default gain to be used
|
||||||
|
static const float kGain;
|
||||||
|
AdjustGammaOp(const float &gamma, const float &gain) : gamma_(gamma), gain_(gain) {}
|
||||||
|
|
||||||
|
~AdjustGammaOp() override = default;
|
||||||
|
|
||||||
|
/// Provide stream operator for displaying it
|
||||||
|
friend std::ostream &operator<<(std::ostream &out, const AdjustGammaOp &so) {
|
||||||
|
so.Print(out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override;
|
||||||
|
|
||||||
|
std::string Name() const override { return kAdjustGammaOp; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
float gamma_;
|
||||||
|
float gain_;
|
||||||
|
};
|
||||||
|
} // namespace dataset
|
||||||
|
} // namespace mindspore
|
||||||
|
|
||||||
|
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_ADJUST_GAMMA_OP_H_
|
|
@ -872,6 +872,64 @@ Status AdjustContrast(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tens
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status AdjustGamma(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, const float &gamma,
|
||||||
|
const float &gain) {
|
||||||
|
try {
|
||||||
|
int num_channels = 1;
|
||||||
|
if (input->Rank() < 2) {
|
||||||
|
RETURN_STATUS_UNEXPECTED("AdjustGamma: image shape is not <...,H,W,C> or <H,W>.");
|
||||||
|
}
|
||||||
|
if (input->Rank() > 2) {
|
||||||
|
num_channels = input->shape()[-1];
|
||||||
|
}
|
||||||
|
if (num_channels != 1 && num_channels != 3) {
|
||||||
|
RETURN_STATUS_UNEXPECTED("AdjustGamma: channel of input image should be 1 or 3.");
|
||||||
|
}
|
||||||
|
if (input->type().IsFloat()) {
|
||||||
|
for (auto itr = input->begin<float>(); itr != input->end<float>(); itr++) {
|
||||||
|
*itr = pow((*itr) * gain, gamma);
|
||||||
|
*itr = std::min(std::max((*itr), 0.0f), 1.0f);
|
||||||
|
}
|
||||||
|
*output = input;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input);
|
||||||
|
if (!input_cv->mat().data) {
|
||||||
|
RETURN_STATUS_UNEXPECTED("AdjustGamma: load image failed.");
|
||||||
|
}
|
||||||
|
cv::Mat input_img = input_cv->mat();
|
||||||
|
std::shared_ptr<CVTensor> output_cv;
|
||||||
|
RETURN_IF_NOT_OK(CVTensor::CreateEmpty(input_cv->shape(), input_cv->type(), &output_cv));
|
||||||
|
uchar LUT[256] = {};
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
float f = i / 255.0;
|
||||||
|
f = pow(f, gamma);
|
||||||
|
LUT[i] = static_cast<uchar>(floor(std::min(f * (255.0 + 1 - 1e-3) * gain, 255.0)));
|
||||||
|
}
|
||||||
|
if (input_img.channels() == 1) {
|
||||||
|
cv::MatIterator_<uchar> it = input_img.begin<uchar>();
|
||||||
|
cv::MatIterator_<uchar> it_end = input_img.end<uchar>();
|
||||||
|
for (; it != it_end; ++it) {
|
||||||
|
*it = LUT[(*it)];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cv::MatIterator_<cv::Vec3b> it = input_img.begin<cv::Vec3b>();
|
||||||
|
cv::MatIterator_<cv::Vec3b> it_end = input_img.end<cv::Vec3b>();
|
||||||
|
for (; it != it_end; ++it) {
|
||||||
|
(*it)[0] = LUT[(*it)[0]];
|
||||||
|
(*it)[1] = LUT[(*it)[1]];
|
||||||
|
(*it)[2] = LUT[(*it)[2]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output_cv->mat() = input_img * 1;
|
||||||
|
*output = std::static_pointer_cast<Tensor>(output_cv);
|
||||||
|
}
|
||||||
|
} catch (const cv::Exception &e) {
|
||||||
|
RETURN_STATUS_UNEXPECTED("AdjustGamma: " + std::string(e.what()));
|
||||||
|
}
|
||||||
|
return Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
Status AutoContrast(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, const float &cutoff,
|
Status AutoContrast(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, const float &cutoff,
|
||||||
const std::vector<uint32_t> &ignore) {
|
const std::vector<uint32_t> &ignore) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -234,6 +234,16 @@ Status AdjustContrast(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tens
|
||||||
Status AutoContrast(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, const float &cutoff,
|
Status AutoContrast(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, const float &cutoff,
|
||||||
const std::vector<uint32_t> &ignore);
|
const std::vector<uint32_t> &ignore);
|
||||||
|
|
||||||
|
/// \brief Returns image with gamma correction.
|
||||||
|
/// \param[in] input: Tensor of shape <H,W,3>/<H,W,1>/<H,W> in RGB/Grayscale and any OpenCV compatible type,
|
||||||
|
/// see CVTensor.
|
||||||
|
/// \param[in] gamma: Non negative real number, same as gamma in the equation. gamma larger than 1 make the shadows
|
||||||
|
/// darker, while gamma smaller than 1 make dark regions lighter.
|
||||||
|
/// \param[in] gain: The constant multiplier.
|
||||||
|
/// \param[out] output: Adjusted image of same shape and type.
|
||||||
|
Status AdjustGamma(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, const float &gamma,
|
||||||
|
const float &gain);
|
||||||
|
|
||||||
/// \brief Returns image with adjusted saturation.
|
/// \brief Returns image with adjusted saturation.
|
||||||
/// \param input: Tensor of shape <H,W,3> in RGB order and any OpenCv compatible type, see CVTensor.
|
/// \param input: Tensor of shape <H,W,3> in RGB order and any OpenCv compatible type, see CVTensor.
|
||||||
/// \param alpha: Alpha value to adjust saturation by. Should be a positive number.
|
/// \param alpha: Alpha value to adjust saturation by. Should be a positive number.
|
||||||
|
|
|
@ -38,6 +38,11 @@ Status ValidateFloatScalarPositive(const std::string &op_name, const std::string
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status ValidateFloatScalarNonNegative(const std::string &op_name, const std::string &scalar_name, float scalar) {
|
||||||
|
RETURN_IF_NOT_OK(ValidateScalar(op_name, scalar_name, scalar, {0}, false));
|
||||||
|
return Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
Status ValidateVectorFillvalue(const std::string &op_name, const std::vector<uint8_t> &fill_value) {
|
Status ValidateVectorFillvalue(const std::string &op_name, const std::vector<uint8_t> &fill_value) {
|
||||||
if (fill_value.empty() || (fill_value.size() != 1 && fill_value.size() != 3)) {
|
if (fill_value.empty() || (fill_value.size() != 1 && fill_value.size() != 3)) {
|
||||||
std::string err_msg =
|
std::string err_msg =
|
||||||
|
|
|
@ -36,6 +36,9 @@ Status ValidateIntScalarPositive(const std::string &op_name, const std::string &
|
||||||
// Helper function to positive float scalar
|
// Helper function to positive float scalar
|
||||||
Status ValidateFloatScalarPositive(const std::string &op_name, const std::string &scalar_name, float scalar);
|
Status ValidateFloatScalarPositive(const std::string &op_name, const std::string &scalar_name, float scalar);
|
||||||
|
|
||||||
|
// Helper function to non-negative float scalar
|
||||||
|
Status ValidateFloatScalarNonNegative(const std::string &op_name, const std::string &scalar_name, float scalar);
|
||||||
|
|
||||||
// Helper function to validate scalar
|
// Helper function to validate scalar
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Status ValidateScalar(const std::string &op_name, const std::string &scalar_name, const T scalar,
|
Status ValidateScalar(const std::string &op_name, const std::string &scalar_name, const T scalar,
|
||||||
|
|
|
@ -2,6 +2,7 @@ file(GLOB_RECURSE _CURRENT_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cc"
|
||||||
set_property(SOURCE ${_CURRENT_SRC_FILES} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_MD)
|
set_property(SOURCE ${_CURRENT_SRC_FILES} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_MD)
|
||||||
|
|
||||||
set(DATASET_KERNELS_IR_VISION_SRC_FILES
|
set(DATASET_KERNELS_IR_VISION_SRC_FILES
|
||||||
|
adjust_gamma_ir.cc
|
||||||
affine_ir.cc
|
affine_ir.cc
|
||||||
auto_contrast_ir.cc
|
auto_contrast_ir.cc
|
||||||
bounding_box_augment_ir.cc
|
bounding_box_augment_ir.cc
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2021 Huawei Technologies Co., Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "minddata/dataset/kernels/ir/vision/adjust_gamma_ir.h"
|
||||||
|
|
||||||
|
#ifndef ENABLE_ANDROID
|
||||||
|
#include "minddata/dataset/kernels/image/adjust_gamma_op.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "minddata/dataset/kernels/ir/validators.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace dataset {
|
||||||
|
|
||||||
|
namespace vision {
|
||||||
|
|
||||||
|
#ifndef ENABLE_ANDROID
|
||||||
|
|
||||||
|
// AdjustGammaOperation
|
||||||
|
AdjustGammaOperation::AdjustGammaOperation(float gamma, float gain) : gamma_(gamma), gain_(gain) {}
|
||||||
|
|
||||||
|
Status AdjustGammaOperation::ValidateParams() {
|
||||||
|
// gamma
|
||||||
|
RETURN_IF_NOT_OK(ValidateFloatScalarNonNegative("AdjustGamma", "gamma", gamma_));
|
||||||
|
return Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<TensorOp> AdjustGammaOperation::Build() {
|
||||||
|
std::shared_ptr<AdjustGammaOp> tensor_op = std::make_shared<AdjustGammaOp>(gamma_, gain_);
|
||||||
|
return tensor_op;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status AdjustGammaOperation::to_json(nlohmann::json *out_json) {
|
||||||
|
nlohmann::json args;
|
||||||
|
args["gamma"] = gamma_;
|
||||||
|
args["gain"] = gain_;
|
||||||
|
*out_json = args;
|
||||||
|
return Status::OK();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace vision
|
||||||
|
} // namespace dataset
|
||||||
|
} // namespace mindspore
|
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2021 Huawei Technologies Co., Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IR_VISION_ADJUST_GAMMA_IR_H_
|
||||||
|
#define MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IR_VISION_ADJUST_GAMMA_IR_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "include/api/status.h"
|
||||||
|
#include "minddata/dataset/include/dataset/constants.h"
|
||||||
|
#include "minddata/dataset/include/dataset/transforms.h"
|
||||||
|
#include "minddata/dataset/kernels/ir/tensor_operation.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace dataset {
|
||||||
|
|
||||||
|
namespace vision {
|
||||||
|
|
||||||
|
constexpr char kAdjustGammaOperation[] = "AdjustGamma";
|
||||||
|
|
||||||
|
class AdjustGammaOperation : public TensorOperation {
|
||||||
|
public:
|
||||||
|
explicit AdjustGammaOperation(float gamma, float gain);
|
||||||
|
|
||||||
|
~AdjustGammaOperation() = default;
|
||||||
|
|
||||||
|
std::shared_ptr<TensorOp> Build() override;
|
||||||
|
|
||||||
|
Status ValidateParams() override;
|
||||||
|
|
||||||
|
std::string Name() const override { return kAdjustGammaOperation; }
|
||||||
|
|
||||||
|
Status to_json(nlohmann::json *out_json) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float gamma_;
|
||||||
|
float gain_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vision
|
||||||
|
} // namespace dataset
|
||||||
|
} // namespace mindspore
|
||||||
|
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IR_VISION_ADJUST_GAMMA_IR_H_
|
|
@ -53,6 +53,7 @@ namespace dataset {
|
||||||
constexpr char kTensorOp[] = "TensorOp";
|
constexpr char kTensorOp[] = "TensorOp";
|
||||||
|
|
||||||
// image
|
// image
|
||||||
|
constexpr char kAdjustGammaOp[] = "AdjustGammaOp";
|
||||||
constexpr char kAffineOp[] = "AffineOp";
|
constexpr char kAffineOp[] = "AffineOp";
|
||||||
constexpr char kAutoContrastOp[] = "AutoContrastOp";
|
constexpr char kAutoContrastOp[] = "AutoContrastOp";
|
||||||
constexpr char kBoundingBoxAugmentOp[] = "BoundingBoxAugmentOp";
|
constexpr char kBoundingBoxAugmentOp[] = "BoundingBoxAugmentOp";
|
||||||
|
|
|
@ -54,7 +54,7 @@ from .validators import check_prob, check_crop, check_center_crop, check_resize_
|
||||||
check_uniform_augment_cpp, \
|
check_uniform_augment_cpp, \
|
||||||
check_bounding_box_augment_cpp, check_random_select_subpolicy_op, check_auto_contrast, check_random_affine, \
|
check_bounding_box_augment_cpp, check_random_select_subpolicy_op, check_auto_contrast, check_random_affine, \
|
||||||
check_random_solarize, check_soft_dvpp_decode_random_crop_resize_jpeg, check_positive_degrees, FLOAT_MAX_INTEGER, \
|
check_random_solarize, check_soft_dvpp_decode_random_crop_resize_jpeg, check_positive_degrees, FLOAT_MAX_INTEGER, \
|
||||||
check_cut_mix_batch_c, check_posterize, check_gaussian_blur, check_rotate, check_slice_patches
|
check_cut_mix_batch_c, check_posterize, check_gaussian_blur, check_rotate, check_slice_patches, check_adjust_gamma
|
||||||
from ..transforms.c_transforms import TensorOperation
|
from ..transforms.c_transforms import TensorOperation
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,6 +107,37 @@ def parse_padding(padding):
|
||||||
return padding
|
return padding
|
||||||
|
|
||||||
|
|
||||||
|
class AdjustGamma(ImageTensorOperation):
|
||||||
|
r"""
|
||||||
|
Apply gamma correction on input image. Input image is expected to be in [..., H, W, C] or [H, W, C] format.
|
||||||
|
.. math::
|
||||||
|
I_{\text{out}} = 255 \times \text{gain} \times \left(\frac{I_{\text{in}}}{255}\right)^{\gamma}
|
||||||
|
|
||||||
|
See `Gamma Correction`_ for more details.
|
||||||
|
|
||||||
|
.. _Gamma Correction: https://en.wikipedia.org/wiki/Gamma_correction
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gamma (float): Non negative real number.
|
||||||
|
The output image pixel value is exponentially related to the input image pixel value.
|
||||||
|
gamma larger than 1 make the shadows darker,
|
||||||
|
while gamma smaller than 1 make dark regions lighter.
|
||||||
|
gain (float, optional): The constant multiplier (default=1).
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> transforms_list = [c_vision.Decode(), c_vision.AdjustGamma(gamma=10.0, gain=1.0)]
|
||||||
|
>>> image_folder_dataset = image_folder_dataset.map(operations=transforms_list,
|
||||||
|
... input_columns=["image"])
|
||||||
|
"""
|
||||||
|
@check_adjust_gamma
|
||||||
|
def __init__(self, gamma, gain=1):
|
||||||
|
self.gamma = gamma
|
||||||
|
self.gain = gain
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
return cde.AdjustGammaOperation(self.gamma, self.gain)
|
||||||
|
|
||||||
|
|
||||||
class AutoContrast(ImageTensorOperation):
|
class AutoContrast(ImageTensorOperation):
|
||||||
"""
|
"""
|
||||||
Apply automatic contrast on input image. This operator calculates histogram of image, reassign cutoff percent
|
Apply automatic contrast on input image. This operator calculates histogram of image, reassign cutoff percent
|
||||||
|
|
|
@ -31,7 +31,8 @@ from .validators import check_prob, check_center_crop, check_five_crop, check_re
|
||||||
check_normalize_py, check_normalizepad_py, check_random_crop, check_random_color_adjust, check_random_rotation, \
|
check_normalize_py, check_normalizepad_py, check_random_crop, check_random_color_adjust, check_random_rotation, \
|
||||||
check_ten_crop, check_num_channels, check_pad, check_rgb_to_hsv, check_hsv_to_rgb, \
|
check_ten_crop, check_num_channels, check_pad, check_rgb_to_hsv, check_hsv_to_rgb, \
|
||||||
check_random_perspective, check_random_erasing, check_cutout, check_linear_transform, check_random_affine, \
|
check_random_perspective, check_random_erasing, check_cutout, check_linear_transform, check_random_affine, \
|
||||||
check_mix_up, check_positive_degrees, check_uniform_augment_py, check_auto_contrast, check_rgb_to_bgr
|
check_mix_up, check_positive_degrees, check_uniform_augment_py, check_auto_contrast, check_rgb_to_bgr, \
|
||||||
|
check_adjust_gamma
|
||||||
from .utils import Inter, Border
|
from .utils import Inter, Border
|
||||||
from .py_transforms_util import is_pil
|
from .py_transforms_util import is_pil
|
||||||
|
|
||||||
|
@ -1375,7 +1376,6 @@ class RgbToBgr:
|
||||||
return util.rgb_to_bgrs(rgb_imgs, self.is_hwc)
|
return util.rgb_to_bgrs(rgb_imgs, self.is_hwc)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RgbToHsv:
|
class RgbToHsv:
|
||||||
"""
|
"""
|
||||||
Convert a NumPy RGB image or a batch of NumPy RGB images to HSV images.
|
Convert a NumPy RGB image or a batch of NumPy RGB images to HSV images.
|
||||||
|
@ -1525,6 +1525,44 @@ class RandomSharpness:
|
||||||
return util.random_sharpness(img, self.degrees)
|
return util.random_sharpness(img, self.degrees)
|
||||||
|
|
||||||
|
|
||||||
|
class AdjustGamma:
|
||||||
|
"""
|
||||||
|
Adjust gamma of the input PIL image.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gamma (float): Non negative real number, same as gamma in the equation.
|
||||||
|
gain (float, optional): The constant multiplier.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
>>> from mindspore.dataset.transforms.py_transforms import Compose
|
||||||
|
>>> transforms_list = Compose([py_vision.Decode(),
|
||||||
|
... py_vision.AdjustGamma(),
|
||||||
|
... py_vision.ToTensor()])
|
||||||
|
>>> # apply the transform to dataset through map function
|
||||||
|
>>> image_folder_dataset = image_folder_dataset.map(operations=transforms_list,
|
||||||
|
... input_columns="image")
|
||||||
|
"""
|
||||||
|
|
||||||
|
@check_adjust_gamma
|
||||||
|
def __init__(self, gamma, gain=1.0):
|
||||||
|
self.gamma = gamma
|
||||||
|
self.gain = gain
|
||||||
|
self.random = False
|
||||||
|
|
||||||
|
def __call__(self, img):
|
||||||
|
"""
|
||||||
|
Call method.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
img (PIL image): Image to be augmented with AutoContrast.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
img (PIL image), Augmented image.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return util.adjust_gamma(img, self.gamma, self.gain)
|
||||||
|
|
||||||
|
|
||||||
class AutoContrast:
|
class AutoContrast:
|
||||||
"""
|
"""
|
||||||
Automatically maximize the contrast of the input PIL image.
|
Automatically maximize the contrast of the input PIL image.
|
||||||
|
|
|
@ -19,7 +19,6 @@ import math
|
||||||
import numbers
|
import numbers
|
||||||
import random
|
import random
|
||||||
import colorsys
|
import colorsys
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PIL import Image, ImageOps, ImageEnhance, __version__
|
from PIL import Image, ImageOps, ImageEnhance, __version__
|
||||||
|
|
||||||
|
@ -1243,6 +1242,7 @@ def rgb_to_bgr(np_rgb_img, is_hwc):
|
||||||
np_bgr_img = np_rgb_img[::-1, :, :]
|
np_bgr_img = np_rgb_img[::-1, :, :]
|
||||||
return np_bgr_img
|
return np_bgr_img
|
||||||
|
|
||||||
|
|
||||||
def rgb_to_bgrs(np_rgb_imgs, is_hwc):
|
def rgb_to_bgrs(np_rgb_imgs, is_hwc):
|
||||||
"""
|
"""
|
||||||
Convert RGB imgs to BGR imgs.
|
Convert RGB imgs to BGR imgs.
|
||||||
|
@ -1473,6 +1473,32 @@ def random_sharpness(img, degrees):
|
||||||
return ImageEnhance.Sharpness(img).enhance(v)
|
return ImageEnhance.Sharpness(img).enhance(v)
|
||||||
|
|
||||||
|
|
||||||
|
def adjust_gamma(img, gamma, gain):
|
||||||
|
"""
|
||||||
|
Adjust gamma of the input PIL image.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
img (PIL image): Image to be augmented with AdjustGamma.
|
||||||
|
gamma (float): Non negative real number, same as gamma in the equation.
|
||||||
|
gain (float, optional): The constant multiplier.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
img (PIL image), Augmented image.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not is_pil(img):
|
||||||
|
raise TypeError("img should be PIL image. Got {}.".format(type(img)))
|
||||||
|
|
||||||
|
gamma_table = [(255 + 1 - 1e-3) * gain * pow(x / 255., gamma) for x in range(256)]
|
||||||
|
if len(img.split()) == 3:
|
||||||
|
gamma_table = gamma_table * 3
|
||||||
|
img = img.point(gamma_table)
|
||||||
|
elif len(img.split()) == 1:
|
||||||
|
img = img.point(gamma_table)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
def auto_contrast(img, cutoff, ignore):
|
def auto_contrast(img, cutoff, ignore):
|
||||||
"""
|
"""
|
||||||
Automatically maximize the contrast of the input PIL image.
|
Automatically maximize the contrast of the input PIL image.
|
||||||
|
|
|
@ -19,10 +19,10 @@ from functools import wraps
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from mindspore._c_dataengine import TensorOp, TensorOperation
|
from mindspore._c_dataengine import TensorOp, TensorOperation
|
||||||
|
|
||||||
from mindspore.dataset.core.validator_helpers import check_value, check_uint8, FLOAT_MAX_INTEGER, check_pos_float32, \
|
from mindspore.dataset.core.validator_helpers import check_value, check_uint8, FLOAT_MIN_INTEGER, FLOAT_MAX_INTEGER, \
|
||||||
check_float32, check_2tuple, check_range, check_positive, INT32_MAX, INT32_MIN, parse_user_args, type_check, \
|
check_pos_float32, check_float32, check_2tuple, check_range, check_positive, INT32_MAX, INT32_MIN, \
|
||||||
type_check_list, check_c_tensor_op, UINT8_MAX, check_value_normalize_std, check_value_cutoff, check_value_ratio, \
|
parse_user_args, type_check, type_check_list, check_c_tensor_op, UINT8_MAX, check_value_normalize_std, \
|
||||||
check_odd
|
check_value_cutoff, check_value_ratio, check_odd
|
||||||
from .utils import Inter, Border, ImageBatchFormat, SliceMode
|
from .utils import Inter, Border, ImageBatchFormat, SliceMode
|
||||||
|
|
||||||
|
|
||||||
|
@ -788,6 +788,22 @@ def check_bounding_box_augment_cpp(method):
|
||||||
return new_method
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
|
def check_adjust_gamma(method):
|
||||||
|
"""Wrapper method to check the parameters of AdjustGamma ops (Python and C++)."""
|
||||||
|
|
||||||
|
@wraps(method)
|
||||||
|
def new_method(self, *args, **kwargs):
|
||||||
|
[gamma, gain], _ = parse_user_args(method, *args, **kwargs)
|
||||||
|
type_check(gamma, (float, int), "gamma")
|
||||||
|
check_value(gamma, (0, FLOAT_MAX_INTEGER))
|
||||||
|
if gain is not None:
|
||||||
|
type_check(gain, (float, int), "gain")
|
||||||
|
check_value(gain, (FLOAT_MIN_INTEGER, FLOAT_MAX_INTEGER))
|
||||||
|
return method(self, *args, **kwargs)
|
||||||
|
|
||||||
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
def check_auto_contrast(method):
|
def check_auto_contrast(method):
|
||||||
"""Wrapper method to check the parameters of AutoContrast ops (Python and C++)."""
|
"""Wrapper method to check the parameters of AutoContrast ops (Python and C++)."""
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,102 @@ class MindDataTestPipeline : public UT::DatasetOpTesting {
|
||||||
|
|
||||||
// Tests for vision C++ API A to Q TensorTransform Operations (in alphabetical order)
|
// Tests for vision C++ API A to Q TensorTransform Operations (in alphabetical order)
|
||||||
|
|
||||||
|
TEST_F(MindDataTestPipeline, TestAdjustGammaSuccess1) {
|
||||||
|
// pipeline 3-channel
|
||||||
|
MS_LOG(INFO) << "Pipeline Test.";
|
||||||
|
std::string MindDataPath = "data/dataset";
|
||||||
|
std::string folder_path = MindDataPath + "/testImageNetData/train/";
|
||||||
|
std::shared_ptr<Dataset> ds1 = ImageFolder(folder_path, true, std::make_shared<RandomSampler>(false, 2));
|
||||||
|
EXPECT_NE(ds1, nullptr);
|
||||||
|
std::shared_ptr<Dataset> ds2 = ImageFolder(folder_path, true, std::make_shared<RandomSampler>(false, 2));
|
||||||
|
EXPECT_NE(ds2, nullptr);
|
||||||
|
|
||||||
|
auto adjustgamma_op = vision::AdjustGamma(10.0);
|
||||||
|
|
||||||
|
ds1 = ds1->Map({adjustgamma_op});
|
||||||
|
EXPECT_NE(ds1, nullptr);
|
||||||
|
|
||||||
|
std::shared_ptr<Iterator> iter1 = ds1->CreateIterator();
|
||||||
|
EXPECT_NE(iter1, nullptr);
|
||||||
|
std::unordered_map<std::string, mindspore::MSTensor> row1;
|
||||||
|
iter1->GetNextRow(&row1);
|
||||||
|
|
||||||
|
std::shared_ptr<Iterator> iter2 = ds2->CreateIterator();
|
||||||
|
EXPECT_NE(iter2, nullptr);
|
||||||
|
std::unordered_map<std::string, mindspore::MSTensor> row2;
|
||||||
|
iter2->GetNextRow(&row2);
|
||||||
|
|
||||||
|
uint64_t i = 0;
|
||||||
|
while (row1.size() != 0) {
|
||||||
|
i++;
|
||||||
|
auto image = row1["image"];
|
||||||
|
iter1->GetNextRow(&row1);
|
||||||
|
iter2->GetNextRow(&row2);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(i, 2);
|
||||||
|
|
||||||
|
iter1->Stop();
|
||||||
|
iter2->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MindDataTestPipeline, TestAdjustGammaSuccess2) {
|
||||||
|
// pipeline 1-channel
|
||||||
|
MS_LOG(INFO) << "Pipeline Test.";
|
||||||
|
std::string MindDataPath = "data/dataset";
|
||||||
|
std::string folder_path = MindDataPath + "/testImageNetData/train/";
|
||||||
|
std::shared_ptr<Dataset> ds1 = ImageFolder(folder_path, true, std::make_shared<RandomSampler>(false, 2));
|
||||||
|
EXPECT_NE(ds1, nullptr);
|
||||||
|
std::shared_ptr<Dataset> ds2 = ImageFolder(folder_path, true, std::make_shared<RandomSampler>(false, 2));
|
||||||
|
EXPECT_NE(ds2, nullptr);
|
||||||
|
|
||||||
|
auto adjustgamma_op = vision::AdjustGamma(10.0);
|
||||||
|
auto rgb2gray_op = vision::RGB2GRAY();
|
||||||
|
|
||||||
|
ds1 = ds1->Map({rgb2gray_op, adjustgamma_op});
|
||||||
|
EXPECT_NE(ds1, nullptr);
|
||||||
|
|
||||||
|
std::shared_ptr<Iterator> iter1 = ds1->CreateIterator();
|
||||||
|
EXPECT_NE(iter1, nullptr);
|
||||||
|
std::unordered_map<std::string, mindspore::MSTensor> row1;
|
||||||
|
iter1->GetNextRow(&row1);
|
||||||
|
|
||||||
|
std::shared_ptr<Iterator> iter2 = ds2->CreateIterator();
|
||||||
|
EXPECT_NE(iter2, nullptr);
|
||||||
|
std::unordered_map<std::string, mindspore::MSTensor> row2;
|
||||||
|
iter2->GetNextRow(&row2);
|
||||||
|
|
||||||
|
uint64_t i = 0;
|
||||||
|
while (row1.size() != 0) {
|
||||||
|
i++;
|
||||||
|
auto image = row1["image"];
|
||||||
|
iter1->GetNextRow(&row1);
|
||||||
|
iter2->GetNextRow(&row2);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(i, 2);
|
||||||
|
|
||||||
|
iter1->Stop();
|
||||||
|
iter2->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MindDataTestPipeline, TestAdjustGammaParamCheck) {
|
||||||
|
// pipeline 3-channel
|
||||||
|
MS_LOG(INFO) << "Pipeline Test.";
|
||||||
|
std::string MindDataPath = "data/dataset";
|
||||||
|
std::string folder_path = MindDataPath + "/testImageNetData/train/";
|
||||||
|
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, true, std::make_shared<RandomSampler>(false, 2));
|
||||||
|
EXPECT_NE(ds, nullptr);
|
||||||
|
|
||||||
|
// Case 1: Negative gamma
|
||||||
|
// Create objects for the tensor ops
|
||||||
|
std::shared_ptr<TensorTransform> adjust_gamma(new vision::AdjustGamma(-1, 1.0));
|
||||||
|
auto ds1 = ds->Map({adjust_gamma});
|
||||||
|
EXPECT_NE(ds1, nullptr);
|
||||||
|
// Create an iterator over the result of the above dataset
|
||||||
|
std::shared_ptr<Iterator> iter1 = ds1->CreateIterator();
|
||||||
|
// Expect failure: invalid value of AdjustGamma
|
||||||
|
EXPECT_EQ(iter1, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(MindDataTestPipeline, TestAutoContrastSuccess1) {
|
TEST_F(MindDataTestPipeline, TestAutoContrastSuccess1) {
|
||||||
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestAutoContrastSuccess1.";
|
MS_LOG(INFO) << "Doing MindDataTestPipeline-TestAutoContrastSuccess1.";
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,10 @@ void CVOpCommon::CheckImageShapeAndData(const std::shared_ptr<Tensor> &output_te
|
||||||
expect_image_path = dir_path + "imagefolder/apple_expect_randomaffine.jpg";
|
expect_image_path = dir_path + "imagefolder/apple_expect_randomaffine.jpg";
|
||||||
actual_image_path = dir_path + "imagefolder/apple_actual_randomaffine.jpg";
|
actual_image_path = dir_path + "imagefolder/apple_actual_randomaffine.jpg";
|
||||||
break;
|
break;
|
||||||
|
case kAdjustGamma:
|
||||||
|
expect_image_path = dir_path + "imagefolder/apple_expect_adjustgamma.png";
|
||||||
|
actual_image_path = dir_path + "imagefolder/apple_actual_adjustgamma.png";
|
||||||
|
break;
|
||||||
case kAutoContrast:
|
case kAutoContrast:
|
||||||
expect_image_path = dir_path + "imagefolder/apple_expect_autocontrast.jpg";
|
expect_image_path = dir_path + "imagefolder/apple_expect_autocontrast.jpg";
|
||||||
actual_image_path = dir_path + "imagefolder/apple_actual_autocontrast.jpg";
|
actual_image_path = dir_path + "imagefolder/apple_actual_autocontrast.jpg";
|
||||||
|
|
|
@ -44,6 +44,7 @@ class CVOpCommon : public Common {
|
||||||
kRandomAffine,
|
kRandomAffine,
|
||||||
kRandomPosterize,
|
kRandomPosterize,
|
||||||
kAutoContrast,
|
kAutoContrast,
|
||||||
|
kAdjustGamma,
|
||||||
kEqualize
|
kEqualize
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,35 @@ TEST_F(MindDataTestExecute, TestAllpassBiquadWithWrongArg) {
|
||||||
EXPECT_FALSE(s01.IsOk());
|
EXPECT_FALSE(s01.IsOk());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(MindDataTestExecute, TestAdjustGammaEager1) {
|
||||||
|
// 3-channel eager
|
||||||
|
MS_LOG(INFO) << "3-channel image test";
|
||||||
|
// Read images
|
||||||
|
auto image = ReadFileToTensor("data/dataset/apple.jpg");
|
||||||
|
|
||||||
|
// Transform params
|
||||||
|
auto decode = vision::Decode();
|
||||||
|
auto adjust_gamma_op = vision::AdjustGamma(0.1, 1.0);
|
||||||
|
|
||||||
|
auto transform = Execute({decode, adjust_gamma_op});
|
||||||
|
Status rc = transform(image, &image);
|
||||||
|
EXPECT_EQ(rc, Status::OK());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MindDataTestExecute, TestAdjustGammaEager2) {
|
||||||
|
// 1-channel eager
|
||||||
|
MS_LOG(INFO) << "1-channel image test";
|
||||||
|
auto m1 = ReadFileToTensor("data/dataset/apple.jpg");
|
||||||
|
// Transform params
|
||||||
|
auto decode = vision::Decode();
|
||||||
|
auto rgb2gray = vision::RGB2GRAY();
|
||||||
|
auto adjust_gamma_op = vision::AdjustGamma(0.1, 1.0);
|
||||||
|
|
||||||
|
auto transform = Execute({decode, rgb2gray, adjust_gamma_op});
|
||||||
|
Status rc = transform(m1, &m1);
|
||||||
|
EXPECT_EQ(rc, Status::OK());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(MindDataTestExecute, TestComposeTransforms) {
|
TEST_F(MindDataTestExecute, TestComposeTransforms) {
|
||||||
MS_LOG(INFO) << "Doing TestComposeTransforms.";
|
MS_LOG(INFO) << "Doing TestComposeTransforms.";
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,329 @@
|
||||||
|
# Copyright 2021 Huawei Technologies Co., Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
# ==============================================================================
|
||||||
|
"""
|
||||||
|
Testing AdjustGamma op in DE
|
||||||
|
"""
|
||||||
|
import numpy as np
|
||||||
|
from numpy.testing import assert_allclose
|
||||||
|
import PIL
|
||||||
|
|
||||||
|
import mindspore.dataset as ds
|
||||||
|
import mindspore.dataset.transforms.py_transforms
|
||||||
|
import mindspore.dataset.vision.py_transforms as F
|
||||||
|
import mindspore.dataset.vision.c_transforms as C
|
||||||
|
from mindspore import log as logger
|
||||||
|
|
||||||
|
DATA_DIR = "../data/dataset/testImageNetData/train/"
|
||||||
|
MNIST_DATA_DIR = "../data/dataset/testMnistData"
|
||||||
|
|
||||||
|
DATA_DIR_2 = ["../data/dataset/test_tf_file_3_images/train-0000-of-0001.data"]
|
||||||
|
SCHEMA_DIR = "../data/dataset/test_tf_file_3_images/datasetSchema.json"
|
||||||
|
|
||||||
|
GENERATE_GOLDEN = False
|
||||||
|
|
||||||
|
|
||||||
|
def generate_numpy_random_rgb(shape):
|
||||||
|
"""
|
||||||
|
Only generate floating points that are fractions like n / 256, since they
|
||||||
|
are RGB pixels. Some low-precision floating point types in this test can't
|
||||||
|
handle arbitrary precision floating points well.
|
||||||
|
"""
|
||||||
|
return np.random.randint(0, 256, shape) / 255.
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_c_eager():
|
||||||
|
# Eager 3-channel
|
||||||
|
rgb_flat = generate_numpy_random_rgb((64, 3)).astype(np.float32)
|
||||||
|
img_in = rgb_flat.reshape((8, 8, 3))
|
||||||
|
|
||||||
|
adjustgamma_op = C.AdjustGamma(10, 1)
|
||||||
|
img_out = adjustgamma_op(img_in)
|
||||||
|
assert img_out is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_py_eager():
|
||||||
|
# Eager 3-channel
|
||||||
|
rgb_flat = generate_numpy_random_rgb((64, 3)).astype(np.uint8)
|
||||||
|
img_in = PIL.Image.fromarray(rgb_flat.reshape((8, 8, 3)))
|
||||||
|
|
||||||
|
adjustgamma_op = F.AdjustGamma(10, 1)
|
||||||
|
img_out = adjustgamma_op(img_in)
|
||||||
|
assert img_out is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_c_eager_gray():
|
||||||
|
# Eager 3-channel
|
||||||
|
rgb_flat = generate_numpy_random_rgb((64, 1)).astype(np.float32)
|
||||||
|
img_in = rgb_flat.reshape((8, 8))
|
||||||
|
|
||||||
|
adjustgamma_op = C.AdjustGamma(10, 1)
|
||||||
|
img_out = adjustgamma_op(img_in)
|
||||||
|
assert img_out is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_py_eager_gray():
|
||||||
|
# Eager 3-channel
|
||||||
|
rgb_flat = generate_numpy_random_rgb((64, 1)).astype(np.uint8)
|
||||||
|
img_in = PIL.Image.fromarray(rgb_flat.reshape((8, 8)))
|
||||||
|
|
||||||
|
adjustgamma_op = F.AdjustGamma(10, 1)
|
||||||
|
img_out = adjustgamma_op(img_in)
|
||||||
|
assert img_out is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_invalid_gamma_param_c():
|
||||||
|
"""
|
||||||
|
Test AdjustGamma C Op with invalid ignore parameter
|
||||||
|
"""
|
||||||
|
logger.info("Test AdjustGamma C Op with invalid ignore parameter")
|
||||||
|
try:
|
||||||
|
data_set = ds.ImageFolderDataset(dataset_dir=DATA_DIR, shuffle=False)
|
||||||
|
data_set = data_set.map(operations=[C.Decode(),
|
||||||
|
C.Resize((224, 224)),
|
||||||
|
lambda img: np.array(img[:, :, 0])],
|
||||||
|
input_columns=["image"])
|
||||||
|
# invalid gamma
|
||||||
|
data_set = data_set.map(operations=C.AdjustGamma(gamma=-10.0,
|
||||||
|
gain=1.0),
|
||||||
|
input_columns="image")
|
||||||
|
except ValueError as error:
|
||||||
|
logger.info("Got an exception in AdjustGamma: {}".format(str(error)))
|
||||||
|
assert "Input is not within the required interval of " in str(error)
|
||||||
|
try:
|
||||||
|
data_set = ds.ImageFolderDataset(dataset_dir=DATA_DIR, shuffle=False)
|
||||||
|
data_set = data_set.map(operations=[C.Decode(),
|
||||||
|
C.Resize((224, 224)),
|
||||||
|
lambda img: np.array(img[:, :, 0])],
|
||||||
|
input_columns=["image"])
|
||||||
|
# invalid gamma
|
||||||
|
data_set = data_set.map(operations=C.AdjustGamma(gamma=[1, 2],
|
||||||
|
gain=1.0),
|
||||||
|
input_columns="image")
|
||||||
|
except TypeError as error:
|
||||||
|
logger.info("Got an exception in AdjustGamma: {}".format(str(error)))
|
||||||
|
assert "is not of type [<class 'float'>, <class 'int'>], but got" in str(error)
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_invalid_gamma_param_py():
|
||||||
|
"""
|
||||||
|
Test AdjustGamma python Op with invalid ignore parameter
|
||||||
|
"""
|
||||||
|
logger.info("Test AdjustGamma python Op with invalid ignore parameter")
|
||||||
|
try:
|
||||||
|
data_set = ds.ImageFolderDataset(dataset_dir=DATA_DIR, shuffle=False)
|
||||||
|
trans = mindspore.dataset.transforms.py_transforms.Compose([
|
||||||
|
F.Decode(),
|
||||||
|
F.Resize((224, 224)),
|
||||||
|
F.AdjustGamma(gamma=-10.0),
|
||||||
|
F.ToTensor()
|
||||||
|
])
|
||||||
|
data_set = data_set.map(operations=[trans],
|
||||||
|
input_columns=["image"])
|
||||||
|
except ValueError as error:
|
||||||
|
logger.info("Got an exception in AdjustGamma: {}".format(str(error)))
|
||||||
|
assert "Input is not within the required interval of " in str(error)
|
||||||
|
try:
|
||||||
|
data_set = ds.ImageFolderDataset(dataset_dir=DATA_DIR, shuffle=False)
|
||||||
|
trans = mindspore.dataset.transforms.py_transforms.Compose([
|
||||||
|
F.Decode(),
|
||||||
|
F.Resize((224, 224)),
|
||||||
|
F.AdjustGamma(gamma=[1, 2]),
|
||||||
|
F.ToTensor()
|
||||||
|
])
|
||||||
|
data_set = data_set.map(operations=[trans],
|
||||||
|
input_columns=["image"])
|
||||||
|
except TypeError as error:
|
||||||
|
logger.info("Got an exception in AdjustGamma: {}".format(str(error)))
|
||||||
|
assert "is not of type [<class 'float'>, <class 'int'>], but got" in str(error)
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_invalid_gain_param_c():
|
||||||
|
"""
|
||||||
|
Test AdjustGamma C Op with invalid gain parameter
|
||||||
|
"""
|
||||||
|
logger.info("Test AdjustGamma C Op with invalid gain parameter")
|
||||||
|
try:
|
||||||
|
data_set = ds.ImageFolderDataset(dataset_dir=DATA_DIR, shuffle=False)
|
||||||
|
data_set = data_set.map(operations=[C.Decode(),
|
||||||
|
C.Resize((224, 224)),
|
||||||
|
lambda img: np.array(img[:, :, 0])],
|
||||||
|
input_columns=["image"])
|
||||||
|
# invalid gain
|
||||||
|
data_set = data_set.map(operations=C.AdjustGamma(gamma=10.0,
|
||||||
|
gain=[1, 10]),
|
||||||
|
input_columns="image")
|
||||||
|
except TypeError as error:
|
||||||
|
logger.info("Got an exception in AdjustGamma: {}".format(str(error)))
|
||||||
|
assert "is not of type [<class 'float'>, <class 'int'>], but got " in str(error)
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_invalid_gain_param_py():
|
||||||
|
"""
|
||||||
|
Test AdjustGamma python Op with invalid gain parameter
|
||||||
|
"""
|
||||||
|
logger.info("Test AdjustGamma python Op with invalid gain parameter")
|
||||||
|
try:
|
||||||
|
data_set = ds.ImageFolderDataset(dataset_dir=DATA_DIR, shuffle=False)
|
||||||
|
trans = mindspore.dataset.transforms.py_transforms.Compose([
|
||||||
|
F.Decode(),
|
||||||
|
F.Resize((224, 224)),
|
||||||
|
F.AdjustGamma(gamma=10.0, gain=[1, 10]),
|
||||||
|
F.ToTensor()
|
||||||
|
])
|
||||||
|
data_set = data_set.map(operations=[trans],
|
||||||
|
input_columns=["image"])
|
||||||
|
except TypeError as error:
|
||||||
|
logger.info("Got an exception in AdjustGamma: {}".format(str(error)))
|
||||||
|
assert "is not of type [<class 'float'>, <class 'int'>], but got " in str(error)
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_pipeline_c():
|
||||||
|
"""
|
||||||
|
Test AdjustGamma C Op Pipeline
|
||||||
|
"""
|
||||||
|
# First dataset
|
||||||
|
transforms1 = [C.Decode(), C.Resize([64, 64])]
|
||||||
|
transforms1 = mindspore.dataset.transforms.py_transforms.Compose(
|
||||||
|
transforms1)
|
||||||
|
ds1 = ds.TFRecordDataset(DATA_DIR_2,
|
||||||
|
SCHEMA_DIR,
|
||||||
|
columns_list=["image"],
|
||||||
|
shuffle=False)
|
||||||
|
ds1 = ds1.map(operations=transforms1, input_columns=["image"])
|
||||||
|
|
||||||
|
# Second dataset
|
||||||
|
transforms2 = [
|
||||||
|
C.Decode(),
|
||||||
|
C.Resize([64, 64]),
|
||||||
|
C.AdjustGamma(1.0, 1.0)
|
||||||
|
]
|
||||||
|
transform2 = mindspore.dataset.transforms.py_transforms.Compose(
|
||||||
|
transforms2)
|
||||||
|
ds2 = ds.TFRecordDataset(DATA_DIR_2,
|
||||||
|
SCHEMA_DIR,
|
||||||
|
columns_list=["image"],
|
||||||
|
shuffle=False)
|
||||||
|
ds2 = ds2.map(operations=transform2, input_columns=["image"])
|
||||||
|
|
||||||
|
num_iter = 0
|
||||||
|
for data1, data2 in zip(ds1.create_dict_iterator(num_epochs=1),
|
||||||
|
ds2.create_dict_iterator(num_epochs=1)):
|
||||||
|
num_iter += 1
|
||||||
|
ori_img = data1["image"].asnumpy()
|
||||||
|
cvt_img = data2["image"].asnumpy()
|
||||||
|
assert_allclose(ori_img.flatten(),
|
||||||
|
cvt_img.flatten(),
|
||||||
|
rtol=1e-5,
|
||||||
|
atol=0)
|
||||||
|
assert ori_img.shape == cvt_img.shape
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_pipeline_py():
|
||||||
|
"""
|
||||||
|
Test AdjustGamma python Op Pipeline
|
||||||
|
"""
|
||||||
|
# First dataset
|
||||||
|
transforms1 = [F.Decode(), F.Resize([64, 64]), F.ToTensor()]
|
||||||
|
transforms1 = mindspore.dataset.transforms.py_transforms.Compose(
|
||||||
|
transforms1)
|
||||||
|
ds1 = ds.TFRecordDataset(DATA_DIR_2,
|
||||||
|
SCHEMA_DIR,
|
||||||
|
columns_list=["image"],
|
||||||
|
shuffle=False)
|
||||||
|
ds1 = ds1.map(operations=transforms1, input_columns=["image"])
|
||||||
|
|
||||||
|
# Second dataset
|
||||||
|
transforms2 = [
|
||||||
|
F.Decode(),
|
||||||
|
F.Resize([64, 64]),
|
||||||
|
F.AdjustGamma(1.0, 1.0),
|
||||||
|
F.ToTensor()
|
||||||
|
]
|
||||||
|
transform2 = mindspore.dataset.transforms.py_transforms.Compose(
|
||||||
|
transforms2)
|
||||||
|
ds2 = ds.TFRecordDataset(DATA_DIR_2,
|
||||||
|
SCHEMA_DIR,
|
||||||
|
columns_list=["image"],
|
||||||
|
shuffle=False)
|
||||||
|
ds2 = ds2.map(operations=transform2, input_columns=["image"])
|
||||||
|
|
||||||
|
num_iter = 0
|
||||||
|
for data1, data2 in zip(ds1.create_dict_iterator(num_epochs=1),
|
||||||
|
ds2.create_dict_iterator(num_epochs=1)):
|
||||||
|
num_iter += 1
|
||||||
|
ori_img = data1["image"].asnumpy()
|
||||||
|
cvt_img = data2["image"].asnumpy()
|
||||||
|
assert_allclose(ori_img.flatten(),
|
||||||
|
cvt_img.flatten(),
|
||||||
|
rtol=1e-5,
|
||||||
|
atol=0)
|
||||||
|
assert ori_img.shape == cvt_img.shape
|
||||||
|
|
||||||
|
|
||||||
|
def test_adjust_gamma_pipeline_py_gray():
|
||||||
|
"""
|
||||||
|
Test AdjustGamma python Op Pipeline 1-channel
|
||||||
|
"""
|
||||||
|
# First dataset
|
||||||
|
transforms1 = [F.Decode(), F.Resize([64, 64]), F.Grayscale(), F.ToTensor()]
|
||||||
|
transforms1 = mindspore.dataset.transforms.py_transforms.Compose(
|
||||||
|
transforms1)
|
||||||
|
ds1 = ds.TFRecordDataset(DATA_DIR_2,
|
||||||
|
SCHEMA_DIR,
|
||||||
|
columns_list=["image"],
|
||||||
|
shuffle=False)
|
||||||
|
ds1 = ds1.map(operations=transforms1, input_columns=["image"])
|
||||||
|
|
||||||
|
# Second dataset
|
||||||
|
transforms2 = [
|
||||||
|
F.Decode(),
|
||||||
|
F.Resize([64, 64]),
|
||||||
|
F.Grayscale(),
|
||||||
|
F.AdjustGamma(1.0, 1.0),
|
||||||
|
F.ToTensor()
|
||||||
|
]
|
||||||
|
transform2 = mindspore.dataset.transforms.py_transforms.Compose(
|
||||||
|
transforms2)
|
||||||
|
ds2 = ds.TFRecordDataset(DATA_DIR_2,
|
||||||
|
SCHEMA_DIR,
|
||||||
|
columns_list=["image"],
|
||||||
|
shuffle=False)
|
||||||
|
ds2 = ds2.map(operations=transform2, input_columns=["image"])
|
||||||
|
|
||||||
|
num_iter = 0
|
||||||
|
for data1, data2 in zip(ds1.create_dict_iterator(num_epochs=1),
|
||||||
|
ds2.create_dict_iterator(num_epochs=1)):
|
||||||
|
num_iter += 1
|
||||||
|
ori_img = data1["image"].asnumpy()
|
||||||
|
cvt_img = data2["image"].asnumpy()
|
||||||
|
assert_allclose(ori_img.flatten(),
|
||||||
|
cvt_img.flatten(),
|
||||||
|
rtol=1e-5,
|
||||||
|
atol=0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_adjust_gamma_c_eager()
|
||||||
|
test_adjust_gamma_py_eager()
|
||||||
|
test_adjust_gamma_c_eager_gray()
|
||||||
|
test_adjust_gamma_py_eager_gray()
|
||||||
|
|
||||||
|
test_adjust_gamma_invalid_gamma_param_c()
|
||||||
|
test_adjust_gamma_invalid_gamma_param_py()
|
||||||
|
test_adjust_gamma_invalid_gain_param_c()
|
||||||
|
test_adjust_gamma_invalid_gain_param_py()
|
||||||
|
test_adjust_gamma_pipeline_c()
|
||||||
|
test_adjust_gamma_pipeline_py()
|
||||||
|
test_adjust_gamma_pipeline_py_gray()
|
Loading…
Reference in New Issue