mirror of https://github.com/alibaba/MNN.git
129 lines
6.0 KiB
C++
129 lines
6.0 KiB
C++
//
|
|
// GeometryCropAndResize.cpp
|
|
// MNN
|
|
//
|
|
// Created by MNN on 2020/08/5.
|
|
// Copyright © 2018, Alibaba Group Holding Limited
|
|
//
|
|
|
|
#include "geometry/GeometryComputer.hpp"
|
|
#include "core/OpCommonUtils.hpp"
|
|
#include "geometry/GeometryComputerUtils.hpp"
|
|
#include "ConvertUtils.hpp"
|
|
|
|
namespace MNN {
|
|
class GeometryCropAndResize : public GeometryComputer {
|
|
public:
|
|
virtual bool onCompute(const Op* op, const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs, Context& context, CommandBuffer& res) const override {
|
|
MNN_ASSERT(4 == inputs.size());
|
|
MNN_ASSERT(1 == outputs.size());
|
|
auto img = inputs[0];
|
|
auto boxes = inputs[1];
|
|
auto box_ind = inputs[2];
|
|
auto crop_size = inputs[3];
|
|
auto output = outputs[0];
|
|
auto extrapolation = op->main_as_CropAndResize()->extrapolationValue();
|
|
auto method = op->main_as_CropAndResize()->method();
|
|
// resizeType of Interp : 1-NEAREST, 2-BILINEAR
|
|
const int resizeType = method == CropAndResizeMethod_BILINEAR ? 2 : 1;
|
|
|
|
int batch = img->length(0), ih = img->length(1), iw = img->length(2),
|
|
depth = img->length(3), boxNum = boxes->length(0);
|
|
const int cropHeight = crop_size->host<uint32_t>()[0],
|
|
cropWidth = crop_size->host<uint32_t>()[1];
|
|
|
|
auto des = TensorUtils::getDescribe(output);
|
|
des->memoryType = Tensor::InsideDescribe::MEMORY_VIRTUAL;
|
|
des->dimensionFormat = MNN_DATA_FORMAT_NHWC;
|
|
des->regions.clear();
|
|
des->regions.reserve(boxNum);
|
|
for (int i = 0; i < boxNum; i++) {
|
|
const float y1 = boxes->host<float>()[i*4];
|
|
const float x1 = boxes->host<float>()[i*4+1];
|
|
const float y2 = boxes->host<float>()[i*4+2];
|
|
const float x2 = boxes->host<float>()[i*4+3];
|
|
const int ind = box_ind->host<uint32_t>()[i];
|
|
const float ch = (y2 - y1) * (ih - 1), cw = (x2 - x1) * (iw - 1);
|
|
const float yScale = ch / static_cast<float>(cropHeight - 1);
|
|
const float xScale = cw / static_cast<float>(cropWidth - 1);
|
|
const float yOffset = y1 * (ih - 1), xOffset = x1 * (iw - 1);
|
|
// select croped image from images, convert it's format from NHWC to NC4HW4
|
|
std::shared_ptr<Tensor> cropValue(new Tensor);
|
|
{
|
|
cropValue->buffer().type = halide_type_of<float>();
|
|
cropValue->buffer().dimensions = 4;
|
|
cropValue->setLength(0, 1);
|
|
cropValue->setLength(1, depth);
|
|
cropValue->setLength(2, ih);
|
|
cropValue->setLength(3, iw);
|
|
auto des = TensorUtils::getDescribe(cropValue.get());
|
|
des->memoryType = Tensor::InsideDescribe::MEMORY_VIRTUAL;
|
|
des->dimensionFormat = MNN_DATA_FORMAT_NC4HW4;
|
|
des->regions.clear();
|
|
Tensor::InsideDescribe::Region region;
|
|
region.origin = img;
|
|
region.size[1] = depth;
|
|
region.size[2] = ih * iw;
|
|
region.src.offset = ind * ih * iw * depth;
|
|
region.dst.offset = 0;
|
|
region.src.stride[1] = 1;
|
|
region.src.stride[2] = depth;
|
|
region.dst.stride[1] = ih * iw;
|
|
region.dst.stride[2] = 1;
|
|
des->regions.emplace_back(std::move(region));
|
|
res.extras.emplace_back(cropValue);
|
|
}
|
|
// using Interp Op deal with crop and resize for selected image
|
|
std::shared_ptr<Tensor> resizeValue;
|
|
{
|
|
resizeValue.reset(Tensor::createDevice<float>({1, depth, cropHeight, cropWidth}));
|
|
auto des = TensorUtils::getDescribe(resizeValue.get());
|
|
des->dimensionFormat = MNN_DATA_FORMAT_NC4HW4;
|
|
std::unique_ptr<OpT> interp(new OpT);
|
|
interp->type = OpType_Interp;
|
|
interp->main.type = OpParameter_Interp;
|
|
interp->main.value = new InterpT;
|
|
interp->main.AsInterp()->widthScale = xScale;
|
|
interp->main.AsInterp()->heightScale = yScale;
|
|
interp->main.AsInterp()->widthOffset = xOffset;
|
|
interp->main.AsInterp()->heightOffset = yOffset;
|
|
interp->main.AsInterp()->alignCorners = false;
|
|
interp->main.AsInterp()->resizeType = resizeType;
|
|
auto cmd = GeometryComputerUtils::makeCommand(interp.get(), {cropValue.get()}, {resizeValue.get()});
|
|
res.extras.emplace_back(resizeValue);
|
|
res.command.emplace_back(cmd);
|
|
}
|
|
// convert resize image's format from NC4HW4 to NHWC, add it to output's batch
|
|
{
|
|
Tensor::InsideDescribe::Region region;
|
|
region.origin = resizeValue.get();
|
|
region.size[1] = cropHeight * cropWidth;
|
|
region.size[2] = depth;
|
|
region.src.offset = 0;
|
|
region.dst.offset = i * cropHeight * cropWidth * depth;
|
|
region.src.stride[1] = 1;
|
|
region.src.stride[2] = cropHeight * cropWidth;
|
|
region.dst.stride[1] = depth;
|
|
region.dst.stride[2] = 1;
|
|
des->regions.emplace_back(std::move(region));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
virtual std::vector<bool> onGetOutputVirtual(const Op* op, const std::vector<Tensor*>& inputs,
|
|
const std::vector<Tensor*>& outputs) const override {
|
|
//return {false};
|
|
return {true};
|
|
}
|
|
};
|
|
|
|
static void _create() {
|
|
std::shared_ptr<GeometryComputer> comp(new GeometryCropAndResize);
|
|
// GeometryComputer::registerGeometryComputer(comp, {OpType_CropAndResize});
|
|
}
|
|
|
|
REGISTER_GEOMETRY(GeometryCropAndResize, _create);
|
|
|
|
} // namespace MNN
|