source/cv/ImageProcess.cpp (170 lines of code) (raw):

// // ImageProcess.cpp // MNN // // Created by MNN on 2018/12/24. // Copyright © 2018, Alibaba Group Holding Limited // #include <algorithm> #include <map> #include <MNN/ImageProcess.hpp> #include "core/Macro.h" #include "core/TensorUtils.hpp" #define MNN_OPEN_TIME_TRACE #include <MNN/AutoTime.hpp> #include "backend/cpu/CPUTensorConvert.hpp" #include <MNN/MNNForwardType.h> #include "core/Backend.hpp" #include <MNN/Tensor.hpp> #include <MNN/Interpreter.hpp> #include "core/Execution.hpp" #include "core/Backend.hpp" #include "MNN_generated.h" #include "ImageProcessUtils.hpp" #ifdef _MSC_VER #include "backend/cpu/x86_x64/cpu_id.h" #endif namespace MNN { void registerBackend(); namespace CV { struct ImageProcess::Inside { Config config; // ImageProcessUtils* proc; std::unique_ptr<ImageProcessUtils> proc; }; void ImageProcess::destroy(ImageProcess* pro) { if (nullptr != pro) { delete pro; } } ImageProcess::~ImageProcess() { delete mInside; } ImageProcess::ImageProcess(const Config& config) { mInside = new Inside; mInside->config = config; registerBackend(); auto coreFunctions = MNNGetCoreFunctions(); mInside->proc.reset(new ImageProcessUtils(config, coreFunctions)); } ImageProcess* ImageProcess::create(const Config& config, const Tensor* dstTensor) { // TODO Get dstTensor' backend return new ImageProcess(config); } ImageProcess* ImageProcess::create(const ImageFormat sourceFormat, const ImageFormat destFormat, const float* means, const int meanCount, const float* normals, const int normalCount, const Tensor* dstTensor) { MNN::CV::ImageProcess::Config config; if (means != nullptr && meanCount > 0) { ::memcpy(config.mean, means, sizeof(float) * meanCount); } if (normals != nullptr && normalCount > 0) { ::memcpy(config.normal, normals, sizeof(float) * normalCount); } config.sourceFormat = sourceFormat; config.destFormat = destFormat; return new ImageProcess(config); } void ImageProcess::setMatrix(const CV::Matrix& matrix) { mInside->proc->setMatrix(matrix); } static int _getBpp(CV::ImageFormat format) { switch (format) { case CV::RGB: case CV::BGR: case CV::YCrCb: case CV::YUV: case CV::HSV: case CV::XYZ: return 3; case CV::RGBA: case CV::BGRA: return 4; case CV::GRAY: return 1; case CV::BGR555: case CV::BGR565: return 2; default: break; } return 0; } Tensor* ImageProcess::createImageTensor(halide_type_t type, int width, int height, int bpp, void* p) { return Tensor::create(std::vector<int>{1, height, width, bpp}, type, p); } static CV::ImageFormat _correctImageFormat(int outputBpp, halide_type_t type, CV::ImageFormat format) { if (outputBpp != 4) { return format; } // TODO, use same judge for uint8 -> float if (type.code == halide_type_float) { return format; } static std::map<CV::ImageFormat, CV::ImageFormat> imageFormatTable = {{CV::RGB, CV::RGBA}, {CV::BGR, CV::BGRA}, {CV::GRAY, CV::RGBA}}; if (imageFormatTable.find(format) != imageFormatTable.end()) { return imageFormatTable.find(format)->second; } return format; } ErrorCode ImageProcess::convert(const uint8_t* source, int iw, int ih, int stride, Tensor* destOrigin) { auto dest = destOrigin; if (nullptr == dest || nullptr == source) { MNN_ERROR("null dest or source for image process\n"); return INPUT_DATA_ERROR; } if (TensorUtils::getDescribeOrigin(dest)->getBackend() == nullptr && destOrigin->buffer().host == nullptr) { MNN_ERROR("Invalid Tensor, the session may not be ready\n"); return INPUT_DATA_ERROR; } std::shared_ptr<Tensor> tempTensor; auto ow = dest->width(); auto oh = dest->height(); auto bpp = dest->channel(); auto dimensionFormat = TensorUtils::getDescribe(dest)->dimensionFormat; auto tensorBn = TensorUtils::getDescribeOrigin(dest)->getBackend(); auto bnType = MNN_FORWARD_CPU; if(tensorBn){ bnType = tensorBn->type(); } if (bnType != MNN_FORWARD_CPU) { tempTensor.reset(Tensor::create({1, bpp, oh, ow}, dest->getType(), nullptr, Tensor::CAFFE_C4),[destOrigin] (void* p) { auto hostTensor = (Tensor*)p; destOrigin->copyFromHostTensor(hostTensor); delete hostTensor; }); dest = tempTensor.get(); } else if (MNN_DATA_FORMAT_NCHW == dimensionFormat) { tempTensor.reset(Tensor::create(dest->shape(), dest->getType(), nullptr, Tensor::CAFFE_C4), [destOrigin](void* p) { auto hostTensor = (Tensor*)p; CPUTensorConverter::convert(hostTensor, destOrigin); delete hostTensor; }); dest = tempTensor.get(); } dimensionFormat = TensorUtils::getDescribe(dest)->dimensionFormat; if (dimensionFormat == MNN_DATA_FORMAT_NC4HW4) { bpp = 4; } int ic = _getBpp(mInside->config.sourceFormat); mInside->proc->setPadding(mPaddingValue); mInside->proc->resizeFunc(ic, iw, ih, bpp, ow, oh, dest->getType(), stride); return mInside->proc->execFunc(source, stride, dest->host<void>()); } ErrorCode ImageProcess::convert(const uint8_t* source, int iw, int ih, int stride, void* dest, int ow, int oh, int outputBpp, int outputStride, halide_type_t type) { int ic = _getBpp(mInside->config.sourceFormat); int oc = outputBpp; if (outputBpp == 0) { oc = _getBpp(mInside->config.destFormat); } mInside->proc->setPadding(mPaddingValue); mInside->proc->resizeFunc(ic, iw, ih, oc, ow, oh, type, stride); return mInside->proc->execFunc(source, stride, dest); } void ImageProcess::setDraw() { if (mInside && mInside->proc) { mInside->proc->setDraw(); } } void ImageProcess::draw(uint8_t* img, int w, int h, int c, const int* regions, int num, const uint8_t* color) { std::vector<int32_t> tmpReg(3 * num); ::memcpy(tmpReg.data(), (void*)regions, 4 * 3 * num); double tmpBuf[4]; ::memcpy(tmpBuf, color, 4 * sizeof(double)); mInside->proc->resizeFunc(c, w, h, c, w, h); mInside->proc->draw(img, w, h, c, tmpReg.data(), num, (uint8_t*)tmpBuf); } } // namespace CV } // namespace MNN