Merge pull request !2920 from danishnxt/AugOps-M1-Pythontags/v0.6.0-beta
| @@ -740,22 +740,16 @@ Status UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, | |||
| 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; | |||
| float bb_Xmin = 0.0, bb_Ymin = 0.0, bb_Xmax = 0.0, bb_Ymax = 0.0; | |||
| std::vector<int> correct_ind; | |||
| std::vector<uint32_t> copyVals; | |||
| std::vector<float> 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; | |||
| RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&bb_Xmin_t, {i, 0})); | |||
| RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&bb_Ymin_t, {i, 1})); | |||
| RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&bb_Xmax_t, {i, 2})); | |||
| RETURN_IF_NOT_OK((*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; | |||
| RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&bb_Xmin, {i, 0})); | |||
| RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&bb_Ymin, {i, 1})); | |||
| RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&bb_Xmax, {i, 2})); | |||
| RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&bb_Ymax, {i, 3})); | |||
| bb_Xmax = bb_Xmin + bb_Xmax; | |||
| bb_Ymax = bb_Ymin + bb_Ymax; | |||
| // check for image / BB overlap | |||
| @@ -766,23 +760,23 @@ Status UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, | |||
| correct_ind.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); | |||
| bb_Xmin = bb_Xmin - (std::min(static_cast<float>(0.0), (bb_Xmin - CB_Xmin)) + CB_Xmin); | |||
| bb_Xmax = bb_Xmax - (std::max(static_cast<float>(0.0), (bb_Xmax - CB_Xmax)) + CB_Xmin); | |||
| bb_Ymin = bb_Ymin - (std::min(static_cast<float>(0.0), (bb_Ymin - CB_Ymin)) + CB_Ymin); | |||
| bb_Ymax = bb_Ymax - (std::max(static_cast<float>(0.0), (bb_Ymax - CB_Ymax)) + CB_Ymin); | |||
| // reset min values and calculate width/height from Box corners | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 0}, static_cast<uint32_t>(bb_Xmin))); | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 1}, static_cast<uint32_t>(bb_Ymin))); | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 2}, static_cast<uint32_t>(bb_Xmax - bb_Xmin))); | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 3}, static_cast<uint32_t>(bb_Ymax - bb_Ymin))); | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 0}, bb_Xmin)); | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 1}, bb_Ymin)); | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 2}, bb_Xmax - bb_Xmin)); | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 3}, 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 = correct_ind.size(); | |||
| uint32_t temp; | |||
| float temp = 0.0; | |||
| for (auto slice : correct_ind) { // for every index in the loop | |||
| for (int ix = 0; ix < bboxDim; ix++) { | |||
| RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&temp, {slice, ix})); | |||
| RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&temp, {slice, ix})); | |||
| copyVals.push_back(temp); | |||
| } | |||
| } | |||
| @@ -794,11 +788,11 @@ Status UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, | |||
| Status PadBBoxes(const std::shared_ptr<Tensor> *bboxList, const size_t &bboxCount, int32_t pad_top, int32_t pad_left) { | |||
| for (int i = 0; i < bboxCount; i++) { | |||
| uint32_t xMin, yMin; | |||
| RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&xMin, {i, 0})); | |||
| RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&yMin, {i, 1})); | |||
| xMin += static_cast<uint32_t>(pad_left); // should not be negative | |||
| yMin += static_cast<uint32_t>(pad_top); | |||
| float xMin = 0.0, yMin = 0.0; | |||
| RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&xMin, {i, 0})); | |||
| RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&yMin, {i, 1})); | |||
| xMin += pad_left; | |||
| yMin += pad_top; | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 0}, xMin)); | |||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 1}, yMin)); | |||
| } | |||
| @@ -807,16 +801,16 @@ Status PadBBoxes(const std::shared_ptr<Tensor> *bboxList, const size_t &bboxCoun | |||
| Status UpdateBBoxesForResize(const std::shared_ptr<Tensor> &bboxList, const 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); | |||
| float bb_Xmin = 0, bb_Ymin = 0, bb_Xwidth = 0, bb_Ywidth = 0; | |||
| // cast to float to preserve fractional | |||
| float W_aspRatio = (target_width_ * 1.0) / (orig_width * 1.0); | |||
| float H_aspRatio = (target_height_ * 1.0) / (orig_height * 1.0); | |||
| for (int i = 0; i < bboxCount; i++) { | |||
| // for each bounding box | |||
| RETURN_IF_NOT_OK(bboxList->GetUnsignedIntAt(&bb_Xmin, {i, 0})); | |||
| RETURN_IF_NOT_OK(bboxList->GetUnsignedIntAt(&bb_Ymin, {i, 1})); | |||
| RETURN_IF_NOT_OK(bboxList->GetUnsignedIntAt(&bb_Xwidth, {i, 2})); | |||
| RETURN_IF_NOT_OK(bboxList->GetUnsignedIntAt(&bb_Ywidth, {i, 3})); | |||
| RETURN_IF_NOT_OK(bboxList->GetItemAt<float>(&bb_Xmin, {i, 0})); | |||
| RETURN_IF_NOT_OK(bboxList->GetItemAt<float>(&bb_Ymin, {i, 1})); | |||
| RETURN_IF_NOT_OK(bboxList->GetItemAt<float>(&bb_Xwidth, {i, 2})); | |||
| RETURN_IF_NOT_OK(bboxList->GetItemAt<float>(&bb_Ywidth, {i, 3})); | |||
| // update positions and widths | |||
| bb_Xmin = bb_Xmin * W_aspRatio; | |||
| bb_Ymin = bb_Ymin * H_aspRatio; | |||
| @@ -34,14 +34,13 @@ Status RandomVerticalFlipWithBBoxOp::Compute(const TensorRow &input, TensorRow * | |||
| // 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; | |||
| RETURN_IF_NOT_OK(input[1]->GetUnsignedIntAt(&boxCorner_y, {i, 1})); // get min y of bbox | |||
| RETURN_IF_NOT_OK(input[1]->GetUnsignedIntAt(&boxHeight, {i, 3})); // get height of bbox | |||
| float boxCorner_y = 0.0, boxHeight = 0.0; | |||
| float newBoxCorner_y = 0.0; | |||
| RETURN_IF_NOT_OK(input[1]->GetItemAt<float>(&boxCorner_y, {i, 1})); // get min y of bbox | |||
| RETURN_IF_NOT_OK(input[1]->GetItemAt<float>(&boxHeight, {i, 3})); // get height of bbox | |||
| // subtract (curCorner + height) from (max) for new Corner position | |||
| newBoxCorner_y = (imHeight - 1) - ((boxCorner_y + boxHeight) - 1); | |||
| newBoxCorner_y = (imHeight - 1.0) - ((boxCorner_y + boxHeight) - 1.0); | |||
| RETURN_IF_NOT_OK(input[1]->SetItemAt({i, 1}, newBoxCorner_y)); | |||
| } | |||
| @@ -62,14 +62,16 @@ | |||
| uint32_t img_h = input[0]->shape()[0]; \ | |||
| uint32_t img_w = input[0]->shape()[1]; \ | |||
| for (uint32_t i = 0; i < num_of_boxes; i++) { \ | |||
| uint32_t min_x = 0; \ | |||
| uint32_t min_y = 0; \ | |||
| uint32_t b_w = 0; \ | |||
| uint32_t b_h = 0; \ | |||
| input[1]->GetItemAt<uint32_t>(&min_x, {i, 0}); \ | |||
| input[1]->GetItemAt<uint32_t>(&min_y, {i, 1}); \ | |||
| input[1]->GetItemAt<uint32_t>(&b_w, {i, 2}); \ | |||
| input[1]->GetItemAt<uint32_t>(&b_h, {i, 3}); \ | |||
| float min_x = 0.0, min_y = 0.0, b_w = 0.0, b_h = 0.0; \ | |||
| bool passing_data_fetch = true; \ | |||
| passing_data_fetch &= input[1]->GetItemAt<float>(&min_x, {i, 0}).IsOk(); \ | |||
| passing_data_fetch &= input[1]->GetItemAt<float>(&min_y, {i, 1}).IsOk(); \ | |||
| passing_data_fetch &= input[1]->GetItemAt<float>(&b_w, {i, 2}).IsOk(); \ | |||
| passing_data_fetch &= input[1]->GetItemAt<float>(&b_h, {i, 3}).IsOk(); \ | |||
| if (!passing_data_fetch) { \ | |||
| return Status(StatusCode::kUnexpectedError, __LINE__, __FILE__, \ | |||
| "Fetching BBox values failed in BOUNDING_BOX_CHECK."); \ | |||
| } \ | |||
| if ((min_x + b_w > img_w) || (min_y + b_h > img_h)) { \ | |||
| return Status(StatusCode::kBoundingBoxOutOfBounds, __LINE__, __FILE__, \ | |||
| "At least one of the bounding boxes is out of bounds of the image."); \ | |||
| @@ -118,14 +118,11 @@ void BBoxOpCommon::SaveImagesWithAnnotations(BBoxOpCommon::FileType type, const | |||
| bool passing_data_fetch = true; | |||
| // For each bounding box draw on the image. | |||
| for (uint32_t i = 0; i < num_of_boxes; i++) { | |||
| uint32_t x = 0; | |||
| uint32_t y = 0; | |||
| uint32_t w = 0; | |||
| uint32_t h = 0; | |||
| passing_data_fetch &= row[1]->GetUnsignedIntAt(&x, {i, 0}).IsOk(); | |||
| passing_data_fetch &= row[1]->GetUnsignedIntAt(&y, {i, 1}).IsOk(); | |||
| passing_data_fetch &= row[1]->GetUnsignedIntAt(&w, {i, 2}).IsOk(); | |||
| passing_data_fetch &= row[1]->GetUnsignedIntAt(&h, {i, 3}).IsOk(); | |||
| float x = 0.0, y = 0.0, w = 0.0, h = 0.0; | |||
| passing_data_fetch &= row[1]->GetItemAt<float>(&x, {i, 0}).IsOk(); | |||
| passing_data_fetch &= row[1]->GetItemAt<float>(&y, {i, 1}).IsOk(); | |||
| passing_data_fetch &= row[1]->GetItemAt<float>(&w, {i, 2}).IsOk(); | |||
| passing_data_fetch &= row[1]->GetItemAt<float>(&h, {i, 3}).IsOk(); | |||
| if (!passing_data_fetch) { | |||
| MS_LOG(ERROR) << "Fetching bbox coordinates failed in SaveImagesWithAnnotations."; | |||
| EXPECT_TRUE(passing_data_fetch); | |||
| @@ -193,24 +190,24 @@ bool BBoxOpCommon::LoadAnnotationFile(const std::string &path, std::shared_ptr<T | |||
| MS_LOG(ERROR) << "No object find in " + path; | |||
| return false; | |||
| } | |||
| std::vector<uint32_t> return_value_list; | |||
| std::vector<float> return_value_list; | |||
| dsize_t bbox_count = 0; // keep track of number of bboxes in file | |||
| dsize_t bbox_val_count = 4; // creating bboxes of size 4 to test function | |||
| // FILE OK TO READ | |||
| while (object != nullptr) { | |||
| bbox_count += 1; | |||
| std::string label_name; | |||
| uint32_t xmin = 0, ymin = 0, xmax = 0, ymax = 0; | |||
| float xmin = 0.0, ymin = 0.0, xmax = 0.0, ymax = 0.0; | |||
| XMLElement *bbox_node = object->FirstChildElement("bndbox"); | |||
| if (bbox_node != nullptr) { | |||
| XMLElement *xmin_node = bbox_node->FirstChildElement("xmin"); | |||
| if (xmin_node != nullptr) xmin = xmin_node->UnsignedText(); | |||
| if (xmin_node != nullptr) xmin = xmin_node->FloatText(); | |||
| XMLElement *ymin_node = bbox_node->FirstChildElement("ymin"); | |||
| if (ymin_node != nullptr) ymin = ymin_node->UnsignedText(); | |||
| if (ymin_node != nullptr) ymin = ymin_node->FloatText(); | |||
| XMLElement *xmax_node = bbox_node->FirstChildElement("xmax"); | |||
| if (xmax_node != nullptr) xmax = xmax_node->UnsignedText(); | |||
| if (xmax_node != nullptr) xmax = xmax_node->FloatText(); | |||
| XMLElement *ymax_node = bbox_node->FirstChildElement("ymax"); | |||
| if (ymax_node != nullptr) ymax = ymax_node->UnsignedText(); | |||
| if (ymax_node != nullptr) ymax = ymax_node->FloatText(); | |||
| } else { | |||
| MS_LOG(ERROR) << "bndbox dismatch in " + path; | |||
| return false; | |||
| @@ -0,0 +1,214 @@ | |||
| # 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. | |||
| # ============================================================================== | |||
| """ | |||
| Testing RandomCropAndResizeWithBBox op in DE | |||
| """ | |||
| import numpy as np | |||
| import mindspore.dataset as ds | |||
| import mindspore.dataset.transforms.vision.c_transforms as c_vision | |||
| from mindspore import log as logger | |||
| from util import visualize_with_bounding_boxes, InvalidBBoxType, check_bad_bbox, \ | |||
| config_get_set_seed, config_get_set_num_parallel_workers, save_and_check_md5 | |||
| GENERATE_GOLDEN = False | |||
| # Updated VOC dataset with correct annotations - DATA_DIR | |||
| DATA_DIR_VOC = "../data/dataset/testVOC2012_2" | |||
| # COCO dataset - DATA_DIR, ANNOTATION_DIR | |||
| DATA_DIR_COCO = ["../data/dataset/testCOCO/train/", "../data/dataset/testCOCO/annotations/train.json"] | |||
| def test_random_resized_crop_with_bbox_op_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomResizedCropWithBBox Op applied, | |||
| tests with MD5 check, expected to pass | |||
| """ | |||
| logger.info("test_random_resized_crop_with_bbox_op_c") | |||
| original_seed = config_get_set_seed(23415) | |||
| original_num_parallel_workers = config_get_set_num_parallel_workers(1) | |||
| # Load dataset | |||
| dataVoc1 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| test_op = c_vision.RandomResizedCropWithBBox((256, 512), (0.5, 0.5), (0.5, 0.5)) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) | |||
| filename = "random_resized_crop_with_bbox_01_c_result.npz" | |||
| save_and_check_md5(dataVoc2, filename, generate_golden=GENERATE_GOLDEN) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataVoc1.create_dict_iterator(), dataVoc2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp) | |||
| # Restore config setting | |||
| ds.config.set_seed(original_seed) | |||
| ds.config.set_num_parallel_workers(original_num_parallel_workers) | |||
| def test_random_resized_crop_with_bbox_op_coco_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomResizedCropWithBBox Op applied, | |||
| Testing with Coco dataset | |||
| """ | |||
| logger.info("test_random_resized_crop_with_bbox_op_coco_c") | |||
| # load dataset | |||
| dataCoco1 = ds.CocoDataset(DATA_DIR_COCO[0], annotation_file=DATA_DIR_COCO[1], task="Detection", | |||
| decode=True, shuffle=False) | |||
| dataCoco2 = ds.CocoDataset(DATA_DIR_COCO[0], annotation_file=DATA_DIR_COCO[1], task="Detection", | |||
| decode=True, shuffle=False) | |||
| test_op = c_vision.RandomResizedCropWithBBox((512, 512), (0.5, 1), (0.5, 1)) | |||
| dataCoco2 = dataCoco2.map(input_columns=["image", "bbox"], | |||
| output_columns=["image", "bbox"], | |||
| columns_order=["image", "bbox"], | |||
| operations=[test_op]) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataCoco1.create_dict_iterator(), dataCoco2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp, "bbox") | |||
| def test_random_resized_crop_with_bbox_op_edge_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomResizedCropWithBBox Op applied, | |||
| tests on dynamically generated edge case, expected to pass | |||
| """ | |||
| logger.info("test_random_resized_crop_with_bbox_op_edge_c") | |||
| # Load dataset | |||
| dataVoc1 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| test_op = c_vision.RandomResizedCropWithBBox((256, 512), (0.5, 0.5), (0.5, 0.5)) | |||
| # maps to convert data into valid edge case data | |||
| dataVoc1 = dataVoc1.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[lambda img, bboxes: (img, np.array([[0, 0, img.shape[1], img.shape[0]]]).astype(bboxes.dtype))]) | |||
| # Test Op added to list of Operations here | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[lambda img, bboxes: (img, np.array([[0, 0, img.shape[1], img.shape[0]]]).astype(bboxes.dtype)), test_op]) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataVoc1.create_dict_iterator(), dataVoc2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp) | |||
| def test_random_resized_crop_with_bbox_op_invalid_c(): | |||
| """ | |||
| Tests RandomResizedCropWithBBox on invalid constructor parameters, expected to raise ValueError | |||
| """ | |||
| logger.info("test_random_resized_crop_with_bbox_op_invalid_c") | |||
| # Load dataset, only Augmented Dataset as test will raise ValueError | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| try: | |||
| # If input range of scale is not in the order of (min, max), ValueError will be raised. | |||
| test_op = c_vision.RandomResizedCropWithBBox((256, 512), (1, 0.5), (0.5, 0.5)) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) | |||
| for _ in dataVoc2.create_dict_iterator(): | |||
| break | |||
| except ValueError as err: | |||
| logger.info("Got an exception in DE: {}".format(str(err))) | |||
| assert "Input range is not valid" in str(err) | |||
| def test_random_resized_crop_with_bbox_op_invalid2_c(): | |||
| """ | |||
| Tests RandomResizedCropWithBBox Op on invalid constructor parameters, expected to raise ValueError | |||
| """ | |||
| logger.info("test_random_resized_crop_with_bbox_op_invalid2_c") | |||
| # Load dataset # only loading the to AugDataset as test will fail on this | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| try: | |||
| # If input range of ratio is not in the order of (min, max), ValueError will be raised. | |||
| test_op = c_vision.RandomResizedCropWithBBox((256, 512), (1, 1), (1, 0.5)) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) | |||
| for _ in dataVoc2.create_dict_iterator(): | |||
| break | |||
| except ValueError as err: | |||
| logger.info("Got an exception in DE: {}".format(str(err))) | |||
| assert "Input range is not valid" in str(err) | |||
| def test_random_resized_crop_with_bbox_op_bad_c(): | |||
| """ | |||
| Test RandomCropWithBBox op with invalid bounding boxes, expected to catch multiple errors. | |||
| """ | |||
| logger.info("test_random_resized_crop_with_bbox_op_bad_c") | |||
| test_op = c_vision.RandomResizedCropWithBBox((256, 512), (0.5, 0.5), (0.5, 0.5)) | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.WidthOverflow, "bounding boxes is out of bounds of the image") | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.HeightOverflow, "bounding boxes is out of bounds of the image") | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.NegativeXY, "min_x") | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.WrongShape, "4 features") | |||
| if __name__ == "__main__": | |||
| test_random_resized_crop_with_bbox_op_c(plot_vis=True) | |||
| test_random_resized_crop_with_bbox_op_coco_c(plot_vis=True) | |||
| test_random_resized_crop_with_bbox_op_edge_c(plot_vis=True) | |||
| test_random_resized_crop_with_bbox_op_invalid_c() | |||
| test_random_resized_crop_with_bbox_op_invalid2_c() | |||
| test_random_resized_crop_with_bbox_op_bad_c() | |||
| @@ -0,0 +1,249 @@ | |||
| # 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. | |||
| # ============================================================================== | |||
| """ | |||
| Testing RandomCropWithBBox op in DE | |||
| """ | |||
| import numpy as np | |||
| import mindspore.dataset as ds | |||
| import mindspore.dataset.transforms.vision.c_transforms as c_vision | |||
| import mindspore.dataset.transforms.vision.utils as mode | |||
| from mindspore import log as logger | |||
| from util import visualize_with_bounding_boxes, InvalidBBoxType, check_bad_bbox, \ | |||
| config_get_set_seed, config_get_set_num_parallel_workers, save_and_check_md5 | |||
| GENERATE_GOLDEN = False | |||
| # Updated VOC dataset with correct annotations - DATA_DIR | |||
| DATA_DIR_VOC = "../data/dataset/testVOC2012_2" | |||
| # COCO dataset - DATA_DIR, ANNOTATION_DIR | |||
| DATA_DIR_COCO = ["../data/dataset/testCOCO/train/", "../data/dataset/testCOCO/annotations/train.json"] | |||
| def test_random_crop_with_bbox_op_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomCropWithBBox Op applied | |||
| """ | |||
| logger.info("test_random_crop_with_bbox_op_c") | |||
| # Load dataset | |||
| dataVoc1 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| # define test OP with values to match existing Op UT | |||
| test_op = c_vision.RandomCropWithBBox([512, 512], [200, 200, 200, 200]) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) # Add column for "annotation" | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataVoc1.create_dict_iterator(), dataVoc2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp) | |||
| def test_random_crop_with_bbox_op_coco_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomCropWithBBox Op applied, | |||
| Testing with Coco dataset | |||
| """ | |||
| logger.info("test_random_crop_with_bbox_op_coco_c") | |||
| # load dataset | |||
| dataCoco1 = ds.CocoDataset(DATA_DIR_COCO[0], annotation_file=DATA_DIR_COCO[1], task="Detection", | |||
| decode=True, shuffle=False) | |||
| dataCoco2 = ds.CocoDataset(DATA_DIR_COCO[0], annotation_file=DATA_DIR_COCO[1], task="Detection", | |||
| decode=True, shuffle=False) | |||
| test_op = c_vision.RandomCropWithBBox([512, 512], [200, 200, 200, 200]) | |||
| dataCoco2 = dataCoco2.map(input_columns=["image", "bbox"], | |||
| output_columns=["image", "bbox"], | |||
| columns_order=["image", "bbox"], | |||
| operations=[test_op]) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataCoco1.create_dict_iterator(), dataCoco2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp, "bbox") | |||
| def test_random_crop_with_bbox_op2_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomCropWithBBox Op applied, | |||
| with md5 check, expected to pass | |||
| """ | |||
| logger.info("test_random_crop_with_bbox_op2_c") | |||
| original_seed = config_get_set_seed(593447) | |||
| original_num_parallel_workers = config_get_set_num_parallel_workers(1) | |||
| # Load dataset | |||
| dataVoc1 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| # define test OP with values to match existing Op unit - test | |||
| test_op = c_vision.RandomCropWithBBox(512, [200, 200, 200, 200], fill_value=(255, 255, 255)) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) | |||
| filename = "random_crop_with_bbox_01_c_result.npz" | |||
| save_and_check_md5(dataVoc2, filename, generate_golden=GENERATE_GOLDEN) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataVoc1.create_dict_iterator(), dataVoc2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp) | |||
| # Restore config setting | |||
| ds.config.set_seed(original_seed) | |||
| ds.config.set_num_parallel_workers(original_num_parallel_workers) | |||
| def test_random_crop_with_bbox_op3_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomCropWithBBox Op applied, | |||
| with Padding Mode explicitly passed | |||
| """ | |||
| logger.info("test_random_crop_with_bbox_op3_c") | |||
| # Load dataset | |||
| dataVoc1 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| # define test OP with values to match existing Op unit - test | |||
| test_op = c_vision.RandomCropWithBBox(512, [200, 200, 200, 200], padding_mode=mode.Border.EDGE) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataVoc1.create_dict_iterator(), dataVoc2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp) | |||
| def test_random_crop_with_bbox_op_edge_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomCropWithBBox Op applied, | |||
| applied on dynamically generated edge case, expected to pass | |||
| """ | |||
| logger.info("test_random_crop_with_bbox_op_edge_c") | |||
| # Load dataset | |||
| dataVoc1 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| # define test OP with values to match existing Op unit - test | |||
| test_op = c_vision.RandomCropWithBBox(512, [200, 200, 200, 200], padding_mode=mode.Border.EDGE) | |||
| # maps to convert data into valid edge case data | |||
| dataVoc1 = dataVoc1.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[lambda img, bboxes: (img, np.array([[0, 0, img.shape[1], img.shape[0]]]).astype(bboxes.dtype))]) | |||
| # Test Op added to list of Operations here | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[lambda img, bboxes: (img, np.array([[0, 0, img.shape[1], img.shape[0]]]).astype(bboxes.dtype)), test_op]) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataVoc1.create_dict_iterator(), dataVoc2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp) | |||
| def test_random_crop_with_bbox_op_invalid_c(): | |||
| """ | |||
| Test RandomCropWithBBox Op on invalid constructor parameters, expected to raise ValueError | |||
| """ | |||
| logger.info("test_random_crop_with_bbox_op_invalid_c") | |||
| # Load dataset | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| try: | |||
| # define test OP with values to match existing Op unit - test | |||
| test_op = c_vision.RandomCropWithBBox([512, 512, 375]) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) # Add column for "annotation" | |||
| for _ in dataVoc2.create_dict_iterator(): | |||
| break | |||
| except TypeError as err: | |||
| logger.info("Got an exception in DE: {}".format(str(err))) | |||
| assert "Size should be a single integer" in str(err) | |||
| def test_random_crop_with_bbox_op_bad_c(): | |||
| """ | |||
| Tests RandomCropWithBBox Op with invalid bounding boxes, expected to catch multiple errors. | |||
| """ | |||
| logger.info("test_random_crop_with_bbox_op_bad_c") | |||
| test_op = c_vision.RandomCropWithBBox([512, 512], [200, 200, 200, 200]) | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.WidthOverflow, "bounding boxes is out of bounds of the image") | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.HeightOverflow, "bounding boxes is out of bounds of the image") | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.NegativeXY, "min_x") | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.WrongShape, "4 features") | |||
| if __name__ == "__main__": | |||
| test_random_crop_with_bbox_op_c(plot_vis=True) | |||
| test_random_crop_with_bbox_op_coco_c(plot_vis=True) | |||
| test_random_crop_with_bbox_op2_c(plot_vis=True) | |||
| test_random_crop_with_bbox_op3_c(plot_vis=True) | |||
| test_random_crop_with_bbox_op_edge_c(plot_vis=True) | |||
| test_random_crop_with_bbox_op_invalid_c() | |||
| test_random_crop_with_bbox_op_bad_c() | |||
| @@ -0,0 +1,220 @@ | |||
| # 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. | |||
| # ============================================================================== | |||
| """ | |||
| Testing RandomVerticalFlipWithBBox op in DE | |||
| """ | |||
| import numpy as np | |||
| import mindspore.dataset as ds | |||
| import mindspore.dataset.transforms.vision.c_transforms as c_vision | |||
| from mindspore import log as logger | |||
| from util import visualize_with_bounding_boxes, InvalidBBoxType, check_bad_bbox, \ | |||
| config_get_set_seed, config_get_set_num_parallel_workers, save_and_check_md5 | |||
| GENERATE_GOLDEN = False | |||
| # Updated VOC dataset with correct annotations - DATA_DIR | |||
| DATA_DIR_VOC = "../data/dataset/testVOC2012_2" | |||
| # COCO dataset - DATA_DIR, ANNOTATION_DIR | |||
| DATA_DIR_COCO = ["../data/dataset/testCOCO/train/", "../data/dataset/testCOCO/annotations/train.json"] | |||
| def test_random_vertical_flip_with_bbox_op_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomVerticalFlipWithBBox Op applied | |||
| """ | |||
| logger.info("test_random_vertical_flip_with_bbox_op_c") | |||
| # Load dataset | |||
| dataVoc1 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", | |||
| decode=True, shuffle=False) | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", | |||
| decode=True, shuffle=False) | |||
| test_op = c_vision.RandomVerticalFlipWithBBox(1) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataVoc1.create_dict_iterator(), dataVoc2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp) | |||
| def test_random_vertical_flip_with_bbox_op_coco_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomVerticalFlipWithBBox Op applied, | |||
| Testing with Coco dataset | |||
| """ | |||
| logger.info("test_random_vertical_flip_with_bbox_op_coco_c") | |||
| # load dataset | |||
| dataCoco1 = ds.CocoDataset(DATA_DIR_COCO[0], annotation_file=DATA_DIR_COCO[1], task="Detection", | |||
| decode=True, shuffle=False) | |||
| dataCoco2 = ds.CocoDataset(DATA_DIR_COCO[0], annotation_file=DATA_DIR_COCO[1], task="Detection", | |||
| decode=True, shuffle=False) | |||
| test_op = c_vision.RandomVerticalFlipWithBBox(1) | |||
| dataCoco2 = dataCoco2.map(input_columns=["image", "bbox"], | |||
| output_columns=["image", "bbox"], | |||
| columns_order=["image", "bbox"], | |||
| operations=[test_op]) | |||
| test_op = c_vision.RandomVerticalFlipWithBBox(1) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataCoco1.create_dict_iterator(), dataCoco2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp, "bbox") | |||
| def test_random_vertical_flip_with_bbox_op_rand_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomVerticalFlipWithBBox Op applied, | |||
| tests with MD5 check, expected to pass | |||
| """ | |||
| logger.info("test_random_vertical_flip_with_bbox_op_rand_c") | |||
| original_seed = config_get_set_seed(29847) | |||
| original_num_parallel_workers = config_get_set_num_parallel_workers(1) | |||
| # Load dataset | |||
| dataVoc1 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", | |||
| decode=True, shuffle=False) | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", | |||
| decode=True, shuffle=False) | |||
| test_op = c_vision.RandomVerticalFlipWithBBox(0.8) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) | |||
| filename = "random_vertical_flip_with_bbox_01_c_result.npz" | |||
| save_and_check_md5(dataVoc2, filename, generate_golden=GENERATE_GOLDEN) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataVoc1.create_dict_iterator(), dataVoc2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp) | |||
| # Restore config setting | |||
| ds.config.set_seed(original_seed) | |||
| ds.config.set_num_parallel_workers(original_num_parallel_workers) | |||
| def test_random_vertical_flip_with_bbox_op_edge_c(plot_vis=False): | |||
| """ | |||
| Prints images and bboxes side by side with and without RandomVerticalFlipWithBBox Op applied, | |||
| applied on dynamically generated edge case, expected to pass | |||
| """ | |||
| logger.info("test_random_vertical_flip_with_bbox_op_edge_c") | |||
| dataVoc1 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", | |||
| decode=True, shuffle=False) | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", | |||
| decode=True, shuffle=False) | |||
| test_op = c_vision.RandomVerticalFlipWithBBox(1) | |||
| # maps to convert data into valid edge case data | |||
| dataVoc1 = dataVoc1.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[lambda img, bboxes: (img, np.array([[0, 0, img.shape[1], img.shape[0]]]).astype(bboxes.dtype))]) | |||
| # Test Op added to list of Operations here | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[lambda img, bboxes: (img, np.array([[0, 0, img.shape[1], img.shape[0]]]).astype(bboxes.dtype)), test_op]) | |||
| unaugSamp, augSamp = [], [] | |||
| for unAug, Aug in zip(dataVoc1.create_dict_iterator(), dataVoc2.create_dict_iterator()): | |||
| unaugSamp.append(unAug) | |||
| augSamp.append(Aug) | |||
| if plot_vis: | |||
| visualize_with_bounding_boxes(unaugSamp, augSamp) | |||
| def test_random_vertical_flip_with_bbox_op_invalid_c(): | |||
| """ | |||
| Test RandomVerticalFlipWithBBox Op on invalid constructor parameters, expected to raise ValueError | |||
| """ | |||
| logger.info("test_random_vertical_flip_with_bbox_op_invalid_c") | |||
| dataVoc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", | |||
| decode=True, shuffle=False) | |||
| try: | |||
| test_op = c_vision.RandomVerticalFlipWithBBox(2) | |||
| # map to apply ops | |||
| dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"], | |||
| output_columns=["image", "annotation"], | |||
| columns_order=["image", "annotation"], | |||
| operations=[test_op]) | |||
| for _ in dataVoc2.create_dict_iterator(): | |||
| break | |||
| except ValueError as err: | |||
| logger.info("Got an exception in DE: {}".format(str(err))) | |||
| assert "Input is not" in str(err) | |||
| def test_random_vertical_flip_with_bbox_op_bad_c(): | |||
| """ | |||
| Tests RandomVerticalFlipWithBBox Op with invalid bounding boxes, expected to catch multiple errors | |||
| """ | |||
| logger.info("test_random_vertical_flip_with_bbox_op_bad_c") | |||
| test_op = c_vision.RandomVerticalFlipWithBBox(1) | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.WidthOverflow, "bounding boxes is out of bounds of the image") | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.HeightOverflow, "bounding boxes is out of bounds of the image") | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.NegativeXY, "min_x") | |||
| data_voc2 = ds.VOCDataset(DATA_DIR_VOC, task="Detection", mode="train", decode=True, shuffle=False) | |||
| check_bad_bbox(data_voc2, test_op, InvalidBBoxType.WrongShape, "4 features") | |||
| if __name__ == "__main__": | |||
| test_random_vertical_flip_with_bbox_op_c(plot_vis=True) | |||
| test_random_vertical_flip_with_bbox_op_coco_c(plot_vis=True) | |||
| test_random_vertical_flip_with_bbox_op_rand_c(plot_vis=True) | |||
| test_random_vertical_flip_with_bbox_op_edge_c(plot_vis=True) | |||
| test_random_vertical_flip_with_bbox_op_invalid_c() | |||
| test_random_vertical_flip_with_bbox_op_bad_c() | |||
| @@ -288,12 +288,13 @@ def config_get_set_num_parallel_workers(num_parallel_workers_new): | |||
| return num_parallel_workers_original | |||
| def visualize_with_bounding_boxes(orig, aug, plot_rows=3): | |||
| def visualize_with_bounding_boxes(orig, aug, annot_name="annotation", plot_rows=3): | |||
| """ | |||
| Take a list of un-augmented and augmented images with "annotation" bounding boxes | |||
| Plot images to compare test correct BBox augment functionality | |||
| :param orig: list of original images and bboxes (without aug) | |||
| :param aug: list of augmented images and bboxes | |||
| :param annot_name: the dict key for bboxes in data, e.g "bbox" (COCO) / "annotation" (VOC) | |||
| :param plot_rows: number of rows on plot (rows = samples on one plot) | |||
| :return: None | |||
| """ | |||
| @@ -301,9 +302,10 @@ def visualize_with_bounding_boxes(orig, aug, plot_rows=3): | |||
| def add_bounding_boxes(ax, bboxes): | |||
| for bbox in bboxes: | |||
| rect = patches.Rectangle((bbox[0], bbox[1]), | |||
| bbox[2], bbox[3], | |||
| linewidth=1, edgecolor='r', facecolor='none') | |||
| bbox[2]*0.997, bbox[3]*0.997, | |||
| linewidth=1.80, edgecolor='r', facecolor='none') | |||
| # Add the patch to the Axes | |||
| # Params to Rectangle slightly modified to prevent drawing overflow | |||
| ax.add_patch(rect) | |||
| # Quick check to confirm correct input parameters | |||
| @@ -337,15 +339,15 @@ def visualize_with_bounding_boxes(orig, aug, plot_rows=3): | |||
| (axA, axB) = (axs[x, 0], axs[x, 1]) if (curPlot > 1) else (axs[0], axs[1]) # select plotting axes based on number of image rows on plot - else case when 1 row | |||
| axA.imshow(dataA["image"]) | |||
| add_bounding_boxes(axA, dataA["annotation"]) | |||
| add_bounding_boxes(axA, dataA[annot_name]) | |||
| axA.title.set_text("Original" + str(cur_ix+1)) | |||
| axB.imshow(dataB["image"]) | |||
| add_bounding_boxes(axB, dataB["annotation"]) | |||
| add_bounding_boxes(axB, dataB[annot_name]) | |||
| axB.title.set_text("Augmented" + str(cur_ix+1)) | |||
| logger.info("Original **\n{} : {}".format(str(cur_ix+1), dataA["annotation"])) | |||
| logger.info("Augmented **\n{} : {}\n".format(str(cur_ix+1), dataB["annotation"])) | |||
| logger.info("Original **\n{} : {}".format(str(cur_ix+1), dataA[annot_name])) | |||
| logger.info("Augmented **\n{} : {}\n".format(str(cur_ix+1), dataB[annot_name])) | |||
| plt.show() | |||
| @@ -381,19 +383,19 @@ def check_bad_bbox(data, test_op, invalid_bbox_type, expected_error): | |||
| width = img.shape[1] | |||
| if invalid_bbox_type_ == InvalidBBoxType.WidthOverflow: | |||
| # use box that overflows on width | |||
| return img, np.array([[0, 0, width + 1, height, 0, 0, 0]]).astype(np.uint32) | |||
| return img, np.array([[0, 0, width + 1, height, 0, 0, 0]]).astype(np.float32) | |||
| if invalid_bbox_type_ == InvalidBBoxType.HeightOverflow: | |||
| # use box that overflows on height | |||
| return img, np.array([[0, 0, width, height + 1, 0, 0, 0]]).astype(np.uint32) | |||
| return img, np.array([[0, 0, width, height + 1, 0, 0, 0]]).astype(np.float32) | |||
| if invalid_bbox_type_ == InvalidBBoxType.NegativeXY: | |||
| # use box with negative xy | |||
| return img, np.array([[-10, -10, width, height, 0, 0, 0]]).astype(np.uint32) | |||
| return img, np.array([[-10, -10, width, height, 0, 0, 0]]).astype(np.float32) | |||
| if invalid_bbox_type_ == InvalidBBoxType.WrongShape: | |||
| # use box that has incorrect shape | |||
| return img, np.array([[0, 0, width - 1]]).astype(np.uint32) | |||
| return img, np.array([[0, 0, width - 1]]).astype(np.float32) | |||
| return img, bboxes | |||
| try: | |||