forked from mindspore-Ecosystem/mindspore
comments added, ptrs to consts, UT tests for BBOps
updated comments for 3 BB AugOps addressing comments, void -> status, macros added, fixed test cmt changed types -> value, fixed ut test funcs, grammar bug type fix fixed condition in tests for viz
This commit is contained in:
parent
46c8ef28de
commit
6442a85b75
|
@ -15,8 +15,8 @@ add_library(kernels-image OBJECT
|
||||||
random_crop_op.cc
|
random_crop_op.cc
|
||||||
random_crop_with_bbox_op.cc
|
random_crop_with_bbox_op.cc
|
||||||
random_horizontal_flip_op.cc
|
random_horizontal_flip_op.cc
|
||||||
random_horizontal_flip_bbox_op.cc
|
random_horizontal_flip_bbox_op.cc
|
||||||
bounding_box_augment_op.cc
|
bounding_box_augment_op.cc
|
||||||
random_resize_op.cc
|
random_resize_op.cc
|
||||||
random_rotation_op.cc
|
random_rotation_op.cc
|
||||||
random_vertical_flip_op.cc
|
random_vertical_flip_op.cc
|
||||||
|
|
|
@ -726,22 +726,22 @@ Status Pad(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -------- BBOX OPERATIONS -------- //
|
// -------- BBOX OPERATIONS -------- //
|
||||||
void UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int *CB_Xmin, int *CB_Ymin, int *CB_Xmax,
|
Status UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int CB_Xmin, int CB_Ymin, int CB_Xmax,
|
||||||
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;
|
uint32_t bb_Xmin_t, bb_Ymin_t, bb_Xmax_t, bb_Ymax_t;
|
||||||
|
|
||||||
std::vector<int> correctInd;
|
std::vector<int> correct_ind;
|
||||||
std::vector<uint32_t> copyVals;
|
std::vector<uint32_t> 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;
|
int bb_Xmin, bb_Xmax, bb_Ymin, bb_Ymax;
|
||||||
(*bboxList)->GetUnsignedIntAt(&bb_Xmin_t, {i, 0});
|
RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&bb_Xmin_t, {i, 0}));
|
||||||
(*bboxList)->GetUnsignedIntAt(&bb_Ymin_t, {i, 1});
|
RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&bb_Ymin_t, {i, 1}));
|
||||||
(*bboxList)->GetUnsignedIntAt(&bb_Xmax_t, {i, 2});
|
RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&bb_Xmax_t, {i, 2}));
|
||||||
(*bboxList)->GetUnsignedIntAt(&bb_Ymax_t, {i, 3});
|
RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&bb_Ymax_t, {i, 3}));
|
||||||
bb_Xmin = bb_Xmin_t;
|
bb_Xmin = bb_Xmin_t;
|
||||||
bb_Ymin = bb_Ymin_t;
|
bb_Ymin = bb_Ymin_t;
|
||||||
bb_Xmax = bb_Xmax_t;
|
bb_Xmax = bb_Xmax_t;
|
||||||
|
@ -749,77 +749,77 @@ void UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, i
|
||||||
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
|
||||||
if (((bb_Xmin > *CB_Xmax) || (bb_Ymin > *CB_Ymax)) || ((bb_Xmax < *CB_Xmin) || (bb_Ymax < *CB_Ymin))) {
|
if (((bb_Xmin > CB_Xmax) || (bb_Ymin > CB_Ymax)) || ((bb_Xmax < CB_Xmin) || (bb_Ymax < CB_Ymin))) {
|
||||||
retFlag = true; // no overlap found
|
continue; // no overlap found
|
||||||
}
|
|
||||||
if (retFlag) { // invalid bbox no longer within image region - reset to zero
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
// Update this bbox and select it to move to the final output tensor
|
// Update this bbox and select it to move to the final output tensor
|
||||||
correctInd.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_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_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_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_Ymax = bb_Ymax - (std::max(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
|
||||||
(*bboxList)->SetItemAt({i, 0}, (uint32_t)(bb_Xmin));
|
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 0}, static_cast<uint32_t>(bb_Xmin)));
|
||||||
(*bboxList)->SetItemAt({i, 1}, (uint32_t)(bb_Ymin));
|
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 1}, static_cast<uint32_t>(bb_Ymin)));
|
||||||
(*bboxList)->SetItemAt({i, 2}, (uint32_t)(bb_Xmax - bb_Xmin));
|
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 2}, static_cast<uint32_t>(bb_Xmax - bb_Xmin)));
|
||||||
(*bboxList)->SetItemAt({i, 3}, (uint32_t)(bb_Ymax - bb_Ymin));
|
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 3}, static_cast<uint32_t>(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 = correctInd.size();
|
*bboxCount = correct_ind.size();
|
||||||
uint32_t temp;
|
uint32_t temp;
|
||||||
for (auto slice : correctInd) { // 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++) {
|
||||||
(*bboxList)->GetUnsignedIntAt(&temp, {slice, ix});
|
RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&temp, {slice, ix}));
|
||||||
copyVals.push_back(temp);
|
copyVals.push_back(temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::shared_ptr<Tensor> retV;
|
std::shared_ptr<Tensor> retV;
|
||||||
Tensor::CreateTensor(&retV, copyVals, TensorShape({(dsize_t)bboxCount, bboxDim}));
|
RETURN_IF_NOT_OK(Tensor::CreateTensor(&retV, copyVals, TensorShape({static_cast<dsize_t>(*bboxCount), bboxDim})));
|
||||||
(*bboxList) = retV; // reset pointer
|
(*bboxList) = retV; // reset pointer
|
||||||
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PadBBoxes(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int32_t *pad_top, int32_t *pad_left) {
|
Status PadBBoxes(std::shared_ptr<Tensor> *bboxList, const size_t &bboxCount, int32_t pad_top, int32_t pad_left) {
|
||||||
uint32_t xMin = 0;
|
for (int i = 0; i < bboxCount; i++) {
|
||||||
uint32_t yMin = 0;
|
uint32_t xMin, yMin;
|
||||||
for (int i = 0; i < *bboxCount; i++) {
|
RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&xMin, {i, 0}));
|
||||||
(*bboxList)->GetUnsignedIntAt(&xMin, {i, 0});
|
RETURN_IF_NOT_OK((*bboxList)->GetUnsignedIntAt(&yMin, {i, 1}));
|
||||||
(*bboxList)->GetUnsignedIntAt(&yMin, {i, 1});
|
xMin += static_cast<uint32_t>(pad_left); // should not be negative
|
||||||
xMin = xMin + (uint32_t)(*pad_left); // should not be negative
|
yMin += static_cast<uint32_t>(pad_top);
|
||||||
yMin = yMin + (uint32_t)(*pad_top);
|
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 0}, xMin));
|
||||||
(*bboxList)->SetItemAt({i, 0}, xMin);
|
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 1}, yMin));
|
||||||
(*bboxList)->SetItemAt({i, 1}, yMin);
|
|
||||||
}
|
}
|
||||||
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateBBoxesForResize(std::shared_ptr<Tensor> *bboxList, 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;
|
uint32_t bb_Xmin, bb_Ymin, bb_Xwidth, bb_Ywidth;
|
||||||
// cast to float to preseve fractional
|
// cast to float to preseve fractional
|
||||||
double W_aspRatio = (*target_width_ * 1.0) / (*orig_width * 1.0);
|
double W_aspRatio = (target_width_ * 1.0) / (orig_width * 1.0);
|
||||||
double H_aspRatio = (*target_height_ * 1.0) / (*orig_height * 1.0);
|
double 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
|
||||||
(*bboxList)->GetUnsignedIntAt(&bb_Xmin, {i, 0});
|
RETURN_IF_NOT_OK(bboxList->GetUnsignedIntAt(&bb_Xmin, {i, 0}));
|
||||||
(*bboxList)->GetUnsignedIntAt(&bb_Ymin, {i, 1});
|
RETURN_IF_NOT_OK(bboxList->GetUnsignedIntAt(&bb_Ymin, {i, 1}));
|
||||||
(*bboxList)->GetUnsignedIntAt(&bb_Xwidth, {i, 2});
|
RETURN_IF_NOT_OK(bboxList->GetUnsignedIntAt(&bb_Xwidth, {i, 2}));
|
||||||
(*bboxList)->GetUnsignedIntAt(&bb_Ywidth, {i, 3});
|
RETURN_IF_NOT_OK(bboxList->GetUnsignedIntAt(&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;
|
||||||
bb_Xwidth = bb_Xwidth * W_aspRatio;
|
bb_Xwidth = bb_Xwidth * W_aspRatio;
|
||||||
bb_Ywidth = bb_Ywidth * H_aspRatio;
|
bb_Ywidth = bb_Ywidth * H_aspRatio;
|
||||||
// reset bounding box values
|
// reset bounding box values
|
||||||
(*bboxList)->SetItemAt({i, 0}, (uint32_t)bb_Xmin);
|
RETURN_IF_NOT_OK(bboxList->SetItemAt({i, 0}, bb_Xmin));
|
||||||
(*bboxList)->SetItemAt({i, 1}, (uint32_t)bb_Ymin);
|
RETURN_IF_NOT_OK(bboxList->SetItemAt({i, 1}, bb_Ymin));
|
||||||
(*bboxList)->SetItemAt({i, 2}, (uint32_t)bb_Xwidth);
|
RETURN_IF_NOT_OK(bboxList->SetItemAt({i, 2}, bb_Xwidth));
|
||||||
(*bboxList)->SetItemAt({i, 3}, (uint32_t)bb_Ywidth);
|
RETURN_IF_NOT_OK(bboxList->SetItemAt({i, 3}, bb_Ywidth));
|
||||||
}
|
}
|
||||||
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dataset
|
} // namespace dataset
|
||||||
} // namespace mindspore
|
} // namespace mindspore
|
||||||
|
|
|
@ -230,12 +230,12 @@ Status Pad(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output
|
||||||
// Updates and checks bounding boxes for new cropped region of image
|
// Updates and checks bounding boxes for new cropped region of image
|
||||||
// @param bboxList: A tensor contaning bounding box tensors
|
// @param bboxList: A tensor contaning bounding box tensors
|
||||||
// @param bboxCount: total Number of bounding boxes - required within caller function to run update loop
|
// @param bboxCount: total Number of bounding boxes - required within caller function to run update loop
|
||||||
// @param CB_Xmin: Images's CropBox Xmin coordinate
|
// @param CB_Xmin: Image's CropBox Xmin coordinate
|
||||||
// @param CB_Xmin: Images's CropBox Ymin coordinate
|
// @param CB_Xmin: Image's CropBox Ymin coordinate
|
||||||
// @param CB_Xmax: Images's CropBox Xmax coordinate - (Xmin + width)
|
// @param CB_Xmax: Image's CropBox Xmax coordinate - (Xmin + width)
|
||||||
// @param CB_Xmax: Images's CropBox Ymax coordinate - (Ymin + height)
|
// @param CB_Xmax: Image's CropBox Ymax coordinate - (Ymin + height)
|
||||||
void UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int *CB_Xmin, int *CB_Ymin, int *CB_Xmax,
|
Status UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int CB_Xmin, int CB_Ymin, int CB_Xmax,
|
||||||
int *CB_Ymax);
|
int CB_Ymax);
|
||||||
|
|
||||||
// Updates bounding boxes with required Top and Left padding
|
// Updates bounding boxes with required Top and Left padding
|
||||||
// Top and Left padding amounts required to adjust bboxs min X,Y values according to padding 'push'
|
// Top and Left padding amounts required to adjust bboxs min X,Y values according to padding 'push'
|
||||||
|
@ -244,7 +244,7 @@ void UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, i
|
||||||
// @param bboxCount: total Number of bounding boxes - required within caller function to run update loop
|
// @param bboxCount: total Number of bounding boxes - required within caller function to run update loop
|
||||||
// @param pad_top: Total amount of padding applied to image top
|
// @param pad_top: Total amount of padding applied to image top
|
||||||
// @param pad_left: Total amount of padding applied to image left side
|
// @param pad_left: Total amount of padding applied to image left side
|
||||||
void PadBBoxes(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int32_t *pad_top, int32_t *pad_left);
|
Status PadBBoxes(std::shared_ptr<Tensor> *bboxList, const size_t &bboxCount, int32_t pad_top, int32_t pad_left);
|
||||||
|
|
||||||
// Updates bounding boxes for an Image Resize Operation - Takes in set of valid BBoxes
|
// Updates bounding boxes for an Image Resize Operation - Takes in set of valid BBoxes
|
||||||
// For e.g those that remain after a crop
|
// For e.g those that remain after a crop
|
||||||
|
@ -255,8 +255,8 @@ void PadBBoxes(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int32_t *pa
|
||||||
// @param target_width_: required height of image post resize
|
// @param target_width_: required height of image post resize
|
||||||
// @param orig_width: current width of image pre resize
|
// @param orig_width: current width of image pre resize
|
||||||
// @param orig_height: current height of image pre resize
|
// @param orig_height: current height of image pre resize
|
||||||
void UpdateBBoxesForResize(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int32_t *target_width_,
|
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);
|
||||||
|
|
||||||
} // namespace dataset
|
} // namespace dataset
|
||||||
} // namespace mindspore
|
} // namespace mindspore
|
||||||
|
|
|
@ -42,16 +42,17 @@ Status RandomCropAndResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow
|
||||||
int crop_height = 0;
|
int crop_height = 0;
|
||||||
int crop_width = 0;
|
int crop_width = 0;
|
||||||
|
|
||||||
(void)RandomCropAndResizeOp::GetCropBox(h_in, w_in, &x, &y, &crop_height, &crop_width);
|
RETURN_IF_NOT_OK(RandomCropAndResizeOp::GetCropBox(h_in, w_in, &x, &y, &crop_height, &crop_width));
|
||||||
|
|
||||||
int maxX = x + crop_width; // max dims of selected CropBox on image
|
int maxX = x + crop_width; // max dims of selected CropBox on image
|
||||||
int maxY = y + crop_height;
|
int maxY = y + crop_height;
|
||||||
|
|
||||||
UpdateBBoxesForCrop(&(*output)[1], &bboxCount, &x, &y, &maxX, &maxY); // IMAGE_UTIL
|
RETURN_IF_NOT_OK(UpdateBBoxesForCrop(&(*output)[1], &bboxCount, x, y, maxX, maxY)); // IMAGE_UTIL
|
||||||
RETURN_IF_NOT_OK(CropAndResize(input[0], &(*output)[0], x, y, crop_height, crop_width, target_height_, target_width_,
|
RETURN_IF_NOT_OK(CropAndResize(input[0], &(*output)[0], x, y, crop_height, crop_width, target_height_, target_width_,
|
||||||
interpolation_));
|
interpolation_));
|
||||||
|
|
||||||
UpdateBBoxesForResize(&(*output)[1], &bboxCount, &target_width_, &target_height_, &crop_width, &crop_height);
|
RETURN_IF_NOT_OK(
|
||||||
|
UpdateBBoxesForResize((*output)[1], bboxCount, target_width_, target_height_, crop_width, crop_height));
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
} // namespace dataset
|
} // namespace dataset
|
||||||
|
|
|
@ -94,10 +94,10 @@ Status RandomCropOp::ImagePadding(const std::shared_ptr<Tensor> &input, std::sha
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RandomCropOp::GenRandomXY(int *x, int *y, int32_t *padded_image_w, int32_t *padded_image_h) {
|
void RandomCropOp::GenRandomXY(int *x, int *y, const int32_t &padded_image_w, const int32_t &padded_image_h) {
|
||||||
// GenCropPoints for cropping
|
// GenCropPoints for cropping
|
||||||
*x = std::uniform_int_distribution<int>(0, *padded_image_w - crop_width_)(rnd_);
|
*x = std::uniform_int_distribution<int>(0, padded_image_w - crop_width_)(rnd_);
|
||||||
*y = std::uniform_int_distribution<int>(0, *padded_image_h - crop_height_)(rnd_);
|
*y = std::uniform_int_distribution<int>(0, padded_image_h - crop_height_)(rnd_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status RandomCropOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
|
Status RandomCropOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) {
|
||||||
|
@ -119,7 +119,7 @@ Status RandomCropOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_p
|
||||||
}
|
}
|
||||||
|
|
||||||
int x, y;
|
int x, y;
|
||||||
GenRandomXY(&x, &y, &padded_image_w, &padded_image_h);
|
GenRandomXY(&x, &y, padded_image_w, padded_image_h);
|
||||||
return Crop(pad_image, output, x, y, crop_width_, crop_height_);
|
return Crop(pad_image, output, x, y, crop_width_, crop_height_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,24 @@ class RandomCropOp : public TensorOp {
|
||||||
|
|
||||||
Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override;
|
Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override;
|
||||||
|
|
||||||
|
// Function breaks out the compute function's image padding functionality and makes available to other Ops
|
||||||
|
// Using this class as a base - restructrued to allow for RandomCropWithBBox Augmentation Op
|
||||||
|
// @param input: Input is the original Image
|
||||||
|
// @param pad_image: Pointer to new Padded image
|
||||||
|
// @param t_pad_top: Total Top Padding - Based on input and value calculated in function if required
|
||||||
|
// @param t_pad_bottom: Total bottom Padding - Based on input and value calculated in function if required
|
||||||
|
// @param t_pad_left: Total left Padding - Based on input and value calculated in function if required
|
||||||
|
// @param t_pad_right: Total right Padding - Based on input and value calculated in function if required
|
||||||
|
// @param padded_image_w: Final Width of the 'pad_image'
|
||||||
|
// @param padded_image_h: Final Height of the 'pad_image'
|
||||||
|
// @param crop_further: Whether image required cropping after padding - False if new padded image matches required
|
||||||
|
// dimensions
|
||||||
Status ImagePadding(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *pad_image, int32_t *t_pad_top,
|
Status ImagePadding(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *pad_image, int32_t *t_pad_top,
|
||||||
int32_t *t_pad_bottom, int32_t *t_pad_left, int32_t *t_pad_right, int32_t *padded_image_w,
|
int32_t *t_pad_bottom, int32_t *t_pad_left, int32_t *t_pad_right, int32_t *padded_image_w,
|
||||||
int32_t *padded_image_h, bool *crop_further);
|
int32_t *padded_image_h, bool *crop_further);
|
||||||
|
|
||||||
void GenRandomXY(int *x, int *y, int32_t *padded_image_w, int32_t *padded_image_h);
|
// Function breaks X,Y generation functionality out of original compute function and makes available to other Ops
|
||||||
|
void GenRandomXY(int *x, int *y, const int32_t &padded_image_w, const int32_t &padded_image_h);
|
||||||
|
|
||||||
Status OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) override;
|
Status OutputShape(const std::vector<TensorShape> &inputs, std::vector<TensorShape> &outputs) override;
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ Status RandomCropWithBBoxOp::Compute(const TensorRow &input, TensorRow *output)
|
||||||
|
|
||||||
// update bounding boxes with new values based on relevant image padding
|
// update bounding boxes with new values based on relevant image padding
|
||||||
if (t_pad_left || t_pad_bottom) {
|
if (t_pad_left || t_pad_bottom) {
|
||||||
PadBBoxes(&(*output)[1], &boxCount, &t_pad_left, &t_pad_top);
|
RETURN_IF_NOT_OK(PadBBoxes(&(*output)[1], boxCount, t_pad_left, t_pad_top));
|
||||||
}
|
}
|
||||||
if (!crop_further) {
|
if (!crop_further) {
|
||||||
// no further cropping required
|
// no further cropping required
|
||||||
|
@ -57,10 +57,10 @@ Status RandomCropWithBBoxOp::Compute(const TensorRow &input, TensorRow *output)
|
||||||
}
|
}
|
||||||
|
|
||||||
int x, y;
|
int x, y;
|
||||||
RandomCropOp::GenRandomXY(&x, &y, &padded_image_w, &padded_image_h);
|
RandomCropOp::GenRandomXY(&x, &y, padded_image_w, padded_image_h);
|
||||||
int maxX = x + RandomCropOp::crop_width_; // max dims of selected CropBox on image
|
int maxX = x + RandomCropOp::crop_width_; // max dims of selected CropBox on image
|
||||||
int maxY = y + RandomCropOp::crop_height_;
|
int maxY = y + RandomCropOp::crop_height_;
|
||||||
UpdateBBoxesForCrop(&(*output)[1], &boxCount, &x, &y, &maxX, &maxY);
|
RETURN_IF_NOT_OK(UpdateBBoxesForCrop(&(*output)[1], &boxCount, x, y, maxX, maxY));
|
||||||
return Crop(pad_image, &(*output)[0], x, y, RandomCropOp::crop_width_, RandomCropOp::crop_height_);
|
return Crop(pad_image, &(*output)[0], x, y, RandomCropOp::crop_width_, RandomCropOp::crop_height_);
|
||||||
}
|
}
|
||||||
} // namespace dataset
|
} // namespace dataset
|
||||||
|
|
|
@ -37,12 +37,12 @@ Status RandomVerticalFlipWithBBoxOp::Compute(const TensorRow &input, TensorRow *
|
||||||
uint32_t boxCorner_y = 0;
|
uint32_t boxCorner_y = 0;
|
||||||
uint32_t boxHeight = 0;
|
uint32_t boxHeight = 0;
|
||||||
uint32_t newBoxCorner_y = 0;
|
uint32_t newBoxCorner_y = 0;
|
||||||
input[1]->GetUnsignedIntAt(&boxCorner_y, {i, 1}); // get min y of bbox
|
RETURN_IF_NOT_OK(input[1]->GetUnsignedIntAt(&boxCorner_y, {i, 1})); // get min y of bbox
|
||||||
input[1]->GetUnsignedIntAt(&boxHeight, {i, 3}); // get height of bbox
|
RETURN_IF_NOT_OK(input[1]->GetUnsignedIntAt(&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);
|
newBoxCorner_y = (imHeight - 1) - (boxCorner_y + boxHeight);
|
||||||
input[1]->SetItemAt({i, 1}, newBoxCorner_y);
|
RETURN_IF_NOT_OK(input[1]->SetItemAt({i, 1}, newBoxCorner_y));
|
||||||
}
|
}
|
||||||
|
|
||||||
(*output).push_back(nullptr);
|
(*output).push_back(nullptr);
|
||||||
|
|
|
@ -151,7 +151,7 @@ class RandomCrop(cde.RandomCropOp):
|
||||||
|
|
||||||
class RandomCropWithBBox(cde.RandomCropWithBBoxOp):
|
class RandomCropWithBBox(cde.RandomCropWithBBoxOp):
|
||||||
"""
|
"""
|
||||||
Crop the input image at a random location, and adjust bounding boxes
|
Crop the input image at a random location and adjust bounding boxes for crop area
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
size (int or sequence): The output size of the cropped image.
|
size (int or sequence): The output size of the cropped image.
|
||||||
|
@ -242,10 +242,10 @@ class RandomVerticalFlip(cde.RandomVerticalFlipOp):
|
||||||
|
|
||||||
class RandomVerticalFlipWithBBox(cde.RandomVerticalFlipWithBBoxOp):
|
class RandomVerticalFlipWithBBox(cde.RandomVerticalFlipWithBBoxOp):
|
||||||
"""
|
"""
|
||||||
Flip the input image vertically and adjust bounding boxes, randomly with a given probability.
|
Flip the input image vertically, randomly with a given probability and adjust bounding boxes as well
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
prob (float): Probability of the image being flipped (default=0.5).
|
prob (float, optional): Probability of the image being flipped (default=0.5).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@check_prob
|
@check_prob
|
||||||
|
|
|
@ -0,0 +1,312 @@
|
||||||
|
# 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
|
||||||
|
"""
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.patches as patches
|
||||||
|
|
||||||
|
import mindspore.dataset as ds
|
||||||
|
import mindspore.dataset.transforms.vision.c_transforms as c_vision
|
||||||
|
|
||||||
|
from mindspore import log as logger
|
||||||
|
|
||||||
|
# updated VOC dataset with correct annotations
|
||||||
|
DATA_DIR = "../data/dataset/testVOC2012_2"
|
||||||
|
|
||||||
|
|
||||||
|
def fix_annotate(bboxes):
|
||||||
|
"""
|
||||||
|
Update Current VOC dataset format to Proposed HQ BBox format
|
||||||
|
|
||||||
|
:param bboxes: in [label, x_min, y_min, w, h, truncate, difficult] format
|
||||||
|
:return: annotation in [x_min, y_min, w, h, label, truncate, difficult] format
|
||||||
|
"""
|
||||||
|
for bbox in bboxes:
|
||||||
|
tmp = bbox[0]
|
||||||
|
bbox[0] = bbox[1]
|
||||||
|
bbox[1] = bbox[2]
|
||||||
|
bbox[2] = bbox[3]
|
||||||
|
bbox[3] = bbox[4]
|
||||||
|
bbox[4] = tmp
|
||||||
|
return bboxes
|
||||||
|
|
||||||
|
|
||||||
|
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')
|
||||||
|
# Add the patch to the Axes
|
||||||
|
ax.add_patch(rect)
|
||||||
|
|
||||||
|
|
||||||
|
def vis_check(orig, aug):
|
||||||
|
if not isinstance(orig, list) or not isinstance(aug, list):
|
||||||
|
return False
|
||||||
|
if len(orig) != len(aug):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def visualize(orig, aug):
|
||||||
|
|
||||||
|
if not vis_check(orig, aug):
|
||||||
|
return
|
||||||
|
|
||||||
|
plotrows = 3
|
||||||
|
compset = int(len(orig)/plotrows)
|
||||||
|
|
||||||
|
orig, aug = np.array(orig), np.array(aug)
|
||||||
|
|
||||||
|
orig = np.split(orig[:compset*plotrows], compset) + [orig[compset*plotrows:]]
|
||||||
|
aug = np.split(aug[:compset*plotrows], compset) + [aug[compset*plotrows:]]
|
||||||
|
|
||||||
|
for ix, allData in enumerate(zip(orig, aug)):
|
||||||
|
base_ix = ix * plotrows # will signal what base level we're on
|
||||||
|
fig, axs = plt.subplots(len(allData[0]), 2)
|
||||||
|
fig.tight_layout(pad=1.5)
|
||||||
|
|
||||||
|
for x, (dataA, dataB) in enumerate(zip(allData[0], allData[1])):
|
||||||
|
cur_ix = base_ix + x
|
||||||
|
|
||||||
|
axs[x, 0].imshow(dataA["image"])
|
||||||
|
add_bounding_boxes(axs[x, 0], dataA["annotation"])
|
||||||
|
axs[x, 0].title.set_text("Original" + str(cur_ix+1))
|
||||||
|
print("Original **\n ", str(cur_ix+1), " :", dataA["annotation"])
|
||||||
|
|
||||||
|
axs[x, 1].imshow(dataB["image"])
|
||||||
|
add_bounding_boxes(axs[x, 1], dataB["annotation"])
|
||||||
|
axs[x, 1].title.set_text("Augmented" + str(cur_ix+1))
|
||||||
|
print("Augmented **\n", str(cur_ix+1), " ", dataB["annotation"], "\n")
|
||||||
|
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
# Functions to pass to Gen for creating invalid bounding boxes
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_neg_xy(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [-50, -50, im_w - 10, im_h - 10]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_overflow_width(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [0, 0, im_w + 10, im_h - 10]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_overflow_height(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [0, 0, im_w - 10, im_h + 10]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_wrong_shape(im, bbox):
|
||||||
|
bbox = np.array([[0, 0, 0]]).astype(bbox.dtype)
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
badGenFuncs = [gen_bad_bbox_neg_xy,
|
||||||
|
gen_bad_bbox_overflow_width,
|
||||||
|
gen_bad_bbox_overflow_height,
|
||||||
|
gen_bad_bbox_wrong_shape]
|
||||||
|
|
||||||
|
|
||||||
|
assertVal = ["min_x",
|
||||||
|
"is out of bounds of the image",
|
||||||
|
"is out of bounds of the image",
|
||||||
|
"4 features"]
|
||||||
|
|
||||||
|
|
||||||
|
# Gen Edge case BBox
|
||||||
|
def gen_bbox_edge(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [0, 0, im_w, im_h]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def test_c_random_resized_crop_with_bbox_op(plot_vis=False):
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes to compare and test
|
||||||
|
"""
|
||||||
|
# Load dataset
|
||||||
|
dataVoc1 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train", decode=True, shuffle=False)
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, 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 fix annotations to HQ standard
|
||||||
|
dataVoc1 = dataVoc1.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
# 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(unaugSamp, augSamp)
|
||||||
|
|
||||||
|
|
||||||
|
def test_c_random_resized_crop_with_bbox_op_edge(plot_vis=False):
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes to compare and test
|
||||||
|
"""
|
||||||
|
# Load dataset
|
||||||
|
dataVoc1 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train", decode=True, shuffle=False)
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, 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 fix annotations to HQ standard
|
||||||
|
dataVoc1 = dataVoc1.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
|
||||||
|
# Modify BBoxes to serve as valid edge cases
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"],
|
||||||
|
output_columns=["image", "annotation"],
|
||||||
|
columns_order=["image", "annotation"],
|
||||||
|
operations=[gen_bbox_edge])
|
||||||
|
|
||||||
|
# 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(unaugSamp, augSamp)
|
||||||
|
|
||||||
|
|
||||||
|
def test_c_random_resized_crop_with_bbox_op_invalid():
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes to compare and test
|
||||||
|
"""
|
||||||
|
# Load dataset # only loading the to AugDataset as test will fail on this
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, 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))
|
||||||
|
|
||||||
|
# maps to fix annotations to HQ standard
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
# 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_c_random_resized_crop_with_bbox_op_invalid2():
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes to compare and test
|
||||||
|
"""
|
||||||
|
# Load dataset # only loading the to AugDataset as test will fail on this
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, 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))
|
||||||
|
|
||||||
|
# maps to fix annotations to HQ standard
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
# 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_c_random_resized_crop_with_bbox_op_bad():
|
||||||
|
# Should Fail - Errors logged to logger
|
||||||
|
for ix, badFunc in enumerate(badGenFuncs):
|
||||||
|
try:
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
test_op = c_vision.RandomVerticalFlipWithBBox(1)
|
||||||
|
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"],
|
||||||
|
output_columns=["image", "annotation"],
|
||||||
|
columns_order=["image", "annotation"],
|
||||||
|
operations=[badFunc])
|
||||||
|
|
||||||
|
# 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 # first sample will cause exception
|
||||||
|
|
||||||
|
except RuntimeError as err:
|
||||||
|
logger.info("Got an exception in DE: {}".format(str(err)))
|
||||||
|
assert assertVal[ix] in str(err)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_c_random_resized_crop_with_bbox_op(False)
|
||||||
|
test_c_random_resized_crop_with_bbox_op_edge(False)
|
||||||
|
test_c_random_resized_crop_with_bbox_op_invalid()
|
||||||
|
test_c_random_resized_crop_with_bbox_op_invalid2()
|
||||||
|
test_c_random_resized_crop_with_bbox_op_bad()
|
|
@ -0,0 +1,360 @@
|
||||||
|
# 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
|
||||||
|
"""
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.patches as patches
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# updated VOC dataset with correct annotations
|
||||||
|
DATA_DIR = "../data/dataset/testVOC2012_2"
|
||||||
|
|
||||||
|
|
||||||
|
def fix_annotate(bboxes):
|
||||||
|
"""
|
||||||
|
Update Current VOC dataset format to Proposed HQ BBox format
|
||||||
|
|
||||||
|
:param bboxes: in [label, x_min, y_min, w, h, truncate, difficult] format
|
||||||
|
:return: annotation in [x_min, y_min, w, h, label, truncate, difficult] format
|
||||||
|
"""
|
||||||
|
for bbox in bboxes:
|
||||||
|
tmp = bbox[0]
|
||||||
|
bbox[0] = bbox[1]
|
||||||
|
bbox[1] = bbox[2]
|
||||||
|
bbox[2] = bbox[3]
|
||||||
|
bbox[3] = bbox[4]
|
||||||
|
bbox[4] = tmp
|
||||||
|
return bboxes
|
||||||
|
|
||||||
|
|
||||||
|
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')
|
||||||
|
# Add the patch to the Axes
|
||||||
|
ax.add_patch(rect)
|
||||||
|
|
||||||
|
|
||||||
|
def vis_check(orig, aug):
|
||||||
|
if not isinstance(orig, list) or not isinstance(aug, list):
|
||||||
|
return False
|
||||||
|
if len(orig) != len(aug):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def visualize(orig, aug):
|
||||||
|
|
||||||
|
if not vis_check(orig, aug):
|
||||||
|
return
|
||||||
|
|
||||||
|
plotrows = 3
|
||||||
|
compset = int(len(orig)/plotrows)
|
||||||
|
|
||||||
|
orig, aug = np.array(orig), np.array(aug)
|
||||||
|
|
||||||
|
orig = np.split(orig[:compset*plotrows], compset) + [orig[compset*plotrows:]]
|
||||||
|
aug = np.split(aug[:compset*plotrows], compset) + [aug[compset*plotrows:]]
|
||||||
|
|
||||||
|
for ix, allData in enumerate(zip(orig, aug)):
|
||||||
|
base_ix = ix * plotrows # will signal what base level we're on
|
||||||
|
fig, axs = plt.subplots(len(allData[0]), 2)
|
||||||
|
fig.tight_layout(pad=1.5)
|
||||||
|
|
||||||
|
for x, (dataA, dataB) in enumerate(zip(allData[0], allData[1])):
|
||||||
|
cur_ix = base_ix + x
|
||||||
|
|
||||||
|
axs[x, 0].imshow(dataA["image"])
|
||||||
|
add_bounding_boxes(axs[x, 0], dataA["annotation"])
|
||||||
|
axs[x, 0].title.set_text("Original" + str(cur_ix+1))
|
||||||
|
print("Original **\n ", str(cur_ix+1), " :", dataA["annotation"])
|
||||||
|
|
||||||
|
axs[x, 1].imshow(dataB["image"])
|
||||||
|
add_bounding_boxes(axs[x, 1], dataB["annotation"])
|
||||||
|
axs[x, 1].title.set_text("Augmented" + str(cur_ix+1))
|
||||||
|
print("Augmented **\n", str(cur_ix+1), " ", dataB["annotation"], "\n")
|
||||||
|
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
# Functions to pass to Gen for creating invalid bounding boxes
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_neg_xy(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [-50, -50, im_w - 10, im_h - 10]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_overflow_width(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [0, 0, im_w + 10, im_h - 10]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_overflow_height(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [0, 0, im_w - 10, im_h + 10]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_wrong_shape(im, bbox):
|
||||||
|
bbox = np.array([[0, 0, 0]]).astype(bbox.dtype)
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
badGenFuncs = [gen_bad_bbox_neg_xy,
|
||||||
|
gen_bad_bbox_overflow_width,
|
||||||
|
gen_bad_bbox_overflow_height,
|
||||||
|
gen_bad_bbox_wrong_shape]
|
||||||
|
|
||||||
|
|
||||||
|
assertVal = ["min_x",
|
||||||
|
"is out of bounds of the image",
|
||||||
|
"is out of bounds of the image",
|
||||||
|
"4 features"]
|
||||||
|
|
||||||
|
|
||||||
|
# Gen Edge case BBox
|
||||||
|
def gen_bbox_edge(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [0, 0, im_w, im_h]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def c_random_crop_with_bbox_op(plot_vis=False):
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes
|
||||||
|
"""
|
||||||
|
# Load dataset
|
||||||
|
dataVoc1 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train", decode=True, shuffle=False)
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, 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, 512], [200, 200, 200, 200])
|
||||||
|
|
||||||
|
# maps to fix annotations to HQ standard
|
||||||
|
dataVoc1 = dataVoc1.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
# 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(unaugSamp, augSamp)
|
||||||
|
|
||||||
|
|
||||||
|
def c_random_crop_with_bbox_op2(plot_vis=False):
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes
|
||||||
|
With Fill Value
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Load dataset
|
||||||
|
dataVoc1 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train", decode=True, shuffle=False)
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, 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))
|
||||||
|
|
||||||
|
# maps to fix annotations to HQ standard
|
||||||
|
dataVoc1 = dataVoc1.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
# 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(unaugSamp, augSamp)
|
||||||
|
|
||||||
|
|
||||||
|
def c_random_crop_with_bbox_op3(plot_vis=False):
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes
|
||||||
|
With Padding Mode passed
|
||||||
|
"""
|
||||||
|
# Load dataset
|
||||||
|
dataVoc1 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train", decode=True, shuffle=False)
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, 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 fix annotations to HQ standard
|
||||||
|
dataVoc1 = dataVoc1.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
# 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(unaugSamp, augSamp)
|
||||||
|
|
||||||
|
|
||||||
|
def c_random_crop_with_bbox_op_edge(plot_vis=False):
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes
|
||||||
|
Testing for an Edge case
|
||||||
|
"""
|
||||||
|
# Load dataset
|
||||||
|
dataVoc1 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train", decode=True, shuffle=False)
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, 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 fix annotations to HQ standard
|
||||||
|
dataVoc1 = dataVoc1.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
|
||||||
|
# Modify BBoxes to serve as valid edge cases
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"],
|
||||||
|
output_columns=["image", "annotation"],
|
||||||
|
columns_order=["image", "annotation"],
|
||||||
|
operations=[gen_bbox_edge])
|
||||||
|
|
||||||
|
# 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(unaugSamp, augSamp)
|
||||||
|
|
||||||
|
|
||||||
|
def c_random_crop_with_bbox_op_invalid():
|
||||||
|
"""
|
||||||
|
Checking for invalid params passed to Aug Constructor
|
||||||
|
"""
|
||||||
|
# Load dataset
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, 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])
|
||||||
|
|
||||||
|
# maps to fix annotations to HQ standard
|
||||||
|
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
|
||||||
|
# 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 c_random_crop_with_bbox_op_bad():
|
||||||
|
# Should Fail - Errors logged to logger
|
||||||
|
for ix, badFunc in enumerate(badGenFuncs):
|
||||||
|
try:
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
test_op = c_vision.RandomCropWithBBox([512, 512], [200, 200, 200, 200])
|
||||||
|
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"],
|
||||||
|
output_columns=["image", "annotation"],
|
||||||
|
columns_order=["image", "annotation"],
|
||||||
|
operations=[badFunc])
|
||||||
|
|
||||||
|
# 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 # first sample will cause exception
|
||||||
|
|
||||||
|
except RuntimeError as err:
|
||||||
|
logger.info("Got an exception in DE: {}".format(str(err)))
|
||||||
|
assert assertVal[ix] in str(err)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
c_random_crop_with_bbox_op(False)
|
||||||
|
c_random_crop_with_bbox_op2(False)
|
||||||
|
c_random_crop_with_bbox_op3(False)
|
||||||
|
c_random_crop_with_bbox_op_edge(False)
|
||||||
|
c_random_crop_with_bbox_op_invalid()
|
||||||
|
c_random_crop_with_bbox_op_bad()
|
|
@ -0,0 +1,326 @@
|
||||||
|
# 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
|
||||||
|
"""
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib.patches as patches
|
||||||
|
|
||||||
|
import mindspore.dataset as ds
|
||||||
|
import mindspore.dataset.transforms.vision.c_transforms as c_vision
|
||||||
|
|
||||||
|
from mindspore import log as logger
|
||||||
|
|
||||||
|
# updated VOC dataset with correct annotations
|
||||||
|
DATA_DIR = "../data/dataset/testVOC2012_2"
|
||||||
|
|
||||||
|
|
||||||
|
def fix_annotate(bboxes):
|
||||||
|
"""
|
||||||
|
Update Current VOC dataset format to Proposed HQ BBox format
|
||||||
|
|
||||||
|
:param bboxes: as [label, x_min, y_min, w, h, truncate, difficult]
|
||||||
|
:return: annotation as [x_min, y_min, w, h, label, truncate, difficult]
|
||||||
|
"""
|
||||||
|
for bbox in bboxes:
|
||||||
|
tmp = bbox[0]
|
||||||
|
bbox[0] = bbox[1]
|
||||||
|
bbox[1] = bbox[2]
|
||||||
|
bbox[2] = bbox[3]
|
||||||
|
bbox[3] = bbox[4]
|
||||||
|
bbox[4] = tmp
|
||||||
|
return bboxes
|
||||||
|
|
||||||
|
|
||||||
|
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')
|
||||||
|
# Add the patch to the Axes
|
||||||
|
ax.add_patch(rect)
|
||||||
|
|
||||||
|
|
||||||
|
def vis_check(orig, aug):
|
||||||
|
if not isinstance(orig, list) or not isinstance(aug, list):
|
||||||
|
return False
|
||||||
|
if len(orig) != len(aug):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def visualize(orig, aug):
|
||||||
|
|
||||||
|
if not vis_check(orig, aug):
|
||||||
|
return
|
||||||
|
|
||||||
|
plotrows = 3
|
||||||
|
compset = int(len(orig)/plotrows)
|
||||||
|
|
||||||
|
orig, aug = np.array(orig), np.array(aug)
|
||||||
|
|
||||||
|
orig = np.split(orig[:compset*plotrows], compset) + [orig[compset*plotrows:]]
|
||||||
|
aug = np.split(aug[:compset*plotrows], compset) + [aug[compset*plotrows:]]
|
||||||
|
|
||||||
|
for ix, allData in enumerate(zip(orig, aug)):
|
||||||
|
base_ix = ix * plotrows # will signal what base level we're on
|
||||||
|
fig, axs = plt.subplots(len(allData[0]), 2)
|
||||||
|
fig.tight_layout(pad=1.5)
|
||||||
|
|
||||||
|
for x, (dataA, dataB) in enumerate(zip(allData[0], allData[1])):
|
||||||
|
cur_ix = base_ix + x
|
||||||
|
|
||||||
|
axs[x, 0].imshow(dataA["image"])
|
||||||
|
add_bounding_boxes(axs[x, 0], dataA["annotation"])
|
||||||
|
axs[x, 0].title.set_text("Original" + str(cur_ix+1))
|
||||||
|
print("Original **\n ", str(cur_ix+1), " :", dataA["annotation"])
|
||||||
|
|
||||||
|
axs[x, 1].imshow(dataB["image"])
|
||||||
|
add_bounding_boxes(axs[x, 1], dataB["annotation"])
|
||||||
|
axs[x, 1].title.set_text("Augmented" + str(cur_ix+1))
|
||||||
|
print("Augmented **\n", str(cur_ix+1), " ", dataB["annotation"], "\n")
|
||||||
|
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
# Functions to pass to Gen for creating invalid bounding boxes
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_neg_xy(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [-50, -50, im_w - 10, im_h - 10]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_overflow_width(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [0, 0, im_w + 10, im_h - 10]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_overflow_height(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [0, 0, im_w - 10, im_h + 10]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bad_bbox_wrong_shape(im, bbox):
|
||||||
|
bbox = np.array([[0, 0, 0]]).astype(bbox.dtype)
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
badGenFuncs = [gen_bad_bbox_neg_xy,
|
||||||
|
gen_bad_bbox_overflow_width,
|
||||||
|
gen_bad_bbox_overflow_height,
|
||||||
|
gen_bad_bbox_wrong_shape]
|
||||||
|
|
||||||
|
assertVal = ["min_x",
|
||||||
|
"is out of bounds of the image",
|
||||||
|
"is out of bounds of the image",
|
||||||
|
"4 features"]
|
||||||
|
|
||||||
|
|
||||||
|
# Gen Edge case BBox
|
||||||
|
def gen_bbox_edge(im, bbox):
|
||||||
|
im_h, im_w = im.shape[0], im.shape[1]
|
||||||
|
bbox[0][:4] = [0, 0, im_w, im_h]
|
||||||
|
return im, bbox
|
||||||
|
|
||||||
|
|
||||||
|
def c_random_vertical_flip_with_bbox_op(plot_vis=False):
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes to
|
||||||
|
compare and test
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Load dataset
|
||||||
|
dataVoc1 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
test_op = c_vision.RandomVerticalFlipWithBBox(1)
|
||||||
|
|
||||||
|
# maps to fix annotations to HQ standard
|
||||||
|
dataVoc1 = dataVoc1.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
# 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(unaugSamp, augSamp)
|
||||||
|
|
||||||
|
|
||||||
|
def c_random_vertical_flip_with_bbox_op_rand(plot_vis=False):
|
||||||
|
"""
|
||||||
|
Prints images side by side with and without Aug applied + bboxes to
|
||||||
|
compare and test
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Load dataset
|
||||||
|
dataVoc1 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
test_op = c_vision.RandomVerticalFlipWithBBox(0.6)
|
||||||
|
|
||||||
|
# maps to fix annotations to HQ standard
|
||||||
|
dataVoc1 = dataVoc1.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
# 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(unaugSamp, augSamp)
|
||||||
|
|
||||||
|
|
||||||
|
def c_random_vertical_flip_with_bbox_op_edge(plot_vis=False):
|
||||||
|
# Should Pass
|
||||||
|
# Load dataset
|
||||||
|
dataVoc1 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
test_op = c_vision.RandomVerticalFlipWithBBox(0.6)
|
||||||
|
|
||||||
|
# maps to fix annotations to HQ standard
|
||||||
|
dataVoc1 = dataVoc1.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
|
||||||
|
# Modify BBoxes to serve as valid edge cases
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"],
|
||||||
|
output_columns=["image", "annotation"],
|
||||||
|
columns_order=["image", "annotation"],
|
||||||
|
operations=[gen_bbox_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(unaugSamp, augSamp)
|
||||||
|
|
||||||
|
|
||||||
|
def c_random_vertical_flip_with_bbox_op_invalid():
|
||||||
|
# Should Fail
|
||||||
|
# Load dataset
|
||||||
|
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
test_op = c_vision.RandomVerticalFlipWithBBox(2)
|
||||||
|
|
||||||
|
# maps to fix annotations to HQ standard
|
||||||
|
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
# 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 c_random_vertical_flip_with_bbox_op_bad():
|
||||||
|
# Should Fail - Errors logged to logger
|
||||||
|
for ix, badFunc in enumerate(badGenFuncs):
|
||||||
|
try:
|
||||||
|
dataVoc2 = ds.VOCDataset(DATA_DIR, task="Detection", mode="train",
|
||||||
|
decode=True, shuffle=False)
|
||||||
|
|
||||||
|
test_op = c_vision.RandomVerticalFlipWithBBox(1)
|
||||||
|
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["annotation"],
|
||||||
|
output_columns=["annotation"],
|
||||||
|
operations=fix_annotate)
|
||||||
|
|
||||||
|
dataVoc2 = dataVoc2.map(input_columns=["image", "annotation"],
|
||||||
|
output_columns=["image", "annotation"],
|
||||||
|
columns_order=["image", "annotation"],
|
||||||
|
operations=[badFunc])
|
||||||
|
|
||||||
|
# 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 # first sample will cause exception
|
||||||
|
|
||||||
|
except RuntimeError as err:
|
||||||
|
logger.info("Got an exception in DE: {}".format(str(err)))
|
||||||
|
assert assertVal[ix] in str(err)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
c_random_vertical_flip_with_bbox_op(False)
|
||||||
|
c_random_vertical_flip_with_bbox_op_rand(False)
|
||||||
|
c_random_vertical_flip_with_bbox_op_edge(False)
|
||||||
|
c_random_vertical_flip_with_bbox_op_invalid()
|
||||||
|
c_random_vertical_flip_with_bbox_op_bad()
|
Loading…
Reference in New Issue