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) { | int CB_Ymax) { | ||||
| // PASS LIST, COUNT OF BOUNDING BOXES | // PASS LIST, COUNT OF BOUNDING BOXES | ||||
| // Also PAss X/Y Min/Max of image cropped region - normally obtained from 'GetCropBox' functions | // 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<int> correct_ind; | ||||
| std::vector<uint32_t> copyVals; | |||||
| std::vector<float> copyVals; | |||||
| dsize_t bboxDim = (*bboxList)->shape()[1]; | dsize_t bboxDim = (*bboxList)->shape()[1]; | ||||
| bool retFlag = false; // true unless overlap found | bool retFlag = false; // true unless overlap found | ||||
| for (int i = 0; i < *bboxCount; i++) { | 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_Xmax = bb_Xmin + bb_Xmax; | ||||
| bb_Ymax = bb_Ymin + bb_Ymax; | bb_Ymax = bb_Ymin + bb_Ymax; | ||||
| // check for image / BB overlap | // check for image / BB overlap | ||||
| @@ -766,23 +760,23 @@ Status UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, | |||||
| correct_ind.push_back(i); | correct_ind.push_back(i); | ||||
| // adjust BBox corners by bringing into new CropBox if beyond | // 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 | // 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 | // 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 | // 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 | // bboxes outside of new cropped region are ignored - empty tensor returned in case of none | ||||
| *bboxCount = correct_ind.size(); | *bboxCount = correct_ind.size(); | ||||
| uint32_t temp; | |||||
| float temp = 0.0; | |||||
| for (auto slice : correct_ind) { // for every index in the loop | for (auto slice : correct_ind) { // for every index in the loop | ||||
| for (int ix = 0; ix < bboxDim; ix++) { | 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); | 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) { | 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++) { | 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, 0}, xMin)); | ||||
| RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 1}, yMin)); | 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_, | 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) { | 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 (int i = 0; i < bboxCount; i++) { | ||||
| // for each bounding box | // 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 | // update positions and widths | ||||
| bb_Xmin = bb_Xmin * W_aspRatio; | bb_Xmin = bb_Xmin * W_aspRatio; | ||||
| bb_Ymin = bb_Ymin * H_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 | // one time allocation -> updated in the loop | ||||
| // type defined based on VOC test dataset | // type defined based on VOC test dataset | ||||
| for (int i = 0; i < boxCount; i++) { | 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 | // 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)); | 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_h = input[0]->shape()[0]; \ | ||||
| uint32_t img_w = input[0]->shape()[1]; \ | uint32_t img_w = input[0]->shape()[1]; \ | ||||
| for (uint32_t i = 0; i < num_of_boxes; i++) { \ | 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)) { \ | if ((min_x + b_w > img_w) || (min_y + b_h > img_h)) { \ | ||||
| return Status(StatusCode::kBoundingBoxOutOfBounds, __LINE__, __FILE__, \ | return Status(StatusCode::kBoundingBoxOutOfBounds, __LINE__, __FILE__, \ | ||||
| "At least one of the bounding boxes is out of bounds of the image."); \ | "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; | bool passing_data_fetch = true; | ||||
| // For each bounding box draw on the image. | // For each bounding box draw on the image. | ||||
| for (uint32_t i = 0; i < num_of_boxes; i++) { | 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) { | if (!passing_data_fetch) { | ||||
| MS_LOG(ERROR) << "Fetching bbox coordinates failed in SaveImagesWithAnnotations."; | MS_LOG(ERROR) << "Fetching bbox coordinates failed in SaveImagesWithAnnotations."; | ||||
| EXPECT_TRUE(passing_data_fetch); | 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; | MS_LOG(ERROR) << "No object find in " + path; | ||||
| return false; | 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_count = 0; // keep track of number of bboxes in file | ||||
| dsize_t bbox_val_count = 4; // creating bboxes of size 4 to test function | dsize_t bbox_val_count = 4; // creating bboxes of size 4 to test function | ||||
| // FILE OK TO READ | // FILE OK TO READ | ||||
| while (object != nullptr) { | while (object != nullptr) { | ||||
| bbox_count += 1; | bbox_count += 1; | ||||
| std::string label_name; | 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"); | XMLElement *bbox_node = object->FirstChildElement("bndbox"); | ||||
| if (bbox_node != nullptr) { | if (bbox_node != nullptr) { | ||||
| XMLElement *xmin_node = bbox_node->FirstChildElement("xmin"); | 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"); | 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"); | 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"); | XMLElement *ymax_node = bbox_node->FirstChildElement("ymax"); | ||||
| if (ymax_node != nullptr) ymax = ymax_node->UnsignedText(); | |||||
| if (ymax_node != nullptr) ymax = ymax_node->FloatText(); | |||||
| } else { | } else { | ||||
| MS_LOG(ERROR) << "bndbox dismatch in " + path; | MS_LOG(ERROR) << "bndbox dismatch in " + path; | ||||
| return false; | 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 | 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 | Take a list of un-augmented and augmented images with "annotation" bounding boxes | ||||
| Plot images to compare test correct BBox augment functionality | Plot images to compare test correct BBox augment functionality | ||||
| :param orig: list of original images and bboxes (without aug) | :param orig: list of original images and bboxes (without aug) | ||||
| :param aug: list of augmented images and bboxes | :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) | :param plot_rows: number of rows on plot (rows = samples on one plot) | ||||
| :return: None | :return: None | ||||
| """ | """ | ||||
| @@ -301,9 +302,10 @@ def visualize_with_bounding_boxes(orig, aug, plot_rows=3): | |||||
| def add_bounding_boxes(ax, bboxes): | def add_bounding_boxes(ax, bboxes): | ||||
| for bbox in bboxes: | for bbox in bboxes: | ||||
| rect = patches.Rectangle((bbox[0], bbox[1]), | 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 | # Add the patch to the Axes | ||||
| # Params to Rectangle slightly modified to prevent drawing overflow | |||||
| ax.add_patch(rect) | ax.add_patch(rect) | ||||
| # Quick check to confirm correct input parameters | # 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, 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"]) | 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)) | axA.title.set_text("Original" + str(cur_ix+1)) | ||||
| axB.imshow(dataB["image"]) | 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)) | 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() | plt.show() | ||||
| @@ -381,19 +383,19 @@ def check_bad_bbox(data, test_op, invalid_bbox_type, expected_error): | |||||
| width = img.shape[1] | width = img.shape[1] | ||||
| if invalid_bbox_type_ == InvalidBBoxType.WidthOverflow: | if invalid_bbox_type_ == InvalidBBoxType.WidthOverflow: | ||||
| # use box that overflows on width | # 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: | if invalid_bbox_type_ == InvalidBBoxType.HeightOverflow: | ||||
| # use box that overflows on height | # 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: | if invalid_bbox_type_ == InvalidBBoxType.NegativeXY: | ||||
| # use box with negative xy | # 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: | if invalid_bbox_type_ == InvalidBBoxType.WrongShape: | ||||
| # use box that has incorrect shape | # 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 | return img, bboxes | ||||
| try: | try: | ||||