Skip to content

Commit fd41815

Browse files
committed
update mnnsr
1 parent 33824f7 commit fd41815

File tree

14 files changed

+205
-10269
lines changed

14 files changed

+205
-10269
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ RealSR-NCNN-Android-GUI could load extra models from sdcard automatily in ver 1.
3434

3535
![](Screenshot_models.jpg)
3636

37-
### Convert pth models by yourself
37+
### Convert models to mnn format
38+
✨ ver 1.11 support [mnn](https://github.com/alibaba/MNN) models. MNN could support more models than ncnn, but it is slower in my experiment.
39+
refer to https://mnn-docs.readthedocs.io/en/latest/tools/convert.html , you could convert ONNX, TFLITE, TorchScript, Tensorflow models to mnn format.
40+
1. `pip install mnn`
41+
2. (for example, convert onnx to mnn) `MNNConvert -f ONNX --modelFile "{onnx_path}" --MNNModel "{mnn_path}" --bizCode biz --fp16 --info --detectSparseSpeedUp`
42+
43+
44+
### Convert pth models to ncnn format by yourself
3845
Also you could convert ESRGAN pth moddls by yourself.
3946
1. Download ESRGAN pytorch models from [OpenModelDB](https://openmodeldb.info/) and unzip it to somewhere.
4047
2. Download [cupscale](https://github.com/n00mkrad/cupscale) and unzip it in your PC.
@@ -178,13 +185,13 @@ Most of the C code is copied from Nihui, cause of the directory structure had to
178185

179186
## Others Open-Source Code Used
180187
- [https://github.com/Tencent/ncnn](https://github.com/Tencent/ncnn) for fast neural network inference on ALL PLATFORMS
188+
- [https://github.com/alibaba/MNN](https://github.com/alibaba/MNN) A lightweight deep learning framework, battle-tested by business-critical use cases in Alibaba.
181189
- [https://github.com/nothings/stb](https://github.com/nothings/stb) for decoding and encoding image on Linux / MacOS
182190
- [https://github.com/tronkko/dirent](https://github.com/tronkko/dirent) for listing files in directory on Windows
183191
- [https://github.com/webmproject/libwebp](https://github.com/webmproject/libwebp) for encoding and decoding Webp images on ALL PLATFORMS
184192
- [https://github.com/avaneev/avir](https://github.com/avaneev/avir) AVIR image resizing algorithm designed by Aleksey Vaneev
185193
- [https://github.com/ImageMagick/ImageMagick6](https://github.com/ImageMagick/ImageMagick6) Use ImageMagick® to resize/convert images.
186194
- [https://github.com/MolotovCherry/Android-ImageMagick7](https://github.com/MolotovCherry/Android-ImageMagick7) The repository has been archived, I use this fork [https://github.com/Miseryset/Android-ImageMagick7](https://github.com/Miseryset/Android-ImageMagick7)
187195

188-
189196
## Others packaged models
190197
- Real-ESRGAN model [Nomos8kSC](https://github.com/Phhofm/models/tree/main/4xNomos8kSC) trained by Phhofm.

README_CHS.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
随着移动互联网的快速发展,智能设备逐渐普及到生活的每个角落。随之而来的是大量的图像数据。有的图片本身分辨率就比较低,难以看清楚细节;有的在存储和传输的过程中被反复压缩和劣化,最终不再清晰。
77
为了获得更加高质量的视觉体验,或者出于更为基本的目的看清楚图片,图像恢复/超分辨率算法应运而生。而手机作为目前我们生活中最常使用的智能设备,显然有使用这一技术的迫切需求。
88

9-
这个仓库正是为安卓设备构建的一个图像超分辨率的应用。具有如下特点:
9+
这个仓库正是为安卓设备构建的一个图像超分辨率的应用。具有如下特点:
1010
✅ 内置超分算法和模型多。最初使用了[RealSR-NCNN](https://github.com/nihui/realsr-ncnn-vulkan)[Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN)的成果,后来又添加了[SRMD-NCNN](https://github.com/nihui/srmd-ncnn-vulkan)[RealCUGAN-NCNN](https://github.com/nihui/realcugan-ncnn-vulkan), [Anime4KCPP](https://github.com/TianZerL/Anime4KCPP)。同时也内置了[waifu2x-ncnn](https://github.com/nihui/waifu2x-ncnn-vulkan)(但是没有内置模型和预设命令,如有需求自行下载并添加)
1111
✅ 兼顾传统插值算法。包括常见的nearest、bilinear、bicubic算法,以及imagemagick的二十多种filter。
1212
✅ 内置缩小算法。除使用用户指定倍率和算法的缩小方式外,resize-ncnn设计了一种自动缩小的算法de-nearest。参见[笔记](https://note.youdao.com/s/6XlIFbWt)
@@ -16,6 +16,7 @@
1616
✅ 自定义优先选用的超分算法和模型。
1717
✅ 自定义预设命令。
1818
✅ 图片处理过程完全在本地运行,无需担心隐私泄漏、服务器排队、服务收费;处理耗时取于决选择的模型、图片大小以及设备的性能。
19+
1920

2021
### 下载地址
2122
[Github Release](https://github.com/tumuyan/RealSR-NCNN-Android/releases)
@@ -44,7 +45,15 @@
4445
![](ScreenshotCHS.jpg)
4546

4647

47-
## 为 RealSR-NCNN-Android-GUI 增加更多模型
48+
49+
## 为 RealSR-NCNN-Android-GUI 增加更多mnn模型
50+
✨ ver 1.11 或者更高版本支持 [mnn](https://github.com/alibaba/MNN) 模型。在我的测试中,mnn的速度要比ncnn慢,但是可以兼容更多模型。
51+
转换模型的方法可以参考 https://mnn-docs.readthedocs.io/en/latest/tools/convert.html 模型转换工具能够将其他格式的模型(如:ONNX, TFLITE, TorchScript, Tensorflow等)转换为MNN模型
52+
1. (首先确认你已经安装了Python环境)`pip install mnn`
53+
2. (举例转换onnx模型到mnn格式)直接输入命令 `MNNConvert -f ONNX --modelFile "{onnx_path}" --MNNModel "{mnn_path}" --bizCode biz --fp16 --info --detectSparseSpeedUp`
54+
55+
56+
## 为 RealSR-NCNN-Android-GUI 增加更多ncnn模型
4857
RealSR-NCNN-Android-GUI 在 ver 1.7.6 以上的版本可以自动加载自定义模型。
4958
你可以从 https://huggingface.co/tumuyan2/realsr-models 下载更多模型:
5059
1. 在文件管理器里新建一个目录
@@ -196,6 +205,7 @@ RealSR-NCNN-Android-GUI\app\src\main\assets\
196205

197206
## 使用的其他开源项目
198207
- [https://github.com/Tencent/ncnn](https://github.com/Tencent/ncnn) for fast neural network inference on ALL PLATFORMS
208+
- [https://github.com/alibaba/MNN](https://github.com/alibaba/MNN) A lightweight deep learning framework, battle-tested by business-critical use cases in Alibaba.
199209
- [https://github.com/nothings/stb](https://github.com/nothings/stb) for decoding and encoding image on Linux / MacOS
200210
- [https://github.com/tronkko/dirent](https://github.com/tronkko/dirent) for listing files in directory on Windows
201211
- [https://github.com/webmproject/libwebp](https://github.com/webmproject/libwebp) for encoding and decoding Webp images on ALL PLATFORMS

RealSR-NCNN-Android-CLI/MNN-SR/src/main/jni/CMakeLists.txt

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
project(mnnsr)
1+
project(mnnsr-ncnn)
22

33
cmake_minimum_required(VERSION 3.4.1)
4+
#set(CMAKE_CXX_STANDARD 20)
5+
#set(CMAKE_CXX_STANDARD_REQUIRED ON)
46
set(CMAKE_BUILD_TYPE Debug)
57
#set(CMAKE_BUILD_TYPE Release)
68

@@ -54,9 +56,9 @@ else() # Android Studio
5456
set_target_properties(MNN PROPERTIES IMPORTED_LOCATION
5557
${mnn_DIR}/${ANDROID_ABI}/libMNN.so)
5658

57-
add_library(c++_shared SHARED IMPORTED)
58-
set_target_properties(c++_shared PROPERTIES IMPORTED_LOCATION
59-
${mnn_DIR}/${ANDROID_ABI}/libc++_shared.so)
59+
# add_library(c++_shared SHARED IMPORTED)
60+
# set_target_properties(c++_shared PROPERTIES IMPORTED_LOCATION
61+
# ${mnn_DIR}/${ANDROID_ABI}/libc++_shared.so)
6062

6163
add_library(MNN_CL SHARED IMPORTED)
6264
set_target_properties(MNN_CL PROPERTIES IMPORTED_LOCATION
@@ -73,11 +75,17 @@ else() # Android Studio
7375
endif()
7476

7577
message(STATUS "TARGET_ARCH: ${TARGET_ARCH}")
78+
79+
80+
find_package(OpenCV REQUIRED)
81+
include_directories(${OpenCV_DIR}/include)
82+
message(STATUS "find opencv result: ${OpenCV_LIBS}")
83+
84+
7685
include_directories(${mnn_DIR}/include)
7786
#include_directories(${mnn_DIR}/${ANDROID_ABI}/include/MNN)
7887

7988

80-
8189
if(EXISTS ${MNN_LIB})
8290
message(STATUS "find mnn: ${MNN_LIB}")
8391
else()
@@ -102,8 +110,6 @@ else()
102110
endif()
103111
message(STATUS "find ncnn result: ${NCNN_LIB}")
104112

105-
find_package(OpenCV REQUIRED)
106-
include_directories(${OpenCV_DIR}/include)
107113

108114
set(libwebp_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../3rdparty/libwebp)
109115

@@ -136,9 +142,9 @@ if(NOT USE_SYSTEM_WEBP)
136142
endif()
137143

138144

139-
add_executable(${PROJECT_NAME} main.cpp mnnsr.cpp)
145+
add_executable(${PROJECT_NAME} main.cpp mnnsr.cpp)
140146

141-
target_link_libraries(${PROJECT_NAME} webp ${MNN_LIB} ${OpenCV_LIBS} ${NCNN_LIB})
147+
target_link_libraries(${PROJECT_NAME} webp ${OpenCV_LIBS} ${MNN_LIB} ${NCNN_LIB})
142148

143149
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
144150
COMMAND ${CMAKE_COMMAND} -E copy_directory

RealSR-NCNN-Android-CLI/MNN-SR/src/main/jni/main.cpp

Lines changed: 43 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,12 @@
2929
#define STBI_NO_PIC
3030
#define STBI_NO_STDIO
3131

32-
#include "stb_image.h"
3332

3433
#define STB_IMAGE_WRITE_IMPLEMENTATION
3534

36-
#include "stb_image_write.h"
3735

3836
#endif // _WIN32
3937

40-
#include "webp_image.h"
4138
#include <chrono>
4239

4340
using namespace std::chrono;
@@ -107,11 +104,6 @@ static std::vector<int> parse_optarg_int_array(const char *optarg) {
107104

108105
#endif // _WIN32
109106

110-
// ncnn
111-
//#include "cpu.h"
112-
//#include "gpu.h"
113-
//#include "platform.h"
114-
115107

116108
#include "mnnsr.h"
117109
#include "filesystem_utils.h"
@@ -217,7 +209,6 @@ void *load(void *args) {
217209
const LoadThreadParams *ltp = (const LoadThreadParams *) args;
218210
const int count = ltp->input_files.size();
219211
const int scale = ltp->scale;
220-
// const bool check = ltp->check_threshold > 0;
221212

222213
#pragma omp parallel for schedule(static, 1) num_threads(ltp->jobs_load)
223214
for (int i = 0; i < count; i++) {
@@ -272,9 +263,9 @@ void *load(void *args) {
272263
}
273264
merge(channels.data(), 3, inimage);
274265
v.inimage = inimage;
275-
} else if(c==3){
266+
} else if (c == 3) {
276267
v.inimage = image;
277-
} else{
268+
} else {
278269
fprintf(stderr, "[error] channel=%d, %s\n", image.channels(), imagepath.c_str());
279270
continue;
280271
}
@@ -346,54 +337,6 @@ class SaveThreadParams {
346337

347338
};
348339

349-
float compareNcnnMats(const ncnn::Mat &mat1, const ncnn::Mat &mat2) {
350-
fprintf(stderr, "check result: mat1 %dx%dx%d, mat2 %dx%dx%d, elempack: %d, elemsize: %zu",
351-
mat1.w, mat1.h, mat1.c, mat2.w, mat2.h, mat2.c, mat1.elempack, mat1.elemsize);
352-
353-
// 检查两个Mat对象的维度是否相同
354-
if (mat1.w != mat2.w || mat1.h != mat2.h) {
355-
return -1;
356-
}
357-
358-
// 检查两个Mat对象的数据类型是否相同
359-
if (mat1.elemsize != mat2.elemsize || mat1.elempack != mat2.elempack) {
360-
return -2;
361-
}
362-
363-
// 比较每个通道的像素差异
364-
long sum_diff = 0;
365-
int channels = std::min(mat1.c, mat2.c);
366-
size_t plane_size = mat1.w * mat1.h * mat1.elemsize * mat1.elempack;
367-
for (int c = 0; c < channels; c++) {
368-
369-
const unsigned char *data1 = mat1.channel(c);
370-
const unsigned char *data2 = mat2.channel(c);
371-
372-
// fprintf(stderr, ", q=%d", sizeof(data1) / mat1.w / mat1.h);
373-
for (size_t i = 0; i < plane_size; i++) {
374-
int diff = abs(data1[i] - data2[i]);
375-
sum_diff += diff;
376-
// if(i<48)
377-
// fprintf(stderr, "compare[%d]: %d, %d, diff=%d\n", i, data1[i],data2[i],diff);
378-
}
379-
}
380-
381-
/* for (int c = 0; c < channels; ++c) {
382-
const unsigned char *data1 = mat1.channel(c);
383-
const unsigned char *data2 = mat2.channel(c);
384-
for (int i = 0; i < mat1.h; ++i) {
385-
for (int j = 0; j < mat1.w; ++j) {
386-
int diff = abs(data1[i * mat1.w + j] - data2[i * mat2.w + j]);
387-
sum_diff += diff;
388-
}
389-
}
390-
}*/
391-
392-
// 计算平均差异
393-
float avg_diff = (float) sum_diff / (plane_size * channels);
394-
return avg_diff;
395-
}
396-
397340
void *save(void *args) {
398341
const SaveThreadParams *stp = (const SaveThreadParams *) args;
399342
const int verbose = stp->verbose;
@@ -485,9 +428,9 @@ void *save(void *args) {
485428
}
486429

487430
#if _WIN32
488-
const std::wstring& optarg_in (L"A:\\Media\\realsr-ncnn-vulkan-20210210-windows\\input3.jpg");
489-
const std::wstring& optarg_out(L"A:\\Media\\realsr-ncnn-vulkan-20210210-windows\\output3.jpg");
490-
const std::wstring& optarg_mo (L"A:\\Media\\realsr-ncnn-vulkan-20210210-windows\\models-Real-ESRGAN-anime");
431+
const std::wstring& optarg_in (L"");
432+
const std::wstring& optarg_out(L"");
433+
const std::wstring& optarg_mo (L"");
491434
#else
492435
const char *optarg_in = "/sdcard/10086/input3.jpg";
493436
const char *optarg_out = "/sdcard/10086/output3.jpg";
@@ -507,7 +450,7 @@ int main(int argc, char **argv)
507450
path_t inputpath;
508451
path_t outputpath;
509452
int scale = 4;
510-
int tilesize = 128;
453+
int tilesize = 0;
511454
#if _DEMO_PATH
512455
path_t model = optarg_mo;
513456
#else
@@ -545,7 +488,10 @@ int main(int argc, char **argv)
545488
model = optarg;
546489
break;
547490
case L'g':
548-
// gpuid = parse_optarg_int_array(optarg);
491+
gpuid = parse_optarg_int_array(optarg);
492+
if(gpuid.size()>0 && gpuid[0]==-1){
493+
backend_type = MNN_FORWARD_CPU;
494+
}
549495
break;
550496
case L'j':
551497
swscanf(optarg, L"%d:%*[^:]:%d", &jobs_load, &jobs_save);
@@ -563,7 +509,8 @@ int main(int argc, char **argv)
563509
case L'c':
564510
check_threshold = _wtoi(optarg);
565511
break;
566-
case L'b':
512+
case L'b':
513+
if(backend_type != MNN_FORWARD_CPU)
567514
backend_type = (MNNForwardType)_wtoi(optarg);
568515
case L'h':
569516
default:
@@ -591,7 +538,10 @@ int main(int argc, char **argv)
591538
model = optarg;
592539
break;
593540
case 'g':
594-
// gpuid = parse_optarg_int_array(optarg);
541+
gpuid = parse_optarg_int_array(optarg);
542+
if (gpuid.size() > 0 && gpuid[0] == -1) {
543+
backend_type = MNN_FORWARD_CPU;
544+
}
595545
break;
596546
case 'j':
597547
sscanf(optarg, "%d:%*[^:]:%d", &jobs_load, &jobs_save);
@@ -610,7 +560,8 @@ int main(int argc, char **argv)
610560
check_threshold = atoi(optarg);
611561
break;
612562
case 'b':
613-
backend_type = (MNNForwardType) atoi(optarg);
563+
if (backend_type != MNN_FORWARD_CPU)
564+
backend_type = (MNNForwardType) atoi(optarg);
614565
case 'h':
615566
default:
616567
print_usage();
@@ -733,7 +684,7 @@ int main(int argc, char **argv)
733684

734685
int prepadding = 0;
735686

736-
if (model.find(PATHSTR("models-")) != path_t::npos) {
687+
if (model.find(PATHSTR("models-")) != path_t::npos ||( model.size() >= 4 && model.compare(model.size() - 4, 4, ".mnn") == 0)) {
737688
prepadding = 5;
738689
} else {
739690
fprintf(stderr, "unknown model dir type\n");
@@ -747,14 +698,21 @@ int main(int argc, char **argv)
747698

748699
#if _WIN32
749700
wchar_t modelpath[256];
750-
swprintf(modelpath, 256, L"%s/x%d.mnn", model.c_str(), scale);
701+
if(model.ends_with(".mnn")){
702+
swprintf(modelpath, 256, L"%s", model.c_str());
703+
}else{
704+
swprintf(modelpath, 256, L"%s/x%d.mnn", model.c_str(), scale);
705+
}
751706
fprintf(stderr, "search model: %ws\n", modelpath);
752707

753708
path_t modelfullpath = sanitize_filepath(modelpath);
754709
FILE* mp = _wfopen(modelfullpath.c_str(), L"rb");
755710
#else
756711
char modelpath[256];
757-
sprintf(modelpath, "%s/x%d.mnn", model.c_str(), scale);
712+
if (( model.size() >= 4 && model.compare(model.size() - 4, 4, ".mnn") == 0))
713+
sprintf(modelpath, "%s", model.c_str());
714+
else
715+
sprintf(modelpath, "%s/x%d.mnn", model.c_str(), scale);
758716
fprintf(stderr, "search model: %s\n", modelpath);
759717

760718
path_t modelfullpath = sanitize_filepath(modelpath);
@@ -793,6 +751,13 @@ int main(int argc, char **argv)
793751
return -1;
794752
}
795753

754+
// 移动到文件末尾
755+
fseek(mp, 0, SEEK_END);
756+
// 获取文件大小
757+
long modelsize = ftell(mp)/1000000;
758+
// 重置文件指针到开头
759+
fseek(mp, 0, SEEK_SET);
760+
fclose(mp);
796761

797762
#if _WIN32
798763
CoInitializeEx(NULL, COINIT_MULTITHREADED);
@@ -805,25 +770,29 @@ int main(int argc, char **argv)
805770

806771
const int use_gpu_count = 1;
807772
if (jobs_proc.empty()) {
808-
jobs_proc.resize(use_gpu_count, 2);
773+
jobs_proc.resize(use_gpu_count, 1);
809774
}
810775
int total_jobs_proc = 0;
811776
total_jobs_proc += jobs_proc[0];
812777

813778
fprintf(stderr, "busy...\n");
814779
{
815-
MNNSR mnnsr = MNNSR(0, false, 1);
780+
MNNSR mnnsr = MNNSR();
816781

817-
if (tilesize == 0)
782+
if (tilesize == 0){
818783
tilesize = 128;
784+
tilesize =4000/ modelsize;
785+
if(tilesize>300)
786+
tilesize = 300;
787+
}
819788
if (tilesize < 64)
820789
tilesize = 64;
821790
mnnsr.tilesize = tilesize;
822791
mnnsr.prepadding = prepadding;
823792
mnnsr.backend_type = backend_type;
824793

825794
mnnsr.scale = scale;
826-
mnnsr.load(modelfullpath);
795+
mnnsr.load(modelfullpath, modelsize>10);
827796

828797
// main routine
829798
{

0 commit comments

Comments
 (0)