From 70f3198703b652bfaee3e12e85a6643d2ca2f9cd Mon Sep 17 00:00:00 2001 From: nihuini Date: Wed, 11 Sep 2019 16:13:12 +0800 Subject: [PATCH] conversion between ncnn Mat and android Bitmap makes life easier :D --- src/CMakeLists.txt | 4 + src/mat.h | 22 ++++- src/mat_pixel.cpp | 2 +- src/mat_pixel_android.cpp | 195 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 src/mat_pixel_android.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1aa23e955..34a97c3da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,10 @@ set(ncnn_SRCS benchmark.cpp ) +if (ANDROID) + list(APPEND ncnn_SRCS mat_pixel_android.cpp) +endif() + macro(ncnn_add_layer class) string(TOLOWER ${class} name) diff --git a/src/mat.h b/src/mat.h index 6d35d546f..e583ae8e7 100644 --- a/src/mat.h +++ b/src/mat.h @@ -30,6 +30,13 @@ #include #endif // NCNN_VULKAN +#if NCNN_PIXEL +#if __ANDROID_API__ >= 9 +#include +#include +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PIXEL + namespace ncnn { #if NCNN_VULKAN @@ -145,9 +152,9 @@ public: PIXEL_CONVERT_MASK = 0xffff0000, PIXEL_RGB = 1, - PIXEL_BGR = (1 << 1), - PIXEL_GRAY = (1 << 2), - PIXEL_RGBA = (1 << 3), + PIXEL_BGR = 2, + PIXEL_GRAY = 3, + PIXEL_RGBA = 4, PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT), PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT), @@ -174,6 +181,15 @@ public: void to_pixels(unsigned char* pixels, int type) const; // convenient export to pixel data and resize to specific size void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const; + +#if __ANDROID_API__ >= 9 + // convenient construct from android Bitmap + static Mat from_android_bitmap(JNIEnv* env, jobject bitmap, int type_to, Allocator* allocator = 0); + // convenient construct from android Bitmap and resize to specific size + static Mat from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator = 0); + // convenient export to android Bitmap and resize to the android Bitmap size + void to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const; +#endif // __ANDROID_API__ >= 9 #endif // NCNN_PIXEL // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip diff --git a/src/mat_pixel.cpp b/src/mat_pixel.cpp index 8cf81d41a..861c978e7 100644 --- a/src/mat_pixel.cpp +++ b/src/mat_pixel.cpp @@ -1515,7 +1515,7 @@ Mat Mat::from_pixels(const unsigned char* pixels, int type, int w, int h, Alloca Mat Mat::from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator) { if (w == target_width && h == target_height) - return Mat::from_pixels(pixels, type, w, h); + return Mat::from_pixels(pixels, type, w, h, allocator); int type_from = type & PIXEL_FORMAT_MASK; diff --git a/src/mat_pixel_android.cpp b/src/mat_pixel_android.cpp new file mode 100644 index 000000000..95fdb211a --- /dev/null +++ b/src/mat_pixel_android.cpp @@ -0,0 +1,195 @@ +// Tencent is pleased to support the open source community by making ncnn available. +// +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// 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 "mat.h" + +#if NCNN_PIXEL +#if __ANDROID_API__ >= 9 + +#include + +#include +#include + +namespace ncnn { + +static Mat get_continous_pixels(const unsigned char* data, int w, int h, int elempack, int stride) +{ + if (stride == w * elempack) + return Mat(w, h, (void*)data, (size_t)elempack, elempack); + + Mat m(w, h, (size_t)elempack, elempack); + + unsigned char* ptr = m; + for (int y=0; y> PIXEL_CONVERT_SHIFT) : (type_to & PIXEL_FORMAT_MASK); + + void* data; + AndroidBitmap_lockPixels(env, bitmap, &data); + + Mat continous_pixels = get_continous_pixels((const unsigned char*)data, info.width, info.height, elempack, info.stride); + + int type = type_to == type_from ? type_from : (type_from | (type_to << PIXEL_CONVERT_SHIFT)); + + Mat m = Mat::from_pixels(continous_pixels, type, info.width, info.height, allocator); + + AndroidBitmap_unlockPixels(env, bitmap); + + return m; +} + +Mat Mat::from_android_bitmap_resize(JNIEnv* env, jobject bitmap, int type_to, int target_width, int target_height, Allocator* allocator) +{ + AndroidBitmapInfo info; + AndroidBitmap_getInfo(env, bitmap, &info); + + int type_from; + int elempack; + + if (info.format == ANDROID_BITMAP_FORMAT_A_8) + { + type_from = PIXEL_GRAY; + elempack = 1; + } + else if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) + { + type_from = PIXEL_RGBA; + elempack = 4; + } + else + { + // unsuppored android bitmap format + return Mat(); + } + + // let PIXEL_RGBA2XXX become PIXEL_XXX + type_to = (type_to & PIXEL_CONVERT_MASK) ? (type_to >> PIXEL_CONVERT_SHIFT) : (type_to & PIXEL_FORMAT_MASK); + + void* data; + AndroidBitmap_lockPixels(env, bitmap, &data); + + Mat continous_pixels = get_continous_pixels((const unsigned char*)data, info.width, info.height, elempack, info.stride); + + int type = type_to == type_from ? type_from : (type_from | (type_to << PIXEL_CONVERT_SHIFT)); + + Mat m = Mat::from_pixels_resize(continous_pixels, type, info.width, info.height, target_width, target_height, allocator); + + AndroidBitmap_unlockPixels(env, bitmap); + + return m; +} + +void Mat::to_android_bitmap(JNIEnv* env, jobject bitmap, int type_from) const +{ + AndroidBitmapInfo info; + AndroidBitmap_getInfo(env, bitmap, &info); + + int type_to; + int elempack; + + if (info.format == ANDROID_BITMAP_FORMAT_A_8) + { + type_to = PIXEL_GRAY; + elempack = 1; + } + else if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) + { + type_to = PIXEL_RGBA; + elempack = 4; + } + else + { + // unsuppored android bitmap format + return; + } + + // let PIXEL_XXX2RGBA become PIXEL_XXX + type_from = (type_from & PIXEL_CONVERT_MASK) ? (type_from & PIXEL_FORMAT_MASK) : type_from; + + void* data; + AndroidBitmap_lockPixels(env, bitmap, &data); + + Mat continous_pixels = get_continous_pixels((const unsigned char*)data, info.width, info.height, elempack, info.stride); + + int type = type_from == type_to ? type_to : (type_from | (type_to << PIXEL_CONVERT_SHIFT)); + + to_pixels_resize(continous_pixels, type, info.width, info.height); + + set_continous_pixels(continous_pixels, (unsigned char*)data, info.stride); + + AndroidBitmap_unlockPixels(env, bitmap); +} + +} // namespace ncnn + +#endif // __ANDROID_API__ >= 9 +#endif // NCNN_PIXEL