mirror of https://github.com/alibaba/MNN.git
434 lines
13 KiB
C++
434 lines
13 KiB
C++
//
|
|
// ImageBlitter.cpp
|
|
// MNN
|
|
//
|
|
// Created by MNN on 2018/12/24.
|
|
// Copyright © 2018, Alibaba Group Holding Limited
|
|
//
|
|
|
|
#include "cv/ImageBlitter.hpp"
|
|
#include <string.h>
|
|
#include <mutex>
|
|
#include "core/Macro.h"
|
|
#ifdef MNN_USE_NEON
|
|
#include <arm_neon.h>
|
|
#endif
|
|
|
|
#include <map>
|
|
extern "C" {
|
|
void MNNNV21ToRGBUnit(const unsigned char* source, unsigned char* dest, size_t countDiv8, const unsigned char* uv);
|
|
void MNNNV21ToBGRUnit(const unsigned char* source, unsigned char* dest, size_t countDiv8, const unsigned char* uv);
|
|
void MNNNV21ToRGBAUnit(const unsigned char* source, unsigned char* dest, size_t countDiv8, const unsigned char* uv);
|
|
}
|
|
|
|
namespace MNN {
|
|
namespace CV {
|
|
|
|
static void _gray2C4(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
for (int i = 0; i < countD8; ++i) {
|
|
auto gray = vld1_u8(source + 8 * i);
|
|
|
|
uint8x8x4_t rgba;
|
|
rgba.val[0] = gray;
|
|
rgba.val[1] = gray;
|
|
rgba.val[2] = gray;
|
|
rgba.val[3] = vdup_n_u8(255);
|
|
vst4_u8(dest + 32 * i, rgba);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
dest[4 * i + 0] = source[i];
|
|
dest[4 * i + 1] = source[i];
|
|
dest[4 * i + 2] = source[i];
|
|
dest[4 * i + 3] = 255;
|
|
}
|
|
}
|
|
|
|
static void _gray2C3(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
for (int i = 0; i < countD8; ++i) {
|
|
auto gray = vld1_u8(source + 8 * i);
|
|
|
|
uint8x8x3_t rgba;
|
|
rgba.val[0] = gray;
|
|
rgba.val[1] = gray;
|
|
rgba.val[2] = gray;
|
|
vst3_u8(dest + 24 * i, rgba);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
dest[3 * i + 0] = source[i];
|
|
dest[3 * i + 1] = source[i];
|
|
dest[3 * i + 2] = source[i];
|
|
}
|
|
}
|
|
|
|
static void _copyC1(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
::memcpy(dest, source, count * sizeof(unsigned char));
|
|
}
|
|
|
|
static void _copyC4(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
::memcpy(dest, source, 4 * count * sizeof(unsigned char));
|
|
}
|
|
|
|
static void _copyC3(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
::memcpy(dest, source, 3 * count * sizeof(unsigned char));
|
|
}
|
|
|
|
static void _rgba2bgra(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
for (int i = 0; i < countD8; ++i) {
|
|
uint8x8x4_t rgba = vld4_u8(source + 32 * i);
|
|
auto t = rgba.val[0];
|
|
rgba.val[0] = rgba.val[2];
|
|
rgba.val[2] = t;
|
|
vst4_u8(dest + 32 * i, rgba);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
dest[4 * i + 0] = source[4 * i + 2];
|
|
dest[4 * i + 1] = source[4 * i + 1];
|
|
dest[4 * i + 2] = source[4 * i + 0];
|
|
dest[4 * i + 3] = source[4 * i + 3];
|
|
}
|
|
}
|
|
static void _rgba2bgr(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
for (int i = 0; i < countD8; ++i) {
|
|
uint8x8x4_t rgba = vld4_u8(source + 32 * i);
|
|
|
|
uint8x8x3_t bgr;
|
|
bgr.val[0] = rgba.val[2];
|
|
bgr.val[1] = rgba.val[1];
|
|
bgr.val[2] = rgba.val[0];
|
|
vst3_u8(dest + 24 * i, bgr);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
dest[3 * i + 0] = source[4 * i + 2];
|
|
dest[3 * i + 1] = source[4 * i + 1];
|
|
dest[3 * i + 2] = source[4 * i + 0];
|
|
}
|
|
}
|
|
static void _rgb2bgr(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
for (int i = 0; i < countD8; ++i) {
|
|
uint8x8x3_t rgba = vld3_u8(source + 24 * i);
|
|
uint8x8x3_t bgr;
|
|
bgr.val[0] = rgba.val[2];
|
|
bgr.val[1] = rgba.val[1];
|
|
bgr.val[2] = rgba.val[0];
|
|
vst3_u8(dest + 24 * i, bgr);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
dest[3 * i + 0] = source[3 * i + 2];
|
|
dest[3 * i + 1] = source[3 * i + 1];
|
|
dest[3 * i + 2] = source[3 * i + 0];
|
|
}
|
|
}
|
|
static void _bgra2bgr(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
for (int i = 0; i < countD8; ++i) {
|
|
uint8x8x4_t bgra = vld4_u8(source + 32 * i);
|
|
|
|
uint8x8x3_t bgr;
|
|
bgr.val[0] = bgra.val[0];
|
|
bgr.val[1] = bgra.val[1];
|
|
bgr.val[2] = bgra.val[2];
|
|
vst3_u8(dest + 24 * i, bgr);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
dest[3 * i + 0] = source[4 * i + 0];
|
|
dest[3 * i + 1] = source[4 * i + 1];
|
|
dest[3 * i + 2] = source[4 * i + 2];
|
|
}
|
|
}
|
|
|
|
static void _bgra2gray(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
auto rC = vdup_n_u8(19);
|
|
auto gC = vdup_n_u8(38);
|
|
auto bC = vdup_n_u8(7);
|
|
for (int i = 0; i < countD8; ++i) {
|
|
auto rgb = vld4_u8(source + 32 * i);
|
|
auto res = vmull_u8(rC, rgb.val[2]) + vmull_u8(gC, rgb.val[1]) + vmull_u8(bC, rgb.val[0]);
|
|
auto resU8 = vshrn_n_u16(res, 6);
|
|
vst1_u8(dest + 8 * i, resU8);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
int r = source[4 * i + 2];
|
|
int g = source[4 * i + 1];
|
|
int b = source[4 * i + 0];
|
|
|
|
int y = (19 * r + 38 * g + 7 * b) >> 6;
|
|
|
|
dest[i] = y;
|
|
}
|
|
}
|
|
|
|
static void _rgba2gray(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
auto rC = vdup_n_u8(19);
|
|
auto gC = vdup_n_u8(38);
|
|
auto bC = vdup_n_u8(7);
|
|
for (int i = 0; i < countD8; ++i) {
|
|
auto rgb = vld4_u8(source + 32 * i);
|
|
auto res = vmull_u8(rC, rgb.val[0]) + vmull_u8(gC, rgb.val[1]) + vmull_u8(bC, rgb.val[2]);
|
|
auto resU8 = vshrn_n_u16(res, 6);
|
|
vst1_u8(dest + 8 * i, resU8);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
int r = source[4 * i + 0];
|
|
int g = source[4 * i + 1];
|
|
int b = source[4 * i + 2];
|
|
|
|
int y = (19 * r + 38 * g + 7 * b) >> 6;
|
|
|
|
dest[i] = y;
|
|
}
|
|
}
|
|
|
|
static void _rgb2gray(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
auto rC = vdup_n_u8(19);
|
|
auto gC = vdup_n_u8(38);
|
|
auto bC = vdup_n_u8(7);
|
|
for (int i = 0; i < countD8; ++i) {
|
|
auto rgb = vld3_u8(source + 24 * i);
|
|
auto res = vmull_u8(rC, rgb.val[0]) + vmull_u8(gC, rgb.val[1]) + vmull_u8(bC, rgb.val[2]);
|
|
auto resU8 = vshrn_n_u16(res, 6);
|
|
vst1_u8(dest + 8 * i, resU8);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
int r = source[3 * i + 0];
|
|
int g = source[3 * i + 1];
|
|
int b = source[3 * i + 2];
|
|
|
|
int y = (19 * r + 38 * g + 7 * b) >> 6;
|
|
|
|
dest[i] = y;
|
|
}
|
|
}
|
|
|
|
static void _bgr2gray(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
int countD8 = (int)count / 8;
|
|
if (countD8 > 0) {
|
|
auto rC = vdup_n_u8(19);
|
|
auto gC = vdup_n_u8(38);
|
|
auto bC = vdup_n_u8(7);
|
|
for (int i = 0; i < countD8; ++i) {
|
|
auto rgb = vld3_u8(source + 24 * i);
|
|
auto res = vmull_u8(rC, rgb.val[2]) + vmull_u8(gC, rgb.val[1]) + vmull_u8(bC, rgb.val[0]);
|
|
auto resU8 = vshrn_n_u16(res, 6);
|
|
vst1_u8(dest + 8 * i, resU8);
|
|
}
|
|
sta = countD8 * 8;
|
|
}
|
|
#endif
|
|
|
|
for (int i = sta; i < count; ++i) {
|
|
int r = source[3 * i + 2];
|
|
int g = source[3 * i + 1];
|
|
int b = source[3 * i + 0];
|
|
|
|
int y = (19 * r + 38 * g + 7 * b) >> 6;
|
|
|
|
dest[i] = y;
|
|
}
|
|
}
|
|
|
|
void MNNNV21ToRGBA(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
auto y = source;
|
|
auto uv = source + count;
|
|
auto dst = dest;
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
const int unit = 16;
|
|
size_t countDiv8 = count / unit;
|
|
if (countDiv8 > 0) {
|
|
MNNNV21ToRGBAUnit(source, dest, countDiv8, uv);
|
|
sta = (int)countDiv8 * unit;
|
|
}
|
|
#endif
|
|
|
|
for (int i = sta; i < count; ++i) {
|
|
int Y = y[i];
|
|
int U = (int)uv[(i / 2) * 2 + 1] - 128;
|
|
int V = (int)uv[(i / 2) * 2 + 0] - 128;
|
|
|
|
Y = Y << 6;
|
|
int R = (Y + 73 * V) >> 6;
|
|
int G = (Y - 25 * U - 37 * V) >> 6;
|
|
int B = (Y + 130 * U) >> 6;
|
|
|
|
R = std::min(std::max(R, 0), 255);
|
|
G = std::min(std::max(G, 0), 255);
|
|
B = std::min(std::max(B, 0), 255);
|
|
|
|
dst[4 * i + 0] = (uint8_t)R;
|
|
dst[4 * i + 1] = (uint8_t)G;
|
|
dst[4 * i + 2] = (uint8_t)B;
|
|
dst[4 * i + 3] = 255;
|
|
}
|
|
}
|
|
|
|
void MNNNV21ToRGB(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
auto y = source;
|
|
auto uv = source + count;
|
|
auto dst = dest;
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
const int unit = 16;
|
|
size_t countDiv8 = count / unit;
|
|
if (countDiv8 > 0) {
|
|
MNNNV21ToRGBUnit(source, dest, countDiv8, uv);
|
|
sta = (int)countDiv8 * unit;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
int Y = y[i];
|
|
int U = (int)uv[(i / 2) * 2 + 1] - 128;
|
|
int V = (int)uv[(i / 2) * 2 + 0] - 128;
|
|
|
|
Y = Y << 6;
|
|
int R = (Y + 73 * V) >> 6;
|
|
int G = (Y - 25 * U - 37 * V) >> 6;
|
|
int B = (Y + 130 * U) >> 6;
|
|
|
|
R = std::min(std::max(R, 0), 255);
|
|
G = std::min(std::max(G, 0), 255);
|
|
B = std::min(std::max(B, 0), 255);
|
|
|
|
dst[3 * i + 0] = (uint8_t)R;
|
|
dst[3 * i + 1] = (uint8_t)G;
|
|
dst[3 * i + 2] = (uint8_t)B;
|
|
}
|
|
}
|
|
|
|
void MNNNV21ToBGR(const unsigned char* source, unsigned char* dest, size_t count) {
|
|
auto y = source;
|
|
auto uv = source + count;
|
|
auto dst = dest;
|
|
int sta = 0;
|
|
#ifdef MNN_USE_NEON
|
|
const int unit = 16;
|
|
size_t countDiv8 = count / unit;
|
|
if (countDiv8 > 0) {
|
|
MNNNV21ToBGRUnit(source, dest, countDiv8, uv);
|
|
sta = (int)countDiv8 * unit;
|
|
}
|
|
#endif
|
|
for (int i = sta; i < count; ++i) {
|
|
int Y = y[i];
|
|
int U = (int)uv[(i / 2) * 2 + 1] - 128;
|
|
int V = (int)uv[(i / 2) * 2 + 0] - 128;
|
|
|
|
Y = Y << 6;
|
|
int R = (Y + 73 * V) >> 6;
|
|
int G = (Y - 25 * U - 37 * V) >> 6;
|
|
int B = (Y + 130 * U) >> 6;
|
|
|
|
R = std::min(std::max(R, 0), 255);
|
|
G = std::min(std::max(G, 0), 255);
|
|
B = std::min(std::max(B, 0), 255);
|
|
|
|
dst[3 * i + 0] = (uint8_t)B;
|
|
dst[3 * i + 1] = (uint8_t)G;
|
|
dst[3 * i + 2] = (uint8_t)R;
|
|
}
|
|
}
|
|
|
|
#define CHECKFORMAT(src, dst, func)\
|
|
if (source == src && dest == dst) return func
|
|
|
|
ImageBlitter::BLITTER ImageBlitter::choose(ImageFormat source, ImageFormat dest) {
|
|
if (source == YUV_NV12) {
|
|
source = YUV_NV21;
|
|
}
|
|
CHECKFORMAT(RGBA, RGBA, _copyC4);
|
|
CHECKFORMAT(RGBA, BGRA, _rgba2bgra);
|
|
CHECKFORMAT(RGBA, BGR, _rgba2bgr);
|
|
CHECKFORMAT(RGBA, RGB, _bgra2bgr);
|
|
CHECKFORMAT(RGBA, GRAY, _rgba2gray);
|
|
CHECKFORMAT(BGRA, RGBA, _rgba2bgra);
|
|
CHECKFORMAT(BGRA, BGRA, _copyC4);
|
|
CHECKFORMAT(BGRA, BGR, _bgra2bgr);
|
|
CHECKFORMAT(BGRA, RGB, _rgba2bgr);
|
|
CHECKFORMAT(BGRA, GRAY, _bgra2gray);
|
|
CHECKFORMAT(RGB, RGB, _copyC3);
|
|
CHECKFORMAT(RGB, BGR, _rgb2bgr);
|
|
CHECKFORMAT(RGB, GRAY, _rgb2gray);
|
|
|
|
CHECKFORMAT(BGR, BGR, _copyC3);
|
|
CHECKFORMAT(BGR, RGB, _rgb2bgr);
|
|
CHECKFORMAT(BGR, GRAY, _bgr2gray);
|
|
|
|
CHECKFORMAT(GRAY, RGBA, _gray2C4);
|
|
CHECKFORMAT(GRAY, BGRA, _gray2C4);
|
|
CHECKFORMAT(GRAY, BGR, _gray2C3);
|
|
CHECKFORMAT(GRAY, RGB, _gray2C3);
|
|
CHECKFORMAT(GRAY, GRAY, _copyC1);
|
|
|
|
CHECKFORMAT(YUV_NV21, GRAY, _copyC1);
|
|
CHECKFORMAT(YUV_NV21, RGB, MNNNV21ToRGB);
|
|
CHECKFORMAT(YUV_NV21, BGR, MNNNV21ToBGR);
|
|
CHECKFORMAT(YUV_NV21, RGBA, MNNNV21ToRGBA);
|
|
|
|
return nullptr;
|
|
}
|
|
} // namespace CV
|
|
} // namespace MNN
|