MNN/source/cv/ImageProcess.cpp

199 lines
6.4 KiB
C++
Raw Normal View History

2019-04-17 10:49:11 +08:00
//
// ImageProcess.cpp
// MNN
//
// Created by MNN on 2018/12/24.
// Copyright © 2018, Alibaba Group Holding Limited
//
#include <algorithm>
#include <map>
#include <MNN/ImageProcess.hpp>
2019-12-27 22:16:57 +08:00
#include "core/Macro.h"
#include "core/TensorUtils.hpp"
2019-04-17 10:49:11 +08:00
#define MNN_OPEN_TIME_TRACE
2019-12-27 22:16:57 +08:00
#include <MNN/AutoTime.hpp>
2020-02-29 16:44:08 +08:00
#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"
2024-02-29 16:21:40 +08:00
#include "ImageProcessUtils.hpp"
2021-04-08 15:34:23 +08:00
#ifdef _MSC_VER
#include "backend/cpu/x86_x64/cpu_id.h"
#endif
2019-04-17 10:49:11 +08:00
namespace MNN {
void registerBackend();
2019-04-17 10:49:11 +08:00
namespace CV {
struct ImageProcess::Inside {
Config config;
2024-02-29 16:21:40 +08:00
// ImageProcessUtils* proc;
std::unique_ptr<ImageProcessUtils> proc;
2019-04-17 10:49:11 +08:00
};
2022-08-12 10:30:48 +08:00
void ImageProcess::destroy(ImageProcess* pro) {
if (nullptr != pro) {
delete pro;
}
}
2019-04-17 10:49:11 +08:00
ImageProcess::~ImageProcess() {
delete mInside;
}
ImageProcess::ImageProcess(const Config& config) {
mInside = new Inside;
mInside->config = config;
registerBackend();
2023-06-16 09:42:45 +08:00
auto coreFunctions = MNNGetCoreFunctions();
2024-02-29 16:21:40 +08:00
mInside->proc.reset(new ImageProcessUtils(config, coreFunctions));
2019-04-17 10:49:11 +08:00
}
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);
}
2024-02-29 16:21:40 +08:00
void ImageProcess::setMatrix(const CV::Matrix& matrix) {
mInside->proc->setMatrix(matrix);
2019-04-17 10:49:11 +08:00
}
2024-02-29 16:21:40 +08:00
static int _getBpp(CV::ImageFormat format) {
2019-04-17 10:49:11 +08:00
switch (format) {
2024-02-29 16:21:40 +08:00
case CV::RGB:
case CV::BGR:
case CV::YCrCb:
case CV::YUV:
case CV::HSV:
case CV::XYZ:
2019-04-17 10:49:11 +08:00
return 3;
2024-02-29 16:21:40 +08:00
case CV::RGBA:
case CV::BGRA:
2019-04-17 10:49:11 +08:00
return 4;
2024-02-29 16:21:40 +08:00
case CV::GRAY:
2019-04-17 10:49:11 +08:00
return 1;
2024-02-29 16:21:40 +08:00
case CV::BGR555:
case CV::BGR565:
return 2;
2019-04-17 10:49:11 +08:00
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);
}
2024-02-29 16:21:40 +08:00
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;
}
2024-02-29 16:21:40 +08:00
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;
}
2019-04-17 10:49:11 +08:00
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;
}
2024-04-19 11:58:21 +08:00
if (TensorUtils::getDescribeOrigin(dest)->getBackend() == nullptr && destOrigin->buffer().host == nullptr) {
2020-11-05 16:41:56 +08:00
MNN_ERROR("Invalid Tensor, the session may not be ready\n");
return INPUT_DATA_ERROR;
}
2019-04-17 10:49:11 +08:00
std::shared_ptr<Tensor> tempTensor;
2020-02-29 16:44:08 +08:00
auto ow = dest->width();
auto oh = dest->height();
auto bpp = dest->channel();
auto dimensionFormat = TensorUtils::getDescribe(dest)->dimensionFormat;
2024-04-19 11:58:21 +08:00
auto tensorBn = TensorUtils::getDescribeOrigin(dest)->getBackend();
auto bnType = MNN_FORWARD_CPU;
if(tensorBn){
bnType = tensorBn->type();
}
if (bnType != MNN_FORWARD_CPU) {
2020-02-29 16:44:08 +08:00
tempTensor.reset(Tensor::create({1, bpp, oh, ow}, dest->getType(), nullptr, Tensor::CAFFE_C4),[destOrigin] (void* p) {
2019-04-17 10:49:11 +08:00
auto hostTensor = (Tensor*)p;
destOrigin->copyFromHostTensor(hostTensor);
delete hostTensor;
});
dest = tempTensor.get();
}
2020-02-29 16:44:08 +08:00
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();
2019-04-17 10:49:11 +08:00
}
2020-02-29 16:44:08 +08:00
dimensionFormat = TensorUtils::getDescribe(dest)->dimensionFormat;
2019-04-17 10:49:11 +08:00
if (dimensionFormat == MNN_DATA_FORMAT_NC4HW4) {
bpp = 4;
2019-04-17 10:49:11 +08:00
}
2024-02-29 16:21:40 +08:00
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>());
}
2019-04-17 10:49:11 +08:00
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) {
2024-02-29 16:21:40 +08:00
int ic = _getBpp(mInside->config.sourceFormat);
int oc = outputBpp;
if (outputBpp == 0) {
oc = _getBpp(mInside->config.destFormat);
}
2024-02-29 16:21:40 +08:00
mInside->proc->setPadding(mPaddingValue);
mInside->proc->resizeFunc(ic, iw, ih, oc, ow, oh, type, stride);
return mInside->proc->execFunc(source, stride, dest);
2019-04-17 10:49:11 +08:00
}
2022-02-18 11:30:27 +08:00
2022-05-06 19:51:20 +08:00
void ImageProcess::setDraw() {
2024-02-29 16:21:40 +08:00
if (mInside && mInside->proc) {
mInside->proc->setDraw();
2022-05-06 19:51:20 +08:00
}
}
2022-02-18 11:30:27 +08:00
void ImageProcess::draw(uint8_t* img, int w, int h, int c, const int* regions, int num, const uint8_t* color) {
2024-02-29 16:21:40 +08:00
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);
2022-02-18 11:30:27 +08:00
}
2019-04-17 10:49:11 +08:00
} // namespace CV
} // namespace MNN