From: @shenwei41 Reviewed-by: @liucunwei,@jonyguo Signed-off-by: @liucunweitags/v1.1.0
| @@ -47,6 +47,7 @@ | |||
| #include "minddata/dataset/kernels/image/random_crop_op.h" | |||
| #include "minddata/dataset/kernels/image/random_crop_decode_resize_op.h" | |||
| #include "minddata/dataset/kernels/image/random_crop_with_bbox_op.h" | |||
| #include "minddata/dataset/kernels/image/random_crop_and_resize_with_bbox_op.h" | |||
| #include "minddata/dataset/kernels/image/random_horizontal_flip_op.h" | |||
| #include "minddata/dataset/kernels/image/random_horizontal_flip_with_bbox_op.h" | |||
| #include "minddata/dataset/kernels/image/random_posterize_op.h" | |||
| @@ -283,6 +284,17 @@ std::shared_ptr<RandomResizedCropOperation> RandomResizedCrop(std::vector<int32_ | |||
| return op->ValidateParams() ? op : nullptr; | |||
| } | |||
| // Function to create RandomResizedCropOperation. | |||
| std::shared_ptr<RandomResizedCropWithBBoxOperation> RandomResizedCropWithBBox(std::vector<int32_t> size, | |||
| std::vector<float> scale, | |||
| std::vector<float> ratio, | |||
| InterpolationMode interpolation, | |||
| int32_t max_attempts) { | |||
| auto op = std::make_shared<RandomResizedCropWithBBoxOperation>(size, scale, ratio, interpolation, max_attempts); | |||
| // Input validation | |||
| return op->ValidateParams() ? op : nullptr; | |||
| } | |||
| // Function to create RandomRotationOperation. | |||
| std::shared_ptr<RandomRotationOperation> RandomRotation(std::vector<float> degrees, InterpolationMode resample, | |||
| bool expand, std::vector<float> center, | |||
| @@ -1441,6 +1453,85 @@ std::shared_ptr<TensorOp> RandomResizedCropOperation::Build() { | |||
| return tensor_op; | |||
| } | |||
| // RandomResizedCropWithBBoxOperation | |||
| RandomResizedCropWithBBoxOperation::RandomResizedCropWithBBoxOperation(std::vector<int32_t> size, | |||
| std::vector<float> scale, | |||
| std::vector<float> ratio, | |||
| InterpolationMode interpolation, | |||
| int32_t max_attempts) | |||
| : size_(size), scale_(scale), ratio_(ratio), interpolation_(interpolation), max_attempts_(max_attempts) {} | |||
| Status RandomResizedCropWithBBoxOperation::ValidateParams() { | |||
| // size | |||
| if (size_.size() != 2 && size_.size() != 1) { | |||
| std::string err_msg = | |||
| "RandomResizedCropWithBBox: size must be a vector of one or two values, got: " + std::to_string(size_.size()); | |||
| MS_LOG(ERROR) << err_msg; | |||
| RETURN_STATUS_SYNTAX_ERROR(err_msg); | |||
| } | |||
| if (size_[0] <= 0 || (size_.size() == 2 && size_[1] <= 0)) { | |||
| std::string err_msg = "RandomResizedCropWithBBox: size must only contain positive integers."; | |||
| MS_LOG(ERROR) << "RandomResizedCropWithBBox: size must only contain positive integers, got: " << size_; | |||
| RETURN_STATUS_SYNTAX_ERROR(err_msg); | |||
| } | |||
| // scale | |||
| if (scale_.size() != 2) { | |||
| std::string err_msg = | |||
| "RandomResizedCropWithBBox: scale must be a vector of two values, got: " + std::to_string(scale_.size()); | |||
| MS_LOG(ERROR) << err_msg; | |||
| RETURN_STATUS_SYNTAX_ERROR(err_msg); | |||
| } | |||
| if (scale_[0] < 0 || scale_[1] < 0) { | |||
| std::string err_msg = "RandomResizedCropWithBBox: scale must be greater than or equal to 0."; | |||
| MS_LOG(ERROR) << "RandomResizedCropWithBBox: scale must be greater than or equal to 0, got: " << scale_; | |||
| RETURN_STATUS_SYNTAX_ERROR(err_msg); | |||
| } | |||
| if (scale_[1] < scale_[0]) { | |||
| std::string err_msg = "RandomResizedCropWithBBox: scale must have a size of two in the format of (min, max)."; | |||
| MS_LOG(ERROR) << "RandomResizedCropWithBBox: scale must have a size of two in the format of (min, max), but got: " | |||
| << scale_; | |||
| RETURN_STATUS_SYNTAX_ERROR(err_msg); | |||
| } | |||
| // ratio | |||
| if (ratio_.size() != 2) { | |||
| std::string err_msg = | |||
| "RandomResizedCropWithBBox: ratio must be a vector of two values, got: " + std::to_string(ratio_.size()); | |||
| MS_LOG(ERROR) << err_msg; | |||
| RETURN_STATUS_SYNTAX_ERROR(err_msg); | |||
| } | |||
| if (ratio_[0] < 0 || ratio_[1] < 0) { | |||
| std::string err_msg = "RandomResizedCropWithBBox: ratio must be greater than or equal to 0."; | |||
| MS_LOG(ERROR) << "RandomResizedCropWithBBox: ratio must be greater than or equal to 0, got: " << ratio_; | |||
| RETURN_STATUS_SYNTAX_ERROR(err_msg); | |||
| } | |||
| if (ratio_[1] < ratio_[0]) { | |||
| std::string err_msg = "RandomResizedCropWithBBox: ratio must have a size of two in the format of (min, max)."; | |||
| MS_LOG(ERROR) << "RandomResizedCropWithBBox: ratio must have a size of two in the format of (min, max), but got: " | |||
| << ratio_; | |||
| RETURN_STATUS_SYNTAX_ERROR(err_msg); | |||
| } | |||
| // max_attempts | |||
| if (max_attempts_ < 1) { | |||
| std::string err_msg = "RandomResizedCropWithBBox: max_attempts must be greater than or equal to 1, got: " + | |||
| std::to_string(max_attempts_); | |||
| MS_LOG(ERROR) << err_msg; | |||
| RETURN_STATUS_SYNTAX_ERROR(err_msg); | |||
| } | |||
| return Status::OK(); | |||
| } | |||
| std::shared_ptr<TensorOp> RandomResizedCropWithBBoxOperation::Build() { | |||
| int32_t height = size_[0]; | |||
| int32_t width = size_[0]; | |||
| // User specified the width value. | |||
| if (size_.size() == 2) { | |||
| width = size_[1]; | |||
| } | |||
| std::shared_ptr<RandomCropAndResizeWithBBoxOp> tensor_op = std::make_shared<RandomCropAndResizeWithBBoxOp>( | |||
| height, width, scale_[0], scale_[1], ratio_[0], ratio_[1], interpolation_, max_attempts_); | |||
| return tensor_op; | |||
| } | |||
| // Function to create RandomRotationOperation. | |||
| RandomRotationOperation::RandomRotationOperation(std::vector<float> degrees, InterpolationMode interpolation_mode, | |||
| bool expand, std::vector<float> center, | |||
| @@ -64,6 +64,7 @@ class RandomPosterizeOperation; | |||
| class RandomResizeOperation; | |||
| class RandomResizeWithBBoxOperation; | |||
| class RandomResizedCropOperation; | |||
| class RandomResizedCropWithBBoxOperation; | |||
| class RandomRotationOperation; | |||
| class RandomSelectSubpolicyOperation; | |||
| class RandomSharpnessOperation; | |||
| @@ -343,6 +344,23 @@ std::shared_ptr<RandomResizedCropOperation> RandomResizedCrop( | |||
| std::vector<int32_t> size, std::vector<float> scale = {0.08, 1.0}, std::vector<float> ratio = {3. / 4., 4. / 3.}, | |||
| InterpolationMode interpolation = InterpolationMode::kLinear, int32_t max_attempts = 10); | |||
| /// \brief Function to create a RandomResizedCropWithBBox TensorOperation. | |||
| /// \notes Crop the input image to a random size and aspect ratio. | |||
| /// \param[in] size A vector representing the output size of the cropped image. | |||
| /// If size is a single value, a square crop of size (size, size) is returned. | |||
| /// If size has 2 values, it should be (height, width). | |||
| /// \param[in] scale Range [min, max) of respective size of the original | |||
| /// size to be cropped (default=(0.08, 1.0)) | |||
| /// \param[in] ratio Range [min, max) of aspect ratio to be cropped | |||
| /// (default=(3. / 4., 4. / 3.)). | |||
| /// \param[in] interpolation Image interpolation mode (default=InterpolationMode::kLinear) | |||
| /// \param[in] max_attempts The maximum number of attempts to propose a valid | |||
| /// crop_area (default=10). If exceeded, fall back to use center_crop instead. | |||
| /// \return Shared pointer to the current TensorOperation. | |||
| std::shared_ptr<RandomResizedCropWithBBoxOperation> RandomResizedCropWithBBox( | |||
| std::vector<int32_t> size, std::vector<float> scale = {0.08, 1.0}, std::vector<float> ratio = {3. / 4., 4. / 3.}, | |||
| InterpolationMode interpolation = InterpolationMode::kLinear, int32_t max_attempts = 10); | |||
| /// \brief Function to create a RandomRotation TensorOp | |||
| /// \notes Rotates the image according to parameters | |||
| /// \param[in] degrees A float vector of size 2, representing the starting and ending degree | |||
| @@ -863,6 +881,27 @@ class RandomResizedCropOperation : public TensorOperation { | |||
| int32_t max_attempts_; | |||
| }; | |||
| class RandomResizedCropWithBBoxOperation : public TensorOperation { | |||
| public: | |||
| explicit RandomResizedCropWithBBoxOperation(std::vector<int32_t> size, std::vector<float> scale = {0.08, 1.0}, | |||
| std::vector<float> ratio = {3. / 4., 4. / 3.}, | |||
| InterpolationMode interpolation = InterpolationMode::kNearestNeighbour, | |||
| int32_t max_attempts = 10); | |||
| ~RandomResizedCropWithBBoxOperation() = default; | |||
| std::shared_ptr<TensorOp> Build() override; | |||
| Status ValidateParams() override; | |||
| private: | |||
| std::vector<int32_t> size_; | |||
| std::vector<float> scale_; | |||
| std::vector<float> ratio_; | |||
| InterpolationMode interpolation_; | |||
| int32_t max_attempts_; | |||
| }; | |||
| class RandomRotationOperation : public TensorOperation { | |||
| public: | |||
| RandomRotationOperation(std::vector<float> degrees, InterpolationMode interpolation_mode, bool expand, | |||
| @@ -1969,6 +1969,133 @@ TEST_F(MindDataTestPipeline, TestRandomResizedCropFail4) { | |||
| EXPECT_EQ(random_resized_crop, nullptr); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestRandomResizedCropWithBBoxSuccess1) { | |||
| // Testing RandomResizedCropWithBBox with default values | |||
| // Create an VOC Dataset | |||
| std::string folder_path = datasets_root_path_ + "/testVOC2012_2"; | |||
| std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 4)); | |||
| EXPECT_NE(ds, nullptr); | |||
| // Create objects for the tensor ops | |||
| std::shared_ptr<TensorOperation> random_resized_crop = vision::RandomResizedCropWithBBox({5}); | |||
| EXPECT_NE(random_resized_crop, nullptr); | |||
| // Create a Map operation on ds | |||
| ds = ds->Map({random_resized_crop}, {"image", "bbox"}); | |||
| EXPECT_NE(ds, nullptr); | |||
| // Create an iterator over the result of the above dataset | |||
| // This will trigger the creation of the Execution Tree and launch it. | |||
| std::shared_ptr<Iterator> iter = ds->CreateIterator(); | |||
| EXPECT_NE(iter, nullptr); | |||
| // Iterate the dataset and get each row | |||
| std::unordered_map<std::string, std::shared_ptr<Tensor>> row; | |||
| iter->GetNextRow(&row); | |||
| uint64_t i = 0; | |||
| while (row.size() != 0) { | |||
| i++; | |||
| auto image = row["image"]; | |||
| MS_LOG(INFO) << "Tensor image shape: " << image->shape(); | |||
| EXPECT_EQ(image->shape()[0] == 5 && image->shape()[1] == 5, true); | |||
| iter->GetNextRow(&row); | |||
| } | |||
| EXPECT_EQ(i, 4); | |||
| // Manually terminate the pipeline | |||
| iter->Stop(); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestRandomResizedCropWithBBoxSuccess2) { | |||
| // Testing RandomResizedCropWithBBox with non-default values | |||
| // Create an VOC Dataset | |||
| std::string folder_path = datasets_root_path_ + "/testVOC2012_2"; | |||
| std::shared_ptr<Dataset> ds = VOC(folder_path, "Detection", "train", {}, true, SequentialSampler(0, 4)); | |||
| EXPECT_NE(ds, nullptr); | |||
| // Create objects for the tensor ops | |||
| std::shared_ptr<TensorOperation> random_resized_crop = vision::RandomResizedCropWithBBox( | |||
| {5, 10}, {0.25, 0.75}, {0.5, 1.25}, mindspore::dataset::InterpolationMode::kArea, 20); | |||
| EXPECT_NE(random_resized_crop, nullptr); | |||
| // Create a Map operation on ds | |||
| ds = ds->Map({random_resized_crop}, {"image", "bbox"}); | |||
| EXPECT_NE(ds, nullptr); | |||
| // Create an iterator over the result of the above dataset | |||
| // This will trigger the creation of the Execution Tree and launch it. | |||
| std::shared_ptr<Iterator> iter = ds->CreateIterator(); | |||
| EXPECT_NE(iter, nullptr); | |||
| // Iterate the dataset and get each row | |||
| std::unordered_map<std::string, std::shared_ptr<Tensor>> row; | |||
| iter->GetNextRow(&row); | |||
| uint64_t i = 0; | |||
| while (row.size() != 0) { | |||
| i++; | |||
| auto image = row["image"]; | |||
| MS_LOG(INFO) << "Tensor image shape: " << image->shape(); | |||
| EXPECT_EQ(image->shape()[0] == 5 && image->shape()[1] == 10, true); | |||
| iter->GetNextRow(&row); | |||
| } | |||
| EXPECT_EQ(i, 4); | |||
| // Manually terminate the pipeline | |||
| iter->Stop(); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestRandomResizedCropWithBBoxFail1) { | |||
| // This should fail because size has negative value | |||
| // Create a Cifar10 Dataset | |||
| std::string folder_path = datasets_root_path_ + "/testCifar10Data/"; | |||
| std::shared_ptr<Dataset> ds = Cifar10(folder_path, "all", RandomSampler(false, 10)); | |||
| EXPECT_NE(ds, nullptr); | |||
| // Create objects for the tensor ops | |||
| std::shared_ptr<TensorOperation> random_resized_crop = vision::RandomResizedCropWithBBox({5, -10}); | |||
| EXPECT_EQ(random_resized_crop, nullptr); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestRandomResizedCropWithBBoxFail2) { | |||
| // This should fail because scale isn't in {min, max} format | |||
| // Create a Cifar10 Dataset | |||
| std::string folder_path = datasets_root_path_ + "/testCifar10Data/"; | |||
| std::shared_ptr<Dataset> ds = Cifar10(folder_path, "all", RandomSampler(false, 10)); | |||
| EXPECT_NE(ds, nullptr); | |||
| // Create objects for the tensor ops | |||
| std::shared_ptr<TensorOperation> random_resized_crop = vision::RandomResizedCropWithBBox({5, 10}, {4, 3}); | |||
| EXPECT_EQ(random_resized_crop, nullptr); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestRandomResizedCropWithBBoxFail3) { | |||
| // This should fail because ratio isn't in {min, max} format | |||
| // Create a Cifar10 Dataset | |||
| std::string folder_path = datasets_root_path_ + "/testCifar10Data/"; | |||
| std::shared_ptr<Dataset> ds = Cifar10(folder_path, "all", RandomSampler(false, 10)); | |||
| EXPECT_NE(ds, nullptr); | |||
| // Create objects for the tensor ops | |||
| std::shared_ptr<TensorOperation> random_resized_crop = vision::RandomResizedCropWithBBox({5, 10}, {4, 5}, {7, 6}); | |||
| EXPECT_EQ(random_resized_crop, nullptr); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestRandomResizedCropWithBBoxFail4) { | |||
| // This should fail because scale has a size of more than 2 | |||
| // Create a Cifar10 Dataset | |||
| std::string folder_path = datasets_root_path_ + "/testCifar10Data/"; | |||
| std::shared_ptr<Dataset> ds = Cifar10(folder_path, "all", RandomSampler(false, 10)); | |||
| EXPECT_NE(ds, nullptr); | |||
| // Create objects for the tensor ops | |||
| std::shared_ptr<TensorOperation> random_resized_crop = vision::RandomResizedCropWithBBox({5, 10, 20}, {4, 5}, {7, 6}); | |||
| EXPECT_EQ(random_resized_crop, nullptr); | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestRandomRotation) { | |||
| MS_LOG(INFO) << "Doing MindDataTestPipeline-TestRandomRotation."; | |||
| @@ -2116,8 +2243,8 @@ TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicyFail) { | |||
| EXPECT_EQ(random_select_subpolicy1, nullptr); | |||
| // RandomSelectSubpolicy: policy must not be empty | |||
| std::shared_ptr<TensorOperation> random_select_subpolicy2 = vision::RandomSelectSubpolicy( | |||
| {{{vision::Invert(), 0.5}, {vision::Equalize(), 0.5}}, {{nullptr, 1}}}); | |||
| std::shared_ptr<TensorOperation> random_select_subpolicy2 = | |||
| vision::RandomSelectSubpolicy({{{vision::Invert(), 0.5}, {vision::Equalize(), 0.5}}, {{nullptr, 1}}}); | |||
| EXPECT_EQ(random_select_subpolicy2, nullptr); | |||
| // RandomSelectSubpolicy: policy must not be empty | |||
| @@ -2125,13 +2252,13 @@ TEST_F(MindDataTestPipeline, TestRandomSelectSubpolicyFail) { | |||
| EXPECT_EQ(random_select_subpolicy3, nullptr); | |||
| // RandomSelectSubpolicy: policy must not be empty | |||
| std::shared_ptr<TensorOperation> random_select_subpolicy4 = vision::RandomSelectSubpolicy( | |||
| {{{vision::Invert(), 0.5}, {vision::Equalize(), 0.5}}, {}}); | |||
| std::shared_ptr<TensorOperation> random_select_subpolicy4 = | |||
| vision::RandomSelectSubpolicy({{{vision::Invert(), 0.5}, {vision::Equalize(), 0.5}}, {}}); | |||
| EXPECT_EQ(random_select_subpolicy4, nullptr); | |||
| // RandomSelectSubpolicy: policy must not be empty | |||
| std::shared_ptr<TensorOperation> random_select_subpolicy5 = vision::RandomSelectSubpolicy( | |||
| {{{}, {vision::Equalize(), 0.5}}, {{vision::Resize({15, 15}), 1}}}); | |||
| std::shared_ptr<TensorOperation> random_select_subpolicy5 = | |||
| vision::RandomSelectSubpolicy({{{}, {vision::Equalize(), 0.5}}, {{vision::Resize({15, 15}), 1}}}); | |||
| EXPECT_EQ(random_select_subpolicy5, nullptr); | |||
| } | |||
| @@ -2569,7 +2696,8 @@ TEST_F(MindDataTestPipeline, TestRescaleFail) { | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestSoftDvppDecodeRandomCropResizeJpegSuccess1) { | |||
| MS_LOG(INFO) << "Doing MindDataTestPipeline-TestSoftDvppDecodeRandomCropResizeJpegSuccess1 with single integer input."; | |||
| MS_LOG(INFO) | |||
| << "Doing MindDataTestPipeline-TestSoftDvppDecodeRandomCropResizeJpegSuccess1 with single integer input."; | |||
| // Create an ImageFolder Dataset | |||
| std::string folder_path = datasets_root_path_ + "/testPK/data/"; | |||
| @@ -2610,7 +2738,8 @@ TEST_F(MindDataTestPipeline, TestSoftDvppDecodeRandomCropResizeJpegSuccess1) { | |||
| } | |||
| TEST_F(MindDataTestPipeline, TestSoftDvppDecodeRandomCropResizeJpegSuccess2) { | |||
| MS_LOG(INFO) << "Doing MindDataTestPipeline-TestSoftDvppDecodeRandomCropResizeJpegSuccess2 with (height, width) input."; | |||
| MS_LOG(INFO) | |||
| << "Doing MindDataTestPipeline-TestSoftDvppDecodeRandomCropResizeJpegSuccess2 with (height, width) input."; | |||
| // Create an ImageFolder Dataset | |||
| std::string folder_path = datasets_root_path_ + "/testPK/data/"; | |||