| @@ -1 +1 @@ | |||||
| Subproject commit 1350673d51b3f8535bc217a7780e6a0b52ff9a41 | |||||
| Subproject commit 45ca7863ac6410c8e2f83168481ddc6b43bcea33 | |||||
| @@ -56,13 +56,16 @@ | |||||
| #include "dataset/kernels/image/pad_op.h" | #include "dataset/kernels/image/pad_op.h" | ||||
| #include "dataset/kernels/image/random_color_adjust_op.h" | #include "dataset/kernels/image/random_color_adjust_op.h" | ||||
| #include "dataset/kernels/image/random_crop_and_resize_op.h" | #include "dataset/kernels/image/random_crop_and_resize_op.h" | ||||
| #include "dataset/kernels/image/random_crop_and_resize_with_bbox_op.h" | |||||
| #include "dataset/kernels/image/random_crop_decode_resize_op.h" | #include "dataset/kernels/image/random_crop_decode_resize_op.h" | ||||
| #include "dataset/kernels/image/random_crop_op.h" | #include "dataset/kernels/image/random_crop_op.h" | ||||
| #include "dataset/kernels/image/random_crop_with_bbox_op.h" | |||||
| #include "dataset/kernels/image/random_horizontal_flip_bbox_op.h" | #include "dataset/kernels/image/random_horizontal_flip_bbox_op.h" | ||||
| #include "dataset/kernels/image/random_horizontal_flip_op.h" | #include "dataset/kernels/image/random_horizontal_flip_op.h" | ||||
| #include "dataset/kernels/image/random_resize_op.h" | #include "dataset/kernels/image/random_resize_op.h" | ||||
| #include "dataset/kernels/image/random_rotation_op.h" | #include "dataset/kernels/image/random_rotation_op.h" | ||||
| #include "dataset/kernels/image/random_vertical_flip_op.h" | #include "dataset/kernels/image/random_vertical_flip_op.h" | ||||
| #include "dataset/kernels/image/random_vertical_flip_with_bbox_op.h" | |||||
| #include "dataset/kernels/image/rescale_op.h" | #include "dataset/kernels/image/rescale_op.h" | ||||
| #include "dataset/kernels/image/resize_bilinear_op.h" | #include "dataset/kernels/image/resize_bilinear_op.h" | ||||
| #include "dataset/kernels/image/resize_op.h" | #include "dataset/kernels/image/resize_op.h" | ||||
| @@ -381,6 +384,12 @@ void bindTensorOps2(py::module *m) { | |||||
| *m, "RandomVerticalFlipOp", "Tensor operation to randomly flip an image vertically.") | *m, "RandomVerticalFlipOp", "Tensor operation to randomly flip an image vertically.") | ||||
| .def(py::init<float>(), py::arg("probability") = RandomVerticalFlipOp::kDefProbability); | .def(py::init<float>(), py::arg("probability") = RandomVerticalFlipOp::kDefProbability); | ||||
| (void)py::class_<RandomVerticalFlipWithBBoxOp, TensorOp, std::shared_ptr<RandomVerticalFlipWithBBoxOp>>( | |||||
| *m, "RandomVerticalFlipWithBBoxOp", | |||||
| "Tensor operation to randomly flip an image vertically" | |||||
| " and adjust bounding boxes.") | |||||
| .def(py::init<float>(), py::arg("probability") = RandomVerticalFlipWithBBoxOp::kDefProbability); | |||||
| (void)py::class_<RandomCropOp, TensorOp, std::shared_ptr<RandomCropOp>>(*m, "RandomCropOp", | (void)py::class_<RandomCropOp, TensorOp, std::shared_ptr<RandomCropOp>>(*m, "RandomCropOp", | ||||
| "Gives random crop of specified size " | "Gives random crop of specified size " | ||||
| "Takes crop size") | "Takes crop size") | ||||
| @@ -392,6 +401,20 @@ void bindTensorOps2(py::module *m) { | |||||
| py::arg("fillG") = RandomCropOp::kDefFillG, py::arg("fillB") = RandomCropOp::kDefFillB); | py::arg("fillG") = RandomCropOp::kDefFillG, py::arg("fillB") = RandomCropOp::kDefFillB); | ||||
| (void)py::class_<HwcToChwOp, TensorOp, std::shared_ptr<HwcToChwOp>>(*m, "ChannelSwapOp").def(py::init<>()); | (void)py::class_<HwcToChwOp, TensorOp, std::shared_ptr<HwcToChwOp>>(*m, "ChannelSwapOp").def(py::init<>()); | ||||
| (void)py::class_<RandomCropWithBBoxOp, TensorOp, std::shared_ptr<RandomCropWithBBoxOp>>(*m, "RandomCropWithBBoxOp", | |||||
| "Gives random crop of given " | |||||
| "size + adjusts bboxes " | |||||
| "Takes crop size") | |||||
| .def(py::init<int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, BorderType, bool, uint8_t, uint8_t, uint8_t>(), | |||||
| py::arg("cropHeight"), py::arg("cropWidth"), py::arg("padTop") = RandomCropWithBBoxOp::kDefPadTop, | |||||
| py::arg("padBottom") = RandomCropWithBBoxOp::kDefPadBottom, | |||||
| py::arg("padLeft") = RandomCropWithBBoxOp::kDefPadLeft, | |||||
| py::arg("padRight") = RandomCropWithBBoxOp::kDefPadRight, | |||||
| py::arg("borderType") = RandomCropWithBBoxOp::kDefBorderType, | |||||
| py::arg("padIfNeeded") = RandomCropWithBBoxOp::kDefPadIfNeeded, | |||||
| py::arg("fillR") = RandomCropWithBBoxOp::kDefFillR, py::arg("fillG") = RandomCropWithBBoxOp::kDefFillG, | |||||
| py::arg("fillB") = RandomCropWithBBoxOp::kDefFillB); | |||||
| (void)py::class_<OneHotOp, TensorOp, std::shared_ptr<OneHotOp>>( | (void)py::class_<OneHotOp, TensorOp, std::shared_ptr<OneHotOp>>( | ||||
| *m, "OneHotOp", "Tensor operation to apply one hot encoding. Takes number of classes.") | *m, "OneHotOp", "Tensor operation to apply one hot encoding. Takes number of classes.") | ||||
| .def(py::init<int32_t>()); | .def(py::init<int32_t>()); | ||||
| @@ -488,6 +511,20 @@ void bindTensorOps3(py::module *m) { | |||||
| py::arg("interpolation") = RandomCropAndResizeOp::kDefInterpolation, | py::arg("interpolation") = RandomCropAndResizeOp::kDefInterpolation, | ||||
| py::arg("maxIter") = RandomCropAndResizeOp::kDefMaxIter); | py::arg("maxIter") = RandomCropAndResizeOp::kDefMaxIter); | ||||
| (void)py::class_<RandomCropAndResizeWithBBoxOp, TensorOp, std::shared_ptr<RandomCropAndResizeWithBBoxOp>>( | |||||
| *m, "RandomCropAndResizeWithBBoxOp", | |||||
| "Tensor operation to randomly crop an image (with BBoxes) and resize to a given size." | |||||
| "Takes output height and width and" | |||||
| "optional parameters for lower and upper bound for aspect ratio (h/w) and scale," | |||||
| "interpolation mode, and max attempts to crop") | |||||
| .def(py::init<int32_t, int32_t, float, float, float, float, InterpolationMode, int32_t>(), py::arg("targetHeight"), | |||||
| py::arg("targetWidth"), py::arg("scaleLb") = RandomCropAndResizeWithBBoxOp::kDefScaleLb, | |||||
| py::arg("scaleUb") = RandomCropAndResizeWithBBoxOp::kDefScaleUb, | |||||
| py::arg("aspectLb") = RandomCropAndResizeWithBBoxOp::kDefAspectLb, | |||||
| py::arg("aspectUb") = RandomCropAndResizeWithBBoxOp::kDefAspectUb, | |||||
| py::arg("interpolation") = RandomCropAndResizeWithBBoxOp::kDefInterpolation, | |||||
| py::arg("maxIter") = RandomCropAndResizeWithBBoxOp::kDefMaxIter); | |||||
| (void)py::class_<RandomColorAdjustOp, TensorOp, std::shared_ptr<RandomColorAdjustOp>>( | (void)py::class_<RandomColorAdjustOp, TensorOp, std::shared_ptr<RandomColorAdjustOp>>( | ||||
| *m, "RandomColorAdjustOp", | *m, "RandomColorAdjustOp", | ||||
| "Tensor operation to adjust an image's color randomly." | "Tensor operation to adjust an image's color randomly." | ||||
| @@ -10,14 +10,17 @@ add_library(kernels-image OBJECT | |||||
| pad_op.cc | pad_op.cc | ||||
| random_color_adjust_op.cc | random_color_adjust_op.cc | ||||
| random_crop_decode_resize_op.cc | random_crop_decode_resize_op.cc | ||||
| random_crop_and_resize_with_bbox_op.cc | |||||
| random_crop_and_resize_op.cc | random_crop_and_resize_op.cc | ||||
| random_crop_op.cc | random_crop_op.cc | ||||
| random_crop_with_bbox_op.cc | |||||
| random_horizontal_flip_op.cc | random_horizontal_flip_op.cc | ||||
| random_horizontal_flip_bbox_op.cc | random_horizontal_flip_bbox_op.cc | ||||
| bounding_box_augment_op.cc | bounding_box_augment_op.cc | ||||
| random_resize_op.cc | random_resize_op.cc | ||||
| random_rotation_op.cc | random_rotation_op.cc | ||||
| random_vertical_flip_op.cc | random_vertical_flip_op.cc | ||||
| random_vertical_flip_with_bbox_op.cc | |||||
| rescale_op.cc | rescale_op.cc | ||||
| resize_bilinear_op.cc | resize_bilinear_op.cc | ||||
| resize_op.cc | resize_op.cc | ||||
| @@ -16,6 +16,7 @@ | |||||
| #include "dataset/kernels/image/image_utils.h" | #include "dataset/kernels/image/image_utils.h" | ||||
| #include <opencv2/imgproc/types_c.h> | #include <opencv2/imgproc/types_c.h> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include <vector> | |||||
| #include <stdexcept> | #include <stdexcept> | ||||
| #include <utility> | #include <utility> | ||||
| #include <opencv2/imgcodecs.hpp> | #include <opencv2/imgcodecs.hpp> | ||||
| @@ -724,5 +725,101 @@ Status Pad(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output | |||||
| RETURN_STATUS_UNEXPECTED("Unexpected error in pad"); | RETURN_STATUS_UNEXPECTED("Unexpected error in pad"); | ||||
| } | } | ||||
| } | } | ||||
| // -------- BBOX OPERATIONS -------- // | |||||
| void UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int *CB_Xmin, int *CB_Ymin, int *CB_Xmax, | |||||
| int *CB_Ymax) { | |||||
| // PASS LIST, COUNT OF BOUNDING BOXES | |||||
| // Also PAss X/Y Min/Max of image cropped region - normally obtained from 'GetCropBox' functions | |||||
| uint32_t bb_Xmin_t, bb_Ymin_t, bb_Xmax_t, bb_Ymax_t; | |||||
| std::vector<int> correctInd; | |||||
| std::vector<uint32_t> copyVals; | |||||
| dsize_t bboxDim = (*bboxList)->shape()[1]; | |||||
| bool retFlag = false; // true unless overlap found | |||||
| for (int i = 0; i < *bboxCount; i++) { | |||||
| int bb_Xmin, bb_Xmax, bb_Ymin, bb_Ymax; | |||||
| (*bboxList)->GetUnsignedIntAt(&bb_Xmin_t, {i, 0}); | |||||
| (*bboxList)->GetUnsignedIntAt(&bb_Ymin_t, {i, 1}); | |||||
| (*bboxList)->GetUnsignedIntAt(&bb_Xmax_t, {i, 2}); | |||||
| (*bboxList)->GetUnsignedIntAt(&bb_Ymax_t, {i, 3}); | |||||
| bb_Xmin = bb_Xmin_t; | |||||
| bb_Ymin = bb_Ymin_t; | |||||
| bb_Xmax = bb_Xmax_t; | |||||
| bb_Ymax = bb_Ymax_t; | |||||
| bb_Xmax = bb_Xmin + bb_Xmax; | |||||
| bb_Ymax = bb_Ymin + bb_Ymax; | |||||
| // check for image / BB overlap | |||||
| if (((bb_Xmin > *CB_Xmax) || (bb_Ymin > *CB_Ymax)) || ((bb_Xmax < *CB_Xmin) || (bb_Ymax < *CB_Ymin))) { | |||||
| retFlag = true; // no overlap found | |||||
| } | |||||
| if (retFlag) { // invalid bbox no longer within image region - reset to zero | |||||
| continue; | |||||
| } | |||||
| // Update this bbox and select it to move to the final output tensor | |||||
| correctInd.push_back(i); | |||||
| // adjust BBox corners by bringing into new CropBox if beyond | |||||
| // Also reseting/adjusting for boxes to lie within CropBox instead of Image - subtract CropBox Xmin/YMin | |||||
| bb_Xmin = bb_Xmin - (std::min(0, (bb_Xmin - *CB_Xmin)) + *CB_Xmin); | |||||
| bb_Xmax = bb_Xmax - (std::max(0, (bb_Xmax - *CB_Xmax)) + *CB_Xmin); | |||||
| bb_Ymin = bb_Ymin - (std::min(0, (bb_Ymin - *CB_Ymin)) + *CB_Ymin); | |||||
| bb_Ymax = bb_Ymax - (std::max(0, (bb_Ymax - *CB_Ymax)) + *CB_Ymin); | |||||
| // reset min values and calculate width/height from Box corners | |||||
| (*bboxList)->SetItemAt({i, 0}, (uint32_t)(bb_Xmin)); | |||||
| (*bboxList)->SetItemAt({i, 1}, (uint32_t)(bb_Ymin)); | |||||
| (*bboxList)->SetItemAt({i, 2}, (uint32_t)(bb_Xmax - bb_Xmin)); | |||||
| (*bboxList)->SetItemAt({i, 3}, (uint32_t)(bb_Ymax - bb_Ymin)); | |||||
| } | |||||
| // 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 | |||||
| *bboxCount = correctInd.size(); | |||||
| uint32_t temp; | |||||
| for (auto slice : correctInd) { // for every index in the loop | |||||
| for (int ix = 0; ix < bboxDim; ix++) { | |||||
| (*bboxList)->GetUnsignedIntAt(&temp, {slice, ix}); | |||||
| copyVals.push_back(temp); | |||||
| } | |||||
| } | |||||
| std::shared_ptr<Tensor> retV; | |||||
| Tensor::CreateTensor(&retV, copyVals, TensorShape({(dsize_t)bboxCount, bboxDim})); | |||||
| (*bboxList) = retV; // reset pointer | |||||
| } | |||||
| void PadBBoxes(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int32_t *pad_top, int32_t *pad_left) { | |||||
| uint32_t xMin = 0; | |||||
| uint32_t yMin = 0; | |||||
| for (int i = 0; i < *bboxCount; i++) { | |||||
| (*bboxList)->GetUnsignedIntAt(&xMin, {i, 0}); | |||||
| (*bboxList)->GetUnsignedIntAt(&yMin, {i, 1}); | |||||
| xMin = xMin + (uint32_t)(*pad_left); // should not be negative | |||||
| yMin = yMin + (uint32_t)(*pad_top); | |||||
| (*bboxList)->SetItemAt({i, 0}, xMin); | |||||
| (*bboxList)->SetItemAt({i, 1}, yMin); | |||||
| } | |||||
| } | |||||
| void UpdateBBoxesForResize(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int32_t *target_width_, | |||||
| int32_t *target_height_, int *orig_width, int *orig_height) { | |||||
| uint32_t bb_Xmin, bb_Ymin, bb_Xwidth, bb_Ywidth; | |||||
| // cast to float to preseve fractional | |||||
| double W_aspRatio = (*target_width_ * 1.0) / (*orig_width * 1.0); | |||||
| double H_aspRatio = (*target_height_ * 1.0) / (*orig_height * 1.0); | |||||
| for (int i = 0; i < *bboxCount; i++) { | |||||
| // for each bounding box | |||||
| (*bboxList)->GetUnsignedIntAt(&bb_Xmin, {i, 0}); | |||||
| (*bboxList)->GetUnsignedIntAt(&bb_Ymin, {i, 1}); | |||||
| (*bboxList)->GetUnsignedIntAt(&bb_Xwidth, {i, 2}); | |||||
| (*bboxList)->GetUnsignedIntAt(&bb_Ywidth, {i, 3}); | |||||
| // update positions and widths | |||||
| bb_Xmin = bb_Xmin * W_aspRatio; | |||||
| bb_Ymin = bb_Ymin * H_aspRatio; | |||||
| bb_Xwidth = bb_Xwidth * W_aspRatio; | |||||
| bb_Ywidth = bb_Ywidth * H_aspRatio; | |||||
| // reset bounding box values | |||||
| (*bboxList)->SetItemAt({i, 0}, (uint32_t)bb_Xmin); | |||||
| (*bboxList)->SetItemAt({i, 1}, (uint32_t)bb_Ymin); | |||||
| (*bboxList)->SetItemAt({i, 2}, (uint32_t)bb_Xwidth); | |||||
| (*bboxList)->SetItemAt({i, 3}, (uint32_t)bb_Ywidth); | |||||
| } | |||||
| } | |||||
| } // namespace dataset | } // namespace dataset | ||||
| } // namespace mindspore | } // namespace mindspore | ||||
| @@ -225,7 +225,39 @@ Status Erase(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *outp | |||||
| Status Pad(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, const int32_t &pad_top, | Status Pad(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, const int32_t &pad_top, | ||||
| const int32_t &pad_bottom, const int32_t &pad_left, const int32_t &pad_right, const BorderType &border_types, | const int32_t &pad_bottom, const int32_t &pad_left, const int32_t &pad_right, const BorderType &border_types, | ||||
| uint8_t fill_r = 0, uint8_t fill_g = 0, uint8_t fill_b = 0); | uint8_t fill_r = 0, uint8_t fill_g = 0, uint8_t fill_b = 0); | ||||
| // -------- BBOX OPERATIONS -------- // | |||||
| // Updates and checks bounding boxes for new cropped region of image | |||||
| // @param bboxList: A tensor contaning bounding box tensors | |||||
| // @param bboxCount: total Number of bounding boxes - required within caller function to run update loop | |||||
| // @param CB_Xmin: Images's CropBox Xmin coordinate | |||||
| // @param CB_Xmin: Images's CropBox Ymin coordinate | |||||
| // @param CB_Xmax: Images's CropBox Xmax coordinate - (Xmin + width) | |||||
| // @param CB_Xmax: Images's CropBox Ymax coordinate - (Ymin + height) | |||||
| void UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int *CB_Xmin, int *CB_Ymin, int *CB_Xmax, | |||||
| int *CB_Ymax); | |||||
| // Updates bounding boxes with required Top and Left padding | |||||
| // Top and Left padding amounts required to adjust bboxs min X,Y values according to padding 'push' | |||||
| // Top/Left since images 0,0 coordinate is taken from top left | |||||
| // @param bboxList: A tensor contaning bounding box tensors | |||||
| // @param bboxCount: total Number of bounding boxes - required within caller function to run update loop | |||||
| // @param pad_top: Total amount of padding applied to image top | |||||
| // @param pad_left: Total amount of padding applied to image left side | |||||
| void PadBBoxes(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int32_t *pad_top, int32_t *pad_left); | |||||
| // Updates bounding boxes for an Image Resize Operation - Takes in set of valid BBoxes | |||||
| // For e.g those that remain after a crop | |||||
| // @param bboxList: A tensor contaning bounding box tensors | |||||
| // @param bboxCount: total Number of bounding boxes - required within caller function to run update loop | |||||
| // @param bboxList: A tensor contaning bounding box tensors | |||||
| // @param target_width_: required width of image post resize | |||||
| // @param target_width_: required height of image post resize | |||||
| // @param orig_width: current width of image pre resize | |||||
| // @param orig_height: current height of image pre resize | |||||
| void UpdateBBoxesForResize(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int32_t *target_width_, | |||||
| int32_t *target_height_, int *orig_width, int *orig_height); | |||||
| } // namespace dataset | } // namespace dataset | ||||
| } // namespace mindspore | } // namespace mindspore | ||||
| #endif // DATASET_KERNELS_IMAGE_IMAGE_UTILS_H_ | #endif // DATASET_KERNELS_IMAGE_IMAGE_UTILS_H_ | ||||
| @@ -0,0 +1,58 @@ | |||||
| /** | |||||
| * 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 | |||||
| * | |||||
| * 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 <random> | |||||
| #include <utility> | |||||
| #include "dataset/util/random.h" | |||||
| #include "dataset/util/status.h" | |||||
| #include "dataset/kernels/image/image_utils.h" | |||||
| #include "dataset/kernels/image/random_crop_and_resize_with_bbox_op.h" | |||||
| namespace mindspore { | |||||
| namespace dataset { | |||||
| Status RandomCropAndResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) { | |||||
| IO_CHECK_VECTOR(input, output); | |||||
| BOUNDING_BOX_CHECK(input); | |||||
| CHECK_FAIL_RETURN_UNEXPECTED(input[0]->shape().Size() >= 2, "The shape of input is abnormal"); | |||||
| (*output).push_back(nullptr); // init memory for return vector | |||||
| (*output).push_back(nullptr); | |||||
| (*output)[1] = std::move(input[1]); // move boxes over to output | |||||
| 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; | |||||
| (void)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; | |||||
| 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_)); | |||||
| UpdateBBoxesForResize(&(*output)[1], &bboxCount, &target_width_, &target_height_, &crop_width, &crop_height); | |||||
| return Status::OK(); | |||||
| } | |||||
| } // namespace dataset | |||||
| } // namespace mindspore | |||||
| @@ -0,0 +1,46 @@ | |||||
| /** | |||||
| * 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 | |||||
| * | |||||
| * 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 DATASET_KERNELS_IMAGE_RANDOM_CROP_AND_RESIZE_WITH_BBOX_OP_H_ | |||||
| #define DATASET_KERNELS_IMAGE_RANDOM_CROP_AND_RESIZE_WITH_BBOX_OP_H_ | |||||
| #include "dataset/kernels/image/random_crop_and_resize_op.h" | |||||
| namespace mindspore { | |||||
| namespace dataset { | |||||
| class RandomCropAndResizeWithBBoxOp : public RandomCropAndResizeOp { | |||||
| public: | |||||
| // Constructor for RandomCropAndResizeWithBBoxOp, with default value and passing to base class constructor | |||||
| RandomCropAndResizeWithBBoxOp(int32_t target_height, int32_t target_width, float scale_lb = kDefScaleLb, | |||||
| float scale_ub = kDefScaleUb, float aspect_lb = kDefAspectLb, | |||||
| float aspect_ub = kDefAspectUb, InterpolationMode interpolation = kDefInterpolation, | |||||
| int32_t max_iter = kDefMaxIter) | |||||
| : RandomCropAndResizeOp(target_height, target_width, scale_lb, scale_ub, aspect_lb, aspect_ub, interpolation, | |||||
| max_iter) {} | |||||
| ~RandomCropAndResizeWithBBoxOp() override = default; | |||||
| void Print(std::ostream &out) const override { | |||||
| out << "RandomCropAndResizeWithBBox: " << RandomCropAndResizeOp::target_height_ << " " | |||||
| << RandomCropAndResizeOp::target_width_; | |||||
| } | |||||
| Status Compute(const TensorRow &input, TensorRow *output) override; | |||||
| }; | |||||
| } // namespace dataset | |||||
| } // namespace mindspore | |||||
| #endif // DATASET_KERNELS_IMAGE_RANDOM_CROP_AND_RESIZE_WITH_BBOX_OP_H_ | |||||
| @@ -48,44 +48,81 @@ RandomCropOp::RandomCropOp(int32_t crop_height, int32_t crop_width, int32_t pad_ | |||||
| rnd_.seed(GetSeed()); | rnd_.seed(GetSeed()); | ||||
| } | } | ||||
| Status RandomCropOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) { | |||||
| IO_CHECK(input, output); | |||||
| // Apply padding first then crop | |||||
| std::shared_ptr<Tensor> pad_image; | |||||
| 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) { | |||||
| *t_pad_top = pad_top_; | |||||
| *t_pad_bottom = pad_bottom_; | |||||
| *t_pad_left = pad_left_; | |||||
| *t_pad_right = pad_right_; | |||||
| RETURN_IF_NOT_OK( | 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_FAIL_RETURN_UNEXPECTED(pad_image->shape().Size() >= 2, "Abnormal shape"); | |||||
| int32_t padded_image_h = pad_image->shape()[0]; | |||||
| int32_t padded_image_w = pad_image->shape()[1]; | |||||
| // no need to crop if same size | |||||
| if (padded_image_h == crop_height_ && padded_image_w == crop_width_) { | |||||
| *output = pad_image; | |||||
| Pad(input, pad_image, pad_top_, pad_bottom_, pad_left_, pad_right_, border_type_, fill_r_, fill_g_, fill_b_)); | |||||
| CHECK_FAIL_RETURN_UNEXPECTED((*pad_image)->shape().Size() >= 2, "Abnormal shape"); | |||||
| *padded_image_h = (*pad_image)->shape()[0]; | |||||
| *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 | |||||
| return Status::OK(); | return Status::OK(); | ||||
| } | |||||
| if (pad_if_needed_) { | |||||
| } else if (pad_if_needed_) { | |||||
| // check the dimensions of the image for padding, if we do need padding, then we change the pad values | // 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_) { | |||||
| RETURN_IF_NOT_OK(Pad(pad_image, &pad_image, crop_height_ - padded_image_h, crop_height_ - padded_image_h, 0, 0, | |||||
| if (*padded_image_h < crop_height_) { | |||||
| 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_)); | border_type_, fill_r_, fill_g_, fill_b_)); | ||||
| // update pad total above/below | |||||
| t_pad_top += (crop_height_ - *padded_image_h); | |||||
| t_pad_bottom += (crop_height_ - *padded_image_h); | |||||
| } | } | ||||
| 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, | |||||
| 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_)); | border_type_, fill_r_, fill_g_, fill_b_)); | ||||
| // update pad total left/right | |||||
| t_pad_left += (crop_width_ - *padded_image_w); | |||||
| t_pad_right += (crop_width_ - *padded_image_w); | |||||
| } | } | ||||
| padded_image_h = pad_image->shape()[0]; | |||||
| padded_image_w = pad_image->shape()[1]; | |||||
| *padded_image_h = (*pad_image)->shape()[0]; | |||||
| *padded_image_w = (*pad_image)->shape()[1]; | |||||
| } | } | ||||
| if (padded_image_h < crop_height_ || padded_image_w < crop_width_ || crop_height_ == 0 || crop_width_ == 0) { | |||||
| if (*padded_image_h < crop_height_ || *padded_image_w < crop_width_ || crop_height_ == 0 || crop_width_ == 0) { | |||||
| return Status(StatusCode::kShapeMisMatch, __LINE__, __FILE__, | return Status(StatusCode::kShapeMisMatch, __LINE__, __FILE__, | ||||
| "Crop size is greater than the image dimensions or is zero."); | "Crop size is greater than the image dimensions or is zero."); | ||||
| } | } | ||||
| // random top corner | |||||
| int x = std::uniform_int_distribution<int>(0, padded_image_w - crop_width_)(rnd_); | |||||
| int y = std::uniform_int_distribution<int>(0, padded_image_h - crop_height_)(rnd_); | |||||
| return Status::OK(); | |||||
| } | |||||
| void RandomCropOp::GenRandomXY(int *x, int *y, int32_t *padded_image_w, int32_t *padded_image_h) { | |||||
| // GenCropPoints for cropping | |||||
| *x = std::uniform_int_distribution<int>(0, *padded_image_w - crop_width_)(rnd_); | |||||
| *y = std::uniform_int_distribution<int>(0, *padded_image_h - crop_height_)(rnd_); | |||||
| } | |||||
| Status RandomCropOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) { | |||||
| IO_CHECK(input, output); | |||||
| // Apply padding first then crop | |||||
| std::shared_ptr<Tensor> pad_image; | |||||
| int32_t t_pad_top, t_pad_bottom, t_pad_left, t_pad_right; | |||||
| int32_t padded_image_w; | |||||
| int32_t padded_image_h; | |||||
| bool crop_further = true; // whether image needs further cropping based on new size & requirements | |||||
| RETURN_IF_NOT_OK( // error code sent back directly | |||||
| ImagePadding(input, &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 = pad_image; | |||||
| return Status::OK(); | |||||
| } | |||||
| int x, y; | |||||
| GenRandomXY(&x, &y, &padded_image_w, &padded_image_h); | |||||
| return Crop(pad_image, output, x, y, crop_width_, crop_height_); | return Crop(pad_image, output, x, y, crop_width_, crop_height_); | ||||
| } | } | ||||
| Status RandomCropOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) { | Status RandomCropOp::OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) { | ||||
| RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs)); | RETURN_IF_NOT_OK(TensorOp::OutputShape(inputs, outputs)); | ||||
| outputs.clear(); | outputs.clear(); | ||||
| @@ -50,11 +50,20 @@ class RandomCropOp : public TensorOp { | |||||
| void Print(std::ostream &out) const override { out << "RandomCropOp: " << crop_height_ << " " << crop_width_; } | void Print(std::ostream &out) const override { out << "RandomCropOp: " << crop_height_ << " " << crop_width_; } | ||||
| Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override; | Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override; | ||||
| Status 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); | |||||
| void GenRandomXY(int *x, int *y, int32_t *padded_image_w, int32_t *padded_image_h); | |||||
| Status OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) override; | Status OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) override; | ||||
| private: | |||||
| protected: | |||||
| int32_t crop_height_ = 0; | int32_t crop_height_ = 0; | ||||
| int32_t crop_width_ = 0; | int32_t crop_width_ = 0; | ||||
| private: | |||||
| int32_t pad_top_ = 0; | int32_t pad_top_ = 0; | ||||
| int32_t pad_bottom_ = 0; | int32_t pad_bottom_ = 0; | ||||
| int32_t pad_left_ = 0; | int32_t pad_left_ = 0; | ||||
| @@ -0,0 +1,67 @@ | |||||
| /** | |||||
| * 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 | |||||
| * | |||||
| * 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 <random> | |||||
| #include <algorithm> | |||||
| #include <utility> | |||||
| #include "dataset/kernels/image/random_crop_with_bbox_op.h" | |||||
| #include "dataset/kernels/image/image_utils.h" | |||||
| #include "dataset/util/random.h" | |||||
| #include "dataset/util/status.h" | |||||
| namespace mindspore { | |||||
| namespace dataset { | |||||
| Status RandomCropWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) { | |||||
| IO_CHECK_VECTOR(input, output); | |||||
| BOUNDING_BOX_CHECK(input); | |||||
| std::shared_ptr<Tensor> pad_image; | |||||
| int32_t t_pad_top, t_pad_bottom, t_pad_left, t_pad_right; | |||||
| size_t boxCount = input[1]->shape()[0]; // number of rows | |||||
| int32_t padded_image_h; | |||||
| int32_t padded_image_w; | |||||
| (*output).push_back(nullptr); | |||||
| (*output).push_back(nullptr); | |||||
| (*output)[1] = std::move(input[1]); // since some boxes may be removed | |||||
| 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, | |||||
| &padded_image_w, &padded_image_h, &crop_further)); | |||||
| // update bounding boxes with new values based on relevant image padding | |||||
| if (t_pad_left || t_pad_bottom) { | |||||
| PadBBoxes(&(*output)[1], &boxCount, &t_pad_left, &t_pad_top); | |||||
| } | |||||
| if (!crop_further) { | |||||
| // no further cropping required | |||||
| (*output)[0] = pad_image; | |||||
| (*output)[1] = std::move(input[1]); | |||||
| 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_; | |||||
| UpdateBBoxesForCrop(&(*output)[1], &boxCount, &x, &y, &maxX, &maxY); | |||||
| return Crop(pad_image, &(*output)[0], x, y, RandomCropOp::crop_width_, RandomCropOp::crop_height_); | |||||
| } | |||||
| } // namespace dataset | |||||
| } // namespace mindspore | |||||
| @@ -0,0 +1,48 @@ | |||||
| /** | |||||
| * 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 | |||||
| * | |||||
| * 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 DATASET_KERNELS_IMAGE_RANDOM_CROP_WITH_BBOX_OP_H_ | |||||
| #define DATASET_KERNELS_IMAGE_RANDOM_CROP_WITH_BBOX_OP_H_ | |||||
| #include <memory> | |||||
| #include <vector> | |||||
| #include "dataset/kernels/image/random_crop_op.h" | |||||
| namespace mindspore { | |||||
| namespace dataset { | |||||
| class RandomCropWithBBoxOp : public RandomCropOp { | |||||
| public: | |||||
| // Constructor for RandomCropWithBBoxOp, with default value and passing to base class constructor | |||||
| RandomCropWithBBoxOp(int32_t crop_height, int32_t crop_width, int32_t pad_top = kDefPadTop, | |||||
| int32_t pad_bottom = kDefPadBottom, int32_t pad_left = kDefPadLeft, | |||||
| int32_t pad_right = kDefPadRight, BorderType border_types = kDefBorderType, | |||||
| bool pad_if_needed = kDefPadIfNeeded, uint8_t fill_r = kDefFillR, uint8_t fill_g = kDefFillG, | |||||
| uint8_t fill_b = kDefFillB) | |||||
| : RandomCropOp(crop_height, crop_width, pad_top, pad_bottom, pad_left, pad_right, border_types, pad_if_needed, | |||||
| fill_r, fill_g, fill_b) {} | |||||
| ~RandomCropWithBBoxOp() override = default; | |||||
| void Print(std::ostream &out) const override { | |||||
| out << "RandomCropWithBBoxOp: " << RandomCropOp::crop_height_ << " " << RandomCropOp::crop_width_; | |||||
| } | |||||
| Status Compute(const TensorRow &input, TensorRow *output) override; | |||||
| }; | |||||
| } // namespace dataset | |||||
| } // namespace mindspore | |||||
| #endif // DATASET_KERNELS_IMAGE_RANDOM_CROP_WITH_BBOX_OP_H_ | |||||
| @@ -0,0 +1,58 @@ | |||||
| /** | |||||
| * 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 | |||||
| * | |||||
| * 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 <utility> | |||||
| #include "dataset/util/status.h" | |||||
| #include "dataset/kernels/image/image_utils.h" | |||||
| #include "dataset/kernels/image/random_vertical_flip_with_bbox_op.h" | |||||
| namespace mindspore { | |||||
| namespace dataset { | |||||
| const float RandomVerticalFlipWithBBoxOp::kDefProbability = 0.5; | |||||
| Status RandomVerticalFlipWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) { | |||||
| IO_CHECK_VECTOR(input, output); | |||||
| BOUNDING_BOX_CHECK(input); | |||||
| if (distribution_(rnd_)) { | |||||
| 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++) { | |||||
| uint32_t boxCorner_y = 0; | |||||
| uint32_t boxHeight = 0; | |||||
| uint32_t newBoxCorner_y = 0; | |||||
| input[1]->GetUnsignedIntAt(&boxCorner_y, {i, 1}); // get min y of bbox | |||||
| input[1]->GetUnsignedIntAt(&boxHeight, {i, 3}); // get height of bbox | |||||
| // subtract (curCorner + height) from (max) for new Corner position | |||||
| newBoxCorner_y = (imHeight - 1) - (boxCorner_y + boxHeight); | |||||
| input[1]->SetItemAt({i, 1}, newBoxCorner_y); | |||||
| } | |||||
| (*output).push_back(nullptr); | |||||
| (*output).push_back(nullptr); | |||||
| (*output)[1] = std::move(input[1]); | |||||
| return VerticalFlip(input[0], &(*output)[0]); | |||||
| } | |||||
| *output = input; | |||||
| return Status::OK(); | |||||
| } | |||||
| } // namespace dataset | |||||
| } // namespace mindspore | |||||
| @@ -0,0 +1,52 @@ | |||||
| /** | |||||
| * 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 | |||||
| * | |||||
| * 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 DATASET_KERNELS_IMAGE_RANDOM_VERTICAL_FLIP_WITH_BBOX_OP_H_ | |||||
| #define DATASET_KERNELS_IMAGE_RANDOM_VERTICAL_FLIP_WITH_BBOX_OP_H_ | |||||
| #include <memory> | |||||
| #include <random> | |||||
| #include "dataset/core/tensor.h" | |||||
| #include "dataset/kernels/tensor_op.h" | |||||
| #include "dataset/util/status.h" | |||||
| #include "dataset/util/random.h" | |||||
| namespace mindspore { | |||||
| namespace dataset { | |||||
| class RandomVerticalFlipWithBBoxOp : public TensorOp { | |||||
| public: | |||||
| // Default values, also used by python_bindings.cc | |||||
| static const float kDefProbability; | |||||
| // Constructor for RandomVerticalFlipWithBBoxOp | |||||
| // @param probability: Probablity of Image flipping, 0.5 by default | |||||
| explicit RandomVerticalFlipWithBBoxOp(float probability = kDefProbability) : distribution_(probability) { | |||||
| rnd_.seed(GetSeed()); | |||||
| } | |||||
| ~RandomVerticalFlipWithBBoxOp() override = default; | |||||
| void Print(std::ostream &out) const override { out << "RandomVerticalFlipWithBBoxOp"; } | |||||
| Status Compute(const TensorRow &input, TensorRow *output) override; | |||||
| private: | |||||
| std::mt19937 rnd_; | |||||
| std::bernoulli_distribution distribution_; | |||||
| }; | |||||
| } // namespace dataset | |||||
| } // namespace mindspore | |||||
| #endif // DATASET_KERNELS_IMAGE_RANDOM_VERTICAL_FLIP_WITH_BBOX_OP_H_ | |||||
| @@ -149,6 +149,54 @@ class RandomCrop(cde.RandomCropOp): | |||||
| super().__init__(*size, *padding, border_type, pad_if_needed, *fill_value) | super().__init__(*size, *padding, border_type, pad_if_needed, *fill_value) | ||||
| class RandomCropWithBBox(cde.RandomCropWithBBoxOp): | |||||
| """ | |||||
| Crop the input image at a random location, and adjust bounding boxes | |||||
| Args: | |||||
| size (int or sequence): The output size of the cropped image. | |||||
| If size is an int, a square crop of size (size, size) is returned. | |||||
| If size is a sequence of length 2, it should be (height, width). | |||||
| padding (int or sequence, optional): The number of pixels to pad the image (default=None). | |||||
| If padding is not None, pad image firstly with padding values. | |||||
| If a single number is provided, it pads all borders with this value. | |||||
| If a tuple or list of 2 values are provided, it pads the (left and top) | |||||
| with the first value and (right and bottom) with the second value. | |||||
| If 4 values are provided as a list or tuple,it pads the left, top, right and bottom respectively. | |||||
| pad_if_needed (bool, optional): Pad the image if either side is smaller than | |||||
| the given output size (default=False). | |||||
| fill_value (int or tuple, optional): The pixel intensity of the borders if | |||||
| the padding_mode is Border.CONSTANT (default=0). If it is a 3-tuple, it is used to | |||||
| fill R, G, B channels respectively. | |||||
| padding_mode (Border mode, optional): The method of padding (default=Border.CONSTANT). Can be any of | |||||
| [Border.CONSTANT, Border.EDGE, Border.REFLECT, Border.SYMMETRIC]. | |||||
| - Border.CONSTANT, means it fills the border with constant values. | |||||
| - Border.EDGE, means it pads with the last value on the edge. | |||||
| - Border.REFLECT, means it reflects the values on the edge omitting the last | |||||
| value of edge. | |||||
| - Border.SYMMETRIC, means it reflects the values on the edge repeating the last | |||||
| value of edge. | |||||
| """ | |||||
| @check_random_crop | |||||
| def __init__(self, size, padding=None, pad_if_needed=False, fill_value=0, padding_mode=Border.CONSTANT): | |||||
| self.size = size | |||||
| self.padding = padding | |||||
| self.pad_if_needed = pad_if_needed | |||||
| self.fill_value = fill_value | |||||
| self.padding_mode = padding_mode.value | |||||
| if padding is None: | |||||
| padding = (0, 0, 0, 0) | |||||
| if isinstance(fill_value, int): # temporary fix | |||||
| fill_value = tuple([fill_value] * 3) | |||||
| border_type = DE_C_BORDER_TYPE[padding_mode] | |||||
| super().__init__(*size, *padding, border_type, pad_if_needed, *fill_value) | |||||
| class RandomHorizontalFlip(cde.RandomHorizontalFlipOp): | class RandomHorizontalFlip(cde.RandomHorizontalFlipOp): | ||||
| """ | """ | ||||
| Flip the input image horizontally, randomly with a given probability. | Flip the input image horizontally, randomly with a given probability. | ||||
| @@ -192,6 +240,20 @@ class RandomVerticalFlip(cde.RandomVerticalFlipOp): | |||||
| super().__init__(prob) | super().__init__(prob) | ||||
| class RandomVerticalFlipWithBBox(cde.RandomVerticalFlipWithBBoxOp): | |||||
| """ | |||||
| Flip the input image vertically and adjust bounding boxes, randomly with a given probability. | |||||
| Args: | |||||
| prob (float): Probability of the image being flipped (default=0.5). | |||||
| """ | |||||
| @check_prob | |||||
| def __init__(self, prob=0.5): | |||||
| self.prob = prob | |||||
| super().__init__(prob) | |||||
| class BoundingBoxAug(cde.BoundingBoxAugOp): | class BoundingBoxAug(cde.BoundingBoxAugOp): | ||||
| """ | """ | ||||
| Flip the input image vertically, randomly with a given probability. | Flip the input image vertically, randomly with a given probability. | ||||
| @@ -237,6 +299,42 @@ class Resize(cde.ResizeOp): | |||||
| super().__init__(*size, interpoltn) | super().__init__(*size, interpoltn) | ||||
| class RandomResizedCropWithBBox(cde.RandomCropAndResizeWithBBoxOp): | |||||
| """ | |||||
| Crop the input image to a random size and aspect ratio and adjust the Bounding Boxes accordingly | |||||
| Args: | |||||
| size (int or sequence): The size of the output image. | |||||
| If size is an int, a square crop of size (size, size) is returned. | |||||
| If size is a sequence of length 2, it should be (height, width). | |||||
| scale (tuple, optional): Range (min, max) of respective size of the original | |||||
| size to be cropped (default=(0.08, 1.0)). | |||||
| ratio (tuple, optional): Range (min, max) of aspect ratio to be cropped | |||||
| (default=(3. / 4., 4. / 3.)). | |||||
| interpolation (Inter mode, optional): Image interpolation mode (default=Inter.BILINEAR). | |||||
| It can be any of [Inter.BILINEAR, Inter.NEAREST, Inter.BICUBIC]. | |||||
| - Inter.BILINEAR, means interpolation method is bilinear interpolation. | |||||
| - Inter.NEAREST, means interpolation method is nearest-neighbor interpolation. | |||||
| - Inter.BICUBIC, means interpolation method is bicubic interpolation. | |||||
| max_attempts (int, optional): The maximum number of attempts to propose a valid | |||||
| crop_area (default=10). If exceeded, fall back to use center_crop instead. | |||||
| """ | |||||
| @check_random_resize_crop | |||||
| def __init__(self, size, scale=(0.08, 1.0), ratio=(3. / 4., 4. / 3.), | |||||
| interpolation=Inter.BILINEAR, max_attempts=10): | |||||
| self.size = size | |||||
| self.scale = scale | |||||
| self.ratio = ratio | |||||
| self.interpolation = interpolation | |||||
| self.max_attempts = max_attempts | |||||
| interpoltn = DE_C_INTER_MODE[interpolation] | |||||
| super().__init__(*size, *scale, *ratio, interpoltn, max_attempts) | |||||
| class RandomResizedCrop(cde.RandomCropAndResizeOp): | class RandomResizedCrop(cde.RandomCropAndResizeOp): | ||||
| """ | """ | ||||
| Crop the input image to a random size and aspect ratio. | Crop the input image to a random size and aspect ratio. | ||||