adding bbox class
This commit is contained in:
parent
13d1738ff3
commit
641e751d5e
|
@ -4,6 +4,7 @@ add_subdirectory(soft_dvpp)
|
|||
add_library(kernels-image OBJECT
|
||||
affine_op.cc
|
||||
auto_contrast_op.cc
|
||||
bounding_box.cc
|
||||
center_crop_op.cc
|
||||
crop_op.cc
|
||||
cut_out_op.cc
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/**
|
||||
* Copyright 2020 Huawei Technologies Co., Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "minddata/dataset/kernels/image/bounding_box.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
|
||||
const uint8_t kNumOfCols = 4;
|
||||
|
||||
BoundingBox::BoundingBox(bbox_float x, bbox_float y, bbox_float width, bbox_float height)
|
||||
: x_(x), y_(y), width_(width), height_(height) {}
|
||||
|
||||
Status BoundingBox::ReadFromTensor(const TensorPtr &bbox_tensor, dsize_t index_of_bbox,
|
||||
std::shared_ptr<BoundingBox> *bbox_out) {
|
||||
bbox_float x;
|
||||
bbox_float y;
|
||||
bbox_float width;
|
||||
bbox_float height;
|
||||
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&x, {index_of_bbox, 0}));
|
||||
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&y, {index_of_bbox, 1}));
|
||||
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&width, {index_of_bbox, 2}));
|
||||
RETURN_IF_NOT_OK(bbox_tensor->GetItemAt<bbox_float>(&height, {index_of_bbox, 3}));
|
||||
*bbox_out = std::make_shared<BoundingBox>(x, y, width, height);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status BoundingBox::ValidateBoundingBoxes(const TensorRow &image_and_bbox) {
|
||||
if (image_and_bbox.size() != 2) {
|
||||
return Status(StatusCode::kBoundingBoxInvalidShape, __LINE__, __FILE__,
|
||||
"Requires Image and Bounding Boxes, likely missed bounding boxes.");
|
||||
}
|
||||
if (image_and_bbox[1]->shape().Size() < 2) {
|
||||
return Status(StatusCode::kBoundingBoxInvalidShape, __LINE__, __FILE__,
|
||||
"Bounding boxes shape should have at least two dimensions.");
|
||||
}
|
||||
uint32_t num_of_features = image_and_bbox[1]->shape()[1];
|
||||
if (num_of_features < 4) {
|
||||
return Status(StatusCode::kBoundingBoxInvalidShape, __LINE__, __FILE__,
|
||||
"Bounding boxes should be have at least 4 features.");
|
||||
}
|
||||
std::vector<std::shared_ptr<BoundingBox>> bbox_list;
|
||||
RETURN_IF_NOT_OK(GetListOfBoundingBoxes(image_and_bbox[1], &bbox_list));
|
||||
uint32_t img_h = image_and_bbox[0]->shape()[0];
|
||||
uint32_t img_w = image_and_bbox[0]->shape()[1];
|
||||
for (auto &bbox : bbox_list) {
|
||||
if ((bbox->x() + bbox->width() > img_w) || (bbox->y() + bbox->height() > img_h)) {
|
||||
return Status(StatusCode::kBoundingBoxOutOfBounds, __LINE__, __FILE__,
|
||||
"At least one of the bounding boxes is out of bounds of the image.");
|
||||
}
|
||||
if (static_cast<int>(bbox->x()) < 0 || static_cast<int>(bbox->y()) < 0) {
|
||||
return Status(StatusCode::kBoundingBoxOutOfBounds, __LINE__, __FILE__,
|
||||
"At least one of the bounding boxes has negative min_x or min_y.");
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status BoundingBox::WriteToTensor(const TensorPtr &bbox_tensor, dsize_t index_of_bbox) {
|
||||
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 0}, x_));
|
||||
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 1}, y_));
|
||||
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 2}, width_));
|
||||
RETURN_IF_NOT_OK(bbox_tensor->SetItemAt<bbox_float>({index_of_bbox, 3}, height_));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status BoundingBox::GetListOfBoundingBoxes(const TensorPtr &bbox_tensor,
|
||||
std::vector<std::shared_ptr<BoundingBox>> *bbox_out) {
|
||||
dsize_t num_of_boxes = bbox_tensor->shape()[0];
|
||||
for (dsize_t i = 0; i < num_of_boxes; i++) {
|
||||
std::shared_ptr<BoundingBox> bbox;
|
||||
RETURN_IF_NOT_OK(ReadFromTensor(bbox_tensor, i, &bbox));
|
||||
bbox_out->push_back(bbox);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status BoundingBox::CreateTensorFromBoundingBoxList(const std::vector<std::shared_ptr<BoundingBox>> &bboxes,
|
||||
TensorPtr *tensor_out) {
|
||||
dsize_t num_of_boxes = bboxes.size();
|
||||
std::vector<bbox_float> bboxes_for_tensor;
|
||||
for (dsize_t i = 0; i < num_of_boxes; i++) {
|
||||
bbox_float b_data[kNumOfCols] = {bboxes[i]->x(), bboxes[i]->y(), bboxes[i]->width(), bboxes[i]->height()};
|
||||
bboxes_for_tensor.insert(bboxes_for_tensor.end(), b_data, b_data + kNumOfCols);
|
||||
}
|
||||
RETURN_IF_NOT_OK(Tensor::CreateFromVector(bboxes_for_tensor, TensorShape{num_of_boxes, kNumOfCols}, tensor_out));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status BoundingBox::PadBBoxes(const TensorPtr *bbox_list, size_t bbox_count, int32_t pad_top, int32_t pad_left) {
|
||||
for (dsize_t i = 0; i < bbox_count; i++) {
|
||||
std::shared_ptr<BoundingBox> bbox;
|
||||
RETURN_IF_NOT_OK(ReadFromTensor(*bbox_list, i, &bbox));
|
||||
bbox->SetX(bbox->x() + pad_left);
|
||||
bbox->SetY(bbox->y() + pad_top);
|
||||
RETURN_IF_NOT_OK(bbox->WriteToTensor(*bbox_list, i));
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status BoundingBox::UpdateBBoxesForCrop(TensorPtr *bbox_list, size_t *bbox_count, int32_t CB_Xmin, int32_t CB_Ymin,
|
||||
int32_t CB_Xmax, int32_t CB_Ymax) {
|
||||
// PASS LIST, COUNT OF BOUNDING BOXES
|
||||
// Also PAss X/Y Min/Max of image cropped region - normally obtained from 'GetCropBox' functions
|
||||
std::vector<dsize_t> correct_ind;
|
||||
std::vector<bbox_float> copyVals;
|
||||
bool retFlag = false; // true unless overlap found
|
||||
dsize_t bboxDim = (*bbox_list)->shape()[1];
|
||||
for (dsize_t i = 0; i < *bbox_count; i++) {
|
||||
std::shared_ptr<BoundingBox> bbox;
|
||||
RETURN_IF_NOT_OK(ReadFromTensor(*bbox_list, i, &bbox));
|
||||
bbox_float bb_Xmax = bbox->x() + bbox->width();
|
||||
bbox_float bb_Ymax = bbox->y() + bbox->height();
|
||||
// check for image / BB overlap
|
||||
if (((bbox->x() > CB_Xmax) || (bbox->y() > CB_Ymax)) || ((bb_Xmax < CB_Xmin) || (bb_Ymax < CB_Ymin))) {
|
||||
continue; // no overlap found
|
||||
}
|
||||
// Update this bbox and select it to move to the final output tensor
|
||||
correct_ind.push_back(i);
|
||||
// adjust BBox corners by bringing into new CropBox if beyond
|
||||
// Also reseting/adjusting for boxes to lie within CropBox instead of Image - subtract CropBox Xmin/YMin
|
||||
|
||||
bbox_float bb_Xmin = bbox->x() - std::min(static_cast<bbox_float>(0.0), (bbox->x() - CB_Xmin)) - CB_Xmin;
|
||||
bbox_float bb_Ymin = bbox->y() - std::min(static_cast<bbox_float>(0.0), (bbox->y() - CB_Ymin)) - CB_Ymin;
|
||||
bb_Xmax = bb_Xmax - std::max(static_cast<bbox_float>(0.0), (bb_Xmax - CB_Xmax)) - CB_Xmin;
|
||||
bb_Ymax = bb_Ymax - std::max(static_cast<bbox_float>(0.0), (bb_Ymax - CB_Ymax)) - CB_Ymin;
|
||||
|
||||
// bound check for float values
|
||||
bb_Xmin = std::max(bb_Xmin, static_cast<bbox_float>(0));
|
||||
bb_Ymin = std::max(bb_Ymin, static_cast<bbox_float>(0));
|
||||
bb_Xmax = std::min(bb_Xmax, static_cast<bbox_float>(CB_Xmax - CB_Xmin)); // find max value relative to new image
|
||||
bb_Ymax = std::min(bb_Ymax, static_cast<bbox_float>(CB_Ymax - CB_Ymin));
|
||||
|
||||
// reset min values and calculate width/height from Box corners
|
||||
bbox->SetX(bb_Xmin);
|
||||
bbox->SetY(bb_Ymin);
|
||||
bbox->SetWidth(bb_Xmax - bb_Xmin);
|
||||
bbox->SetHeight(bb_Ymax - bb_Ymin);
|
||||
RETURN_IF_NOT_OK(bbox->WriteToTensor(*bbox_list, i));
|
||||
}
|
||||
// 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
|
||||
*bbox_count = correct_ind.size();
|
||||
bbox_float temp = 0.0;
|
||||
for (auto slice : correct_ind) { // for every index in the loop
|
||||
for (dsize_t ix = 0; ix < bboxDim; ix++) {
|
||||
RETURN_IF_NOT_OK((*bbox_list)->GetItemAt<bbox_float>(&temp, {slice, ix}));
|
||||
copyVals.push_back(temp);
|
||||
}
|
||||
}
|
||||
std::shared_ptr<Tensor> retV;
|
||||
RETURN_IF_NOT_OK(
|
||||
Tensor::CreateFromVector(copyVals, TensorShape({static_cast<dsize_t>(*bbox_count), bboxDim}), &retV));
|
||||
(*bbox_list) = retV; // reset pointer
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status BoundingBox::UpdateBBoxesForResize(const TensorPtr &bbox_list, size_t bbox_count, int32_t target_width,
|
||||
int32_t target_height, int32_t orig_width, int32_t orig_height) {
|
||||
// cast to float to preserve fractional
|
||||
bbox_float W_aspRatio = (target_width * 1.0) / (orig_width * 1.0);
|
||||
bbox_float H_aspRatio = (target_height * 1.0) / (orig_height * 1.0);
|
||||
for (dsize_t i = 0; i < bbox_count; i++) {
|
||||
// for each bounding box
|
||||
std::shared_ptr<BoundingBox> bbox;
|
||||
RETURN_IF_NOT_OK(ReadFromTensor(bbox_list, i, &bbox));
|
||||
// update positions and widths
|
||||
bbox->SetX(bbox->x() * W_aspRatio);
|
||||
bbox->SetY(bbox->y() * H_aspRatio);
|
||||
bbox->SetWidth(bbox->width() * W_aspRatio);
|
||||
bbox->SetHeight(bbox->height() * H_aspRatio);
|
||||
// reset bounding box values
|
||||
bbox->WriteToTensor(bbox_list, i);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* Copyright 2020 Huawei Technologies Co., Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_BOUNDING_BOX_H_
|
||||
#define MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_BOUNDING_BOX_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "minddata/dataset/core/tensor.h"
|
||||
#include "minddata/dataset/core/tensor_row.h"
|
||||
#include "minddata/dataset/util/status.h"
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
class BoundingBox {
|
||||
public:
|
||||
typedef float_t bbox_float;
|
||||
|
||||
/// \brief Constructor for BoundingBox
|
||||
/// \param[in] x horizontal axis coordinate of bounding box
|
||||
/// \param[in] y vertical axis coordinate of bounding box
|
||||
/// \param[in] width width of bounding box on horizontal axis
|
||||
/// \param[in] height height of bounding box on vertical axis
|
||||
BoundingBox(bbox_float x, bbox_float y, bbox_float width, bbox_float height);
|
||||
|
||||
~BoundingBox() = default;
|
||||
|
||||
/// \brief Provide stream operator for displaying a bounding box.
|
||||
friend std::ostream &operator<<(std::ostream &out, const BoundingBox &bbox) {
|
||||
out << "Bounding Box with (X,Y,W,H): (" << bbox.x_ << "," << bbox.y_ << "," << bbox.width_ << "," << bbox.height_
|
||||
<< ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Getters
|
||||
bbox_float x() { return x_; }
|
||||
bbox_float y() { return y_; }
|
||||
bbox_float width() { return width_; }
|
||||
bbox_float height() { return height_; }
|
||||
|
||||
/// Setters
|
||||
void SetX(bbox_float x) { x_ = x; }
|
||||
void SetY(bbox_float y) { y_ = y; }
|
||||
void SetWidth(bbox_float w) { width_ = w; }
|
||||
void SetHeight(bbox_float h) { height_ = h; }
|
||||
|
||||
/// \brief Set the bounding box data to bbox at a certain index in the tensor.
|
||||
/// \param[in] bbox_tensor tensor containing a list of bounding boxes of shape (m, n) where n >= 4
|
||||
/// and first 4 items of each row are x,y,w,h of the bounding box
|
||||
/// \param[in] index_of_bbox index of bounding box to set to tensor
|
||||
/// \returns Status status of bounding box set
|
||||
Status WriteToTensor(const TensorPtr &bbox_tensor, dsize_t index_of_bbox = 0);
|
||||
|
||||
/// \brief Create a bounding box object from an item at a certain index in a tensor.
|
||||
/// \param[in] bbox_tensor tensor containing a list of bounding boxes of shape (m, n) where n >= 4
|
||||
/// and first 4 items of each row are x,y,w,h of the bounding box
|
||||
/// \param[in] index_of_bbox index of bounding box to fetch from the tensor
|
||||
/// \param[out] bbox_out output bounding box
|
||||
/// \returns Status status of bounding box fetch
|
||||
static Status ReadFromTensor(const TensorPtr &bbox_tensor, dsize_t index_of_bbox,
|
||||
std::shared_ptr<BoundingBox> *bbox_out);
|
||||
|
||||
/// \brief Validate a list of bounding boxes with respect to an image.
|
||||
/// \param[in] image_and_bbox tensor containing a list of bounding boxes of shape (m, n) where n >= 4
|
||||
/// and first 4 items of each row are x,y,w,h of the bounding box and an image of shape (H, W, C) or (H, W)
|
||||
/// \returns Status status of bounding box fetch
|
||||
static Status ValidateBoundingBoxes(const TensorRow &image_and_bbox);
|
||||
|
||||
/// \brief Get a list of bounding boxes from a tensor.
|
||||
/// \param[in] bbox_tensor tensor containing a list of bounding boxes of shape (m, n) where n >= 4
|
||||
/// and first 4 items of each row are x,y,w,h of the bounding box
|
||||
/// \param[out] bbox_out output vector of bounding boxes
|
||||
/// \returns Status status of bounding box list fetch
|
||||
static Status GetListOfBoundingBoxes(const TensorPtr &bbox_tensor,
|
||||
std::vector<std::shared_ptr<BoundingBox>> *bbox_out);
|
||||
|
||||
/// \brief Creates a tensor from a list of bounding boxes.
|
||||
/// \param[in] bboxes list of bounding boxes
|
||||
/// \param[out] tensor_out output tensor
|
||||
/// \returns Status status of tensor creation
|
||||
static Status CreateTensorFromBoundingBoxList(const std::vector<std::shared_ptr<BoundingBox>> &bboxes,
|
||||
TensorPtr *tensor_out);
|
||||
|
||||
/// \brief Updates bounding boxes with required Top and Left padding
|
||||
/// \note Top and Left padding amounts required to adjust bboxs min X,Y values according to padding 'push'
|
||||
/// Top/Left since images 0,0 coordinate is taken from top left
|
||||
/// \param bboxList: A tensor contaning bounding box tensors
|
||||
/// \param bboxCount: total Number of bounding boxes - required within caller function to run update loop
|
||||
/// \param pad_top: Total amount of padding applied to image top
|
||||
/// \param pad_left: Total amount of padding applied to image left side
|
||||
static Status PadBBoxes(const TensorPtr *bbox_list, size_t bbox_count, int32_t pad_top, int32_t pad_left);
|
||||
|
||||
/// \brief Updates and checks bounding boxes for new cropped region of image
|
||||
/// \param bbox_list: A tensor contaning bounding box tensors
|
||||
/// \param bbox_count: total Number of bounding boxes - required within caller function to run update loop
|
||||
/// \param CB_Xmin: Image's CropBox Xmin coordinate
|
||||
/// \param CB_Xmin: Image's CropBox Ymin coordinate
|
||||
/// \param CB_Xmax: Image's CropBox Xmax coordinate - (Xmin + width)
|
||||
/// \param CB_Xmax: Image's CropBox Ymax coordinate - (Ymin + height)
|
||||
static Status UpdateBBoxesForCrop(TensorPtr *bbox_list, size_t *bbox_count, int32_t CB_Xmin, int32_t CB_Ymin,
|
||||
int32_t CB_Xmax, int32_t CB_Ymax);
|
||||
|
||||
/// \brief Updates bounding boxes for an Image Resize Operation - Takes in set of valid BBoxes
|
||||
/// For e.g those that remain after a crop
|
||||
/// \param bbox_list: A tensor contaning bounding box tensors
|
||||
/// \param bbox_count: total Number of bounding boxes - required within caller function to run update loop
|
||||
/// \param target_width: required width of image post resize
|
||||
/// \param target_height: required height of image post resize
|
||||
/// \param orig_width: current width of image pre resize
|
||||
/// \param orig_height: current height of image pre resize
|
||||
static Status UpdateBBoxesForResize(const TensorPtr &bbox_list, size_t bbox_count, int32_t target_width,
|
||||
int32_t target_height, int32_t orig_width, int32_t orig_height);
|
||||
|
||||
private:
|
||||
bbox_float x_;
|
||||
bbox_float y_;
|
||||
bbox_float width_;
|
||||
bbox_float height_;
|
||||
};
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
|
||||
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_BOUNDING_BOX_H_
|
|
@ -17,6 +17,7 @@
|
|||
#include <vector>
|
||||
#include <utility>
|
||||
#include "minddata/dataset/kernels/image/bounding_box_augment_op.h"
|
||||
#include "minddata/dataset/kernels/image/bounding_box.h"
|
||||
#include "minddata/dataset/kernels/image/resize_op.h"
|
||||
#include "minddata/dataset/kernels/image/image_utils.h"
|
||||
#include "minddata/dataset/core/cv_tensor.h"
|
||||
|
@ -32,7 +33,7 @@ BoundingBoxAugmentOp::BoundingBoxAugmentOp(std::shared_ptr<TensorOp> transform,
|
|||
|
||||
Status BoundingBoxAugmentOp::Compute(const TensorRow &input, TensorRow *output) {
|
||||
IO_CHECK_VECTOR(input, output);
|
||||
BOUNDING_BOX_CHECK(input); // check if bounding boxes are valid
|
||||
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
|
||||
uint32_t num_of_boxes = input[1]->shape()[0];
|
||||
std::shared_ptr<Tensor> crop_out;
|
||||
std::shared_ptr<Tensor> res_out;
|
||||
|
@ -40,31 +41,25 @@ Status BoundingBoxAugmentOp::Compute(const TensorRow &input, TensorRow *output)
|
|||
for (uint32_t i = 0; i < num_of_boxes; i++) {
|
||||
// using a uniform distribution to ensure op happens with probability ratio_
|
||||
if (uniform_(rnd_) < ratio_) {
|
||||
float min_x = 0;
|
||||
float min_y = 0;
|
||||
float b_w = 0;
|
||||
float b_h = 0;
|
||||
// get the required items
|
||||
RETURN_IF_NOT_OK(input[1]->GetItemAt<float>(&min_x, {i, 0}));
|
||||
RETURN_IF_NOT_OK(input[1]->GetItemAt<float>(&min_y, {i, 1}));
|
||||
RETURN_IF_NOT_OK(input[1]->GetItemAt<float>(&b_w, {i, 2}));
|
||||
RETURN_IF_NOT_OK(input[1]->GetItemAt<float>(&b_h, {i, 3}));
|
||||
RETURN_IF_NOT_OK(Crop(input_restore, &crop_out, static_cast<int>(min_x), static_cast<int>(min_y),
|
||||
static_cast<int>(b_w), static_cast<int>(b_h)));
|
||||
std::shared_ptr<BoundingBox> bbox;
|
||||
RETURN_IF_NOT_OK(BoundingBox::ReadFromTensor(input[1], i, &bbox));
|
||||
RETURN_IF_NOT_OK(Crop(input_restore, &crop_out, static_cast<int>(bbox->x()), static_cast<int>(bbox->y()),
|
||||
static_cast<int>(bbox->width()), static_cast<int>(bbox->height())));
|
||||
// transform the cropped bbox region
|
||||
RETURN_IF_NOT_OK(transform_->Compute(crop_out, &res_out));
|
||||
// place the transformed region back in the restored input
|
||||
std::shared_ptr<CVTensor> res_img = CVTensor::AsCVTensor(res_out);
|
||||
// check if transformed crop is out of bounds of the box
|
||||
if (res_img->mat().cols > b_w || res_img->mat().rows > b_h || res_img->mat().cols < b_w ||
|
||||
res_img->mat().rows < b_h) {
|
||||
if (res_img->mat().cols > bbox->width() || res_img->mat().rows > bbox->height() ||
|
||||
res_img->mat().cols < bbox->width() || res_img->mat().rows < bbox->height()) {
|
||||
// if so, resize to fit in the box
|
||||
std::shared_ptr<TensorOp> resize_op =
|
||||
std::make_shared<ResizeOp>(static_cast<int32_t>(b_h), static_cast<int32_t>(b_w));
|
||||
std::make_shared<ResizeOp>(static_cast<int32_t>(bbox->height()), static_cast<int32_t>(bbox->width()));
|
||||
RETURN_IF_NOT_OK(resize_op->Compute(std::static_pointer_cast<Tensor>(res_img), &res_out));
|
||||
res_img = CVTensor::AsCVTensor(res_out);
|
||||
}
|
||||
res_img->mat().copyTo(input_restore->mat()(cv::Rect(min_x, min_y, res_img->mat().cols, res_img->mat().rows)));
|
||||
res_img->mat().copyTo(
|
||||
input_restore->mat()(cv::Rect(bbox->x(), bbox->y(), res_img->mat().cols, res_img->mat().rows)));
|
||||
}
|
||||
}
|
||||
(*output).push_back(std::move(std::static_pointer_cast<Tensor>(input_restore)));
|
||||
|
|
|
@ -950,103 +950,6 @@ Status RgbaToBgr(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *
|
|||
RETURN_STATUS_UNEXPECTED("Unexpected error in RgbaToBgr.");
|
||||
}
|
||||
}
|
||||
// -------- BBOX OPERATIONS -------- //
|
||||
Status UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int CB_Xmin, int CB_Ymin, int CB_Xmax,
|
||||
int CB_Ymax) {
|
||||
// PASS LIST, COUNT OF BOUNDING BOXES
|
||||
// Also PAss X/Y Min/Max of image cropped region - normally obtained from 'GetCropBox' functions
|
||||
float bb_Xmin = 0.0, bb_Ymin = 0.0, bb_Xmax = 0.0, bb_Ymax = 0.0;
|
||||
std::vector<int> correct_ind;
|
||||
std::vector<float> copyVals;
|
||||
dsize_t bboxDim = (*bboxList)->shape()[1];
|
||||
bool retFlag = false; // true unless overlap found
|
||||
for (int i = 0; i < *bboxCount; i++) {
|
||||
RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&bb_Xmin, {i, 0}));
|
||||
RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&bb_Ymin, {i, 1}));
|
||||
RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&bb_Xmax, {i, 2}));
|
||||
RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&bb_Ymax, {i, 3}));
|
||||
bb_Xmax = bb_Xmin + bb_Xmax;
|
||||
bb_Ymax = bb_Ymin + bb_Ymax;
|
||||
// check for image / BB overlap
|
||||
if (((bb_Xmin > CB_Xmax) || (bb_Ymin > CB_Ymax)) || ((bb_Xmax < CB_Xmin) || (bb_Ymax < CB_Ymin))) {
|
||||
continue; // no overlap found
|
||||
}
|
||||
// Update this bbox and select it to move to the final output tensor
|
||||
correct_ind.push_back(i);
|
||||
// adjust BBox corners by bringing into new CropBox if beyond
|
||||
// Also reseting/adjusting for boxes to lie within CropBox instead of Image - subtract CropBox Xmin/YMin
|
||||
|
||||
bb_Xmin = bb_Xmin - std::min(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;
|
||||
|
||||
// bound check for float values
|
||||
bb_Xmin = std::max(bb_Xmin, static_cast<float>(0));
|
||||
bb_Ymin = std::max(bb_Ymin, static_cast<float>(0));
|
||||
bb_Xmax = std::min(bb_Xmax, static_cast<float>(CB_Xmax - CB_Xmin)); // find max value relative to new image
|
||||
bb_Ymax = std::min(bb_Ymax, static_cast<float>(CB_Ymax - CB_Ymin));
|
||||
|
||||
// reset min values and calculate width/height from Box corners
|
||||
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 0}, bb_Xmin));
|
||||
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 1}, bb_Ymin));
|
||||
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 2}, bb_Xmax - bb_Xmin));
|
||||
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 3}, bb_Ymax - bb_Ymin));
|
||||
}
|
||||
// create new tensor and copy over bboxes still valid to the image
|
||||
// bboxes outside of new cropped region are ignored - empty tensor returned in case of none
|
||||
*bboxCount = correct_ind.size();
|
||||
float temp = 0.0;
|
||||
for (auto slice : correct_ind) { // for every index in the loop
|
||||
for (int ix = 0; ix < bboxDim; ix++) {
|
||||
RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&temp, {slice, ix}));
|
||||
copyVals.push_back(temp);
|
||||
}
|
||||
}
|
||||
std::shared_ptr<Tensor> retV;
|
||||
RETURN_IF_NOT_OK(Tensor::CreateFromVector(copyVals, TensorShape({static_cast<dsize_t>(*bboxCount), bboxDim}), &retV));
|
||||
(*bboxList) = retV; // reset pointer
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
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++) {
|
||||
float xMin = 0.0, yMin = 0.0;
|
||||
RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&xMin, {i, 0}));
|
||||
RETURN_IF_NOT_OK((*bboxList)->GetItemAt<float>(&yMin, {i, 1}));
|
||||
xMin += pad_left;
|
||||
yMin += pad_top;
|
||||
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 0}, xMin));
|
||||
RETURN_IF_NOT_OK((*bboxList)->SetItemAt({i, 1}, yMin));
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
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) {
|
||||
float bb_Xmin = 0, bb_Ymin = 0, bb_Xwidth = 0, bb_Ywidth = 0;
|
||||
// cast to float to preserve fractional
|
||||
float W_aspRatio = (target_width_ * 1.0) / (orig_width * 1.0);
|
||||
float H_aspRatio = (target_height_ * 1.0) / (orig_height * 1.0);
|
||||
for (int i = 0; i < bboxCount; i++) {
|
||||
// for each bounding box
|
||||
RETURN_IF_NOT_OK(bboxList->GetItemAt<float>(&bb_Xmin, {i, 0}));
|
||||
RETURN_IF_NOT_OK(bboxList->GetItemAt<float>(&bb_Ymin, {i, 1}));
|
||||
RETURN_IF_NOT_OK(bboxList->GetItemAt<float>(&bb_Xwidth, {i, 2}));
|
||||
RETURN_IF_NOT_OK(bboxList->GetItemAt<float>(&bb_Ywidth, {i, 3}));
|
||||
// update positions and widths
|
||||
bb_Xmin = bb_Xmin * W_aspRatio;
|
||||
bb_Ymin = bb_Ymin * H_aspRatio;
|
||||
bb_Xwidth = bb_Xwidth * W_aspRatio;
|
||||
bb_Ywidth = bb_Ywidth * H_aspRatio;
|
||||
// reset bounding box values
|
||||
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_Xwidth));
|
||||
RETURN_IF_NOT_OK(bboxList->SetItemAt({i, 3}, bb_Ywidth));
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status GetJpegImageInfo(const std::shared_ptr<Tensor> &input, int *img_width, int *img_height) {
|
||||
struct jpeg_decompress_struct cinfo {};
|
||||
|
|
|
@ -262,38 +262,6 @@ Status RgbaToRgb(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *
|
|||
/// \return Status code
|
||||
Status RgbaToBgr(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output);
|
||||
|
||||
/// -------- BBOX OPERATIONS -------- ///
|
||||
/// \brief Updates and checks bounding boxes for new cropped region of image
|
||||
/// \param bboxList: A tensor contaning bounding box tensors
|
||||
/// \param bboxCount: total Number of bounding boxes - required within caller function to run update loop
|
||||
/// \param CB_Xmin: Image's CropBox Xmin coordinate
|
||||
/// \param CB_Xmin: Image's CropBox Ymin coordinate
|
||||
/// \param CB_Xmax: Image's CropBox Xmax coordinate - (Xmin + width)
|
||||
/// \param CB_Xmax: Image's CropBox Ymax coordinate - (Ymin + height)
|
||||
Status UpdateBBoxesForCrop(std::shared_ptr<Tensor> *bboxList, size_t *bboxCount, int CB_Xmin, int CB_Ymin, int CB_Xmax,
|
||||
int CB_Ymax);
|
||||
|
||||
/// \brief Updates bounding boxes with required Top and Left padding
|
||||
/// \note Top and Left padding amounts required to adjust bboxs min X,Y values according to padding 'push'
|
||||
/// Top/Left since images 0,0 coordinate is taken from top left
|
||||
/// \param bboxList: A tensor contaning bounding box tensors
|
||||
/// \param bboxCount: total Number of bounding boxes - required within caller function to run update loop
|
||||
/// \param pad_top: Total amount of padding applied to image top
|
||||
/// \param pad_left: Total amount of padding applied to image left side
|
||||
Status PadBBoxes(const std::shared_ptr<Tensor> *bboxList, const size_t &bboxCount, int32_t pad_top, int32_t pad_left);
|
||||
|
||||
/// \brief Updates bounding boxes for an Image Resize Operation - Takes in set of valid BBoxes
|
||||
/// For e.g those that remain after a crop
|
||||
/// \param bboxList: A tensor contaning bounding box tensors
|
||||
/// \param bboxCount: total Number of bounding boxes - required within caller function to run update loop
|
||||
/// \param bboxList: A tensor contaning bounding box tensors
|
||||
/// \param target_width_: required width of image post resize
|
||||
/// \param target_width_: required height of image post resize
|
||||
/// \param orig_width: current width of image pre resize
|
||||
/// \param orig_height: current height of image pre resize
|
||||
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);
|
||||
|
||||
/// \brief Get jpeg image width and height
|
||||
/// \param input: CVTensor containing the not decoded image 1D bytes
|
||||
/// \param img_width: the jpeg image width
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "minddata/dataset/util/random.h"
|
||||
#include "minddata/dataset/util/status.h"
|
||||
#include "minddata/dataset/kernels/image/bounding_box.h"
|
||||
#include "minddata/dataset/kernels/image/image_utils.h"
|
||||
#include "minddata/dataset/kernels/image/random_crop_and_resize_with_bbox_op.h"
|
||||
|
||||
|
@ -27,8 +28,8 @@ namespace dataset {
|
|||
|
||||
Status RandomCropAndResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
|
||||
IO_CHECK_VECTOR(input, output);
|
||||
BOUNDING_BOX_CHECK(input);
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(input[0]->shape().Size() >= 2, "The shape of input is abnormal");
|
||||
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(input[0]->shape().Size() >= 2, "The shape of input is not >= 2");
|
||||
|
||||
output->resize(2);
|
||||
(*output)[1] = std::move(input[1]); // move boxes over to output
|
||||
|
@ -46,12 +47,12 @@ Status RandomCropAndResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow
|
|||
int maxX = x + crop_width; // max dims of selected CropBox on image
|
||||
int maxY = y + crop_height;
|
||||
|
||||
RETURN_IF_NOT_OK(UpdateBBoxesForCrop(&(*output)[1], &bboxCount, x, y, maxX, maxY)); // IMAGE_UTIL
|
||||
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForCrop(&(*output)[1], &bboxCount, x, y, maxX, maxY)); // IMAGE_UTIL
|
||||
RETURN_IF_NOT_OK(CropAndResize(input[0], &(*output)[0], x, y, crop_height, crop_width, target_height_, target_width_,
|
||||
interpolation_));
|
||||
|
||||
RETURN_IF_NOT_OK(
|
||||
UpdateBBoxesForResize((*output)[1], bboxCount, target_width_, target_height_, crop_width, crop_height));
|
||||
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForResize((*output)[1], bboxCount, target_width_, target_height_,
|
||||
crop_width, crop_height));
|
||||
return Status::OK();
|
||||
}
|
||||
} // namespace dataset
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <utility>
|
||||
|
||||
#include "minddata/dataset/kernels/image/random_crop_with_bbox_op.h"
|
||||
#include "minddata/dataset/kernels/image/bounding_box.h"
|
||||
#include "minddata/dataset/kernels/image/image_utils.h"
|
||||
#include "minddata/dataset/util/random.h"
|
||||
#include "minddata/dataset/util/status.h"
|
||||
|
@ -27,7 +28,7 @@ namespace mindspore {
|
|||
namespace dataset {
|
||||
Status RandomCropWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
|
||||
IO_CHECK_VECTOR(input, output);
|
||||
BOUNDING_BOX_CHECK(input);
|
||||
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
|
||||
|
||||
std::shared_ptr<Tensor> pad_image;
|
||||
int32_t t_pad_top, t_pad_bottom, t_pad_left, t_pad_right;
|
||||
|
@ -46,7 +47,7 @@ Status RandomCropWithBBoxOp::Compute(const TensorRow &input, TensorRow *output)
|
|||
|
||||
// update bounding boxes with new values based on relevant image padding
|
||||
if (t_pad_left || t_pad_bottom) {
|
||||
RETURN_IF_NOT_OK(PadBBoxes(&(*output)[1], boxCount, t_pad_left, t_pad_top));
|
||||
RETURN_IF_NOT_OK(BoundingBox::PadBBoxes(&(*output)[1], boxCount, t_pad_left, t_pad_top));
|
||||
}
|
||||
if (!crop_further) {
|
||||
// no further cropping required
|
||||
|
@ -59,7 +60,7 @@ Status RandomCropWithBBoxOp::Compute(const TensorRow &input, TensorRow *output)
|
|||
RandomCropOp::GenRandomXY(&x, &y, padded_image_w, padded_image_h);
|
||||
int maxX = x + RandomCropOp::crop_width_; // max dims of selected CropBox on image
|
||||
int maxY = y + RandomCropOp::crop_height_;
|
||||
RETURN_IF_NOT_OK(UpdateBBoxesForCrop(&(*output)[1], &boxCount, x, y, maxX, maxY));
|
||||
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForCrop(&(*output)[1], &boxCount, x, y, maxX, maxY));
|
||||
return Crop(pad_image, &(*output)[0], x, y, RandomCropOp::crop_width_, RandomCropOp::crop_height_);
|
||||
}
|
||||
} // namespace dataset
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
#include <utility>
|
||||
#include "minddata/dataset/kernels/image/random_horizontal_flip_with_bbox_op.h"
|
||||
#include "minddata/dataset/kernels/image/bounding_box.h"
|
||||
#include "minddata/dataset/kernels/image/image_utils.h"
|
||||
#include "minddata/dataset/util/status.h"
|
||||
#include "minddata/dataset/core/cv_tensor.h"
|
||||
|
@ -25,22 +26,21 @@ const float RandomHorizontalFlipWithBBoxOp::kDefProbability = 0.5;
|
|||
|
||||
Status RandomHorizontalFlipWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
|
||||
IO_CHECK_VECTOR(input, output);
|
||||
BOUNDING_BOX_CHECK(input);
|
||||
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
|
||||
if (distribution_(rnd_)) {
|
||||
// To test bounding boxes algorithm, create random bboxes from image dims
|
||||
size_t num_of_boxes = input[1]->shape()[0]; // set to give number of bboxes
|
||||
float img_center = (input[0]->shape()[1] / 2.); // get the center of the image
|
||||
for (int i = 0; i < num_of_boxes; i++) {
|
||||
float b_w = 0; // bounding box width
|
||||
float min_x = 0;
|
||||
// get the required items
|
||||
RETURN_IF_NOT_OK(input[1]->GetItemAt<float>(&min_x, {i, 0}));
|
||||
RETURN_IF_NOT_OK(input[1]->GetItemAt<float>(&b_w, {i, 2}));
|
||||
std::shared_ptr<BoundingBox> bbox;
|
||||
RETURN_IF_NOT_OK(BoundingBox::ReadFromTensor(input[1], i, &bbox));
|
||||
// do the flip
|
||||
float diff = img_center - min_x; // get distance from min_x to center
|
||||
float refl_min_x = diff + img_center; // get reflection of min_x
|
||||
float new_min_x = refl_min_x - b_w; // subtract from the reflected min_x to get the new one
|
||||
RETURN_IF_NOT_OK(input[1]->SetItemAt<float>({i, 0}, new_min_x));
|
||||
BoundingBox::bbox_float diff = img_center - bbox->x(); // get distance from min_x to center
|
||||
BoundingBox::bbox_float refl_min_x = diff + img_center; // get reflection of min_x
|
||||
BoundingBox::bbox_float new_min_x =
|
||||
refl_min_x - bbox->width(); // subtract from the reflected min_x to get the new one
|
||||
bbox->SetX(new_min_x);
|
||||
RETURN_IF_NOT_OK(bbox->WriteToTensor(input[1], i));
|
||||
}
|
||||
(*output).resize(2);
|
||||
// move input to output pointer of bounding boxes
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <utility>
|
||||
|
||||
#include "minddata/dataset/util/status.h"
|
||||
#include "minddata/dataset/kernels/image/bounding_box.h"
|
||||
#include "minddata/dataset/kernels/image/image_utils.h"
|
||||
#include "minddata/dataset/kernels/image/random_vertical_flip_with_bbox_op.h"
|
||||
|
||||
|
@ -25,7 +26,7 @@ namespace dataset {
|
|||
const float RandomVerticalFlipWithBBoxOp::kDefProbability = 0.5;
|
||||
Status RandomVerticalFlipWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
|
||||
IO_CHECK_VECTOR(input, output);
|
||||
BOUNDING_BOX_CHECK(input);
|
||||
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
|
||||
|
||||
if (distribution_(rnd_)) {
|
||||
dsize_t imHeight = input[0]->shape()[0];
|
||||
|
@ -34,14 +35,13 @@ Status RandomVerticalFlipWithBBoxOp::Compute(const TensorRow &input, TensorRow *
|
|||
// one time allocation -> updated in the loop
|
||||
// type defined based on VOC test dataset
|
||||
for (int i = 0; i < boxCount; i++) {
|
||||
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
|
||||
std::shared_ptr<BoundingBox> bbox;
|
||||
RETURN_IF_NOT_OK(BoundingBox::ReadFromTensor(input[1], i, &bbox));
|
||||
|
||||
// subtract (curCorner + height) from (max) for new Corner position
|
||||
newBoxCorner_y = (imHeight - 1.0) - ((boxCorner_y + boxHeight) - 1.0);
|
||||
RETURN_IF_NOT_OK(input[1]->SetItemAt({i, 1}, newBoxCorner_y));
|
||||
BoundingBox::bbox_float newBoxCorner_y = (imHeight - 1.0) - ((bbox->y() + bbox->height()) - 1.0);
|
||||
bbox->SetY(newBoxCorner_y);
|
||||
RETURN_IF_NOT_OK(bbox->WriteToTensor(input[1], i));
|
||||
}
|
||||
|
||||
output->resize(2);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <utility>
|
||||
#include <memory>
|
||||
#include "minddata/dataset/kernels/image/resize_op.h"
|
||||
#include "minddata/dataset/kernels/image/bounding_box.h"
|
||||
#include "minddata/dataset/kernels/image/image_utils.h"
|
||||
#include "minddata/dataset/core/cv_tensor.h"
|
||||
#include "minddata/dataset/core/tensor.h"
|
||||
|
@ -29,7 +30,7 @@ namespace dataset {
|
|||
|
||||
Status ResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
|
||||
IO_CHECK_VECTOR(input, output);
|
||||
BOUNDING_BOX_CHECK(input);
|
||||
RETURN_IF_NOT_OK(BoundingBox::ValidateBoundingBoxes(input));
|
||||
|
||||
int32_t input_h = input[0]->shape()[0];
|
||||
int32_t input_w = input[0]->shape()[1];
|
||||
|
@ -45,7 +46,7 @@ Status ResizeWithBBoxOp::Compute(const TensorRow &input, TensorRow *output) {
|
|||
int32_t output_w = (*output)[0]->shape()[1]; // output width if ResizeWithBBox
|
||||
|
||||
size_t bboxCount = input[1]->shape()[0]; // number of rows in bbox tensor
|
||||
RETURN_IF_NOT_OK(UpdateBBoxesForResize((*output)[1], bboxCount, output_w, output_h, input_w, input_h));
|
||||
RETURN_IF_NOT_OK(BoundingBox::UpdateBBoxesForResize((*output)[1], bboxCount, output_w, output_h, input_w, input_h));
|
||||
return Status::OK();
|
||||
}
|
||||
} // namespace dataset
|
||||
|
|
|
@ -43,46 +43,6 @@
|
|||
} \
|
||||
} while (false)
|
||||
|
||||
#define BOUNDING_BOX_CHECK(input) \
|
||||
do { \
|
||||
if (input.size() != 2) { \
|
||||
return Status(StatusCode::kBoundingBoxInvalidShape, __LINE__, __FILE__, \
|
||||
"Requires Image and Bounding Boxes, likely missed bounding boxes."); \
|
||||
} \
|
||||
if (input[1]->shape().Size() < 2) { \
|
||||
return Status(StatusCode::kBoundingBoxInvalidShape, __LINE__, __FILE__, \
|
||||
"Bounding boxes shape should have at least two dimensions."); \
|
||||
} \
|
||||
uint32_t num_of_features = input[1]->shape()[1]; \
|
||||
if (num_of_features < 4) { \
|
||||
return Status(StatusCode::kBoundingBoxInvalidShape, __LINE__, __FILE__, \
|
||||
"Bounding boxes should be have at least 4 features."); \
|
||||
} \
|
||||
uint32_t num_of_boxes = input[1]->shape()[0]; \
|
||||
uint32_t img_h = input[0]->shape()[0]; \
|
||||
uint32_t img_w = input[0]->shape()[1]; \
|
||||
for (uint32_t i = 0; i < num_of_boxes; i++) { \
|
||||
float min_x = 0.0, min_y = 0.0, b_w = 0.0, b_h = 0.0; \
|
||||
bool passing_data_fetch = true; \
|
||||
passing_data_fetch &= input[1]->GetItemAt<float>(&min_x, {i, 0}).IsOk(); \
|
||||
passing_data_fetch &= input[1]->GetItemAt<float>(&min_y, {i, 1}).IsOk(); \
|
||||
passing_data_fetch &= input[1]->GetItemAt<float>(&b_w, {i, 2}).IsOk(); \
|
||||
passing_data_fetch &= input[1]->GetItemAt<float>(&b_h, {i, 3}).IsOk(); \
|
||||
if (!passing_data_fetch) { \
|
||||
return Status(StatusCode::kUnexpectedError, __LINE__, __FILE__, \
|
||||
"Fetching BBox values failed in BOUNDING_BOX_CHECK."); \
|
||||
} \
|
||||
if ((min_x + b_w > img_w) || (min_y + b_h > img_h)) { \
|
||||
return Status(StatusCode::kBoundingBoxOutOfBounds, __LINE__, __FILE__, \
|
||||
"At least one of the bounding boxes is out of bounds of the image."); \
|
||||
} \
|
||||
if (static_cast<int>(min_x) < 0 || static_cast<int>(min_y) < 0) { \
|
||||
return Status(StatusCode::kBoundingBoxOutOfBounds, __LINE__, __FILE__, \
|
||||
"At least one of the bounding boxes has negative min_x or min_y."); \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
"""
|
||||
Testing RandomPosterize 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_list, save_and_check_md5, \
|
||||
config_get_set_seed, config_get_set_num_parallel_workers
|
||||
config_get_set_seed, config_get_set_num_parallel_workers, diff_mse
|
||||
|
||||
GENERATE_GOLDEN = False
|
||||
|
||||
|
@ -27,9 +28,10 @@ DATA_DIR = ["../data/dataset/test_tf_file_3_images/train-0000-of-0001.data"]
|
|||
SCHEMA_DIR = "../data/dataset/test_tf_file_3_images/datasetSchema.json"
|
||||
|
||||
|
||||
def skip_test_random_posterize_op_c(plot=False, run_golden=True):
|
||||
def test_random_posterize_op_c(plot=False, run_golden=False):
|
||||
"""
|
||||
Test RandomPosterize in C transformations
|
||||
Test RandomPosterize in C transformations (uses assertion on mse as using md5 could have jpeg decoding
|
||||
inconsistencies)
|
||||
"""
|
||||
logger.info("test_random_posterize_op_c")
|
||||
|
||||
|
@ -57,6 +59,12 @@ def skip_test_random_posterize_op_c(plot=False, run_golden=True):
|
|||
image_posterize.append(image1)
|
||||
image_original.append(image2)
|
||||
|
||||
# check mse as md5 can be inconsistent.
|
||||
# mse = 2.9668956 is calculated from
|
||||
# a thousand runs of diff_mse(np.array(image_original), np.array(image_posterize)) that all produced the same mse.
|
||||
# allow for an error of 0.0000005
|
||||
assert abs(2.9668956 - diff_mse(np.array(image_original), np.array(image_posterize))) <= 0.0000005
|
||||
|
||||
if run_golden:
|
||||
# check results with md5 comparison
|
||||
filename = "random_posterize_01_result_c.npz"
|
||||
|
@ -70,7 +78,7 @@ def skip_test_random_posterize_op_c(plot=False, run_golden=True):
|
|||
ds.config.set_num_parallel_workers(original_num_parallel_workers)
|
||||
|
||||
|
||||
def skip_test_random_posterize_op_fixed_point_c(plot=False, run_golden=True):
|
||||
def test_random_posterize_op_fixed_point_c(plot=False, run_golden=True):
|
||||
"""
|
||||
Test RandomPosterize in C transformations with fixed point
|
||||
"""
|
||||
|
@ -144,6 +152,6 @@ def test_random_posterize_exception_bit():
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
skip_test_random_posterize_op_c(plot=True)
|
||||
skip_test_random_posterize_op_fixed_point_c(plot=True)
|
||||
test_random_posterize_op_c(plot=False, run_golden=False)
|
||||
test_random_posterize_op_fixed_point_c(plot=False)
|
||||
test_random_posterize_exception_bit()
|
||||
|
|
Loading…
Reference in New Issue