add slice patches in python and c++
This commit is contained in:
parent
1e54401388
commit
9a1de0af65
|
@ -131,5 +131,12 @@ PYBIND_REGISTER(ImageBatchFormat, 0, ([](const py::module *m) {
|
|||
.export_values();
|
||||
}));
|
||||
|
||||
PYBIND_REGISTER(SliceMode, 0, ([](const py::module *m) {
|
||||
(void)py::enum_<SliceMode>(*m, "SliceMode", py::arithmetic())
|
||||
.value("DE_SLICE_PAD", SliceMode::kPad)
|
||||
.value("DE_SLICE_DROP", SliceMode::kDrop)
|
||||
.export_values();
|
||||
}));
|
||||
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "minddata/dataset/kernels/ir/vision/resize_with_bbox_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/rgb_to_bgr_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/rotate_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/slice_patches_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/softdvpp_decode_random_crop_resize_jpeg_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/softdvpp_decode_resize_jpeg_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/uniform_aug_ir.h"
|
||||
|
@ -553,6 +554,18 @@ PYBIND_REGISTER(RotateOperation, 1, ([](const py::module *m) {
|
|||
}));
|
||||
}));
|
||||
|
||||
PYBIND_REGISTER(
|
||||
SlicePatchesOperation, 1, ([](const py::module *m) {
|
||||
(void)py::class_<vision::SlicePatchesOperation, TensorOperation, std::shared_ptr<vision::SlicePatchesOperation>>(
|
||||
*m, "SlicePatchesOperation")
|
||||
.def(py::init([](int32_t num_height, int32_t num_width, SliceMode slice_mode, uint8_t fill_value) {
|
||||
auto slice_patches =
|
||||
std::make_shared<vision::SlicePatchesOperation>(num_height, num_width, slice_mode, fill_value);
|
||||
THROW_IF_ERROR(slice_patches->ValidateParams());
|
||||
return slice_patches;
|
||||
}));
|
||||
}));
|
||||
|
||||
PYBIND_REGISTER(SoftDvppDecodeRandomCropResizeJpegOperation, 1, ([](const py::module *m) {
|
||||
(void)py::class_<vision::SoftDvppDecodeRandomCropResizeJpegOperation, TensorOperation,
|
||||
std::shared_ptr<vision::SoftDvppDecodeRandomCropResizeJpegOperation>>(
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#include "minddata/dataset/kernels/ir/vision/rgba_to_bgr_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/rgba_to_rgb_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/rotate_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/slice_patches_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/softdvpp_decode_random_crop_resize_jpeg_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/softdvpp_decode_resize_jpeg_ir.h"
|
||||
#include "minddata/dataset/kernels/ir/vision/swap_red_blue_ir.h"
|
||||
|
@ -877,6 +878,24 @@ RGBA2RGB::RGBA2RGB() {}
|
|||
|
||||
std::shared_ptr<TensorOperation> RGBA2RGB::Parse() { return std::make_shared<RgbaToRgbOperation>(); }
|
||||
|
||||
// SlicePatches Transform Operation.
|
||||
struct SlicePatches::Data {
|
||||
Data(int32_t num_height, int32_t num_width, SliceMode slice_mode, uint8_t fill_value)
|
||||
: num_height_(num_height), num_width_(num_width), slice_mode_(slice_mode), fill_value_(fill_value) {}
|
||||
int32_t num_height_;
|
||||
int32_t num_width_;
|
||||
SliceMode slice_mode_;
|
||||
uint8_t fill_value_;
|
||||
};
|
||||
|
||||
SlicePatches::SlicePatches(int32_t num_height, int32_t num_width, SliceMode slice_mode, uint8_t fill_value)
|
||||
: data_(std::make_shared<Data>(num_height, num_width, slice_mode, fill_value)) {}
|
||||
|
||||
std::shared_ptr<TensorOperation> SlicePatches::Parse() {
|
||||
return std::make_shared<SlicePatchesOperation>(data_->num_height_, data_->num_width_, data_->slice_mode_,
|
||||
data_->fill_value_);
|
||||
}
|
||||
|
||||
// SoftDvppDecodeRandomCropResizeJpeg Transform Operation.
|
||||
struct SoftDvppDecodeRandomCropResizeJpeg::Data {
|
||||
Data(const std::vector<int32_t> &size, const std::vector<float> &scale, const std::vector<float> &ratio,
|
||||
|
|
|
@ -125,6 +125,12 @@ enum class RelationalOp {
|
|||
kGreaterEqual, ///< equal to `>=`
|
||||
};
|
||||
|
||||
/// \brief Possible modes for slice patches.
|
||||
enum class SliceMode {
|
||||
kPad = 0, ///< Pad some pixels before slice to patches.
|
||||
kDrop = 1, ///< Drop remainder pixels before slice to patches.
|
||||
};
|
||||
|
||||
/// \brief Possible options for SamplingStrategy.
|
||||
enum class SamplingStrategy {
|
||||
kRandom = 0, ///< Random sampling with replacement.
|
||||
|
|
|
@ -823,6 +823,33 @@ class RGBA2RGB final : public TensorTransform {
|
|||
std::shared_ptr<TensorOperation> Parse() override;
|
||||
};
|
||||
|
||||
/// \note Slice the tensor to multiple patches in horizontal and vertical directions.
|
||||
class SlicePatches final : public TensorTransform {
|
||||
public:
|
||||
/// \brief Constructor.
|
||||
/// \param[in] num_height The number of patches in vertical direction (default=1).
|
||||
/// \param[in] num_width The number of patches in horizontal direction (default=1).
|
||||
/// \param[in] slice_mode An enum for the mode of slice (default=SliceMode::kPad).
|
||||
/// \param[in] fill_value A value representing the pixel to fill the padding area in right and
|
||||
/// bottom border if slice_mode is kPad. Then padded tensor could be just sliced to multiple patches (default=0).
|
||||
/// \note The usage scenerio is suitable to tensor with large height and width. The tensor will keep the same
|
||||
/// if set both num_height and num_width to 1. And the number of output tensors is equal to num_height*num_width.
|
||||
SlicePatches(int32_t num_height = 1, int32_t num_width = 1, SliceMode slice_mode = SliceMode::kPad,
|
||||
uint8_t fill_value = 0);
|
||||
|
||||
/// \brief Destructor.
|
||||
~SlicePatches() = default;
|
||||
|
||||
protected:
|
||||
/// \brief Function to convert TensorTransform object into a TensorOperation object.
|
||||
/// \return Shared pointer to TensorOperation object.
|
||||
std::shared_ptr<TensorOperation> Parse() override;
|
||||
|
||||
private:
|
||||
struct Data;
|
||||
std::shared_ptr<Data> data_;
|
||||
};
|
||||
|
||||
/// \brief Decode, randomly crop and resize a JPEG image using the simulation algorithm of
|
||||
/// Ascend series chip DVPP module. The application scenario is consistent with SoftDvppDecodeResizeJpeg.
|
||||
/// The input image size should be in range [32*32, 8192*8192].
|
||||
|
|
|
@ -52,6 +52,7 @@ add_library(kernels-image OBJECT
|
|||
rgba_to_bgr_op.cc
|
||||
rgba_to_rgb_op.cc
|
||||
sharpness_op.cc
|
||||
slice_patches_op.cc
|
||||
solarize_op.cc
|
||||
swap_red_blue_op.cc
|
||||
uniform_aug_op.cc
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include "utils/ms_utils.h"
|
||||
#include "minddata/dataset/core/cv_tensor.h"
|
||||
|
@ -29,6 +28,9 @@
|
|||
#include "minddata/dataset/kernels/image/resize_cubic_op.h"
|
||||
|
||||
const int32_t MAX_INT_PRECISION = 16777216; // float int precision is 16777216
|
||||
const int32_t DEFAULT_NUM_HEIGHT = 1;
|
||||
const int32_t DEFAULT_NUM_WIDTH = 1;
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
int GetCVInterpolationMode(InterpolationMode mode) {
|
||||
|
@ -1281,5 +1283,81 @@ Status GaussianBlur(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor
|
|||
RETURN_STATUS_UNEXPECTED("GaussianBlur: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
Status ComputePatchSize(const std::shared_ptr<CVTensor> &input_cv,
|
||||
std::shared_ptr<std::pair<int32_t, int32_t>> *patch_size, int32_t num_height, int32_t num_width,
|
||||
SliceMode slice_mode) {
|
||||
if (input_cv->mat().data == nullptr) {
|
||||
RETURN_STATUS_UNEXPECTED("SlicePatches: Tensor could not convert to CV Tensor.");
|
||||
}
|
||||
if (input_cv->Rank() != 3 && input_cv->Rank() != 2) {
|
||||
RETURN_STATUS_UNEXPECTED("SlicePatches: image shape is not <H,W,C> or <H,W>.");
|
||||
}
|
||||
|
||||
cv::Mat in_img = input_cv->mat();
|
||||
cv::Size s = in_img.size();
|
||||
if (num_height == 0 || num_height > s.height) {
|
||||
RETURN_STATUS_UNEXPECTED("SlicePatches: The number of patches on height axis equals 0 or is greater than height.");
|
||||
}
|
||||
if (num_width == 0 || num_width > s.width) {
|
||||
RETURN_STATUS_UNEXPECTED("SlicePatches: The number of patches on width axis equals 0 or is greater than width.");
|
||||
}
|
||||
int32_t patch_h = s.height / num_height;
|
||||
if (s.height % num_height != 0) {
|
||||
if (slice_mode == SliceMode::kPad) {
|
||||
patch_h += 1; // patch_h * num_height - s.height
|
||||
}
|
||||
}
|
||||
int32_t patch_w = s.width / num_width;
|
||||
if (s.width % num_width != 0) {
|
||||
if (slice_mode == SliceMode::kPad) {
|
||||
patch_w += 1; // patch_w * num_width - s.width
|
||||
}
|
||||
}
|
||||
(*patch_size)->first = patch_h;
|
||||
(*patch_size)->second = patch_w;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status SlicePatches(const std::shared_ptr<Tensor> &input, std::vector<std::shared_ptr<Tensor>> *output,
|
||||
int32_t num_height, int32_t num_width, SliceMode slice_mode, uint8_t fill_value) {
|
||||
if (num_height == DEFAULT_NUM_HEIGHT && num_width == DEFAULT_NUM_WIDTH) {
|
||||
(*output).push_back(input);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
auto patch_size = std::make_shared<std::pair<int32_t, int32_t>>(0, 0);
|
||||
int32_t patch_h = 0;
|
||||
int32_t patch_w = 0;
|
||||
|
||||
std::shared_ptr<CVTensor> input_cv = CVTensor::AsCVTensor(input);
|
||||
RETURN_IF_NOT_OK(ComputePatchSize(input_cv, &patch_size, num_height, num_width, slice_mode));
|
||||
std::tie(patch_h, patch_w) = *patch_size;
|
||||
|
||||
cv::Mat in_img = input_cv->mat();
|
||||
cv::Size s = in_img.size();
|
||||
try {
|
||||
cv::Mat out_img;
|
||||
if (slice_mode == SliceMode::kPad) { // padding on right and bottom directions
|
||||
auto padding_h = patch_h * num_height - s.height;
|
||||
auto padding_w = patch_w * num_width - s.width;
|
||||
out_img = cv::Mat(s.height + padding_h, s.width + padding_w, in_img.type(), cv::Scalar::all(fill_value));
|
||||
in_img.copyTo(out_img(cv::Rect(0, 0, s.width, s.height)));
|
||||
} else {
|
||||
out_img = in_img;
|
||||
}
|
||||
for (int i = 0; i < num_height; ++i) {
|
||||
for (int j = 0; j < num_width; ++j) {
|
||||
std::shared_ptr<CVTensor> patch_cv;
|
||||
cv::Rect patch(j * patch_w, i * patch_h, patch_w, patch_h);
|
||||
RETURN_IF_NOT_OK(CVTensor::CreateFromMat(out_img(patch), &patch_cv));
|
||||
(*output).push_back(std::static_pointer_cast<Tensor>(patch_cv));
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
} catch (const cv::Exception &e) {
|
||||
RETURN_STATUS_UNEXPECTED("SlicePatches: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#undef HAVE_STDDEF_H
|
||||
|
@ -338,6 +339,25 @@ Status Affine(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *out
|
|||
Status GaussianBlur(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output, int32_t kernel_size_x,
|
||||
int32_t kernel_size_y, float sigma_x, float sigma_y);
|
||||
|
||||
/// \brief Slice tensor to multiple patches.
|
||||
/// \param[in] input Input Tensor
|
||||
/// \param[out] output Vector of Output Tensor
|
||||
/// \param[in] num_height Number of patches in vertical direction.
|
||||
/// \param[in] num_width Number of patches in horizontal direction.
|
||||
/// \param[in] slice_mode Mode represents padding or drop.
|
||||
/// \param[in] fill_value The value of filled pixel in right and bottom border when padding.
|
||||
Status SlicePatches(const std::shared_ptr<Tensor> &input, std::vector<std::shared_ptr<Tensor>> *output,
|
||||
int32_t num_height, int32_t num_width, SliceMode slice_mode, uint8_t fill_value);
|
||||
|
||||
/// \brief Compute patch height and width.
|
||||
/// \param[in] input Input CVTensor
|
||||
/// \param[out] patch_size Size of patch
|
||||
/// \param[in] num_height Number of patches in vertical direction.
|
||||
/// \param[in] num_width Number of patches in horizontal direction.
|
||||
/// \param[in] slice_mode Mode represents padding or drop.
|
||||
Status ComputePatchSize(const std::shared_ptr<CVTensor> &input_cv,
|
||||
std::shared_ptr<std::pair<int32_t, int32_t>> *patch_size, int32_t num_height, int32_t num_width,
|
||||
SliceMode slice_mode);
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_IMAGE_UTILS_H_
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Copyright 2021 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/slice_patches_op.h"
|
||||
#include "minddata/dataset/kernels/image/image_utils.h"
|
||||
#include "minddata/dataset/util/status.h"
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
|
||||
const int32_t SlicePatchesOp::kDefNumH = 1;
|
||||
const int32_t SlicePatchesOp::kDefNumW = 1;
|
||||
const uint8_t SlicePatchesOp::kDefFillV = 0;
|
||||
const SliceMode SlicePatchesOp::kDefSliceMode = SliceMode::kPad;
|
||||
|
||||
SlicePatchesOp::SlicePatchesOp(int32_t num_height, int32_t num_width, SliceMode slice_mode, uint8_t fill_value)
|
||||
: num_height_(num_height), num_width_(num_width), slice_mode_(slice_mode), fill_value_(fill_value) {}
|
||||
|
||||
Status SlicePatchesOp::Compute(const TensorRow &input, TensorRow *output) {
|
||||
IO_CHECK_VECTOR(input, output);
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(input.size() == 1, "Input tensor size should be 1.");
|
||||
|
||||
auto in_tensor = input[0];
|
||||
auto in_type = in_tensor->type();
|
||||
auto in_shape = in_tensor->shape();
|
||||
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(in_type.IsNumeric(), "Input Tensor type should be numeric.");
|
||||
CHECK_FAIL_RETURN_UNEXPECTED(in_shape.Rank() >= 2, "Input Tensor rank should be greater than 2.");
|
||||
|
||||
std::vector<std::shared_ptr<Tensor>> out;
|
||||
RETURN_IF_NOT_OK(SlicePatches(in_tensor, &out, num_height_, num_width_, slice_mode_, fill_value_));
|
||||
(void)std::copy(out.begin(), out.end(), std::back_inserter(*output));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* Copyright 2021 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_SLICE_PATCHES_OP_H_
|
||||
#define MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_SLICE_PATCHES_OP_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "minddata/dataset/core/tensor.h"
|
||||
#include "minddata/dataset/kernels/tensor_op.h"
|
||||
#include "minddata/dataset/util/status.h"
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
class SlicePatchesOp : public TensorOp {
|
||||
public:
|
||||
// Default values, also used by python_bindings.cc
|
||||
static const int32_t kDefNumH;
|
||||
static const int32_t kDefNumW;
|
||||
static const uint8_t kDefFillV;
|
||||
static const SliceMode kDefSliceMode;
|
||||
|
||||
SlicePatchesOp(int32_t num_height = kDefNumH, int32_t num_width = kDefNumW, SliceMode slice_mode = kDefSliceMode,
|
||||
uint8_t fill_value = kDefFillV);
|
||||
|
||||
~SlicePatchesOp() override = default;
|
||||
|
||||
void Print(std::ostream &out) const override {
|
||||
out << Name() << " patches number on height: " << num_height_ << ", patches number on width: " << num_width_;
|
||||
}
|
||||
|
||||
Status Compute(const TensorRow &input, TensorRow *output) override;
|
||||
|
||||
std::string Name() const override { return kSlicePatchesOp; }
|
||||
|
||||
protected:
|
||||
int32_t num_height_; // number of patches on height axis
|
||||
int32_t num_width_; // number of patches on width axis
|
||||
SliceMode slice_mode_; // PadModel, DropModel
|
||||
uint8_t fill_value_; // border width in number of pixels in right and bottom direction
|
||||
};
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
|
||||
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_SLICE_PATCHES_OP_H_
|
|
@ -47,6 +47,7 @@ set(DATASET_KERNELS_IR_VISION_SRC_FILES
|
|||
rgba_to_bgr_ir.cc
|
||||
rgba_to_rgb_ir.cc
|
||||
rotate_ir.cc
|
||||
slice_patches_ir.cc
|
||||
softdvpp_decode_random_crop_resize_jpeg_ir.cc
|
||||
softdvpp_decode_resize_jpeg_ir.cc
|
||||
swap_red_blue_ir.cc
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* Copyright 2021 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 <algorithm>
|
||||
|
||||
#include "minddata/dataset/kernels/ir/vision/slice_patches_ir.h"
|
||||
#include "minddata/dataset/kernels/image/slice_patches_op.h"
|
||||
#include "minddata/dataset/kernels/ir/validators.h"
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
|
||||
namespace vision {
|
||||
// SlicePatchesOperation
|
||||
SlicePatchesOperation::SlicePatchesOperation(int32_t num_height, int32_t num_width, SliceMode slice_mode,
|
||||
uint8_t fill_value)
|
||||
: TensorOperation(),
|
||||
num_height_(num_height),
|
||||
num_width_(num_width),
|
||||
slice_mode_(slice_mode),
|
||||
fill_value_(fill_value) {}
|
||||
|
||||
SlicePatchesOperation::~SlicePatchesOperation() = default;
|
||||
|
||||
std::string SlicePatchesOperation::Name() const { return kSlicePatchesOperation; }
|
||||
|
||||
Status SlicePatchesOperation::ValidateParams() {
|
||||
RETURN_IF_NOT_OK(ValidateIntScalarPositive("SlicePatches", "num_height", num_height_));
|
||||
RETURN_IF_NOT_OK(ValidateIntScalarPositive("SlicePatches", "num_width", num_width_));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
std::shared_ptr<TensorOp> SlicePatchesOperation::Build() {
|
||||
auto tensor_op = std::make_shared<SlicePatchesOp>(num_height_, num_width_, slice_mode_, fill_value_);
|
||||
return tensor_op;
|
||||
}
|
||||
|
||||
Status SlicePatchesOperation::to_json(nlohmann::json *out_json) {
|
||||
nlohmann::json args;
|
||||
args["num_height"] = num_height_;
|
||||
args["num_width"] = num_width_;
|
||||
args["slice_mode"] = slice_mode_;
|
||||
args["fill_value"] = fill_value_;
|
||||
*out_json = args;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
} // namespace vision
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* Copyright 2021 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_IR_VISION_SLICE_PATCHES_IR_H_
|
||||
#define MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IR_VISION_SLICE_PATCHES_IR_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "include/api/status.h"
|
||||
#include "minddata/dataset/include/dataset/constants.h"
|
||||
#include "minddata/dataset/include/dataset/transforms.h"
|
||||
#include "minddata/dataset/kernels/ir/tensor_operation.h"
|
||||
|
||||
namespace mindspore {
|
||||
namespace dataset {
|
||||
|
||||
namespace vision {
|
||||
|
||||
constexpr char kSlicePatchesOperation[] = "SlicePatches";
|
||||
|
||||
class SlicePatchesOperation : public TensorOperation {
|
||||
public:
|
||||
SlicePatchesOperation(int32_t num_height, int32_t num_width, SliceMode slice_mode, uint8_t fill_value);
|
||||
|
||||
~SlicePatchesOperation();
|
||||
|
||||
std::shared_ptr<TensorOp> Build() override;
|
||||
|
||||
Status ValidateParams() override;
|
||||
|
||||
std::string Name() const override;
|
||||
|
||||
Status to_json(nlohmann::json *out_json) override;
|
||||
|
||||
private:
|
||||
int32_t num_height_;
|
||||
int32_t num_width_;
|
||||
SliceMode slice_mode_;
|
||||
uint8_t fill_value_;
|
||||
};
|
||||
|
||||
} // namespace vision
|
||||
} // namespace dataset
|
||||
} // namespace mindspore
|
||||
#endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IR_VISION_SLICE_PATCHES_IR_H_
|
|
@ -105,6 +105,7 @@ constexpr char kRgbToBgrOp[] = "RgbToBgrOp";
|
|||
constexpr char kRgbToGrayOp[] = "RgbToGrayOp";
|
||||
constexpr char kRotateOp[] = "RotateOp";
|
||||
constexpr char kSharpnessOp[] = "SharpnessOp";
|
||||
constexpr char kSlicePatchesOp[] = "SlicePatchesOp";
|
||||
constexpr char kSoftDvppDecodeRandomCropResizeJpegOp[] = "SoftDvppDecodeRandomCropResizeJpegOp";
|
||||
constexpr char kSoftDvppDecodeReiszeJpegOp[] = "SoftDvppDecodeReiszeJpegOp";
|
||||
constexpr char kSolarizeOp[] = "SolarizeOp";
|
||||
|
|
|
@ -47,14 +47,14 @@ import numpy as np
|
|||
from PIL import Image
|
||||
import mindspore._c_dataengine as cde
|
||||
|
||||
from .utils import Inter, Border, ImageBatchFormat
|
||||
from .utils import Inter, Border, ImageBatchFormat, SliceMode
|
||||
from .validators import check_prob, check_crop, check_center_crop, check_resize_interpolation, check_random_resize_crop, \
|
||||
check_mix_up_batch_c, check_normalize_c, check_normalizepad_c, check_random_crop, check_random_color_adjust, \
|
||||
check_random_rotation, check_range, check_resize, check_rescale, check_pad, check_cutout, \
|
||||
check_uniform_augment_cpp, \
|
||||
check_bounding_box_augment_cpp, check_random_select_subpolicy_op, check_auto_contrast, check_random_affine, \
|
||||
check_random_solarize, check_soft_dvpp_decode_random_crop_resize_jpeg, check_positive_degrees, FLOAT_MAX_INTEGER, \
|
||||
check_cut_mix_batch_c, check_posterize, check_gaussian_blur, check_rotate
|
||||
check_cut_mix_batch_c, check_posterize, check_gaussian_blur, check_rotate, check_slice_patches
|
||||
from ..transforms.c_transforms import TensorOperation
|
||||
|
||||
|
||||
|
@ -87,6 +87,8 @@ DE_C_INTER_MODE = {Inter.NEAREST: cde.InterpolationMode.DE_INTER_NEAREST_NEIGHBO
|
|||
Inter.AREA: cde.InterpolationMode.DE_INTER_AREA,
|
||||
Inter.PILCUBIC: cde.InterpolationMode.DE_INTER_PILCUBIC}
|
||||
|
||||
DE_C_SLICE_MODE = {SliceMode.PAD: cde.SliceMode.DE_SLICE_PAD,
|
||||
SliceMode.DROP: cde.SliceMode.DE_SLICE_DROP}
|
||||
|
||||
def parse_padding(padding):
|
||||
""" Parses and prepares the padding tuple"""
|
||||
|
@ -1541,6 +1543,43 @@ class Rotate(ImageTensorOperation):
|
|||
return cde.RotateOperation(degrees, interpolation, expand, center, fill_value)
|
||||
|
||||
|
||||
class SlicePatches(ImageTensorOperation):
|
||||
"""
|
||||
Slice Tensor to multiple patches in horizontal and vertical directions.
|
||||
|
||||
The usage scenerio is suitable to large height and width Tensor. The Tensor
|
||||
will keep the same if set both num_height and num_width to 1. And the
|
||||
number of output tensors is equal to num_height*num_width.
|
||||
|
||||
Args:
|
||||
num_height (int, optional): The number of patches in vertical direction (default=1).
|
||||
num_height (int, optional): The number of patches in horizontal direction (default=1).
|
||||
slice_mode (Inter mode, optional): An mode represents pad or drop (default=SliceMode.PAD).
|
||||
It can be any of [SliceMode.PAD, SliceMode.DROP].
|
||||
fill_value (int, optional): The border width in number of pixels in
|
||||
right and bottom direction if slice_mode is set to be SliceMode.PAD (default=0).
|
||||
|
||||
Examples:
|
||||
>>> # default padding mode
|
||||
>>> slice_patches_op = c_vision.SlicePatches(num_h, num_w)
|
||||
>>> cols = ['img' + str(x) for x in range(num_h*num_w)]
|
||||
>>> dataset1 = dataset1.map(operations=decode_op, input_columns=["image"])
|
||||
>>> dataset1 = dataset1.map(operations=resize_op, input_columns=["image"])
|
||||
>>> dataset1 = dataset1.map(operations=slice_patches_op, input_columns=[
|
||||
... "image"], output_columns=cols, column_order=cols)
|
||||
"""
|
||||
|
||||
@check_slice_patches
|
||||
def __init__(self, num_height=1, num_width=1, slice_mode=SliceMode.PAD, fill_value=0):
|
||||
self.num_height = num_height
|
||||
self.num_width = num_width
|
||||
self.slice_mode = slice_mode
|
||||
self.fill_value = fill_value
|
||||
|
||||
def parse(self):
|
||||
return cde.SlicePatchesOperation(self.num_height, self.num_width,
|
||||
DE_C_SLICE_MODE[self.slice_mode], self.fill_value)
|
||||
|
||||
class SoftDvppDecodeRandomCropResizeJpeg(ImageTensorOperation):
|
||||
"""
|
||||
A combination of `Crop`, `Decode` and `Resize` using the simulation algorithm of Ascend series chip DVPP module.
|
||||
|
|
|
@ -42,3 +42,7 @@ class ImageBatchFormat(IntEnum):
|
|||
"""Image Batch Format"""
|
||||
NHWC = 0
|
||||
NCHW = 1
|
||||
|
||||
class SliceMode(IntEnum):
|
||||
PAD = 0
|
||||
DROP = 1
|
||||
|
|
|
@ -22,7 +22,7 @@ from mindspore._c_dataengine import TensorOp, TensorOperation
|
|||
from mindspore.dataset.core.validator_helpers import check_value, check_uint8, FLOAT_MAX_INTEGER, check_pos_float32, \
|
||||
check_float32, check_2tuple, check_range, check_positive, INT32_MAX, parse_user_args, type_check, type_check_list, \
|
||||
check_c_tensor_op, UINT8_MAX, check_value_normalize_std, check_value_cutoff, check_value_ratio, check_odd
|
||||
from .utils import Inter, Border, ImageBatchFormat
|
||||
from .utils import Inter, Border, ImageBatchFormat, SliceMode
|
||||
|
||||
|
||||
def check_crop_size(size):
|
||||
|
@ -513,6 +513,27 @@ def check_pad(method):
|
|||
return new_method
|
||||
|
||||
|
||||
def check_slice_patches(method):
|
||||
"""Wrapper method to check the parameters of slice patches."""
|
||||
|
||||
@wraps(method)
|
||||
def new_method(self, *args, **kwargs):
|
||||
[num_height, num_width, slice_mode, fill_value], _ = parse_user_args(method, *args, **kwargs)
|
||||
if num_height is not None:
|
||||
type_check(num_height, (int,), "num_height")
|
||||
check_value(num_height, (1, INT32_MAX), "num_height")
|
||||
if num_width is not None:
|
||||
type_check(num_width, (int,), "num_width")
|
||||
check_value(num_width, (1, INT32_MAX), "num_width")
|
||||
if slice_mode is not None:
|
||||
type_check(slice_mode, (SliceMode,), "slice_mode")
|
||||
if fill_value is not None:
|
||||
type_check(fill_value, (int,), "fill_value")
|
||||
check_value(fill_value, [0, 255], "fill_value")
|
||||
return method(self, *args, **kwargs)
|
||||
|
||||
return new_method
|
||||
|
||||
def check_random_perspective(method):
|
||||
"""Wrapper method to check the parameters of random perspective."""
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ SET(DE_UT_SRCS
|
|||
c_api_vision_random_subselect_policy_test.cc
|
||||
c_api_vision_random_test.cc
|
||||
c_api_vision_r_to_z_test.cc
|
||||
c_api_vision_slice_patches_test.cc
|
||||
c_api_vision_soft_dvpp_test.cc
|
||||
c_api_vision_uniform_aug_test.cc
|
||||
c_api_vision_vertical_flip_test.cc
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* Copyright 2021 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 "common/common.h"
|
||||
#include "minddata/dataset/include/dataset/datasets.h"
|
||||
#include "minddata/dataset/include/dataset/execute.h"
|
||||
#include "minddata/dataset/include/dataset/vision.h"
|
||||
#include "utils/log_adapter.h"
|
||||
|
||||
using namespace mindspore::dataset;
|
||||
|
||||
class MindDataTestSlicePatches : public UT::DatasetOpTesting {
|
||||
protected:
|
||||
};
|
||||
|
||||
TEST_F(MindDataTestSlicePatches, TestSlicePacthesParamCheck) {
|
||||
MS_LOG(INFO) << "Doing TestSlicePatchesParamCheck with invalid parameters.";
|
||||
// Create an ImageFolder Dataset
|
||||
std::string folder_path = datasets_root_path_ + "/testPK/data/";
|
||||
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, true, std::make_shared<RandomSampler>(false, 10));
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
// Case 1: num_height is not positive
|
||||
// Create objects for the tensor ops
|
||||
std::shared_ptr<TensorTransform> slice_patches_1(new vision::SlicePatches(-1));
|
||||
auto ds1 = ds->Map({slice_patches_1});
|
||||
EXPECT_NE(ds1, nullptr);
|
||||
// Create an iterator over the result of the above dataset
|
||||
std::shared_ptr<Iterator> iter1 = ds1->CreateIterator();
|
||||
// Expect failure: invalid num_height for SlicePatches
|
||||
EXPECT_EQ(iter1, nullptr);
|
||||
|
||||
// Case 2: num_width is not positive
|
||||
// Create objects for the tensor ops
|
||||
std::shared_ptr<TensorTransform> slice_patches_2(new vision::SlicePatches(1, 0));
|
||||
auto ds2 = ds->Map({slice_patches_2});
|
||||
EXPECT_NE(ds2, nullptr);
|
||||
// Create an iterator over the result of the above dataset
|
||||
std::shared_ptr<Iterator> iter2 = ds2->CreateIterator();
|
||||
// Expect failure: invalid num_height for SlicePatches
|
||||
EXPECT_EQ(iter2, nullptr);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(MindDataTestSlicePatches, TestSlicePatchesPipeline) {
|
||||
MS_LOG(INFO) << "Doing TestGaussianBlurPipeline.";
|
||||
|
||||
// Create an ImageFolder Dataset
|
||||
std::string folder_path = datasets_root_path_ + "/testPK/data/";
|
||||
std::shared_ptr<Dataset> ds = ImageFolder(folder_path, true, std::make_shared<RandomSampler>(false, 10));
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
// Create objects for the tensor ops
|
||||
std::shared_ptr<TensorTransform> slice_patches(new vision::SlicePatches(2, 2));
|
||||
|
||||
// Create a Map operation on ds
|
||||
ds = ds->Map({slice_patches}, {"image"}, {"img0", "img1", "img2", "img3"}, {"img0", "img1", "img2", "img3"});
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
// Create a Batch operation on ds
|
||||
int32_t batch_size = 1;
|
||||
ds = ds->Batch(batch_size);
|
||||
EXPECT_NE(ds, nullptr);
|
||||
|
||||
// Create an iterator over the result of the above dataset
|
||||
// This will trigger the creation of the Execution Tree and launch it.
|
||||
std::shared_ptr<Iterator> iter = ds->CreateIterator();
|
||||
EXPECT_NE(iter, nullptr);
|
||||
|
||||
// Iterate the dataset and get each row
|
||||
std::unordered_map<std::string, mindspore::MSTensor> row;
|
||||
ASSERT_OK(iter->GetNextRow(&row));
|
||||
|
||||
uint64_t i = 0;
|
||||
while (!row.empty()) {
|
||||
i++;
|
||||
ASSERT_EQ(row.size(), 4);
|
||||
ASSERT_OK(iter->GetNextRow(&row));
|
||||
}
|
||||
|
||||
EXPECT_EQ(i, 10);
|
||||
|
||||
// Manually terminate the pipeline
|
||||
iter->Stop();
|
||||
}
|
||||
|
||||
TEST_F(MindDataTestSlicePatches, TestSlicePatchesEager) {
|
||||
MS_LOG(INFO) << "Doing TestGaussianBlurEager.";
|
||||
|
||||
// Read images
|
||||
auto image = ReadFileToTensor("data/dataset/apple.jpg");
|
||||
|
||||
std::vector<mindspore::MSTensor> input{image};
|
||||
std::vector<mindspore::MSTensor> output;
|
||||
|
||||
// Transform params
|
||||
auto decode = vision::Decode();
|
||||
auto slice_patches = vision::SlicePatches(2, 2);
|
||||
|
||||
auto transform = Execute({decode, slice_patches});
|
||||
Status rc = transform(input, &output);
|
||||
|
||||
EXPECT_EQ(rc, Status::OK());
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
# Copyright 2021 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 SlicePatches Python API
|
||||
"""
|
||||
import functools
|
||||
import numpy as np
|
||||
|
||||
import mindspore.dataset as ds
|
||||
import mindspore.dataset.vision.c_transforms as c_vision
|
||||
import mindspore.dataset.vision.utils as mode
|
||||
|
||||
from mindspore import log as logger
|
||||
from util import diff_mse, visualize_list
|
||||
|
||||
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 test_slice_patches_01(plot=False):
|
||||
"""
|
||||
slice rgb image(100, 200) to 4 patches
|
||||
"""
|
||||
slice_to_patches([100, 200], 2, 2, True, plot=plot)
|
||||
|
||||
|
||||
def test_slice_patches_02(plot=False):
|
||||
"""
|
||||
no op
|
||||
"""
|
||||
slice_to_patches([100, 200], 1, 1, True, plot=plot)
|
||||
|
||||
|
||||
def test_slice_patches_03(plot=False):
|
||||
"""
|
||||
slice rgb image(99, 199) to 4 patches in pad mode
|
||||
"""
|
||||
slice_to_patches([99, 199], 2, 2, True, plot=plot)
|
||||
|
||||
|
||||
def test_slice_patches_04(plot=False):
|
||||
"""
|
||||
slice rgb image(99, 199) to 4 patches in drop mode
|
||||
"""
|
||||
slice_to_patches([99, 199], 2, 2, False, plot=plot)
|
||||
|
||||
|
||||
def test_slice_patches_05(plot=False):
|
||||
"""
|
||||
slice rgb image(99, 199) to 4 patches in pad mode
|
||||
"""
|
||||
slice_to_patches([99, 199], 2, 2, True, 255, plot=plot)
|
||||
|
||||
|
||||
def slice_to_patches(ori_size, num_h, num_w, pad_or_drop, fill_value=0, plot=False):
|
||||
"""
|
||||
Tool function for slice patches
|
||||
"""
|
||||
logger.info("test_slice_patches_pipeline")
|
||||
|
||||
cols = ['img' + str(x) for x in range(num_h*num_w)]
|
||||
# First dataset
|
||||
dataset1 = ds.TFRecordDataset(DATA_DIR, SCHEMA_DIR, shuffle=False)
|
||||
decode_op = c_vision.Decode()
|
||||
resize_op = c_vision.Resize(ori_size) # H, W
|
||||
slice_patches_op = c_vision.SlicePatches(
|
||||
num_h, num_w, mode.SliceMode.PAD, fill_value)
|
||||
if not pad_or_drop:
|
||||
slice_patches_op = c_vision.SlicePatches(
|
||||
num_h, num_w, mode.SliceMode.DROP)
|
||||
dataset1 = dataset1.map(operations=decode_op, input_columns=["image"])
|
||||
dataset1 = dataset1.map(operations=resize_op, input_columns=["image"])
|
||||
dataset1 = dataset1.map(operations=slice_patches_op,
|
||||
input_columns=["image"], output_columns=cols, column_order=cols)
|
||||
# Second dataset
|
||||
dataset2 = ds.TFRecordDataset(DATA_DIR, SCHEMA_DIR, shuffle=False)
|
||||
dataset2 = dataset2.map(operations=decode_op, input_columns=["image"])
|
||||
dataset2 = dataset2.map(operations=resize_op, input_columns=["image"])
|
||||
func_slice_patches = functools.partial(
|
||||
slice_patches, num_h=num_h, num_w=num_w, pad_or_drop=pad_or_drop, fill_value=fill_value)
|
||||
dataset2 = dataset2.map(operations=func_slice_patches,
|
||||
input_columns=["image"], output_columns=cols, column_order=cols)
|
||||
|
||||
num_iter = 0
|
||||
patches_c = []
|
||||
patches_py = []
|
||||
for data1, data2 in zip(dataset1.create_dict_iterator(num_epochs=1, output_numpy=True),
|
||||
dataset2.create_dict_iterator(num_epochs=1, output_numpy=True)):
|
||||
|
||||
for x in range(num_h*num_w):
|
||||
col = "img" + str(x)
|
||||
mse = diff_mse(data1[col], data2[col])
|
||||
logger.info("slice_patches_{}, mse: {}".format(num_iter + 1, mse))
|
||||
assert mse == 0
|
||||
patches_c.append(data1[col])
|
||||
patches_py.append(data2[col])
|
||||
num_iter += 1
|
||||
if plot:
|
||||
visualize_list(patches_py, patches_c)
|
||||
|
||||
|
||||
def test_slice_patches_exception_01():
|
||||
"""
|
||||
Test SlicePatches with invalid parameters
|
||||
"""
|
||||
logger.info("test_Slice_Patches_exception")
|
||||
try:
|
||||
_ = c_vision.SlicePatches(0, 2)
|
||||
except ValueError as e:
|
||||
logger.info("Got an exception in SlicePatches: {}".format(str(e)))
|
||||
assert "Input num_height is not within" in str(e)
|
||||
|
||||
try:
|
||||
_ = c_vision.SlicePatches(2, 0)
|
||||
except ValueError as e:
|
||||
logger.info("Got an exception in SlicePatches: {}".format(str(e)))
|
||||
assert "Input num_width is not within" in str(e)
|
||||
|
||||
try:
|
||||
_ = c_vision.SlicePatches(2, 2, 1)
|
||||
except TypeError as e:
|
||||
logger.info("Got an exception in SlicePatches: {}".format(str(e)))
|
||||
assert "Argument slice_mode with value" in str(e)
|
||||
|
||||
try:
|
||||
_ = c_vision.SlicePatches(2, 2, mode.SliceMode.PAD, -1)
|
||||
except ValueError as e:
|
||||
logger.info("Got an exception in SlicePatches: {}".format(str(e)))
|
||||
assert "Input fill_value is not within" in str(e)
|
||||
|
||||
|
||||
def slice_patches(image, num_h, num_w, pad_or_drop, fill_value):
|
||||
""" help function which slice patches with numpy """
|
||||
if num_h == 1 and num_w == 1:
|
||||
return image
|
||||
# (H, W, C)
|
||||
H, W, C = image.shape
|
||||
patch_h = H // num_h
|
||||
patch_w = W // num_w
|
||||
if H % num_h != 0:
|
||||
if pad_or_drop:
|
||||
patch_h += 1
|
||||
if W % num_w != 0:
|
||||
if pad_or_drop:
|
||||
patch_w += 1
|
||||
img = image[:, :, :]
|
||||
if pad_or_drop:
|
||||
img = np.full([patch_h*num_h, patch_w*num_w, C], fill_value, dtype=np.uint8)
|
||||
img[:H, :W] = image[:, :, :]
|
||||
patches = []
|
||||
for top in range(num_h):
|
||||
for left in range(num_w):
|
||||
patches.append(img[top*patch_h:(top+1)*patch_h,
|
||||
left*patch_w:(left+1)*patch_w, :])
|
||||
|
||||
return (*patches,)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_slice_patches_01(plot=True)
|
||||
test_slice_patches_02(plot=True)
|
||||
test_slice_patches_03(plot=True)
|
||||
test_slice_patches_04(plot=True)
|
||||
test_slice_patches_05(plot=True)
|
||||
test_slice_patches_exception_01()
|
Loading…
Reference in New Issue