├── .gitignore ├── CMakeLists.txt ├── README.md ├── benchmark └── benchmark.cpp ├── build.bat ├── build.sh ├── generate-vs-project.bat ├── images ├── 1.jpg └── 2.jpg ├── include ├── AngleNet.h ├── CrnnNet.h ├── DbNet.h ├── OcrLite.h ├── OcrResultUtils.h ├── OcrStruct.h ├── OcrUtils.h ├── clipper.hpp ├── getopt.h ├── main.h └── version.h ├── models ├── angle_net.mnn ├── crnn_lite_lstm.mnn ├── crnn_lite_lstm1.mnn ├── dbnet.mnn └── keys.txt ├── run-benchmark.bat ├── run-benchmark.sh ├── run-test.bat ├── run-test.sh ├── src ├── AngleNet.cpp ├── CrnnNet.cpp ├── DbNet.cpp ├── OcrLite.cpp ├── OcrLiteJni.cpp ├── OcrResultUtils.cpp ├── OcrUtils.cpp ├── clipper.cpp ├── getopt.cpp └── main.cpp ├── valgrind-memcheck.sh └── valgrind-memcheck.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | pip-wheel-metadata/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | db.sqlite3 64 | db.sqlite3-journal 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | .python-version 88 | 89 | # pipenv 90 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 91 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 92 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 93 | # install all needed dependencies. 94 | #Pipfile.lock 95 | 96 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 97 | __pypackages__/ 98 | 99 | # Celery stuff 100 | celerybeat-schedule 101 | celerybeat.pid 102 | 103 | # SageMath parsed files 104 | *.sage.py 105 | 106 | # Environments 107 | .env 108 | .venv 109 | env/ 110 | venv/ 111 | ENV/ 112 | env.bak/ 113 | venv.bak/ 114 | 115 | # Spyder project settings 116 | .spyderproject 117 | .spyproject 118 | 119 | # Rope project settings 120 | .ropeproject 121 | 122 | # mkdocs documentation 123 | /site 124 | 125 | # mypy 126 | .mypy_cache/ 127 | .dmypy.json 128 | dmypy.json 129 | 130 | # Pyre type checker 131 | .pyre/ 132 | 133 | #idea 134 | .idea 135 | cmake-build-debug/ 136 | build/ 137 | build-lib/ 138 | opencv-static/ 139 | opencv-shared/ 140 | mnn-static/ 141 | mnn-shared/ 142 | .vscode/ 143 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | project(OcrLiteMnn) 3 | 4 | option(OCR_LIB "OcrLite Jni Support" OFF) 5 | option(OCR_STATIC "Use Static Librarys For Build" ON) 6 | option(OCR_BENCHMARK "build benchmark" ON) 7 | #set(OCR_LIB ON) 8 | #set(OCR_STATIC OFF) 9 | set(OCR_BENCHMARK ON) 10 | 11 | set(CMAKE_CXX_STANDARD 11) 12 | add_definitions(-DUNICODE -D_UNICODE) 13 | if (CMAKE_BUILD_TYPE STREQUAL "Debug") 14 | add_definitions("-Wall -g -O0") 15 | else () 16 | add_definitions("-Wall") 17 | endif () 18 | 19 | # OpenMP flags for MACOS 20 | if (APPLE) 21 | if (CMAKE_C_COMPILER_ID MATCHES "Clang") 22 | set(OpenMP_C "${CMAKE_C_COMPILER}") 23 | set(OpenMP_C_FLAGS "-Xpreprocessor -fopenmp -I/usr/local/opt/libomp/include") 24 | set(OpenMP_C_LIB_NAMES "omp") 25 | set(OpenMP_omp_LIBRARY ${OpenMP_C_LIB_NAMES}) 26 | endif () 27 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 28 | set(OpenMP_CXX "${CMAKE_CXX_COMPILER}") 29 | set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I/usr/local/opt/libomp/include") 30 | set(OpenMP_CXX_LIB_NAMES "omp") 31 | set(OpenMP_omp_LIBRARY ${OpenMP_C_LIB_NAMES}) 32 | endif () 33 | link_directories("/usr/local/opt/libomp/lib") 34 | endif () 35 | 36 | # OpenMP 37 | find_package(OpenMP REQUIRED) 38 | if (OPENMP_FOUND) 39 | message("OPENMP FOUND") 40 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 41 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 42 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") 43 | else () 44 | message(FATAL_ERROR "OpenMP Not Found!") 45 | endif () 46 | 47 | 48 | # MNN 49 | if (OCR_STATIC) 50 | set(MNN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mnn-static") 51 | else () 52 | set(MNN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mnn-shared") 53 | endif () 54 | find_package(MNN REQUIRED) 55 | if (MNN_FOUND) 56 | message(STATUS "MNN_LIBS: ${MNN_LIBS}") 57 | message(STATUS "MNN_INCLUDE_DIRS: ${MNN_INCLUDE_DIRS}") 58 | else () 59 | message(FATAL_ERROR "MNN Not Found!") 60 | endif (MNN_FOUND) 61 | 62 | 63 | # OpenCV 64 | if (OCR_STATIC) 65 | include(${CMAKE_CURRENT_SOURCE_DIR}/opencv-static/OpenCVWrapperConfig.cmake) 66 | else () 67 | include(${CMAKE_CURRENT_SOURCE_DIR}/opencv-shared/OpenCVWrapperConfig.cmake) 68 | endif () 69 | find_package(OpenCV REQUIRED) 70 | if (OpenCV_FOUND) 71 | message(STATUS "OpenCV_LIBS: ${OpenCV_LIBS}") 72 | message(STATUS "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}") 73 | else () 74 | message(FATAL_ERROR "opencv Not Found!") 75 | endif (OpenCV_FOUND) 76 | 77 | # JNI 78 | if (OCR_LIB) 79 | find_package(JNI REQUIRED) 80 | if (JNI_FOUND) 81 | message("JNI FOUND") 82 | message(STATUS "JNI_LIBS: ${JNI_LIBS}") 83 | message(STATUS "JNI_INCLUDE_DIRS: ${JNI_INCLUDE_DIRS}") 84 | include_directories(${JNI_INCLUDE_DIRS}) 85 | else () 86 | message(FATAL_ERROR "JNI Not Found!") 87 | endif () 88 | endif () 89 | 90 | # project include 91 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 92 | 93 | # source 94 | file(GLOB OCR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) 95 | set(OCR_COMPILE_CODE ${OCR_SRC}) 96 | 97 | # static libgcc libstdc++ 98 | if (OCR_STATIC) 99 | if (APPLE) 100 | set(CMAKE_EXE_LINKER_FLAGS "-static-libstdc++") 101 | else () 102 | set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++") 103 | endif () 104 | endif () 105 | 106 | if (OCR_LIB) 107 | add_library(OcrLiteMnn SHARED ${OCR_COMPILE_CODE}) 108 | target_compile_definitions(OcrLiteMnn PRIVATE __JNI__) 109 | target_link_libraries(OcrLiteMnn ${MNN_LIBS} ${OpenCV_LIBS} ${JNI_LIBS} ${OpenMP_CXX_LIB_NAMES}) 110 | else () 111 | add_executable(OcrLiteMnn ${OCR_COMPILE_CODE}) 112 | target_link_libraries(OcrLiteMnn ${MNN_LIBS} ${OpenCV_LIBS} ${OpenMP_CXX_LIB_NAMES}) 113 | endif () 114 | 115 | # benchmark 116 | if (OCR_BENCHMARK AND NOT OCR_LIB) 117 | add_executable(benchmark benchmark/benchmark.cpp 118 | src/AngleNet.cpp 119 | src/clipper.cpp 120 | src/CrnnNet.cpp 121 | src/DbNet.cpp 122 | src/getopt.cpp 123 | src/OcrLite.cpp 124 | src/OcrUtils.cpp) 125 | target_link_libraries(benchmark ${MNN_LIBS} ${OpenCV_LIBS} ${OpenMP_CXX_LIB_NAMES}) 126 | endif () -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 介绍 2 | 3 | ChineseOcr Lite Mnn,超轻量级中文OCR PC Demo,使用MNN推理 4 | 5 | 这个项目使用MNN框架进行推理,使用 [https://github.com/ouyanghuiyu/chineseocr_lite](https://github.com/ouyanghuiyu/chineseocr_lite) 项目中提供的模型,迁移了项目中cpp_projects中的[OcrLiteOnnx](https://github.com/DayBreak-u/chineseocr_lite/tree/onnx/cpp_projects/OcrLiteOnnx)项目,采用阿里MNN框架[https://github.com/alibaba/MNN](https://github.com/alibaba/MNN) 作为推理引擎实现。 6 | 7 | 8 | ### 依赖的第三方库下载 9 | 10 | 下载opencv和MNN 11 | [下载地址](https://github.com/thomaszheng/OcrLiteMnn/releases/tag/v0.0.1) 12 | 13 | * OpenCv动态库:opencv-(版本号)-sharedLib.7z 14 | * OpenCv静态库:opencv-(版本号)-staticLib.7z 15 | * MNN 动态库:Mnn-(版本号)-sharedLib.7z 16 | * MNN 静态库:Mnn-(版本号)-staticLib.7z 17 | * 可以选择只下载两者的动态库或两者的静态库(要么都是静态库要么都是动态库),或者4种全部下载 18 | * 把压缩包解压到项目根目录,解压后目录结构 19 | 20 | ``` 21 | OcrLiteOnnx 22 | ├── mnn-shared 23 | ├── mnn-static 24 | ├── opencv-shared 25 | ├── opencv-static 26 | ``` 27 | 28 | ### 编译环境 29 | 30 | 2. macOS 10.15 31 | 32 | **注意:以下说明仅适用于本机编译。如果需要交叉编译为arm等其它平台(参考android),则需要先交叉编译所有第三方依赖库(mnn、opencv),然后再把依赖库整合替换到本项目里。** 33 | 34 | ### Mac编译说明 35 | 36 | 1. macOS Catalina 10.15.x,安装Xcode 12.1,并安装Xcode Command Line Tools, 终端运行```xcode-select –install``` 37 | 2. 自行下载安装HomeBrew,cmake >=3.1[下载地址](https://cmake.org/download/) 38 | 3. libomp: ```brew install libomp``` 39 | 4. 终端打开项目根目录,```./build.sh```并按照提示输入选项,最后选择'编译成可执行文件' 40 | 5. 测试:```./run-test.sh```(注意修改脚本内的目标图片路径) 41 | 6. 编译JNI动态运行库(可选,可用于java调用) 42 | 43 | * 下载jdk-8u221-macosx-x64.dmg,安装。 44 | * 编辑用户目录下的隐藏文件```.zshrc``` ,添加```export JAVA_HOME=$(/usr/libexec/java_home)``` 45 | * 运行```build.sh```并按照提示输入选项,最后选择'编译成JNI动态库' 46 | 47 | #### macOS部署说明 48 | 49 | opencv或onnxruntime使用动态库时,参考下列方法: 50 | 51 | * 把动态库所在路径加入DYLD_LIBRARY_PATH搜索路径 52 | 53 | * 把动态库复制或链接到到/usr/lib 54 | 55 | 56 | 57 | ### 编译参数说明 58 | 59 | build.sh编译参数: 60 | 61 | 2. ```OCR_LIB=ON```: 启用(ON)或禁用(OFF) ON时编译为jni lib,OFF时编译为可执行文件 62 | 3. ```OCR_STATIC=ON```: 启用(ON)或禁用(OFF) ON时选择opencv和onnxruntime的静态库进行编译,OFF时则选择动态库编译 63 | 64 | ### 输入参数说明 65 | 66 | * 请参考main.h中的命令行参数说明。 67 | * 每个参数有一个短参数名和一个长参数名,用短的或长的均可。 68 | 69 | 1. ```-d或--models```:模型所在文件夹路径,可以相对路径也可以绝对路径。 70 | 2. ```-1或--det```:dbNet模型文件名(含扩展名) 71 | 3. ```-2或--cls```:angleNet模型文件名(含扩展名) 72 | 4. ```-3或--rec```:crnnNet模型文件名(含扩展名) 73 | 5. ```-4或--keys```:keys.txt文件名(含扩展名) 74 | 6. ```-i或--image```:目标图片路径,可以相对路径也可以绝对路径。 75 | 7. ```-t或--numThread```:线程数量。 76 | 8. ```-p或--padding```:图像预处理,在图片外周添加白边,用于提升识别率,文字框没有正确框住所有文字时,增加此值。 77 | 9. ```-s或--maxSideLen``` 78 | :按图片最长边的长度,此值为0代表不缩放,例:1024,如果图片长边大于1024则把图像整体缩小到1024再进行图像分割计算,如果图片长边小于1024则不缩放,如果图片长边小于32,则缩放到32。 79 | 10. ```-b或--boxScoreThresh```:文字框置信度门限,文字框没有正确框住所有文字时,减小此值。 80 | 11. ```-o或--boxThresh```:请自行试验。 81 | 12. ```-u或--unClipRatio```:单个文字框大小倍率,越大时单个文字框越大。此项与图片的大小相关,越大的图片此值应该越大。 82 | 13. ```-a或--doAngle```:启用(1)/禁用(0) 文字方向检测,只有图片倒置的情况下(旋转90~270度的图片),才需要启用文字方向检测。 83 | 14. ```-A或--mostAngle```:启用(1)/禁用(0) 角度投票(整张图片以最大可能文字方向来识别),当禁用文字方向检测时,此项也不起作用。 84 | 15. ```-h或--help```:打印命令行帮助。 85 | 86 | ### 关于内存泄漏与valgrind 87 | 88 | * 项目根目录的valgrind-memcheck.sh用来检查内存泄漏(需要debug编译)。 89 | * valgrind-memcheck.txt是demo在linux平台的检查报告。 90 | * 报告中的"possibly lost"均发生在第三方库,possibly lost可能不一定是泄露,暂时不管。 91 | -------------------------------------------------------------------------------- /benchmark/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "main.h" 4 | #include "version.h" 5 | #include "OcrLite.h" 6 | #include "OcrUtils.h" 7 | 8 | void printHelp(FILE *out, char *argv0) { 9 | fprintf(out, " ------- Usage -------\n"); 10 | fprintf(out, "%s %s", argv0, usageMsg); 11 | fprintf(out, " ------- Required Parameters -------\n"); 12 | fprintf(out, "%s", requiredMsg); 13 | fprintf(out, " ------- Optional Parameters -------\n"); 14 | fprintf(out, "%s", optionalMsg); 15 | fprintf(out, " ------- Other Parameters -------\n"); 16 | fprintf(out, "%s", otherMsg); 17 | fprintf(out, " ------- Examples -------\n"); 18 | fprintf(out, example1Msg, argv0); 19 | fprintf(out, example2Msg, argv0); 20 | } 21 | 22 | int main(int argc, char **argv) { 23 | if (argc <= 1) { 24 | printHelp(stderr, argv[0]); 25 | return -1; 26 | } 27 | std::string modelsDir, modelDetPath, modelClsPath, modelRecPath, keysPath; 28 | std::string imgPath, imgDir, imgName; 29 | int numThread = 4; 30 | int loopCount = 1; 31 | int padding = 50; 32 | int maxSideLen = 1024; 33 | float boxScoreThresh = 0.6f; 34 | float boxThresh = 0.3f; 35 | float unClipRatio = 2.0f; 36 | bool doAngle = true; 37 | int flagDoAngle = 1; 38 | bool mostAngle = true; 39 | int flagMostAngle = 1; 40 | 41 | int opt; 42 | int optionIndex = 0; 43 | while ((opt = getopt_long(argc, argv, "d:1:2:3:4:i:t:p:s:b:o:u:a:A:v:h:l", long_options, &optionIndex)) != -1) { 44 | //printf("option(-%c)=%s\n", opt, optarg); 45 | switch (opt) { 46 | case 'd': 47 | modelsDir = optarg; 48 | printf("modelsPath=%s\n", modelsDir.c_str()); 49 | break; 50 | case '1': 51 | modelDetPath = modelsDir + "/" + optarg; 52 | printf("model dbnet path=%s\n", modelDetPath.c_str()); 53 | break; 54 | case '2': 55 | modelClsPath = modelsDir + "/" + optarg; 56 | printf("model angle path=%s\n", modelClsPath.c_str()); 57 | break; 58 | case '3': 59 | modelRecPath = modelsDir + "/" + optarg; 60 | printf("model crnn path=%s\n", modelRecPath.c_str()); 61 | break; 62 | case '4': 63 | keysPath = modelsDir + "/" + optarg; 64 | printf("keys path=%s\n", keysPath.c_str()); 65 | break; 66 | case 'i': 67 | imgPath.assign(optarg); 68 | imgDir.assign(imgPath.substr(0, imgPath.find_last_of('/') + 1)); 69 | imgName.assign(imgPath.substr(imgPath.find_last_of('/') + 1)); 70 | printf("imgDir=%s, imgName=%s\n", imgDir.c_str(), imgName.c_str()); 71 | break; 72 | case 't': 73 | numThread = (int) strtol(optarg, NULL, 10); 74 | //printf("numThread=%d\n", numThread); 75 | break; 76 | case 'p': 77 | padding = (int) strtol(optarg, NULL, 10); 78 | //printf("padding=%d\n", padding); 79 | break; 80 | case 's': 81 | maxSideLen = (int) strtol(optarg, NULL, 10); 82 | //printf("maxSideLen=%d\n", maxSideLen); 83 | break; 84 | case 'b': 85 | boxScoreThresh = strtof(optarg, NULL); 86 | //printf("boxScoreThresh=%f\n", boxScoreThresh); 87 | break; 88 | case 'o': 89 | boxThresh = strtof(optarg, NULL); 90 | //printf("boxThresh=%f\n", boxThresh); 91 | break; 92 | case 'u': 93 | unClipRatio = strtof(optarg, NULL); 94 | //printf("unClipRatio=%f\n", unClipRatio); 95 | break; 96 | case 'a': 97 | flagDoAngle = (int) strtol(optarg, NULL, 10); 98 | if (flagDoAngle == 0) { 99 | doAngle = false; 100 | } else { 101 | doAngle = true; 102 | } 103 | //printf("doAngle=%d\n", doAngle); 104 | break; 105 | case 'A': 106 | flagMostAngle = (int) strtol(optarg, NULL, 10); 107 | if (flagMostAngle == 0) { 108 | mostAngle = false; 109 | } else { 110 | mostAngle = true; 111 | } 112 | //printf("mostAngle=%d\n", mostAngle); 113 | break; 114 | case 'v': 115 | printf("%s\n", VERSION); 116 | return 0; 117 | case 'h': 118 | printHelp(stdout, argv[0]); 119 | return 0; 120 | case 'l': 121 | loopCount = (int) strtol(optarg, NULL, 10); 122 | //printf("loopCount=%d\n", loopCount); 123 | break; 124 | default: 125 | printf("other option %c :%s\n", opt, optarg); 126 | } 127 | } 128 | if (modelDetPath.empty()) { 129 | modelDetPath = modelsDir + "/" + "dbnet.mnn"; 130 | } 131 | if (modelClsPath.empty()) { 132 | modelClsPath = modelsDir + "/" + "angle_net.mnn"; 133 | } 134 | if (modelRecPath.empty()) { 135 | modelRecPath = modelsDir + "/" + "crnn_lite_lstm.mnn"; 136 | } 137 | if (keysPath.empty()) { 138 | keysPath = modelsDir + "/" + "keys.txt"; 139 | } 140 | bool hasTargetImgFile = isFileExists(imgPath); 141 | if (!hasTargetImgFile) { 142 | fprintf(stderr, "Target image not found: %s\n", imgPath.c_str()); 143 | return -1; 144 | } 145 | bool hasModelDetFile = isFileExists(modelDetPath); 146 | if (!hasModelDetFile) { 147 | fprintf(stderr, "Model dbnet file not found: %s\n", modelDetPath.c_str()); 148 | return -1; 149 | } 150 | bool hasModelClsFile = isFileExists(modelClsPath); 151 | if (!hasModelClsFile) { 152 | fprintf(stderr, "Model angle file not found: %s\n", modelClsPath.c_str()); 153 | return -1; 154 | } 155 | bool hasModelRecFile = isFileExists(modelRecPath); 156 | if (!hasModelRecFile) { 157 | fprintf(stderr, "Model crnn file not found: %s\n", modelRecPath.c_str()); 158 | return -1; 159 | } 160 | bool hasKeysFile = isFileExists(keysPath); 161 | if (!hasKeysFile) { 162 | fprintf(stderr, "keys file not found: %s\n", keysPath.c_str()); 163 | return -1; 164 | } 165 | omp_set_num_threads(numThread); 166 | OcrLite ocrLite; 167 | ocrLite.setNumThread(numThread); 168 | ocrLite.initLogger( 169 | false,//isOutputConsole 170 | false,//isOutputPartImg 171 | false);//isOutputResultImg 172 | 173 | //ocrLite.enableResultTxt(imgDir.c_str(), imgName.c_str()); 174 | printf("=====Input Params=====\n"); 175 | printf( 176 | "numThread(%d),padding(%d),maxSideLen(%d),boxScoreThresh(%f),boxThresh(%f),unClipRatio(%f),doAngle(%d),mostAngle(%d)\n", 177 | numThread, padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle); 178 | 179 | ocrLite.initModels(modelDetPath, modelClsPath, modelRecPath, keysPath); 180 | printf("=====warmup=====\n"); 181 | OcrResult result = ocrLite.detect(imgDir.c_str(), imgName.c_str(), padding, maxSideLen, 182 | boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle); 183 | printf("dbNetTime(%f) detectTime(%f)\n", result.dbNetTime, result.detectTime); 184 | double dbTime = 0.0f; 185 | double detectTime = 0.0f; 186 | for (int i = 0; i < loopCount; ++i) { 187 | printf("=====loop:%d=====\n", i + 1); 188 | OcrResult ocrResult = ocrLite.detect(imgDir.c_str(), imgName.c_str(), 189 | padding, maxSideLen, 190 | boxScoreThresh, boxThresh, 191 | unClipRatio, doAngle, mostAngle); 192 | printf("dbNetTime(%f) detectTime(%f)\n", ocrResult.dbNetTime, ocrResult.detectTime); 193 | dbTime += ocrResult.dbNetTime; 194 | detectTime += ocrResult.detectTime; 195 | } 196 | printf("=====result=====\n"); 197 | printf("average dbNetTime=%fms, average detectTime=%fms\n", dbTime / loopCount, detectTime / loopCount); 198 | return 0; 199 | } 200 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | chcp 65001 3 | cls 4 | @SETLOCAL 5 | echo "========请先参考README.md准备好编译环境========" 6 | echo. 7 | 8 | echo "========编译选项========" 9 | echo "请注意:项目默认使用Release库,除非您自行编译Debug版的MNN和Opencv,否则请不要选择Debug编译" 10 | echo "请输入编译选项并回车: 1)Release, 2)Debug, 3)预设" 11 | set BUILD_TYPE=Release 12 | set /p flag= 13 | if %flag% == 1 (set BUILD_TYPE=Release)^ 14 | else if %flag% == 2 (set BUILD_TYPE=Debug)^ 15 | else if %flag% == 3 (goto :makeAllExe)^ 16 | else (echo 输入错误!Input Error!) 17 | echo. 18 | 19 | echo "请输入OpenMP选项并回车: 1)启用OpenMP(Angle阶段和Crnn阶段多线程并行执行), 2)禁用OpenMP(Angle阶段和Crnn阶段单线程执行)" 20 | set BUILD_OPENMP=ON 21 | set /p flag= 22 | if %flag% == 1 (set BUILD_OPENMP=ON)^ 23 | else if %flag% == 2 (set BUILD_OPENMP=OFF)^ 24 | else (echo 输入错误!Input Error!) 25 | echo. 26 | 27 | echo "使用静态库时,编译出来的可执行文件较大,但部署起来比较方便。" 28 | echo "使用动态库时,编译出来的可执行文件较小,但部署的时候记得把dll复制到可执行文件目录" 29 | echo "请选择要使用的MNN和Opencv库选项并回车: 1)Static静态库,2)Shared动态库" 30 | set BUILD_STATIC=ON 31 | set /p flag= 32 | if %flag% == 1 (set BUILD_STATIC=ON)^ 33 | else if %flag% == 2 (set BUILD_STATIC=OFF)^ 34 | else (echo "输入错误!Input Error!") 35 | echo. 36 | 37 | echo "请注意:如果选择2)编译为JNI动态库时,必须安装配置Oracle JDK" 38 | echo "请选择编译输出类型并回车: 1)编译成可执行文件,2)编译成JNI动态库" 39 | set BUILD_LIB=OFF 40 | set /p flag= 41 | if %flag% == 1 (set BUILD_LIB=OFF)^ 42 | else if %flag% == 2 (set BUILD_LIB=ON)^ 43 | else (echo 输入错误!Input Error!) 44 | echo. 45 | if %BUILD_LIB% == OFF (call :makeExe)^ 46 | else (call :makeLib) 47 | echo cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DOCR_LIB=%BUILD_LIB% -DOCR_STATIC=%BUILD_STATIC% .. 48 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DOCR_LIB=%BUILD_LIB% -DOCR_STATIC=%BUILD_STATIC% .. 49 | nmake 50 | popd 51 | GOTO:EOF 52 | 53 | :makeExe 54 | mkdir build 55 | pushd build 56 | GOTO:EOF 57 | 58 | :makeLib 59 | mkdir build-lib 60 | pushd build-lib 61 | GOTO:EOF 62 | 63 | :makeAllExe 64 | mkdir win-%VSCMD_ARG_TGT_ARCH% 65 | pushd win-%VSCMD_ARG_TGT_ARCH% 66 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DOCR_LIB=OFF -DOCR_STATIC=ON .. 67 | nmake 68 | popd 69 | 70 | mkdir win-lib-%VSCMD_ARG_TGT_ARCH% 71 | pushd win-lib-%VSCMD_ARG_TGT_ARCH% 72 | cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DOCR_LIB=ON -DOCR_STATIC=ON .. 73 | nmake 74 | popd 75 | 76 | @ENDLOCAL 77 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function buildAll() { 4 | mkdir -p ${sysOS} 5 | pushd ${sysOS} 6 | cmake -DCMAKE_BUILD_TYPE=Release -DOCR_LIB=OFF -DOCR_STATIC=ON .. 7 | make -j $NUM_THREADS 8 | popd 9 | 10 | mkdir -p ${sysOS}-Lib 11 | pushd ${sysOS}-Lib 12 | cmake -DCMAKE_BUILD_TYPE=Release -DOCR_LIB=ON -DOCR_STATIC=ON .. 13 | make -j $NUM_THREADS 14 | popd 15 | } 16 | 17 | sysOS=$(uname -s) 18 | NUM_THREADS=1 19 | if [ $sysOS == "Darwin" ]; then 20 | #echo "I'm MacOS" 21 | NUM_THREADS=$(sysctl -n hw.ncpu) 22 | elif [ $sysOS == "Linux" ]; then 23 | #echo "I'm Linux" 24 | NUM_THREADS=$(grep ^processor /proc/cpuinfo | wc -l) 25 | else 26 | echo "Other OS: $sysOS" 27 | fi 28 | 29 | echo "========请先参考README.md准备好编译环境========" 30 | echo 31 | 32 | echo "========编译选项========" 33 | echo "请输入编译选项并回车: 1)Release, 2)Debug, 3)预设" 34 | read -p "" BUILD_TYPE 35 | if [ $BUILD_TYPE == 1 ]; then 36 | BUILD_TYPE=Release 37 | elif [ $BUILD_TYPE == 2 ]; then 38 | BUILD_TYPE=Debug 39 | elif [ $BUILD_TYPE == 3 ]; then 40 | buildAll 41 | exit 42 | else 43 | echo -e "输入错误!Input Error!" 44 | fi 45 | 46 | echo "使用静态库时,编译出来的可执行文件较大,但部署起来比较方便。" 47 | echo "使用动态库时,编译出来的可执行文件较小,但Linux部署时要配置LD_LIBRARY_PATH或链接|复制到/usr/lib。" 48 | echo "请选择要使用的MNN和Opencv库选项并回车: 1)Static静态库,2)Shared动态库" 49 | read -p "" BUILD_STATIC 50 | if [ $BUILD_STATIC == 1 ]; then 51 | BUILD_STATIC=ON 52 | elif [ $BUILD_STATIC == 2 ]; then 53 | BUILD_STATIC=OFF 54 | else 55 | echo -e "输入错误!Input Error!" 56 | fi 57 | 58 | echo "请注意:如果选择2)编译为JNI动态库时,必须安装配置Oracle JDK" 59 | echo "请选择编译输出类型并回车: 1)编译成可执行文件,2)编译成JNI动态库" 60 | read -p "" BUILD_LIB 61 | if [ $BUILD_LIB == 1 ]; then 62 | BUILD_LIB=OFF 63 | elif [ $BUILD_LIB == 2 ]; then 64 | BUILD_LIB=ON 65 | else 66 | echo -e "输入错误!Input Error!" 67 | fi 68 | 69 | 70 | if [ $BUILD_LIB == OFF ]; then 71 | mkdir -p build 72 | pushd build 73 | else 74 | mkdir -p build-lib 75 | pushd build-lib 76 | fi 77 | 78 | echo "cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DOCR_LIB=${BUILD_LIB} -DOCR_STATIC=${BUILD_STATIC} .." 79 | cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DOCR_LIB=$BUILD_LIB -DOCR_STATIC=$BUILD_STATIC .. 80 | make -j $NUM_THREADS 81 | popd -------------------------------------------------------------------------------- /generate-vs-project.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | chcp 65001 3 | cls 4 | @SETLOCAL 5 | echo "========请先参考README.md准备好编译环境========" 6 | echo. 7 | 8 | echo "========编译选项========" 9 | echo "请注意:项目默认使用Release库,除非您自行编译Debug版的MNN和Opencv,否则请不要选择Debug编译" 10 | echo "请输入编译选项并回车: 1)Release, 2)Debug" 11 | set BUILD_TYPE=Release 12 | set /p flag= 13 | if %flag% == 1 (set BUILD_TYPE=Release)^ 14 | else if %flag% == 2 (set BUILD_TYPE=Debug)^ 15 | else (echo 输入错误!Input Error!) 16 | echo. 17 | 18 | echo "请输入OpenMP选项并回车: 1)启用OpenMP(Angle阶段和Crnn阶段多线程并行执行), 2)禁用OpenMP(Angle阶段和Crnn阶段单线程执行)" 19 | set BUILD_OPENMP=ON 20 | set /p flag= 21 | if %flag% == 1 (set BUILD_OPENMP=ON)^ 22 | else if %flag% == 2 (set BUILD_OPENMP=OFF)^ 23 | else (echo 输入错误!Input Error!) 24 | echo. 25 | 26 | echo "使用静态库时,编译出来的可执行文件较大,但部署起来比较方便。" 27 | echo "使用动态库时,编译出来的可执行文件较小,但部署的时候记得把dll复制到可执行文件目录" 28 | echo "请选择要使用的MNN和Opencv库选项并回车: 1)Static静态库,2)Shared动态库" 29 | set BUILD_STATIC=ON 30 | set /p flag= 31 | if %flag% == 1 (set BUILD_STATIC=ON)^ 32 | else if %flag% == 2 (set BUILD_STATIC=OFF)^ 33 | else (echo "输入错误!Input Error!") 34 | echo. 35 | 36 | echo "请注意:如果选择2)编译为JNI动态库时,必须安装配置Oracle JDK" 37 | echo "请选择编译输出类型并回车: 1)编译成可执行文件,2)编译成JNI动态库" 38 | set BUILD_LIB=OFF 39 | set /p flag= 40 | if %flag% == 1 (set BUILD_LIB=OFF)^ 41 | else if %flag% == 2 (set BUILD_LIB=ON)^ 42 | else (echo 输入错误!Input Error!) 43 | echo. 44 | 45 | echo "请输入选项并回车: 0)ALL, 1)vs2017-x86, 2)vs2017-x64, 3)vs2019-x86, 4)vs2019-x64:" 46 | set /p flag= 47 | if %flag% == 0 (call :buildALL)^ 48 | else if %flag% == 1 (call :gen2017-x86)^ 49 | else if %flag% == 2 (call :gen2017-x64)^ 50 | else if %flag% == 3 (call :gen2019-x86)^ 51 | else if %flag% == 4 (call :gen2019-x64)^ 52 | else (echo "输入错误!Input Error!") 53 | GOTO:EOF 54 | 55 | :buildALL 56 | call :gen2017-x86 57 | call :gen2017-x64 58 | call :gen2019-x86 59 | call :gen2019-x64 60 | GOTO:EOF 61 | 62 | :gen2017-x86 63 | mkdir build-win-vs2017-x86 64 | pushd build-win-vs2017-x86 65 | call :cmakeParams "Visual Studio 15 2017" "Win32" 66 | popd 67 | GOTO:EOF 68 | 69 | :gen2017-x64 70 | mkdir build-win-vs2017-x64 71 | pushd build-win-vs2017-x64 72 | call :cmakeParams "Visual Studio 15 2017" "x64" 73 | popd 74 | GOTO:EOF 75 | 76 | :gen2019-x86 77 | mkdir build-win-vs2019-x86 78 | pushd build-win-vs2019-x86 79 | call :cmakeParams "Visual Studio 16 2019" "Win32" 80 | popd 81 | GOTO:EOF 82 | 83 | :gen2019-x64 84 | mkdir build-win-vs2019-x64 85 | pushd build-win-vs2019-x64 86 | call :cmakeParams "Visual Studio 16 2019" "x64" 87 | popd 88 | GOTO:EOF 89 | 90 | :cmakeParams 91 | echo cmake -G "%~1" -A "%~2" -DOCR_OPENMP=%BUILD_OPENMP% -DOCR_LIB=%BUILD_LIB% -DOCR_STATIC=%BUILD_STATIC% .. 92 | cmake -G "%~1" -A "%~2" -DOCR_OPENMP=%BUILD_OPENMP% -DOCR_LIB=%BUILD_LIB% -DOCR_STATIC=%BUILD_STATIC% .. 93 | GOTO:EOF 94 | 95 | @ENDLOCAL 96 | -------------------------------------------------------------------------------- /images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaszheng/OcrLiteMnn/58d19b889157b101f111b1d4d4e810f870181078/images/1.jpg -------------------------------------------------------------------------------- /images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaszheng/OcrLiteMnn/58d19b889157b101f111b1d4d4e810f870181078/images/2.jpg -------------------------------------------------------------------------------- /include/AngleNet.h: -------------------------------------------------------------------------------- 1 | #ifndef __OCR_ANGLENET_H__ 2 | #define __OCR_ANGLENET_H__ 3 | 4 | #include "OcrStruct.h" 5 | #include 6 | #include 7 | 8 | class AngleNet { 9 | public: 10 | AngleNet(); 11 | 12 | ~AngleNet(); 13 | 14 | void setNumThread(int numOfThread); 15 | 16 | void initModel(const std::string &pathStr); 17 | 18 | std::vector getAngles(std::vector &partImgs, const char *path, 19 | const char *imgName, bool doAngle, bool mostAngle); 20 | 21 | private: 22 | bool isOutputAngleImg = false; 23 | 24 | std::shared_ptr net; 25 | MNN::Session* session; 26 | int numThread = 4; 27 | 28 | const float meanValues[3] = {127.5, 127.5, 127.5}; 29 | const float normValues[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5}; 30 | const int dstWidth = 192; 31 | const int dstHeight = 32; 32 | 33 | Angle getAngle(cv::Mat &src); 34 | }; 35 | 36 | 37 | #endif //__OCR_ANGLENET_H__ 38 | -------------------------------------------------------------------------------- /include/CrnnNet.h: -------------------------------------------------------------------------------- 1 | #ifndef __OCR_CRNNNET_H__ 2 | #define __OCR_CRNNNET_H__ 3 | 4 | #include "OcrStruct.h" 5 | #include 6 | #include 7 | 8 | class CrnnNet { 9 | public: 10 | 11 | CrnnNet(); 12 | ~CrnnNet(); 13 | void setNumThread(int numOfThread); 14 | 15 | void initModel(const std::string &pathStr, const std::string &keysPath); 16 | 17 | std::vector getTextLines(std::vector &partImg, const char *path, const char *imgName); 18 | 19 | private: 20 | std::shared_ptr net; 21 | MNN::Session* session; 22 | bool isOutputDebugImg = false; 23 | int numThread = 4; 24 | 25 | const float meanValues[3] = {127.5, 127.5, 127.5}; 26 | const float normValues[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5}; 27 | const int dstHeight = 32; 28 | 29 | std::vector keys; 30 | 31 | TextLine scoreToTextLine(const std::vector &outputData, int h, int w); 32 | 33 | TextLine getTextLine(const cv::Mat &src); 34 | }; 35 | 36 | 37 | #endif //__OCR_CRNNNET_H__ 38 | -------------------------------------------------------------------------------- /include/DbNet.h: -------------------------------------------------------------------------------- 1 | #ifndef __OCR_DBNET_H__ 2 | #define __OCR_DBNET_H__ 3 | 4 | #include "OcrStruct.h" 5 | #include 6 | #include 7 | 8 | class DbNet { 9 | public: 10 | DbNet(); 11 | 12 | ~DbNet(); 13 | 14 | void setNumThread(int numOfThread); 15 | 16 | void initModel(const std::string &pathStr); 17 | 18 | std::vector getTextBoxes(cv::Mat &src, ScaleParam &s, float boxScoreThresh, 19 | float boxThresh, float unClipRatio); 20 | 21 | private: 22 | std::shared_ptr net; 23 | MNN::Session* session; 24 | int numThread = 4; 25 | 26 | const float meanValues[3] = {0.485 * 255, 0.456 * 255, 0.406 * 255}; 27 | const float normValues[3] = {1.0 / 0.229 / 255.0, 1.0 / 0.224 / 255.0, 1.0 / 0.225 / 255.0}; 28 | }; 29 | 30 | 31 | #endif //__OCR_DBNET_H__ 32 | -------------------------------------------------------------------------------- /include/OcrLite.h: -------------------------------------------------------------------------------- 1 | #ifndef __OCR_LITE_H__ 2 | #define __OCR_LITE_H__ 3 | 4 | #include "opencv2/core.hpp" 5 | #include "OcrStruct.h" 6 | #include "DbNet.h" 7 | #include "AngleNet.h" 8 | #include "CrnnNet.h" 9 | 10 | class OcrLite { 11 | public: 12 | OcrLite(); 13 | 14 | ~OcrLite(); 15 | 16 | void setNumThread(int numOfThread); 17 | 18 | void initLogger(bool isConsole, bool isPartImg, bool isResultImg); 19 | 20 | void enableResultTxt(const char *path, const char *imgName); 21 | 22 | void initModels(const std::string &detPath, const std::string &clsPath, 23 | const std::string &recPath, const std::string &keysPath); 24 | 25 | void Logger(const char *format, ...); 26 | 27 | OcrResult detect(const char *path, const char *imgName, 28 | int padding, int maxSideLen, 29 | float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle); 30 | 31 | private: 32 | bool isOutputConsole = false; 33 | bool isOutputPartImg = false; 34 | bool isOutputResultTxt = false; 35 | bool isOutputResultImg = false; 36 | FILE *resultTxt; 37 | DbNet dbNet; 38 | AngleNet angleNet; 39 | CrnnNet crnnNet; 40 | 41 | std::vector getPartImages(cv::Mat &src, std::vector &textBoxes, 42 | const char *path, const char *imgName); 43 | 44 | OcrResult detect(const char *path, const char *imgName, 45 | cv::Mat &src, cv::Rect &originRect, ScaleParam &scale, 46 | float boxScoreThresh = 0.6f, float boxThresh = 0.3f, 47 | float unClipRatio = 2.0f, bool doAngle = true, bool mostAngle = true); 48 | }; 49 | 50 | #endif //__OCR_LITE_H__ 51 | -------------------------------------------------------------------------------- /include/OcrResultUtils.h: -------------------------------------------------------------------------------- 1 | #ifdef __JNI__ 2 | #ifndef __OCR_RESULT_UTILS_H__ 3 | #define __OCR_RESULT_UTILS_H__ 4 | #include 5 | #include "OcrStruct.h" 6 | 7 | class OcrResultUtils { 8 | public: 9 | OcrResultUtils(JNIEnv *env, OcrResult &ocrResult); 10 | 11 | ~OcrResultUtils(); 12 | 13 | jobject getJObject(); 14 | 15 | private: 16 | JNIEnv *jniEnv; 17 | jobject jOcrResult; 18 | 19 | jclass newJListClass(); 20 | 21 | jmethodID getListConstructor(jclass clazz); 22 | 23 | jobject getTextBlock(TextBlock &textBlock); 24 | 25 | jobject getTextBlocks(std::vector &textBlocks); 26 | 27 | jobject newJPoint(cv::Point &point); 28 | 29 | jobject newJBoxPoint(std::vector &boxPoint); 30 | 31 | jfloatArray newJScoreArray(std::vector &scores); 32 | 33 | }; 34 | #endif //__OCR_RESULT_UTILS_H__ 35 | #endif 36 | -------------------------------------------------------------------------------- /include/OcrStruct.h: -------------------------------------------------------------------------------- 1 | #ifndef __OCR_STRUCT_H__ 2 | #define __OCR_STRUCT_H__ 3 | 4 | #include "opencv2/core.hpp" 5 | #include 6 | 7 | struct ScaleParam { 8 | int srcWidth; 9 | int srcHeight; 10 | int dstWidth; 11 | int dstHeight; 12 | float ratioWidth; 13 | float ratioHeight; 14 | }; 15 | 16 | struct TextBox { 17 | std::vector boxPoint; 18 | float score; 19 | }; 20 | 21 | struct Angle { 22 | int index; 23 | float score; 24 | double time; 25 | }; 26 | 27 | struct TextLine { 28 | std::string text; 29 | std::vector charScores; 30 | double time; 31 | }; 32 | 33 | struct TextBlock { 34 | std::vector boxPoint; 35 | float boxScore; 36 | int angleIndex; 37 | float angleScore; 38 | double angleTime; 39 | std::string text; 40 | std::vector charScores; 41 | double crnnTime; 42 | double blockTime; 43 | }; 44 | 45 | struct OcrResult { 46 | double dbNetTime; 47 | std::vector textBlocks; 48 | cv::Mat boxImg; 49 | double detectTime; 50 | std::string strRes; 51 | }; 52 | 53 | #endif //__OCR_STRUCT_H__ 54 | -------------------------------------------------------------------------------- /include/OcrUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef __OCR_UTILS_H__ 2 | #define __OCR_UTILS_H__ 3 | 4 | #include 5 | #include "OcrStruct.h" 6 | #include 7 | #include 8 | 9 | template 10 | static std::unique_ptr makeUnique(Ts &&... params) { 11 | return std::unique_ptr(new T(std::forward(params)...)); 12 | } 13 | 14 | template 15 | static double getMean(std::vector &input) { 16 | auto sum = accumulate(input.begin(), input.end(), 0.0); 17 | return sum / input.size(); 18 | } 19 | 20 | template 21 | static double getStdev(std::vector &input, double mean) { 22 | if (input.size() <= 1) return 0; 23 | double accum = 0.0; 24 | for_each(input.begin(), input.end(), [&](const double d) { 25 | accum += (d - mean) * (d - mean); 26 | }); 27 | double stdev = sqrt(accum / (input.size() - 1)); 28 | return stdev; 29 | } 30 | 31 | double getCurrentTime(); 32 | 33 | inline bool isFileExists(const std::string &name) { 34 | struct stat buffer; 35 | return (stat(name.c_str(), &buffer) == 0); 36 | } 37 | 38 | #ifdef _WIN32 39 | #define my_strtol wcstol 40 | #define my_strrchr wcsrchr 41 | #define my_strcasecmp _wcsicmp 42 | #define my_strdup _strdup 43 | #else 44 | #define my_strtol strtol 45 | #define my_strrchr strrchr 46 | #define my_strcasecmp strcasecmp 47 | #define my_strdup strdup 48 | #endif 49 | 50 | std::wstring strToWstr(std::string str); 51 | 52 | ScaleParam getScaleParam(cv::Mat &src, const float scale); 53 | 54 | ScaleParam getScaleParam(cv::Mat &src, const int targetSize); 55 | 56 | std::vector getBox(const cv::RotatedRect &rect); 57 | 58 | int getThickness(cv::Mat &boxImg); 59 | 60 | void drawTextBox(cv::Mat &boxImg, cv::RotatedRect &rect, int thickness); 61 | 62 | void drawTextBox(cv::Mat &boxImg, const std::vector &box, int thickness); 63 | 64 | void drawTextBoxes(cv::Mat &boxImg, std::vector &textBoxes, int thickness); 65 | 66 | cv::Mat matRotateClockWise180(cv::Mat src); 67 | 68 | cv::Mat matRotateClockWise90(cv::Mat src); 69 | 70 | cv::Mat getRotateCropImage(const cv::Mat &src, std::vector box); 71 | 72 | cv::Mat adjustTargetImg(cv::Mat &src, int dstWidth, int dstHeight); 73 | 74 | std::vector getMinBoxes(const std::vector &inVec, float &minSideLen, float &allEdgeSize); 75 | 76 | float boxScoreFast(const cv::Mat &inMat, const std::vector &inBox); 77 | 78 | std::vector unClip(const std::vector &inBox, float perimeter, float unClipRatio); 79 | 80 | std::vector substractMeanNormalize(cv::Mat &src, const float *meanVals, const float *normVals); 81 | 82 | std::vector getAngleIndexes(std::vector &angles); 83 | 84 | void saveImg(cv::Mat &img, const char *imgPath); 85 | 86 | std::string getSrcImgFilePath(const char *path, const char *imgName); 87 | 88 | std::string getResultTxtFilePath(const char *path, const char *imgName); 89 | 90 | std::string getResultImgFilePath(const char *path, const char *imgName); 91 | 92 | std::string getDebugImgFilePath(const char *path, const char *imgName, int i, const char *tag); 93 | 94 | #endif //__OCR_UTILS_H__ 95 | -------------------------------------------------------------------------------- /include/clipper.hpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * * 3 | * Author : Angus Johnson * 4 | * Version : 6.4.2 * 5 | * Date : 27 February 2017 * 6 | * Website : http://www.angusj.com * 7 | * Copyright : Angus Johnson 2010-2017 * 8 | * * 9 | * License: * 10 | * Use, modification & distribution is subject to Boost Software License Ver 1. * 11 | * http://www.boost.org/LICENSE_1_0.txt * 12 | * * 13 | * Attributions: * 14 | * The code in this library is an extension of Bala Vatti's clipping algorithm: * 15 | * "A generic solution to polygon clipping" * 16 | * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * 17 | * http://portal.acm.org/citation.cfm?id=129906 * 18 | * * 19 | * Computer graphics and geometric modeling: implementation and algorithms * 20 | * By Max K. Agoston * 21 | * Springer; 1 edition (January 4, 2005) * 22 | * http://books.google.com/books?q=vatti+clipping+agoston * 23 | * * 24 | * See also: * 25 | * "Polygon Offsetting by Computing Winding Numbers" * 26 | * Paper no. DETC2005-85513 pp. 565-575 * 27 | * ASME 2005 International Design Engineering Technical Conferences * 28 | * and Computers and Information in Engineering Conference (IDETC/CIE2005) * 29 | * September 24-28, 2005 , Long Beach, California, USA * 30 | * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * 31 | * * 32 | *******************************************************************************/ 33 | 34 | #ifndef clipper_hpp 35 | #define clipper_hpp 36 | 37 | #define CLIPPER_VERSION "6.4.2" 38 | 39 | //use_int32: When enabled 32bit ints are used instead of 64bit ints. This 40 | //improve performance but coordinate values are limited to the range +/- 46340 41 | //#define use_int32 42 | 43 | //use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance. 44 | //#define use_xyz 45 | 46 | //use_lines: Enables line clipping. Adds a very minor cost to performance. 47 | #define use_lines 48 | 49 | //use_deprecated: Enables temporary support for the obsolete functions 50 | //#define use_deprecated 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | namespace ClipperLib { 63 | 64 | enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; 65 | enum PolyType { ptSubject, ptClip }; 66 | //By far the most widely used winding rules for polygon filling are 67 | //EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) 68 | //Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) 69 | //see http://glprogramming.com/red/chapter11.html 70 | enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; 71 | 72 | #ifdef use_int32 73 | typedef int cInt; 74 | static cInt const loRange = 0x7FFF; 75 | static cInt const hiRange = 0x7FFF; 76 | #else 77 | typedef signed long long cInt; 78 | static cInt const loRange = 0x3FFFFFFF; 79 | static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; 80 | typedef signed long long long64; //used by Int128 class 81 | typedef unsigned long long ulong64; 82 | 83 | #endif 84 | 85 | struct IntPoint { 86 | cInt X; 87 | cInt Y; 88 | #ifdef use_xyz 89 | cInt Z; 90 | IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {}; 91 | #else 92 | IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {}; 93 | #endif 94 | 95 | friend inline bool operator== (const IntPoint& a, const IntPoint& b) 96 | { 97 | return a.X == b.X && a.Y == b.Y; 98 | } 99 | friend inline bool operator!= (const IntPoint& a, const IntPoint& b) 100 | { 101 | return a.X != b.X || a.Y != b.Y; 102 | } 103 | }; 104 | //------------------------------------------------------------------------------ 105 | 106 | typedef std::vector< IntPoint > Path; 107 | typedef std::vector< Path > Paths; 108 | 109 | inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;} 110 | inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;} 111 | 112 | std::ostream& operator <<(std::ostream &s, const IntPoint &p); 113 | std::ostream& operator <<(std::ostream &s, const Path &p); 114 | std::ostream& operator <<(std::ostream &s, const Paths &p); 115 | 116 | struct DoublePoint 117 | { 118 | double X; 119 | double Y; 120 | DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} 121 | DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {} 122 | }; 123 | //------------------------------------------------------------------------------ 124 | 125 | #ifdef use_xyz 126 | typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt); 127 | #endif 128 | 129 | enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4}; 130 | enum JoinType {jtSquare, jtRound, jtMiter}; 131 | enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound}; 132 | 133 | class PolyNode; 134 | typedef std::vector< PolyNode* > PolyNodes; 135 | 136 | class PolyNode 137 | { 138 | public: 139 | PolyNode(); 140 | virtual ~PolyNode(){}; 141 | Path Contour; 142 | PolyNodes Childs; 143 | PolyNode* Parent; 144 | PolyNode* GetNext() const; 145 | bool IsHole() const; 146 | bool IsOpen() const; 147 | int ChildCount() const; 148 | private: 149 | //PolyNode& operator =(PolyNode& other); 150 | unsigned Index; //node index in Parent.Childs 151 | bool m_IsOpen; 152 | JoinType m_jointype; 153 | EndType m_endtype; 154 | PolyNode* GetNextSiblingUp() const; 155 | void AddChild(PolyNode& child); 156 | friend class Clipper; //to access Index 157 | friend class ClipperOffset; 158 | }; 159 | 160 | class PolyTree: public PolyNode 161 | { 162 | public: 163 | ~PolyTree(){ Clear(); }; 164 | PolyNode* GetFirst() const; 165 | void Clear(); 166 | int Total() const; 167 | private: 168 | //PolyTree& operator =(PolyTree& other); 169 | PolyNodes AllNodes; 170 | friend class Clipper; //to access AllNodes 171 | }; 172 | 173 | bool Orientation(const Path &poly); 174 | double Area(const Path &poly); 175 | int PointInPolygon(const IntPoint &pt, const Path &path); 176 | 177 | void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); 178 | void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); 179 | void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); 180 | 181 | void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); 182 | void CleanPolygon(Path& poly, double distance = 1.415); 183 | void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415); 184 | void CleanPolygons(Paths& polys, double distance = 1.415); 185 | 186 | void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed); 187 | void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed); 188 | void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution); 189 | 190 | void PolyTreeToPaths(const PolyTree& polytree, Paths& paths); 191 | void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths); 192 | void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths); 193 | 194 | void ReversePath(Path& p); 195 | void ReversePaths(Paths& p); 196 | 197 | struct IntRect { cInt left; cInt top; cInt right; cInt bottom; }; 198 | 199 | //enums that are used internally ... 200 | enum EdgeSide { esLeft = 1, esRight = 2}; 201 | 202 | //forward declarations (for stuff used internally) ... 203 | struct TEdge; 204 | struct IntersectNode; 205 | struct LocalMinimum; 206 | struct OutPt; 207 | struct OutRec; 208 | struct Join; 209 | 210 | typedef std::vector < OutRec* > PolyOutList; 211 | typedef std::vector < TEdge* > EdgeList; 212 | typedef std::vector < Join* > JoinList; 213 | typedef std::vector < IntersectNode* > IntersectList; 214 | 215 | //------------------------------------------------------------------------------ 216 | 217 | //ClipperBase is the ancestor to the Clipper class. It should not be 218 | //instantiated directly. This class simply abstracts the conversion of sets of 219 | //polygon coordinates into edge objects that are stored in a LocalMinima list. 220 | class ClipperBase 221 | { 222 | public: 223 | ClipperBase(); 224 | virtual ~ClipperBase(); 225 | virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); 226 | bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); 227 | virtual void Clear(); 228 | IntRect GetBounds(); 229 | bool PreserveCollinear() {return m_PreserveCollinear;}; 230 | void PreserveCollinear(bool value) {m_PreserveCollinear = value;}; 231 | protected: 232 | void DisposeLocalMinimaList(); 233 | TEdge* AddBoundsToLML(TEdge *e, bool IsClosed); 234 | virtual void Reset(); 235 | TEdge* ProcessBound(TEdge* E, bool IsClockwise); 236 | void InsertScanbeam(const cInt Y); 237 | bool PopScanbeam(cInt &Y); 238 | bool LocalMinimaPending(); 239 | bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin); 240 | OutRec* CreateOutRec(); 241 | void DisposeAllOutRecs(); 242 | void DisposeOutRec(PolyOutList::size_type index); 243 | void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); 244 | void DeleteFromAEL(TEdge *e); 245 | void UpdateEdgeIntoAEL(TEdge *&e); 246 | 247 | typedef std::vector MinimaList; 248 | MinimaList::iterator m_CurrentLM; 249 | MinimaList m_MinimaList; 250 | 251 | bool m_UseFullRange; 252 | EdgeList m_edges; 253 | bool m_PreserveCollinear; 254 | bool m_HasOpenPaths; 255 | PolyOutList m_PolyOuts; 256 | TEdge *m_ActiveEdges; 257 | 258 | typedef std::priority_queue ScanbeamList; 259 | ScanbeamList m_Scanbeam; 260 | }; 261 | //------------------------------------------------------------------------------ 262 | 263 | class Clipper : public virtual ClipperBase 264 | { 265 | public: 266 | Clipper(int initOptions = 0); 267 | bool Execute(ClipType clipType, 268 | Paths &solution, 269 | PolyFillType fillType = pftEvenOdd); 270 | bool Execute(ClipType clipType, 271 | Paths &solution, 272 | PolyFillType subjFillType, 273 | PolyFillType clipFillType); 274 | bool Execute(ClipType clipType, 275 | PolyTree &polytree, 276 | PolyFillType fillType = pftEvenOdd); 277 | bool Execute(ClipType clipType, 278 | PolyTree &polytree, 279 | PolyFillType subjFillType, 280 | PolyFillType clipFillType); 281 | bool ReverseSolution() { return m_ReverseOutput; }; 282 | void ReverseSolution(bool value) {m_ReverseOutput = value;}; 283 | bool StrictlySimple() {return m_StrictSimple;}; 284 | void StrictlySimple(bool value) {m_StrictSimple = value;}; 285 | //set the callback function for z value filling on intersections (otherwise Z is 0) 286 | #ifdef use_xyz 287 | void ZFillFunction(ZFillCallback zFillFunc); 288 | #endif 289 | protected: 290 | virtual bool ExecuteInternal(); 291 | private: 292 | JoinList m_Joins; 293 | JoinList m_GhostJoins; 294 | IntersectList m_IntersectList; 295 | ClipType m_ClipType; 296 | typedef std::list MaximaList; 297 | MaximaList m_Maxima; 298 | TEdge *m_SortedEdges; 299 | bool m_ExecuteLocked; 300 | PolyFillType m_ClipFillType; 301 | PolyFillType m_SubjFillType; 302 | bool m_ReverseOutput; 303 | bool m_UsingPolyTree; 304 | bool m_StrictSimple; 305 | #ifdef use_xyz 306 | ZFillCallback m_ZFill; //custom callback 307 | #endif 308 | void SetWindingCount(TEdge& edge); 309 | bool IsEvenOddFillType(const TEdge& edge) const; 310 | bool IsEvenOddAltFillType(const TEdge& edge) const; 311 | void InsertLocalMinimaIntoAEL(const cInt botY); 312 | void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge); 313 | void AddEdgeToSEL(TEdge *edge); 314 | bool PopEdgeFromSEL(TEdge *&edge); 315 | void CopyAELToSEL(); 316 | void DeleteFromSEL(TEdge *e); 317 | void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); 318 | bool IsContributing(const TEdge& edge) const; 319 | bool IsTopHorz(const cInt XPos); 320 | void DoMaxima(TEdge *e); 321 | void ProcessHorizontals(); 322 | void ProcessHorizontal(TEdge *horzEdge); 323 | void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); 324 | OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); 325 | OutRec* GetOutRec(int idx); 326 | void AppendPolygon(TEdge *e1, TEdge *e2); 327 | void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt); 328 | OutPt* AddOutPt(TEdge *e, const IntPoint &pt); 329 | OutPt* GetLastOutPt(TEdge *e); 330 | bool ProcessIntersections(const cInt topY); 331 | void BuildIntersectList(const cInt topY); 332 | void ProcessIntersectList(); 333 | void ProcessEdgesAtTopOfScanbeam(const cInt topY); 334 | void BuildResult(Paths& polys); 335 | void BuildResult2(PolyTree& polytree); 336 | void SetHoleState(TEdge *e, OutRec *outrec); 337 | void DisposeIntersectNodes(); 338 | bool FixupIntersectionOrder(); 339 | void FixupOutPolygon(OutRec &outrec); 340 | void FixupOutPolyline(OutRec &outrec); 341 | bool IsHole(TEdge *e); 342 | bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl); 343 | void FixHoleLinkage(OutRec &outrec); 344 | void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt); 345 | void ClearJoins(); 346 | void ClearGhostJoins(); 347 | void AddGhostJoin(OutPt *op, const IntPoint offPt); 348 | bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2); 349 | void JoinCommonEdges(); 350 | void DoSimplePolygons(); 351 | void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); 352 | void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec); 353 | void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec); 354 | #ifdef use_xyz 355 | void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2); 356 | #endif 357 | }; 358 | //------------------------------------------------------------------------------ 359 | 360 | class ClipperOffset 361 | { 362 | public: 363 | ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25); 364 | ~ClipperOffset(); 365 | void AddPath(const Path& path, JoinType joinType, EndType endType); 366 | void AddPaths(const Paths& paths, JoinType joinType, EndType endType); 367 | void Execute(Paths& solution, double delta); 368 | void Execute(PolyTree& solution, double delta); 369 | void Clear(); 370 | double MiterLimit; 371 | double ArcTolerance; 372 | private: 373 | Paths m_destPolys; 374 | Path m_srcPoly; 375 | Path m_destPoly; 376 | std::vector m_normals; 377 | double m_delta, m_sinA, m_sin, m_cos; 378 | double m_miterLim, m_StepsPerRad; 379 | IntPoint m_lowest; 380 | PolyNode m_polyNodes; 381 | 382 | void FixOrientations(); 383 | void DoOffset(double delta); 384 | void OffsetPoint(int j, int& k, JoinType jointype); 385 | void DoSquare(int j, int k); 386 | void DoMiter(int j, int k, double r); 387 | void DoRound(int j, int k); 388 | }; 389 | //------------------------------------------------------------------------------ 390 | 391 | class clipperException : public std::exception 392 | { 393 | public: 394 | clipperException(const char* description): m_descr(description) {} 395 | virtual ~clipperException() throw() {} 396 | virtual const char* what() const throw() {return m_descr.c_str();} 397 | private: 398 | std::string m_descr; 399 | }; 400 | //------------------------------------------------------------------------------ 401 | 402 | } //ClipperLib namespace 403 | 404 | #endif //clipper_hpp 405 | 406 | 407 | -------------------------------------------------------------------------------- /include/getopt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * getopt - POSIX like getopt for Windows console Application 3 | * 4 | * win-c - Windows Console Library 5 | * Copyright (c) 2015 Koji Takami 6 | * Released under the MIT license 7 | * https://github.com/takamin/win-c/blob/master/LICENSE 8 | */ 9 | #ifndef _GETOPT_H_ 10 | #define _GETOPT_H_ 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif // __cplusplus 15 | 16 | int getopt(int argc, char *const argv[], 17 | const char *optstring); 18 | 19 | extern char *optarg; 20 | extern int optind, opterr, optopt; 21 | 22 | #define no_argument 0 23 | #define required_argument 1 24 | #define optional_argument 2 25 | 26 | struct option { 27 | const char *name; 28 | int has_arg; 29 | int *flag; 30 | int val; 31 | }; 32 | 33 | int getopt_long(int argc, char *const argv[], 34 | const char *optstring, 35 | const struct option *longopts, int *longindex); 36 | /**************************************************************************** 37 | int getopt_long_only(int argc, char* const argv[], 38 | const char* optstring, 39 | const struct option* longopts, int* longindex); 40 | ****************************************************************************/ 41 | #ifdef __cplusplus 42 | } 43 | #endif // __cplusplus 44 | #endif // _GETOPT_H_ 45 | -------------------------------------------------------------------------------- /include/main.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAIN_H__ 2 | #define __MAIN_H__ 3 | 4 | #include "getopt.h" 5 | 6 | static const struct option long_options[] = { 7 | {"models", required_argument, NULL, 'd'}, 8 | {"det", required_argument, NULL, '1'}, 9 | {"cls", required_argument, NULL, '2'}, 10 | {"rec", required_argument, NULL, '3'}, 11 | {"keys", required_argument, NULL, '4'}, 12 | {"image", required_argument, NULL, 'i'}, 13 | {"numThread", required_argument, NULL, 't'}, 14 | {"padding", required_argument, NULL, 'p'}, 15 | {"maxSideLen", required_argument, NULL, 's'}, 16 | {"boxScoreThresh", required_argument, NULL, 'b'}, 17 | {"boxThresh", required_argument, NULL, 'o'}, 18 | {"unClipRatio", required_argument, NULL, 'u'}, 19 | {"doAngle", required_argument, NULL, 'a'}, 20 | {"mostAngle", required_argument, NULL, 'A'}, 21 | {"version", no_argument, NULL, 'v'}, 22 | {"help", no_argument, NULL, 'h'}, 23 | {"loopCount", required_argument, NULL, 'l'}, 24 | {NULL, no_argument, NULL, 0} 25 | }; 26 | 27 | const char *usageMsg = "(-d --models) (-1 --det) (-2 --cls) (-3 --rec) (-4 --keys) (-i --image)\n"\ 28 | "[-t --numThread] [-p --padding] [-s --maxSideLen]\n" \ 29 | "[-b --boxScoreThresh] [-o --boxThresh] [-u --unClipRatio]\n" \ 30 | "[-a --noAngle] [-A --mostAngle]\n\n"; 31 | 32 | const char *requiredMsg = "-d --models: models directory.\n" \ 33 | "-1 --det: model file name of det.\n" \ 34 | "-2 --cls: model file name of cls.\n" \ 35 | "-3 --rec: model file name of rec.\n" \ 36 | "-4 --keys: keys file name.\n" \ 37 | "-i --image: path of target image.\n\n"; 38 | 39 | const char *optionalMsg = "-t --numThread: value of numThread(int), default: 4\n" \ 40 | "-p --padding: value of padding(int), default: 50\n" \ 41 | "-s --maxSideLen: Long side of picture for resize(int), default: 1024\n" \ 42 | "-b --boxScoreThresh: value of boxScoreThresh(float), default: 0.6\n" \ 43 | "-o --boxThresh: value of boxThresh(float), default: 0.3\n" \ 44 | "-u --unClipRatio: value of unClipRatio(float), default: 2.0\n" \ 45 | "-a --doAngle: Enable(1)/Disable(0) Angle Net, default: Enable\n" \ 46 | "-A --mostAngle: Enable(1)/Disable(0) Most Possible AngleIndex, default: Enable\n\n"; 47 | 48 | const char *otherMsg = "-v --version: show version\n" \ 49 | "-h --help: print this help\n\n"; 50 | 51 | const char *example1Msg = "Example1: %s --models models --det det.mnn --cls cls.mnn --rec rec.mnn --keys keys.txt --image 1.jpg\n"; 52 | const char *example2Msg = "Example2: %s -d models -1 det.mnn -2 cls.mnn -3 rec.mnn -4 keys.txt -i 1.jpg -t 4 -p 50 -s 0 -b 0.6 -o 0.3 -u 2.0 -a 1 -A 1\n"; 53 | 54 | #endif //__MAIN_H__ 55 | -------------------------------------------------------------------------------- /include/version.h: -------------------------------------------------------------------------------- 1 | #ifndef __OCR_VERSION_H__ 2 | #define __OCR_VERSION_H__ 3 | 4 | #define VERSION "1.5.1.20210128" 5 | 6 | #endif //__OCR_VERSION_H__ 7 | -------------------------------------------------------------------------------- /models/angle_net.mnn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaszheng/OcrLiteMnn/58d19b889157b101f111b1d4d4e810f870181078/models/angle_net.mnn -------------------------------------------------------------------------------- /models/crnn_lite_lstm.mnn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaszheng/OcrLiteMnn/58d19b889157b101f111b1d4d4e810f870181078/models/crnn_lite_lstm.mnn -------------------------------------------------------------------------------- /models/crnn_lite_lstm1.mnn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaszheng/OcrLiteMnn/58d19b889157b101f111b1d4d4e810f870181078/models/crnn_lite_lstm1.mnn -------------------------------------------------------------------------------- /models/dbnet.mnn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaszheng/OcrLiteMnn/58d19b889157b101f111b1d4d4e810f870181078/models/dbnet.mnn -------------------------------------------------------------------------------- /models/keys.txt: -------------------------------------------------------------------------------- 1 | ' 2 | 疗 3 | 绚 4 | 诚 5 | 娇 6 | 溜 7 | 题 8 | 贿 9 | 者 10 | 廖 11 | 更 12 | 纳 13 | 加 14 | 奉 15 | 公 16 | 一 17 | 就 18 | 汴 19 | 计 20 | 与 21 | 路 22 | 房 23 | 原 24 | 妇 25 | 2 26 | 0 27 | 8 28 | - 29 | 7 30 | 其 31 | > 32 | : 33 | ] 34 | , 35 | , 36 | 骑 37 | 刈 38 | 全 39 | 消 40 | 昏 41 | 傈 42 | 安 43 | 久 44 | 钟 45 | 嗅 46 | 不 47 | 影 48 | 处 49 | 驽 50 | 蜿 51 | 资 52 | 关 53 | 椤 54 | 地 55 | 瘸 56 | 专 57 | 问 58 | 忖 59 | 票 60 | 嫉 61 | 炎 62 | 韵 63 | 要 64 | 月 65 | 田 66 | 节 67 | 陂 68 | 鄙 69 | 捌 70 | 备 71 | 拳 72 | 伺 73 | 眼 74 | 网 75 | 盎 76 | 大 77 | 傍 78 | 心 79 | 东 80 | 愉 81 | 汇 82 | 蹿 83 | 科 84 | 每 85 | 业 86 | 里 87 | 航 88 | 晏 89 | 字 90 | 平 91 | 录 92 | 先 93 | 1 94 | 3 95 | 彤 96 | 鲶 97 | 产 98 | 稍 99 | 督 100 | 腴 101 | 有 102 | 象 103 | 岳 104 | 注 105 | 绍 106 | 在 107 | 泺 108 | 文 109 | 定 110 | 核 111 | 名 112 | 水 113 | 过 114 | 理 115 | 让 116 | 偷 117 | 率 118 | 等 119 | 这 120 | 发 121 | ” 122 | 为 123 | 含 124 | 肥 125 | 酉 126 | 相 127 | 鄱 128 | 七 129 | 编 130 | 猥 131 | 锛 132 | 日 133 | 镀 134 | 蒂 135 | 掰 136 | 倒 137 | 辆 138 | 栾 139 | 栗 140 | 综 141 | 涩 142 | 州 143 | 雌 144 | 滑 145 | 馀 146 | 了 147 | 机 148 | 块 149 | 司 150 | 宰 151 | 甙 152 | 兴 153 | 矽 154 | 抚 155 | 保 156 | 用 157 | 沧 158 | 秩 159 | 如 160 | 收 161 | 息 162 | 滥 163 | 页 164 | 疑 165 | 埠 166 | ! 167 | ! 168 | 姥 169 | 异 170 | 橹 171 | 钇 172 | 向 173 | 下 174 | 跄 175 | 的 176 | 椴 177 | 沫 178 | 国 179 | 绥 180 | 獠 181 | 报 182 | 开 183 | 民 184 | 蜇 185 | 何 186 | 分 187 | 凇 188 | 长 189 | 讥 190 | 藏 191 | 掏 192 | 施 193 | 羽 194 | 中 195 | 讲 196 | 派 197 | 嘟 198 | 人 199 | 提 200 | 浼 201 | 间 202 | 世 203 | 而 204 | 古 205 | 多 206 | 倪 207 | 唇 208 | 饯 209 | 控 210 | 庚 211 | 首 212 | 赛 213 | 蜓 214 | 味 215 | 断 216 | 制 217 | 觉 218 | 技 219 | 替 220 | 艰 221 | 溢 222 | 潮 223 | 夕 224 | 钺 225 | 外 226 | 摘 227 | 枋 228 | 动 229 | 双 230 | 单 231 | 啮 232 | 户 233 | 枇 234 | 确 235 | 锦 236 | 曜 237 | 杜 238 | 或 239 | 能 240 | 效 241 | 霜 242 | 盒 243 | 然 244 | 侗 245 | 电 246 | 晁 247 | 放 248 | 步 249 | 鹃 250 | 新 251 | 杖 252 | 蜂 253 | 吒 254 | 濂 255 | 瞬 256 | 评 257 | 总 258 | 隍 259 | 对 260 | 独 261 | 合 262 | 也 263 | 是 264 | 府 265 | 青 266 | 天 267 | 诲 268 | 墙 269 | 组 270 | 滴 271 | 级 272 | 邀 273 | 帘 274 | 示 275 | 已 276 | 时 277 | 骸 278 | 仄 279 | 泅 280 | 和 281 | 遨 282 | 店 283 | 雇 284 | 疫 285 | 持 286 | 巍 287 | 踮 288 | 境 289 | 只 290 | 亨 291 | 目 292 | 鉴 293 | 崤 294 | 闲 295 | 体 296 | 泄 297 | 杂 298 | 作 299 | 般 300 | 轰 301 | 化 302 | 解 303 | 迂 304 | 诿 305 | 蛭 306 | 璀 307 | 腾 308 | 告 309 | 版 310 | 服 311 | 省 312 | 师 313 | 小 314 | 规 315 | 程 316 | 线 317 | 海 318 | 办 319 | 引 320 | 二 321 | 桧 322 | 牌 323 | 砺 324 | 洄 325 | 裴 326 | 修 327 | 图 328 | 痫 329 | 胡 330 | 许 331 | 犊 332 | 事 333 | 郛 334 | 基 335 | 柴 336 | 呼 337 | 食 338 | 研 339 | 奶 340 | 律 341 | 蛋 342 | 因 343 | 葆 344 | 察 345 | 戏 346 | 褒 347 | 戒 348 | 再 349 | 李 350 | 骁 351 | 工 352 | 貂 353 | 油 354 | 鹅 355 | 章 356 | 啄 357 | 休 358 | 场 359 | 给 360 | 睡 361 | 纷 362 | 豆 363 | 器 364 | 捎 365 | 说 366 | 敏 367 | 学 368 | 会 369 | 浒 370 | 设 371 | 诊 372 | 格 373 | 廓 374 | 查 375 | 来 376 | 霓 377 | 室 378 | 溆 379 | ¢ 380 | 诡 381 | 寥 382 | 焕 383 | 舜 384 | 柒 385 | 狐 386 | 回 387 | 戟 388 | 砾 389 | 厄 390 | 实 391 | 翩 392 | 尿 393 | 五 394 | 入 395 | 径 396 | 惭 397 | 喹 398 | 股 399 | 宇 400 | 篝 401 | | 402 | ; 403 | 美 404 | 期 405 | 云 406 | 九 407 | 祺 408 | 扮 409 | 靠 410 | 锝 411 | 槌 412 | 系 413 | 企 414 | 酰 415 | 阊 416 | 暂 417 | 蚕 418 | 忻 419 | 豁 420 | 本 421 | 羹 422 | 执 423 | 条 424 | 钦 425 | H 426 | 獒 427 | 限 428 | 进 429 | 季 430 | 楦 431 | 于 432 | 芘 433 | 玖 434 | 铋 435 | 茯 436 | 未 437 | 答 438 | 粘 439 | 括 440 | 样 441 | 精 442 | 欠 443 | 矢 444 | 甥 445 | 帷 446 | 嵩 447 | 扣 448 | 令 449 | 仔 450 | 风 451 | 皈 452 | 行 453 | 支 454 | 部 455 | 蓉 456 | 刮 457 | 站 458 | 蜡 459 | 救 460 | 钊 461 | 汗 462 | 松 463 | 嫌 464 | 成 465 | 可 466 | . 467 | 鹤 468 | 院 469 | 从 470 | 交 471 | 政 472 | 怕 473 | 活 474 | 调 475 | 球 476 | 局 477 | 验 478 | 髌 479 | 第 480 | 韫 481 | 谗 482 | 串 483 | 到 484 | 圆 485 | 年 486 | 米 487 | / 488 | * 489 | 友 490 | 忿 491 | 检 492 | 区 493 | 看 494 | 自 495 | 敢 496 | 刃 497 | 个 498 | 兹 499 | 弄 500 | 流 501 | 留 502 | 同 503 | 没 504 | 齿 505 | 星 506 | 聆 507 | 轼 508 | 湖 509 | 什 510 | 三 511 | 建 512 | 蛔 513 | 儿 514 | 椋 515 | 汕 516 | 震 517 | 颧 518 | 鲤 519 | 跟 520 | 力 521 | 情 522 | 璺 523 | 铨 524 | 陪 525 | 务 526 | 指 527 | 族 528 | 训 529 | 滦 530 | 鄣 531 | 濮 532 | 扒 533 | 商 534 | 箱 535 | 十 536 | 召 537 | 慷 538 | 辗 539 | 所 540 | 莞 541 | 管 542 | 护 543 | 臭 544 | 横 545 | 硒 546 | 嗓 547 | 接 548 | 侦 549 | 六 550 | 露 551 | 党 552 | 馋 553 | 驾 554 | 剖 555 | 高 556 | 侬 557 | 妪 558 | 幂 559 | 猗 560 | 绺 561 | 骐 562 | 央 563 | 酐 564 | 孝 565 | 筝 566 | 课 567 | 徇 568 | 缰 569 | 门 570 | 男 571 | 西 572 | 项 573 | 句 574 | 谙 575 | 瞒 576 | 秃 577 | 篇 578 | 教 579 | 碲 580 | 罚 581 | 声 582 | 呐 583 | 景 584 | 前 585 | 富 586 | 嘴 587 | 鳌 588 | 稀 589 | 免 590 | 朋 591 | 啬 592 | 睐 593 | 去 594 | 赈 595 | 鱼 596 | 住 597 | 肩 598 | 愕 599 | 速 600 | 旁 601 | 波 602 | 厅 603 | 健 604 | 茼 605 | 厥 606 | 鲟 607 | 谅 608 | 投 609 | 攸 610 | 炔 611 | 数 612 | 方 613 | 击 614 | 呋 615 | 谈 616 | 绩 617 | 别 618 | 愫 619 | 僚 620 | 躬 621 | 鹧 622 | 胪 623 | 炳 624 | 招 625 | 喇 626 | 膨 627 | 泵 628 | 蹦 629 | 毛 630 | 结 631 | 5 632 | 4 633 | 谱 634 | 识 635 | 陕 636 | 粽 637 | 婚 638 | 拟 639 | 构 640 | 且 641 | 搜 642 | 任 643 | 潘 644 | 比 645 | 郢 646 | 妨 647 | 醪 648 | 陀 649 | 桔 650 | 碘 651 | 扎 652 | 选 653 | 哈 654 | 骷 655 | 楷 656 | 亿 657 | 明 658 | 缆 659 | 脯 660 | 监 661 | 睫 662 | 逻 663 | 婵 664 | 共 665 | 赴 666 | 淝 667 | 凡 668 | 惦 669 | 及 670 | 达 671 | 揖 672 | 谩 673 | 澹 674 | 减 675 | 焰 676 | 蛹 677 | 番 678 | 祁 679 | 柏 680 | 员 681 | 禄 682 | 怡 683 | 峤 684 | 龙 685 | 白 686 | 叽 687 | 生 688 | 闯 689 | 起 690 | 细 691 | 装 692 | 谕 693 | 竟 694 | 聚 695 | 钙 696 | 上 697 | 导 698 | 渊 699 | 按 700 | 艾 701 | 辘 702 | 挡 703 | 耒 704 | 盹 705 | 饪 706 | 臀 707 | 记 708 | 邮 709 | 蕙 710 | 受 711 | 各 712 | 医 713 | 搂 714 | 普 715 | 滇 716 | 朗 717 | 茸 718 | 带 719 | 翻 720 | 酚 721 | ( 722 | 光 723 | 堤 724 | 墟 725 | 蔷 726 | 万 727 | 幻 728 | 〓 729 | 瑙 730 | 辈 731 | 昧 732 | 盏 733 | 亘 734 | 蛀 735 | 吉 736 | 铰 737 | 请 738 | 子 739 | 假 740 | 闻 741 | 税 742 | 井 743 | 诩 744 | 哨 745 | 嫂 746 | 好 747 | 面 748 | 琐 749 | 校 750 | 馊 751 | 鬣 752 | 缂 753 | 营 754 | 访 755 | 炖 756 | 占 757 | 农 758 | 缀 759 | 否 760 | 经 761 | 钚 762 | 棵 763 | 趟 764 | 张 765 | 亟 766 | 吏 767 | 茶 768 | 谨 769 | 捻 770 | 论 771 | 迸 772 | 堂 773 | 玉 774 | 信 775 | 吧 776 | 瞠 777 | 乡 778 | 姬 779 | 寺 780 | 咬 781 | 溏 782 | 苄 783 | 皿 784 | 意 785 | 赉 786 | 宝 787 | 尔 788 | 钰 789 | 艺 790 | 特 791 | 唳 792 | 踉 793 | 都 794 | 荣 795 | 倚 796 | 登 797 | 荐 798 | 丧 799 | 奇 800 | 涵 801 | 批 802 | 炭 803 | 近 804 | 符 805 | 傩 806 | 感 807 | 道 808 | 着 809 | 菊 810 | 虹 811 | 仲 812 | 众 813 | 懈 814 | 濯 815 | 颞 816 | 眺 817 | 南 818 | 释 819 | 北 820 | 缝 821 | 标 822 | 既 823 | 茗 824 | 整 825 | 撼 826 | 迤 827 | 贲 828 | 挎 829 | 耱 830 | 拒 831 | 某 832 | 妍 833 | 卫 834 | 哇 835 | 英 836 | 矶 837 | 藩 838 | 治 839 | 他 840 | 元 841 | 领 842 | 膜 843 | 遮 844 | 穗 845 | 蛾 846 | 飞 847 | 荒 848 | 棺 849 | 劫 850 | 么 851 | 市 852 | 火 853 | 温 854 | 拈 855 | 棚 856 | 洼 857 | 转 858 | 果 859 | 奕 860 | 卸 861 | 迪 862 | 伸 863 | 泳 864 | 斗 865 | 邡 866 | 侄 867 | 涨 868 | 屯 869 | 萋 870 | 胭 871 | 氡 872 | 崮 873 | 枞 874 | 惧 875 | 冒 876 | 彩 877 | 斜 878 | 手 879 | 豚 880 | 随 881 | 旭 882 | 淑 883 | 妞 884 | 形 885 | 菌 886 | 吲 887 | 沱 888 | 争 889 | 驯 890 | 歹 891 | 挟 892 | 兆 893 | 柱 894 | 传 895 | 至 896 | 包 897 | 内 898 | 响 899 | 临 900 | 红 901 | 功 902 | 弩 903 | 衡 904 | 寂 905 | 禁 906 | 老 907 | 棍 908 | 耆 909 | 渍 910 | 织 911 | 害 912 | 氵 913 | 渑 914 | 布 915 | 载 916 | 靥 917 | 嗬 918 | 虽 919 | 苹 920 | 咨 921 | 娄 922 | 库 923 | 雉 924 | 榜 925 | 帜 926 | 嘲 927 | 套 928 | 瑚 929 | 亲 930 | 簸 931 | 欧 932 | 边 933 | 6 934 | 腿 935 | 旮 936 | 抛 937 | 吹 938 | 瞳 939 | 得 940 | 镓 941 | 梗 942 | 厨 943 | 继 944 | 漾 945 | 愣 946 | 憨 947 | 士 948 | 策 949 | 窑 950 | 抑 951 | 躯 952 | 襟 953 | 脏 954 | 参 955 | 贸 956 | 言 957 | 干 958 | 绸 959 | 鳄 960 | 穷 961 | 藜 962 | 音 963 | 折 964 | 详 965 | ) 966 | 举 967 | 悍 968 | 甸 969 | 癌 970 | 黎 971 | 谴 972 | 死 973 | 罩 974 | 迁 975 | 寒 976 | 驷 977 | 袖 978 | 媒 979 | 蒋 980 | 掘 981 | 模 982 | 纠 983 | 恣 984 | 观 985 | 祖 986 | 蛆 987 | 碍 988 | 位 989 | 稿 990 | 主 991 | 澧 992 | 跌 993 | 筏 994 | 京 995 | 锏 996 | 帝 997 | 贴 998 | 证 999 | 糠 1000 | 才 1001 | 黄 1002 | 鲸 1003 | 略 1004 | 炯 1005 | 饱 1006 | 四 1007 | 出 1008 | 园 1009 | 犀 1010 | 牧 1011 | 容 1012 | 汉 1013 | 杆 1014 | 浈 1015 | 汰 1016 | 瑷 1017 | 造 1018 | 虫 1019 | 瘩 1020 | 怪 1021 | 驴 1022 | 济 1023 | 应 1024 | 花 1025 | 沣 1026 | 谔 1027 | 夙 1028 | 旅 1029 | 价 1030 | 矿 1031 | 以 1032 | 考 1033 | s 1034 | u 1035 | 呦 1036 | 晒 1037 | 巡 1038 | 茅 1039 | 准 1040 | 肟 1041 | 瓴 1042 | 詹 1043 | 仟 1044 | 褂 1045 | 译 1046 | 桌 1047 | 混 1048 | 宁 1049 | 怦 1050 | 郑 1051 | 抿 1052 | 些 1053 | 余 1054 | 鄂 1055 | 饴 1056 | 攒 1057 | 珑 1058 | 群 1059 | 阖 1060 | 岔 1061 | 琨 1062 | 藓 1063 | 预 1064 | 环 1065 | 洮 1066 | 岌 1067 | 宀 1068 | 杲 1069 | 瀵 1070 | 最 1071 | 常 1072 | 囡 1073 | 周 1074 | 踊 1075 | 女 1076 | 鼓 1077 | 袭 1078 | 喉 1079 | 简 1080 | 范 1081 | 薯 1082 | 遐 1083 | 疏 1084 | 粱 1085 | 黜 1086 | 禧 1087 | 法 1088 | 箔 1089 | 斤 1090 | 遥 1091 | 汝 1092 | 奥 1093 | 直 1094 | 贞 1095 | 撑 1096 | 置 1097 | 绱 1098 | 集 1099 | 她 1100 | 馅 1101 | 逗 1102 | 钧 1103 | 橱 1104 | 魉 1105 | [ 1106 | 恙 1107 | 躁 1108 | 唤 1109 | 9 1110 | 旺 1111 | 膘 1112 | 待 1113 | 脾 1114 | 惫 1115 | 购 1116 | 吗 1117 | 依 1118 | 盲 1119 | 度 1120 | 瘿 1121 | 蠖 1122 | 俾 1123 | 之 1124 | 镗 1125 | 拇 1126 | 鲵 1127 | 厝 1128 | 簧 1129 | 续 1130 | 款 1131 | 展 1132 | 啃 1133 | 表 1134 | 剔 1135 | 品 1136 | 钻 1137 | 腭 1138 | 损 1139 | 清 1140 | 锶 1141 | 统 1142 | 涌 1143 | 寸 1144 | 滨 1145 | 贪 1146 | 链 1147 | 吠 1148 | 冈 1149 | 伎 1150 | 迥 1151 | 咏 1152 | 吁 1153 | 览 1154 | 防 1155 | 迅 1156 | 失 1157 | 汾 1158 | 阔 1159 | 逵 1160 | 绀 1161 | 蔑 1162 | 列 1163 | 川 1164 | 凭 1165 | 努 1166 | 熨 1167 | 揪 1168 | 利 1169 | 俱 1170 | 绉 1171 | 抢 1172 | 鸨 1173 | 我 1174 | 即 1175 | 责 1176 | 膦 1177 | 易 1178 | 毓 1179 | 鹊 1180 | 刹 1181 | 玷 1182 | 岿 1183 | 空 1184 | 嘞 1185 | 绊 1186 | 排 1187 | 术 1188 | 估 1189 | 锷 1190 | 违 1191 | 们 1192 | 苟 1193 | 铜 1194 | 播 1195 | 肘 1196 | 件 1197 | 烫 1198 | 审 1199 | 鲂 1200 | 广 1201 | 像 1202 | 铌 1203 | 惰 1204 | 铟 1205 | 巳 1206 | 胍 1207 | 鲍 1208 | 康 1209 | 憧 1210 | 色 1211 | 恢 1212 | 想 1213 | 拷 1214 | 尤 1215 | 疳 1216 | 知 1217 | S 1218 | Y 1219 | F 1220 | D 1221 | A 1222 | 峄 1223 | 裕 1224 | 帮 1225 | 握 1226 | 搔 1227 | 氐 1228 | 氘 1229 | 难 1230 | 墒 1231 | 沮 1232 | 雨 1233 | 叁 1234 | 缥 1235 | 悴 1236 | 藐 1237 | 湫 1238 | 娟 1239 | 苑 1240 | 稠 1241 | 颛 1242 | 簇 1243 | 后 1244 | 阕 1245 | 闭 1246 | 蕤 1247 | 缚 1248 | 怎 1249 | 佞 1250 | 码 1251 | 嘤 1252 | 蔡 1253 | 痊 1254 | 舱 1255 | 螯 1256 | 帕 1257 | 赫 1258 | 昵 1259 | 升 1260 | 烬 1261 | 岫 1262 | 、 1263 | 疵 1264 | 蜻 1265 | 髁 1266 | 蕨 1267 | 隶 1268 | 烛 1269 | 械 1270 | 丑 1271 | 盂 1272 | 梁 1273 | 强 1274 | 鲛 1275 | 由 1276 | 拘 1277 | 揉 1278 | 劭 1279 | 龟 1280 | 撤 1281 | 钩 1282 | 呕 1283 | 孛 1284 | 费 1285 | 妻 1286 | 漂 1287 | 求 1288 | 阑 1289 | 崖 1290 | 秤 1291 | 甘 1292 | 通 1293 | 深 1294 | 补 1295 | 赃 1296 | 坎 1297 | 床 1298 | 啪 1299 | 承 1300 | 吼 1301 | 量 1302 | 暇 1303 | 钼 1304 | 烨 1305 | 阂 1306 | 擎 1307 | 脱 1308 | 逮 1309 | 称 1310 | P 1311 | 神 1312 | 属 1313 | 矗 1314 | 华 1315 | 届 1316 | 狍 1317 | 葑 1318 | 汹 1319 | 育 1320 | 患 1321 | 窒 1322 | 蛰 1323 | 佼 1324 | 静 1325 | 槎 1326 | 运 1327 | 鳗 1328 | 庆 1329 | 逝 1330 | 曼 1331 | 疱 1332 | 克 1333 | 代 1334 | 官 1335 | 此 1336 | 麸 1337 | 耧 1338 | 蚌 1339 | 晟 1340 | 例 1341 | 础 1342 | 榛 1343 | 副 1344 | 测 1345 | 唰 1346 | 缢 1347 | 迹 1348 | 灬 1349 | 霁 1350 | 身 1351 | 岁 1352 | 赭 1353 | 扛 1354 | 又 1355 | 菡 1356 | 乜 1357 | 雾 1358 | 板 1359 | 读 1360 | 陷 1361 | 徉 1362 | 贯 1363 | 郁 1364 | 虑 1365 | 变 1366 | 钓 1367 | 菜 1368 | 圾 1369 | 现 1370 | 琢 1371 | 式 1372 | 乐 1373 | 维 1374 | 渔 1375 | 浜 1376 | 左 1377 | 吾 1378 | 脑 1379 | 钡 1380 | 警 1381 | T 1382 | 啵 1383 | 拴 1384 | 偌 1385 | 漱 1386 | 湿 1387 | 硕 1388 | 止 1389 | 骼 1390 | 魄 1391 | 积 1392 | 燥 1393 | 联 1394 | 踢 1395 | 玛 1396 | | 1397 | 则 1398 | 窿 1399 | 见 1400 | 振 1401 | 畿 1402 | 送 1403 | 班 1404 | 钽 1405 | 您 1406 | 赵 1407 | 刨 1408 | 印 1409 | 讨 1410 | 踝 1411 | 籍 1412 | 谡 1413 | 舌 1414 | 崧 1415 | 汽 1416 | 蔽 1417 | 沪 1418 | 酥 1419 | 绒 1420 | 怖 1421 | 财 1422 | 帖 1423 | 肱 1424 | 私 1425 | 莎 1426 | 勋 1427 | 羔 1428 | 霸 1429 | 励 1430 | 哼 1431 | 帐 1432 | 将 1433 | 帅 1434 | 渠 1435 | 纪 1436 | 婴 1437 | 娩 1438 | 岭 1439 | 厘 1440 | 滕 1441 | 吻 1442 | 伤 1443 | 坝 1444 | 冠 1445 | 戊 1446 | 隆 1447 | 瘁 1448 | 介 1449 | 涧 1450 | 物 1451 | 黍 1452 | 并 1453 | 姗 1454 | 奢 1455 | 蹑 1456 | 掣 1457 | 垸 1458 | 锴 1459 | 命 1460 | 箍 1461 | 捉 1462 | 病 1463 | 辖 1464 | 琰 1465 | 眭 1466 | 迩 1467 | 艘 1468 | 绌 1469 | 繁 1470 | 寅 1471 | 若 1472 | 毋 1473 | 思 1474 | 诉 1475 | 类 1476 | 诈 1477 | 燮 1478 | 轲 1479 | 酮 1480 | 狂 1481 | 重 1482 | 反 1483 | 职 1484 | 筱 1485 | 县 1486 | 委 1487 | 磕 1488 | 绣 1489 | 奖 1490 | 晋 1491 | 濉 1492 | 志 1493 | 徽 1494 | 肠 1495 | 呈 1496 | 獐 1497 | 坻 1498 | 口 1499 | 片 1500 | 碰 1501 | 几 1502 | 村 1503 | 柿 1504 | 劳 1505 | 料 1506 | 获 1507 | 亩 1508 | 惕 1509 | 晕 1510 | 厌 1511 | 号 1512 | 罢 1513 | 池 1514 | 正 1515 | 鏖 1516 | 煨 1517 | 家 1518 | 棕 1519 | 复 1520 | 尝 1521 | 懋 1522 | 蜥 1523 | 锅 1524 | 岛 1525 | 扰 1526 | 队 1527 | 坠 1528 | 瘾 1529 | 钬 1530 | @ 1531 | 卧 1532 | 疣 1533 | 镇 1534 | 譬 1535 | 冰 1536 | 彷 1537 | 频 1538 | 黯 1539 | 据 1540 | 垄 1541 | 采 1542 | 八 1543 | 缪 1544 | 瘫 1545 | 型 1546 | 熹 1547 | 砰 1548 | 楠 1549 | 襁 1550 | 箐 1551 | 但 1552 | 嘶 1553 | 绳 1554 | 啤 1555 | 拍 1556 | 盥 1557 | 穆 1558 | 傲 1559 | 洗 1560 | 盯 1561 | 塘 1562 | 怔 1563 | 筛 1564 | 丿 1565 | 台 1566 | 恒 1567 | 喂 1568 | 葛 1569 | 永 1570 | ¥ 1571 | 烟 1572 | 酒 1573 | 桦 1574 | 书 1575 | 砂 1576 | 蚝 1577 | 缉 1578 | 态 1579 | 瀚 1580 | 袄 1581 | 圳 1582 | 轻 1583 | 蛛 1584 | 超 1585 | 榧 1586 | 遛 1587 | 姒 1588 | 奘 1589 | 铮 1590 | 右 1591 | 荽 1592 | 望 1593 | 偻 1594 | 卡 1595 | 丶 1596 | 氰 1597 | 附 1598 | 做 1599 | 革 1600 | 索 1601 | 戚 1602 | 坨 1603 | 桷 1604 | 唁 1605 | 垅 1606 | 榻 1607 | 岐 1608 | 偎 1609 | 坛 1610 | 莨 1611 | 山 1612 | 殊 1613 | 微 1614 | 骇 1615 | 陈 1616 | 爨 1617 | 推 1618 | 嗝 1619 | 驹 1620 | 澡 1621 | 藁 1622 | 呤 1623 | 卤 1624 | 嘻 1625 | 糅 1626 | 逛 1627 | 侵 1628 | 郓 1629 | 酌 1630 | 德 1631 | 摇 1632 | ※ 1633 | 鬃 1634 | 被 1635 | 慨 1636 | 殡 1637 | 羸 1638 | 昌 1639 | 泡 1640 | 戛 1641 | 鞋 1642 | 河 1643 | 宪 1644 | 沿 1645 | 玲 1646 | 鲨 1647 | 翅 1648 | 哽 1649 | 源 1650 | 铅 1651 | 语 1652 | 照 1653 | 邯 1654 | 址 1655 | 荃 1656 | 佬 1657 | 顺 1658 | 鸳 1659 | 町 1660 | 霭 1661 | 睾 1662 | 瓢 1663 | 夸 1664 | 椁 1665 | 晓 1666 | 酿 1667 | 痈 1668 | 咔 1669 | 侏 1670 | 券 1671 | 噎 1672 | 湍 1673 | 签 1674 | 嚷 1675 | 离 1676 | 午 1677 | 尚 1678 | 社 1679 | 锤 1680 | 背 1681 | 孟 1682 | 使 1683 | 浪 1684 | 缦 1685 | 潍 1686 | 鞅 1687 | 军 1688 | 姹 1689 | 驶 1690 | 笑 1691 | 鳟 1692 | 鲁 1693 | 》 1694 | 孽 1695 | 钜 1696 | 绿 1697 | 洱 1698 | 礴 1699 | 焯 1700 | 椰 1701 | 颖 1702 | 囔 1703 | 乌 1704 | 孔 1705 | 巴 1706 | 互 1707 | 性 1708 | 椽 1709 | 哞 1710 | 聘 1711 | 昨 1712 | 早 1713 | 暮 1714 | 胶 1715 | 炀 1716 | 隧 1717 | 低 1718 | 彗 1719 | 昝 1720 | 铁 1721 | 呓 1722 | 氽 1723 | 藉 1724 | 喔 1725 | 癖 1726 | 瑗 1727 | 姨 1728 | 权 1729 | 胱 1730 | 韦 1731 | 堑 1732 | 蜜 1733 | 酋 1734 | 楝 1735 | 砝 1736 | 毁 1737 | 靓 1738 | 歙 1739 | 锲 1740 | 究 1741 | 屋 1742 | 喳 1743 | 骨 1744 | 辨 1745 | 碑 1746 | 武 1747 | 鸠 1748 | 宫 1749 | 辜 1750 | 烊 1751 | 适 1752 | 坡 1753 | 殃 1754 | 培 1755 | 佩 1756 | 供 1757 | 走 1758 | 蜈 1759 | 迟 1760 | 翼 1761 | 况 1762 | 姣 1763 | 凛 1764 | 浔 1765 | 吃 1766 | 飘 1767 | 债 1768 | 犟 1769 | 金 1770 | 促 1771 | 苛 1772 | 崇 1773 | 坂 1774 | 莳 1775 | 畔 1776 | 绂 1777 | 兵 1778 | 蠕 1779 | 斋 1780 | 根 1781 | 砍 1782 | 亢 1783 | 欢 1784 | 恬 1785 | 崔 1786 | 剁 1787 | 餐 1788 | 榫 1789 | 快 1790 | 扶 1791 | ‖ 1792 | 濒 1793 | 缠 1794 | 鳜 1795 | 当 1796 | 彭 1797 | 驭 1798 | 浦 1799 | 篮 1800 | 昀 1801 | 锆 1802 | 秸 1803 | 钳 1804 | 弋 1805 | 娣 1806 | 瞑 1807 | 夷 1808 | 龛 1809 | 苫 1810 | 拱 1811 | 致 1812 | % 1813 | 嵊 1814 | 障 1815 | 隐 1816 | 弑 1817 | 初 1818 | 娓 1819 | 抉 1820 | 汩 1821 | 累 1822 | 蓖 1823 | " 1824 | 唬 1825 | 助 1826 | 苓 1827 | 昙 1828 | 押 1829 | 毙 1830 | 破 1831 | 城 1832 | 郧 1833 | 逢 1834 | 嚏 1835 | 獭 1836 | 瞻 1837 | 溱 1838 | 婿 1839 | 赊 1840 | 跨 1841 | 恼 1842 | 璧 1843 | 萃 1844 | 姻 1845 | 貉 1846 | 灵 1847 | 炉 1848 | 密 1849 | 氛 1850 | 陶 1851 | 砸 1852 | 谬 1853 | 衔 1854 | 点 1855 | 琛 1856 | 沛 1857 | 枳 1858 | 层 1859 | 岱 1860 | 诺 1861 | 脍 1862 | 榈 1863 | 埂 1864 | 征 1865 | 冷 1866 | 裁 1867 | 打 1868 | 蹴 1869 | 素 1870 | 瘘 1871 | 逞 1872 | 蛐 1873 | 聊 1874 | 激 1875 | 腱 1876 | 萘 1877 | 踵 1878 | 飒 1879 | 蓟 1880 | 吆 1881 | 取 1882 | 咙 1883 | 簋 1884 | 涓 1885 | 矩 1886 | 曝 1887 | 挺 1888 | 揣 1889 | 座 1890 | 你 1891 | 史 1892 | 舵 1893 | 焱 1894 | 尘 1895 | 苏 1896 | 笈 1897 | 脚 1898 | 溉 1899 | 榨 1900 | 诵 1901 | 樊 1902 | 邓 1903 | 焊 1904 | 义 1905 | 庶 1906 | 儋 1907 | 蟋 1908 | 蒲 1909 | 赦 1910 | 呷 1911 | 杞 1912 | 诠 1913 | 豪 1914 | 还 1915 | 试 1916 | 颓 1917 | 茉 1918 | 太 1919 | 除 1920 | 紫 1921 | 逃 1922 | 痴 1923 | 草 1924 | 充 1925 | 鳕 1926 | 珉 1927 | 祗 1928 | 墨 1929 | 渭 1930 | 烩 1931 | 蘸 1932 | 慕 1933 | 璇 1934 | 镶 1935 | 穴 1936 | 嵘 1937 | 恶 1938 | 骂 1939 | 险 1940 | 绋 1941 | 幕 1942 | 碉 1943 | 肺 1944 | 戳 1945 | 刘 1946 | 潞 1947 | 秣 1948 | 纾 1949 | 潜 1950 | 銮 1951 | 洛 1952 | 须 1953 | 罘 1954 | 销 1955 | 瘪 1956 | 汞 1957 | 兮 1958 | 屉 1959 | r 1960 | 林 1961 | 厕 1962 | 质 1963 | 探 1964 | 划 1965 | 狸 1966 | 殚 1967 | 善 1968 | 煊 1969 | 烹 1970 | 〒 1971 | 锈 1972 | 逯 1973 | 宸 1974 | 辍 1975 | 泱 1976 | 柚 1977 | 袍 1978 | 远 1979 | 蹋 1980 | 嶙 1981 | 绝 1982 | 峥 1983 | 娥 1984 | 缍 1985 | 雀 1986 | 徵 1987 | 认 1988 | 镱 1989 | 谷 1990 | = 1991 | 贩 1992 | 勉 1993 | 撩 1994 | 鄯 1995 | 斐 1996 | 洋 1997 | 非 1998 | 祚 1999 | 泾 2000 | 诒 2001 | 饿 2002 | 撬 2003 | 威 2004 | 晷 2005 | 搭 2006 | 芍 2007 | 锥 2008 | 笺 2009 | 蓦 2010 | 候 2011 | 琊 2012 | 档 2013 | 礁 2014 | 沼 2015 | 卵 2016 | 荠 2017 | 忑 2018 | 朝 2019 | 凹 2020 | 瑞 2021 | 头 2022 | 仪 2023 | 弧 2024 | 孵 2025 | 畏 2026 | 铆 2027 | 突 2028 | 衲 2029 | 车 2030 | 浩 2031 | 气 2032 | 茂 2033 | 悖 2034 | 厢 2035 | 枕 2036 | 酝 2037 | 戴 2038 | 湾 2039 | 邹 2040 | 飚 2041 | 攘 2042 | 锂 2043 | 写 2044 | 宵 2045 | 翁 2046 | 岷 2047 | 无 2048 | 喜 2049 | 丈 2050 | 挑 2051 | 嗟 2052 | 绛 2053 | 殉 2054 | 议 2055 | 槽 2056 | 具 2057 | 醇 2058 | 淞 2059 | 笃 2060 | 郴 2061 | 阅 2062 | 饼 2063 | 底 2064 | 壕 2065 | 砚 2066 | 弈 2067 | 询 2068 | 缕 2069 | 庹 2070 | 翟 2071 | 零 2072 | 筷 2073 | 暨 2074 | 舟 2075 | 闺 2076 | 甯 2077 | 撞 2078 | 麂 2079 | 茌 2080 | 蔼 2081 | 很 2082 | 珲 2083 | 捕 2084 | 棠 2085 | 角 2086 | 阉 2087 | 媛 2088 | 娲 2089 | 诽 2090 | 剿 2091 | 尉 2092 | 爵 2093 | 睬 2094 | 韩 2095 | 诰 2096 | 匣 2097 | 危 2098 | 糍 2099 | 镯 2100 | 立 2101 | 浏 2102 | 阳 2103 | 少 2104 | 盆 2105 | 舔 2106 | 擘 2107 | 匪 2108 | 申 2109 | 尬 2110 | 铣 2111 | 旯 2112 | 抖 2113 | 赘 2114 | 瓯 2115 | 居 2116 | ˇ 2117 | 哮 2118 | 游 2119 | 锭 2120 | 茏 2121 | 歌 2122 | 坏 2123 | 甚 2124 | 秒 2125 | 舞 2126 | 沙 2127 | 仗 2128 | 劲 2129 | 潺 2130 | 阿 2131 | 燧 2132 | 郭 2133 | 嗖 2134 | 霏 2135 | 忠 2136 | 材 2137 | 奂 2138 | 耐 2139 | 跺 2140 | 砀 2141 | 输 2142 | 岖 2143 | 媳 2144 | 氟 2145 | 极 2146 | 摆 2147 | 灿 2148 | 今 2149 | 扔 2150 | 腻 2151 | 枝 2152 | 奎 2153 | 药 2154 | 熄 2155 | 吨 2156 | 话 2157 | q 2158 | 额 2159 | 慑 2160 | 嘌 2161 | 协 2162 | 喀 2163 | 壳 2164 | 埭 2165 | 视 2166 | 著 2167 | 於 2168 | 愧 2169 | 陲 2170 | 翌 2171 | 峁 2172 | 颅 2173 | 佛 2174 | 腹 2175 | 聋 2176 | 侯 2177 | 咎 2178 | 叟 2179 | 秀 2180 | 颇 2181 | 存 2182 | 较 2183 | 罪 2184 | 哄 2185 | 岗 2186 | 扫 2187 | 栏 2188 | 钾 2189 | 羌 2190 | 己 2191 | 璨 2192 | 枭 2193 | 霉 2194 | 煌 2195 | 涸 2196 | 衿 2197 | 键 2198 | 镝 2199 | 益 2200 | 岢 2201 | 奏 2202 | 连 2203 | 夯 2204 | 睿 2205 | 冥 2206 | 均 2207 | 糖 2208 | 狞 2209 | 蹊 2210 | 稻 2211 | 爸 2212 | 刿 2213 | 胥 2214 | 煜 2215 | 丽 2216 | 肿 2217 | 璃 2218 | 掸 2219 | 跚 2220 | 灾 2221 | 垂 2222 | 樾 2223 | 濑 2224 | 乎 2225 | 莲 2226 | 窄 2227 | 犹 2228 | 撮 2229 | 战 2230 | 馄 2231 | 软 2232 | 络 2233 | 显 2234 | 鸢 2235 | 胸 2236 | 宾 2237 | 妲 2238 | 恕 2239 | 埔 2240 | 蝌 2241 | 份 2242 | 遇 2243 | 巧 2244 | 瞟 2245 | 粒 2246 | 恰 2247 | 剥 2248 | 桡 2249 | 博 2250 | 讯 2251 | 凯 2252 | 堇 2253 | 阶 2254 | 滤 2255 | 卖 2256 | 斌 2257 | 骚 2258 | 彬 2259 | 兑 2260 | 磺 2261 | 樱 2262 | 舷 2263 | 两 2264 | 娱 2265 | 福 2266 | 仃 2267 | 差 2268 | 找 2269 | 桁 2270 | ÷ 2271 | 净 2272 | 把 2273 | 阴 2274 | 污 2275 | 戬 2276 | 雷 2277 | 碓 2278 | 蕲 2279 | 楚 2280 | 罡 2281 | 焖 2282 | 抽 2283 | 妫 2284 | 咒 2285 | 仑 2286 | 闱 2287 | 尽 2288 | 邑 2289 | 菁 2290 | 爱 2291 | 贷 2292 | 沥 2293 | 鞑 2294 | 牡 2295 | 嗉 2296 | 崴 2297 | 骤 2298 | 塌 2299 | 嗦 2300 | 订 2301 | 拮 2302 | 滓 2303 | 捡 2304 | 锻 2305 | 次 2306 | 坪 2307 | 杩 2308 | 臃 2309 | 箬 2310 | 融 2311 | 珂 2312 | 鹗 2313 | 宗 2314 | 枚 2315 | 降 2316 | 鸬 2317 | 妯 2318 | 阄 2319 | 堰 2320 | 盐 2321 | 毅 2322 | 必 2323 | 杨 2324 | 崃 2325 | 俺 2326 | 甬 2327 | 状 2328 | 莘 2329 | 货 2330 | 耸 2331 | 菱 2332 | 腼 2333 | 铸 2334 | 唏 2335 | 痤 2336 | 孚 2337 | 澳 2338 | 懒 2339 | 溅 2340 | 翘 2341 | 疙 2342 | 杷 2343 | 淼 2344 | 缙 2345 | 骰 2346 | 喊 2347 | 悉 2348 | 砻 2349 | 坷 2350 | 艇 2351 | 赁 2352 | 界 2353 | 谤 2354 | 纣 2355 | 宴 2356 | 晃 2357 | 茹 2358 | 归 2359 | 饭 2360 | 梢 2361 | 铡 2362 | 街 2363 | 抄 2364 | 肼 2365 | 鬟 2366 | 苯 2367 | 颂 2368 | 撷 2369 | 戈 2370 | 炒 2371 | 咆 2372 | 茭 2373 | 瘙 2374 | 负 2375 | 仰 2376 | 客 2377 | 琉 2378 | 铢 2379 | 封 2380 | 卑 2381 | 珥 2382 | 椿 2383 | 镧 2384 | 窨 2385 | 鬲 2386 | 寿 2387 | 御 2388 | 袤 2389 | 铃 2390 | 萎 2391 | 砖 2392 | 餮 2393 | 脒 2394 | 裳 2395 | 肪 2396 | 孕 2397 | 嫣 2398 | 馗 2399 | 嵇 2400 | 恳 2401 | 氯 2402 | 江 2403 | 石 2404 | 褶 2405 | 冢 2406 | 祸 2407 | 阻 2408 | 狈 2409 | 羞 2410 | 银 2411 | 靳 2412 | 透 2413 | 咳 2414 | 叼 2415 | 敷 2416 | 芷 2417 | 啥 2418 | 它 2419 | 瓤 2420 | 兰 2421 | 痘 2422 | 懊 2423 | 逑 2424 | 肌 2425 | 往 2426 | 捺 2427 | 坊 2428 | 甩 2429 | 呻 2430 | 〃 2431 | 沦 2432 | 忘 2433 | 膻 2434 | 祟 2435 | 菅 2436 | 剧 2437 | 崆 2438 | 智 2439 | 坯 2440 | 臧 2441 | 霍 2442 | 墅 2443 | 攻 2444 | 眯 2445 | 倘 2446 | 拢 2447 | 骠 2448 | 铐 2449 | 庭 2450 | 岙 2451 | 瓠 2452 | ′ 2453 | 缺 2454 | 泥 2455 | 迢 2456 | 捶 2457 | ? 2458 | ? 2459 | 郏 2460 | 喙 2461 | 掷 2462 | 沌 2463 | 纯 2464 | 秘 2465 | 种 2466 | 听 2467 | 绘 2468 | 固 2469 | 螨 2470 | 团 2471 | 香 2472 | 盗 2473 | 妒 2474 | 埚 2475 | 蓝 2476 | 拖 2477 | 旱 2478 | 荞 2479 | 铀 2480 | 血 2481 | 遏 2482 | 汲 2483 | 辰 2484 | 叩 2485 | 拽 2486 | 幅 2487 | 硬 2488 | 惶 2489 | 桀 2490 | 漠 2491 | 措 2492 | 泼 2493 | 唑 2494 | 齐 2495 | 肾 2496 | 念 2497 | 酱 2498 | 虚 2499 | 屁 2500 | 耶 2501 | 旗 2502 | 砦 2503 | 闵 2504 | 婉 2505 | 馆 2506 | 拭 2507 | 绅 2508 | 韧 2509 | 忏 2510 | 窝 2511 | 醋 2512 | 葺 2513 | 顾 2514 | 辞 2515 | 倜 2516 | 堆 2517 | 辋 2518 | 逆 2519 | 玟 2520 | 贱 2521 | 疾 2522 | 董 2523 | 惘 2524 | 倌 2525 | 锕 2526 | 淘 2527 | 嘀 2528 | 莽 2529 | 俭 2530 | 笏 2531 | 绑 2532 | 鲷 2533 | 杈 2534 | 择 2535 | 蟀 2536 | 粥 2537 | 嗯 2538 | 驰 2539 | 逾 2540 | 案 2541 | 谪 2542 | 褓 2543 | 胫 2544 | 哩 2545 | 昕 2546 | 颚 2547 | 鲢 2548 | 绠 2549 | 躺 2550 | 鹄 2551 | 崂 2552 | 儒 2553 | 俨 2554 | 丝 2555 | 尕 2556 | 泌 2557 | 啊 2558 | 萸 2559 | 彰 2560 | 幺 2561 | 吟 2562 | 骄 2563 | 苣 2564 | 弦 2565 | 脊 2566 | 瑰 2567 | 〈 2568 | 诛 2569 | 镁 2570 | 析 2571 | 闪 2572 | 剪 2573 | 侧 2574 | 哟 2575 | 框 2576 | 螃 2577 | 守 2578 | 嬗 2579 | 燕 2580 | 狭 2581 | 铈 2582 | 缮 2583 | 概 2584 | 迳 2585 | 痧 2586 | 鲲 2587 | 俯 2588 | 售 2589 | 笼 2590 | 痣 2591 | 扉 2592 | 挖 2593 | 满 2594 | 咋 2595 | 援 2596 | 邱 2597 | 扇 2598 | 歪 2599 | 便 2600 | 玑 2601 | 绦 2602 | 峡 2603 | 蛇 2604 | 叨 2605 | 〖 2606 | 泽 2607 | 胃 2608 | 斓 2609 | 喋 2610 | 怂 2611 | 坟 2612 | 猪 2613 | 该 2614 | 蚬 2615 | 炕 2616 | 弥 2617 | 赞 2618 | 棣 2619 | 晔 2620 | 娠 2621 | 挲 2622 | 狡 2623 | 创 2624 | 疖 2625 | 铕 2626 | 镭 2627 | 稷 2628 | 挫 2629 | 弭 2630 | 啾 2631 | 翔 2632 | 粉 2633 | 履 2634 | 苘 2635 | 哦 2636 | 楼 2637 | 秕 2638 | 铂 2639 | 土 2640 | 锣 2641 | 瘟 2642 | 挣 2643 | 栉 2644 | 习 2645 | 享 2646 | 桢 2647 | 袅 2648 | 磨 2649 | 桂 2650 | 谦 2651 | 延 2652 | 坚 2653 | 蔚 2654 | 噗 2655 | 署 2656 | 谟 2657 | 猬 2658 | 钎 2659 | 恐 2660 | 嬉 2661 | 雒 2662 | 倦 2663 | 衅 2664 | 亏 2665 | 璩 2666 | 睹 2667 | 刻 2668 | 殿 2669 | 王 2670 | 算 2671 | 雕 2672 | 麻 2673 | 丘 2674 | 柯 2675 | 骆 2676 | 丸 2677 | 塍 2678 | 谚 2679 | 添 2680 | 鲈 2681 | 垓 2682 | 桎 2683 | 蚯 2684 | 芥 2685 | 予 2686 | 飕 2687 | 镦 2688 | 谌 2689 | 窗 2690 | 醚 2691 | 菀 2692 | 亮 2693 | 搪 2694 | 莺 2695 | 蒿 2696 | 羁 2697 | 足 2698 | J 2699 | 真 2700 | 轶 2701 | 悬 2702 | 衷 2703 | 靛 2704 | 翊 2705 | 掩 2706 | 哒 2707 | 炅 2708 | 掐 2709 | 冼 2710 | 妮 2711 | l 2712 | 谐 2713 | 稚 2714 | 荆 2715 | 擒 2716 | 犯 2717 | 陵 2718 | 虏 2719 | 浓 2720 | 崽 2721 | 刍 2722 | 陌 2723 | 傻 2724 | 孜 2725 | 千 2726 | 靖 2727 | 演 2728 | 矜 2729 | 钕 2730 | 煽 2731 | 杰 2732 | 酗 2733 | 渗 2734 | 伞 2735 | 栋 2736 | 俗 2737 | 泫 2738 | 戍 2739 | 罕 2740 | 沾 2741 | 疽 2742 | 灏 2743 | 煦 2744 | 芬 2745 | 磴 2746 | 叱 2747 | 阱 2748 | 榉 2749 | 湃 2750 | 蜀 2751 | 叉 2752 | 醒 2753 | 彪 2754 | 租 2755 | 郡 2756 | 篷 2757 | 屎 2758 | 良 2759 | 垢 2760 | 隗 2761 | 弱 2762 | 陨 2763 | 峪 2764 | 砷 2765 | 掴 2766 | 颁 2767 | 胎 2768 | 雯 2769 | 绵 2770 | 贬 2771 | 沐 2772 | 撵 2773 | 隘 2774 | 篙 2775 | 暖 2776 | 曹 2777 | 陡 2778 | 栓 2779 | 填 2780 | 臼 2781 | 彦 2782 | 瓶 2783 | 琪 2784 | 潼 2785 | 哪 2786 | 鸡 2787 | 摩 2788 | 啦 2789 | 俟 2790 | 锋 2791 | 域 2792 | 耻 2793 | 蔫 2794 | 疯 2795 | 纹 2796 | 撇 2797 | 毒 2798 | 绶 2799 | 痛 2800 | 酯 2801 | 忍 2802 | 爪 2803 | 赳 2804 | 歆 2805 | 嘹 2806 | 辕 2807 | 烈 2808 | 册 2809 | 朴 2810 | 钱 2811 | 吮 2812 | 毯 2813 | 癜 2814 | 娃 2815 | 谀 2816 | 邵 2817 | 厮 2818 | 炽 2819 | 璞 2820 | 邃 2821 | 丐 2822 | 追 2823 | 词 2824 | 瓒 2825 | 忆 2826 | 轧 2827 | 芫 2828 | 谯 2829 | 喷 2830 | 弟 2831 | 半 2832 | 冕 2833 | 裙 2834 | 掖 2835 | 墉 2836 | 绮 2837 | 寝 2838 | 苔 2839 | 势 2840 | 顷 2841 | 褥 2842 | 切 2843 | 衮 2844 | 君 2845 | 佳 2846 | 嫒 2847 | 蚩 2848 | 霞 2849 | 佚 2850 | 洙 2851 | 逊 2852 | 镖 2853 | 暹 2854 | 唛 2855 | & 2856 | 殒 2857 | 顶 2858 | 碗 2859 | 獗 2860 | 轭 2861 | 铺 2862 | 蛊 2863 | 废 2864 | 恹 2865 | 汨 2866 | 崩 2867 | 珍 2868 | 那 2869 | 杵 2870 | 曲 2871 | 纺 2872 | 夏 2873 | 薰 2874 | 傀 2875 | 闳 2876 | 淬 2877 | 姘 2878 | 舀 2879 | 拧 2880 | 卷 2881 | 楂 2882 | 恍 2883 | 讪 2884 | 厩 2885 | 寮 2886 | 篪 2887 | 赓 2888 | 乘 2889 | 灭 2890 | 盅 2891 | 鞣 2892 | 沟 2893 | 慎 2894 | 挂 2895 | 饺 2896 | 鼾 2897 | 杳 2898 | 树 2899 | 缨 2900 | 丛 2901 | 絮 2902 | 娌 2903 | 臻 2904 | 嗳 2905 | 篡 2906 | 侩 2907 | 述 2908 | 衰 2909 | 矛 2910 | 圈 2911 | 蚜 2912 | 匕 2913 | 筹 2914 | 匿 2915 | 濞 2916 | 晨 2917 | 叶 2918 | 骋 2919 | 郝 2920 | 挚 2921 | 蚴 2922 | 滞 2923 | 增 2924 | 侍 2925 | 描 2926 | 瓣 2927 | 吖 2928 | 嫦 2929 | 蟒 2930 | 匾 2931 | 圣 2932 | 赌 2933 | 毡 2934 | 癞 2935 | 恺 2936 | 百 2937 | 曳 2938 | 需 2939 | 篓 2940 | 肮 2941 | 庖 2942 | 帏 2943 | 卿 2944 | 驿 2945 | 遗 2946 | 蹬 2947 | 鬓 2948 | 骡 2949 | 歉 2950 | 芎 2951 | 胳 2952 | 屐 2953 | 禽 2954 | 烦 2955 | 晌 2956 | 寄 2957 | 媾 2958 | 狄 2959 | 翡 2960 | 苒 2961 | 船 2962 | 廉 2963 | 终 2964 | 痞 2965 | 殇 2966 | 々 2967 | 畦 2968 | 饶 2969 | 改 2970 | 拆 2971 | 悻 2972 | 萄 2973 | £ 2974 | 瓿 2975 | 乃 2976 | 訾 2977 | 桅 2978 | 匮 2979 | 溧 2980 | 拥 2981 | 纱 2982 | 铍 2983 | 骗 2984 | 蕃 2985 | 龋 2986 | 缬 2987 | 父 2988 | 佐 2989 | 疚 2990 | 栎 2991 | 醍 2992 | 掳 2993 | 蓄 2994 | x 2995 | 惆 2996 | 颜 2997 | 鲆 2998 | 榆 2999 | 〔 3000 | 猎 3001 | 敌 3002 | 暴 3003 | 谥 3004 | 鲫 3005 | 贾 3006 | 罗 3007 | 玻 3008 | 缄 3009 | 扦 3010 | 芪 3011 | 癣 3012 | 落 3013 | 徒 3014 | 臾 3015 | 恿 3016 | 猩 3017 | 托 3018 | 邴 3019 | 肄 3020 | 牵 3021 | 春 3022 | 陛 3023 | 耀 3024 | 刊 3025 | 拓 3026 | 蓓 3027 | 邳 3028 | 堕 3029 | 寇 3030 | 枉 3031 | 淌 3032 | 啡 3033 | 湄 3034 | 兽 3035 | 酷 3036 | 萼 3037 | 碚 3038 | 濠 3039 | 萤 3040 | 夹 3041 | 旬 3042 | 戮 3043 | 梭 3044 | 琥 3045 | 椭 3046 | 昔 3047 | 勺 3048 | 蜊 3049 | 绐 3050 | 晚 3051 | 孺 3052 | 僵 3053 | 宣 3054 | 摄 3055 | 冽 3056 | 旨 3057 | 萌 3058 | 忙 3059 | 蚤 3060 | 眉 3061 | 噼 3062 | 蟑 3063 | 付 3064 | 契 3065 | 瓜 3066 | 悼 3067 | 颡 3068 | 壁 3069 | 曾 3070 | 窕 3071 | 颢 3072 | 澎 3073 | 仿 3074 | 俑 3075 | 浑 3076 | 嵌 3077 | 浣 3078 | 乍 3079 | 碌 3080 | 褪 3081 | 乱 3082 | 蔟 3083 | 隙 3084 | 玩 3085 | 剐 3086 | 葫 3087 | 箫 3088 | 纲 3089 | 围 3090 | 伐 3091 | 决 3092 | 伙 3093 | 漩 3094 | 瑟 3095 | 刑 3096 | 肓 3097 | 镳 3098 | 缓 3099 | 蹭 3100 | 氨 3101 | 皓 3102 | 典 3103 | 畲 3104 | 坍 3105 | 铑 3106 | 檐 3107 | 塑 3108 | 洞 3109 | 倬 3110 | 储 3111 | 胴 3112 | 淳 3113 | 戾 3114 | 吐 3115 | 灼 3116 | 惺 3117 | 妙 3118 | 毕 3119 | 珐 3120 | 缈 3121 | 虱 3122 | 盖 3123 | 羰 3124 | 鸿 3125 | 磅 3126 | 谓 3127 | 髅 3128 | 娴 3129 | 苴 3130 | 唷 3131 | 蚣 3132 | 霹 3133 | 抨 3134 | 贤 3135 | 唠 3136 | 犬 3137 | 誓 3138 | 逍 3139 | 庠 3140 | 逼 3141 | 麓 3142 | 籼 3143 | 釉 3144 | 呜 3145 | 碧 3146 | 秧 3147 | 氩 3148 | 摔 3149 | 霄 3150 | 穸 3151 | 纨 3152 | 辟 3153 | 妈 3154 | 映 3155 | 完 3156 | 牛 3157 | 缴 3158 | 嗷 3159 | 炊 3160 | 恩 3161 | 荔 3162 | 茆 3163 | 掉 3164 | 紊 3165 | 慌 3166 | 莓 3167 | 羟 3168 | 阙 3169 | 萁 3170 | 磐 3171 | 另 3172 | 蕹 3173 | 辱 3174 | 鳐 3175 | 湮 3176 | 吡 3177 | 吩 3178 | 唐 3179 | 睦 3180 | 垠 3181 | 舒 3182 | 圜 3183 | 冗 3184 | 瞿 3185 | 溺 3186 | 芾 3187 | 囱 3188 | 匠 3189 | 僳 3190 | 汐 3191 | 菩 3192 | 饬 3193 | 漓 3194 | 黑 3195 | 霰 3196 | 浸 3197 | 濡 3198 | 窥 3199 | 毂 3200 | 蒡 3201 | 兢 3202 | 驻 3203 | 鹉 3204 | 芮 3205 | 诙 3206 | 迫 3207 | 雳 3208 | 厂 3209 | 忐 3210 | 臆 3211 | 猴 3212 | 鸣 3213 | 蚪 3214 | 栈 3215 | 箕 3216 | 羡 3217 | 渐 3218 | 莆 3219 | 捍 3220 | 眈 3221 | 哓 3222 | 趴 3223 | 蹼 3224 | 埕 3225 | 嚣 3226 | 骛 3227 | 宏 3228 | 淄 3229 | 斑 3230 | 噜 3231 | 严 3232 | 瑛 3233 | 垃 3234 | 椎 3235 | 诱 3236 | 压 3237 | 庾 3238 | 绞 3239 | 焘 3240 | 廿 3241 | 抡 3242 | 迄 3243 | 棘 3244 | 夫 3245 | 纬 3246 | 锹 3247 | 眨 3248 | 瞌 3249 | 侠 3250 | 脐 3251 | 竞 3252 | 瀑 3253 | 孳 3254 | 骧 3255 | 遁 3256 | 姜 3257 | 颦 3258 | 荪 3259 | 滚 3260 | 萦 3261 | 伪 3262 | 逸 3263 | 粳 3264 | 爬 3265 | 锁 3266 | 矣 3267 | 役 3268 | 趣 3269 | 洒 3270 | 颔 3271 | 诏 3272 | 逐 3273 | 奸 3274 | 甭 3275 | 惠 3276 | 攀 3277 | 蹄 3278 | 泛 3279 | 尼 3280 | 拼 3281 | 阮 3282 | 鹰 3283 | 亚 3284 | 颈 3285 | 惑 3286 | 勒 3287 | 〉 3288 | 际 3289 | 肛 3290 | 爷 3291 | 刚 3292 | 钨 3293 | 丰 3294 | 养 3295 | 冶 3296 | 鲽 3297 | 辉 3298 | 蔻 3299 | 画 3300 | 覆 3301 | 皴 3302 | 妊 3303 | 麦 3304 | 返 3305 | 醉 3306 | 皂 3307 | 擀 3308 | 〗 3309 | 酶 3310 | 凑 3311 | 粹 3312 | 悟 3313 | 诀 3314 | 硖 3315 | 港 3316 | 卜 3317 | z 3318 | 杀 3319 | 涕 3320 | ± 3321 | 舍 3322 | 铠 3323 | 抵 3324 | 弛 3325 | 段 3326 | 敝 3327 | 镐 3328 | 奠 3329 | 拂 3330 | 轴 3331 | 跛 3332 | 袱 3333 | e 3334 | t 3335 | 沉 3336 | 菇 3337 | 俎 3338 | 薪 3339 | 峦 3340 | 秭 3341 | 蟹 3342 | 历 3343 | 盟 3344 | 菠 3345 | 寡 3346 | 液 3347 | 肢 3348 | 喻 3349 | 染 3350 | 裱 3351 | 悱 3352 | 抱 3353 | 氙 3354 | 赤 3355 | 捅 3356 | 猛 3357 | 跑 3358 | 氮 3359 | 谣 3360 | 仁 3361 | 尺 3362 | 辊 3363 | 窍 3364 | 烙 3365 | 衍 3366 | 架 3367 | 擦 3368 | 倏 3369 | 璐 3370 | 瑁 3371 | 币 3372 | 楞 3373 | 胖 3374 | 夔 3375 | 趸 3376 | 邛 3377 | 惴 3378 | 饕 3379 | 虔 3380 | 蝎 3381 | § 3382 | 哉 3383 | 贝 3384 | 宽 3385 | 辫 3386 | 炮 3387 | 扩 3388 | 饲 3389 | 籽 3390 | 魏 3391 | 菟 3392 | 锰 3393 | 伍 3394 | 猝 3395 | 末 3396 | 琳 3397 | 哚 3398 | 蛎 3399 | 邂 3400 | 呀 3401 | 姿 3402 | 鄞 3403 | 却 3404 | 歧 3405 | 仙 3406 | 恸 3407 | 椐 3408 | 森 3409 | 牒 3410 | 寤 3411 | 袒 3412 | 婆 3413 | 虢 3414 | 雅 3415 | 钉 3416 | 朵 3417 | 贼 3418 | 欲 3419 | 苞 3420 | 寰 3421 | 故 3422 | 龚 3423 | 坭 3424 | 嘘 3425 | 咫 3426 | 礼 3427 | 硷 3428 | 兀 3429 | 睢 3430 | 汶 3431 | ’ 3432 | 铲 3433 | 烧 3434 | 绕 3435 | 诃 3436 | 浃 3437 | 钿 3438 | 哺 3439 | 柜 3440 | 讼 3441 | 颊 3442 | 璁 3443 | 腔 3444 | 洽 3445 | 咐 3446 | 脲 3447 | 簌 3448 | 筠 3449 | 镣 3450 | 玮 3451 | 鞠 3452 | 谁 3453 | 兼 3454 | 姆 3455 | 挥 3456 | 梯 3457 | 蝴 3458 | 谘 3459 | 漕 3460 | 刷 3461 | 躏 3462 | 宦 3463 | 弼 3464 | b 3465 | 垌 3466 | 劈 3467 | 麟 3468 | 莉 3469 | 揭 3470 | 笙 3471 | 渎 3472 | 仕 3473 | 嗤 3474 | 仓 3475 | 配 3476 | 怏 3477 | 抬 3478 | 错 3479 | 泯 3480 | 镊 3481 | 孰 3482 | 猿 3483 | 邪 3484 | 仍 3485 | 秋 3486 | 鼬 3487 | 壹 3488 | 歇 3489 | 吵 3490 | 炼 3491 | < 3492 | 尧 3493 | 射 3494 | 柬 3495 | 廷 3496 | 胧 3497 | 霾 3498 | 凳 3499 | 隋 3500 | 肚 3501 | 浮 3502 | 梦 3503 | 祥 3504 | 株 3505 | 堵 3506 | 退 3507 | L 3508 | 鹫 3509 | 跎 3510 | 凶 3511 | 毽 3512 | 荟 3513 | 炫 3514 | 栩 3515 | 玳 3516 | 甜 3517 | 沂 3518 | 鹿 3519 | 顽 3520 | 伯 3521 | 爹 3522 | 赔 3523 | 蛴 3524 | 徐 3525 | 匡 3526 | 欣 3527 | 狰 3528 | 缸 3529 | 雹 3530 | 蟆 3531 | 疤 3532 | 默 3533 | 沤 3534 | 啜 3535 | 痂 3536 | 衣 3537 | 禅 3538 | w 3539 | i 3540 | h 3541 | 辽 3542 | 葳 3543 | 黝 3544 | 钗 3545 | 停 3546 | 沽 3547 | 棒 3548 | 馨 3549 | 颌 3550 | 肉 3551 | 吴 3552 | 硫 3553 | 悯 3554 | 劾 3555 | 娈 3556 | 马 3557 | 啧 3558 | 吊 3559 | 悌 3560 | 镑 3561 | 峭 3562 | 帆 3563 | 瀣 3564 | 涉 3565 | 咸 3566 | 疸 3567 | 滋 3568 | 泣 3569 | 翦 3570 | 拙 3571 | 癸 3572 | 钥 3573 | 蜒 3574 | + 3575 | 尾 3576 | 庄 3577 | 凝 3578 | 泉 3579 | 婢 3580 | 渴 3581 | 谊 3582 | 乞 3583 | 陆 3584 | 锉 3585 | 糊 3586 | 鸦 3587 | 淮 3588 | I 3589 | B 3590 | N 3591 | 晦 3592 | 弗 3593 | 乔 3594 | 庥 3595 | 葡 3596 | 尻 3597 | 席 3598 | 橡 3599 | 傣 3600 | 渣 3601 | 拿 3602 | 惩 3603 | 麋 3604 | 斛 3605 | 缃 3606 | 矮 3607 | 蛏 3608 | 岘 3609 | 鸽 3610 | 姐 3611 | 膏 3612 | 催 3613 | 奔 3614 | 镒 3615 | 喱 3616 | 蠡 3617 | 摧 3618 | 钯 3619 | 胤 3620 | 柠 3621 | 拐 3622 | 璋 3623 | 鸥 3624 | 卢 3625 | 荡 3626 | 倾 3627 | ^ 3628 | _ 3629 | 珀 3630 | 逄 3631 | 萧 3632 | 塾 3633 | 掇 3634 | 贮 3635 | 笆 3636 | 聂 3637 | 圃 3638 | 冲 3639 | 嵬 3640 | M 3641 | 滔 3642 | 笕 3643 | 值 3644 | 炙 3645 | 偶 3646 | 蜱 3647 | 搐 3648 | 梆 3649 | 汪 3650 | 蔬 3651 | 腑 3652 | 鸯 3653 | 蹇 3654 | 敞 3655 | 绯 3656 | 仨 3657 | 祯 3658 | 谆 3659 | 梧 3660 | 糗 3661 | 鑫 3662 | 啸 3663 | 豺 3664 | 囹 3665 | 猾 3666 | 巢 3667 | 柄 3668 | 瀛 3669 | 筑 3670 | 踌 3671 | 沭 3672 | 暗 3673 | 苁 3674 | 鱿 3675 | 蹉 3676 | 脂 3677 | 蘖 3678 | 牢 3679 | 热 3680 | 木 3681 | 吸 3682 | 溃 3683 | 宠 3684 | 序 3685 | 泞 3686 | 偿 3687 | 拜 3688 | 檩 3689 | 厚 3690 | 朐 3691 | 毗 3692 | 螳 3693 | 吞 3694 | 媚 3695 | 朽 3696 | 担 3697 | 蝗 3698 | 橘 3699 | 畴 3700 | 祈 3701 | 糟 3702 | 盱 3703 | 隼 3704 | 郜 3705 | 惜 3706 | 珠 3707 | 裨 3708 | 铵 3709 | 焙 3710 | 琚 3711 | 唯 3712 | 咚 3713 | 噪 3714 | 骊 3715 | 丫 3716 | 滢 3717 | 勤 3718 | 棉 3719 | 呸 3720 | 咣 3721 | 淀 3722 | 隔 3723 | 蕾 3724 | 窈 3725 | 饨 3726 | 挨 3727 | 煅 3728 | 短 3729 | 匙 3730 | 粕 3731 | 镜 3732 | 赣 3733 | 撕 3734 | 墩 3735 | 酬 3736 | 馁 3737 | 豌 3738 | 颐 3739 | 抗 3740 | 酣 3741 | 氓 3742 | 佑 3743 | 搁 3744 | 哭 3745 | 递 3746 | 耷 3747 | 涡 3748 | 桃 3749 | 贻 3750 | 碣 3751 | 截 3752 | 瘦 3753 | 昭 3754 | 镌 3755 | 蔓 3756 | 氚 3757 | 甲 3758 | 猕 3759 | 蕴 3760 | 蓬 3761 | 散 3762 | 拾 3763 | 纛 3764 | 狼 3765 | 猷 3766 | 铎 3767 | 埋 3768 | 旖 3769 | 矾 3770 | 讳 3771 | 囊 3772 | 糜 3773 | 迈 3774 | 粟 3775 | 蚂 3776 | 紧 3777 | 鲳 3778 | 瘢 3779 | 栽 3780 | 稼 3781 | 羊 3782 | 锄 3783 | 斟 3784 | 睁 3785 | 桥 3786 | 瓮 3787 | 蹙 3788 | 祉 3789 | 醺 3790 | 鼻 3791 | 昱 3792 | 剃 3793 | 跳 3794 | 篱 3795 | 跷 3796 | 蒜 3797 | 翎 3798 | 宅 3799 | 晖 3800 | 嗑 3801 | 壑 3802 | 峻 3803 | 癫 3804 | 屏 3805 | 狠 3806 | 陋 3807 | 袜 3808 | 途 3809 | 憎 3810 | 祀 3811 | 莹 3812 | 滟 3813 | 佶 3814 | 溥 3815 | 臣 3816 | 约 3817 | 盛 3818 | 峰 3819 | 磁 3820 | 慵 3821 | 婪 3822 | 拦 3823 | 莅 3824 | 朕 3825 | 鹦 3826 | 粲 3827 | 裤 3828 | 哎 3829 | 疡 3830 | 嫖 3831 | 琵 3832 | 窟 3833 | 堪 3834 | 谛 3835 | 嘉 3836 | 儡 3837 | 鳝 3838 | 斩 3839 | 郾 3840 | 驸 3841 | 酊 3842 | 妄 3843 | 胜 3844 | 贺 3845 | 徙 3846 | 傅 3847 | 噌 3848 | 钢 3849 | 栅 3850 | 庇 3851 | 恋 3852 | 匝 3853 | 巯 3854 | 邈 3855 | 尸 3856 | 锚 3857 | 粗 3858 | 佟 3859 | 蛟 3860 | 薹 3861 | 纵 3862 | 蚊 3863 | 郅 3864 | 绢 3865 | 锐 3866 | 苗 3867 | 俞 3868 | 篆 3869 | 淆 3870 | 膀 3871 | 鲜 3872 | 煎 3873 | 诶 3874 | 秽 3875 | 寻 3876 | 涮 3877 | 刺 3878 | 怀 3879 | 噶 3880 | 巨 3881 | 褰 3882 | 魅 3883 | 灶 3884 | 灌 3885 | 桉 3886 | 藕 3887 | 谜 3888 | 舸 3889 | 薄 3890 | 搀 3891 | 恽 3892 | 借 3893 | 牯 3894 | 痉 3895 | 渥 3896 | 愿 3897 | 亓 3898 | 耘 3899 | 杠 3900 | 柩 3901 | 锔 3902 | 蚶 3903 | 钣 3904 | 珈 3905 | 喘 3906 | 蹒 3907 | 幽 3908 | 赐 3909 | 稗 3910 | 晤 3911 | 莱 3912 | 泔 3913 | 扯 3914 | 肯 3915 | 菪 3916 | 裆 3917 | 腩 3918 | 豉 3919 | 疆 3920 | 骜 3921 | 腐 3922 | 倭 3923 | 珏 3924 | 唔 3925 | 粮 3926 | 亡 3927 | 润 3928 | 慰 3929 | 伽 3930 | 橄 3931 | 玄 3932 | 誉 3933 | 醐 3934 | 胆 3935 | 龊 3936 | 粼 3937 | 塬 3938 | 陇 3939 | 彼 3940 | 削 3941 | 嗣 3942 | 绾 3943 | 芽 3944 | 妗 3945 | 垭 3946 | 瘴 3947 | 爽 3948 | 薏 3949 | 寨 3950 | 龈 3951 | 泠 3952 | 弹 3953 | 赢 3954 | 漪 3955 | 猫 3956 | 嘧 3957 | 涂 3958 | 恤 3959 | 圭 3960 | 茧 3961 | 烽 3962 | 屑 3963 | 痕 3964 | 巾 3965 | 赖 3966 | 荸 3967 | 凰 3968 | 腮 3969 | 畈 3970 | 亵 3971 | 蹲 3972 | 偃 3973 | 苇 3974 | 澜 3975 | 艮 3976 | 换 3977 | 骺 3978 | 烘 3979 | 苕 3980 | 梓 3981 | 颉 3982 | 肇 3983 | 哗 3984 | 悄 3985 | 氤 3986 | 涠 3987 | 葬 3988 | 屠 3989 | 鹭 3990 | 植 3991 | 竺 3992 | 佯 3993 | 诣 3994 | 鲇 3995 | 瘀 3996 | 鲅 3997 | 邦 3998 | 移 3999 | 滁 4000 | 冯 4001 | 耕 4002 | 癔 4003 | 戌 4004 | 茬 4005 | 沁 4006 | 巩 4007 | 悠 4008 | 湘 4009 | 洪 4010 | 痹 4011 | 锟 4012 | 循 4013 | 谋 4014 | 腕 4015 | 鳃 4016 | 钠 4017 | 捞 4018 | 焉 4019 | 迎 4020 | 碱 4021 | 伫 4022 | 急 4023 | 榷 4024 | 奈 4025 | 邝 4026 | 卯 4027 | 辄 4028 | 皲 4029 | 卟 4030 | 醛 4031 | 畹 4032 | 忧 4033 | 稳 4034 | 雄 4035 | 昼 4036 | 缩 4037 | 阈 4038 | 睑 4039 | 扌 4040 | 耗 4041 | 曦 4042 | 涅 4043 | 捏 4044 | 瞧 4045 | 邕 4046 | 淖 4047 | 漉 4048 | 铝 4049 | 耦 4050 | 禹 4051 | 湛 4052 | 喽 4053 | 莼 4054 | 琅 4055 | 诸 4056 | 苎 4057 | 纂 4058 | 硅 4059 | 始 4060 | 嗨 4061 | 傥 4062 | 燃 4063 | 臂 4064 | 赅 4065 | 嘈 4066 | 呆 4067 | 贵 4068 | 屹 4069 | 壮 4070 | 肋 4071 | 亍 4072 | 蚀 4073 | 卅 4074 | 豹 4075 | 腆 4076 | 邬 4077 | 迭 4078 | 浊 4079 | } 4080 | 童 4081 | 螂 4082 | 捐 4083 | 圩 4084 | 勐 4085 | 触 4086 | 寞 4087 | 汊 4088 | 壤 4089 | 荫 4090 | 膺 4091 | 渌 4092 | 芳 4093 | 懿 4094 | 遴 4095 | 螈 4096 | 泰 4097 | 蓼 4098 | 蛤 4099 | 茜 4100 | 舅 4101 | 枫 4102 | 朔 4103 | 膝 4104 | 眙 4105 | 避 4106 | 梅 4107 | 判 4108 | 鹜 4109 | 璜 4110 | 牍 4111 | 缅 4112 | 垫 4113 | 藻 4114 | 黔 4115 | 侥 4116 | 惚 4117 | 懂 4118 | 踩 4119 | 腰 4120 | 腈 4121 | 札 4122 | 丞 4123 | 唾 4124 | 慈 4125 | 顿 4126 | 摹 4127 | 荻 4128 | 琬 4129 | ~ 4130 | 斧 4131 | 沈 4132 | 滂 4133 | 胁 4134 | 胀 4135 | 幄 4136 | 莜 4137 | Z 4138 | 匀 4139 | 鄄 4140 | 掌 4141 | 绰 4142 | 茎 4143 | 焚 4144 | 赋 4145 | 萱 4146 | 谑 4147 | 汁 4148 | 铒 4149 | 瞎 4150 | 夺 4151 | 蜗 4152 | 野 4153 | 娆 4154 | 冀 4155 | 弯 4156 | 篁 4157 | 懵 4158 | 灞 4159 | 隽 4160 | 芡 4161 | 脘 4162 | 俐 4163 | 辩 4164 | 芯 4165 | 掺 4166 | 喏 4167 | 膈 4168 | 蝈 4169 | 觐 4170 | 悚 4171 | 踹 4172 | 蔗 4173 | 熠 4174 | 鼠 4175 | 呵 4176 | 抓 4177 | 橼 4178 | 峨 4179 | 畜 4180 | 缔 4181 | 禾 4182 | 崭 4183 | 弃 4184 | 熊 4185 | 摒 4186 | 凸 4187 | 拗 4188 | 穹 4189 | 蒙 4190 | 抒 4191 | 祛 4192 | 劝 4193 | 闫 4194 | 扳 4195 | 阵 4196 | 醌 4197 | 踪 4198 | 喵 4199 | 侣 4200 | 搬 4201 | 仅 4202 | 荧 4203 | 赎 4204 | 蝾 4205 | 琦 4206 | 买 4207 | 婧 4208 | 瞄 4209 | 寓 4210 | 皎 4211 | 冻 4212 | 赝 4213 | 箩 4214 | 莫 4215 | 瞰 4216 | 郊 4217 | 笫 4218 | 姝 4219 | 筒 4220 | 枪 4221 | 遣 4222 | 煸 4223 | 袋 4224 | 舆 4225 | 痱 4226 | 涛 4227 | 母 4228 | 〇 4229 | 启 4230 | 践 4231 | 耙 4232 | 绲 4233 | 盘 4234 | 遂 4235 | 昊 4236 | 搞 4237 | 槿 4238 | 诬 4239 | 纰 4240 | 泓 4241 | 惨 4242 | 檬 4243 | 亻 4244 | 越 4245 | C 4246 | o 4247 | 憩 4248 | 熵 4249 | 祷 4250 | 钒 4251 | 暧 4252 | 塔 4253 | 阗 4254 | 胰 4255 | 咄 4256 | 娶 4257 | 魔 4258 | 琶 4259 | 钞 4260 | 邻 4261 | 扬 4262 | 杉 4263 | 殴 4264 | 咽 4265 | 弓 4266 | 〆 4267 | 髻 4268 | 】 4269 | 吭 4270 | 揽 4271 | 霆 4272 | 拄 4273 | 殖 4274 | 脆 4275 | 彻 4276 | 岩 4277 | 芝 4278 | 勃 4279 | 辣 4280 | 剌 4281 | 钝 4282 | 嘎 4283 | 甄 4284 | 佘 4285 | 皖 4286 | 伦 4287 | 授 4288 | 徕 4289 | 憔 4290 | 挪 4291 | 皇 4292 | 庞 4293 | 稔 4294 | 芜 4295 | 踏 4296 | 溴 4297 | 兖 4298 | 卒 4299 | 擢 4300 | 饥 4301 | 鳞 4302 | 煲 4303 | ‰ 4304 | 账 4305 | 颗 4306 | 叻 4307 | 斯 4308 | 捧 4309 | 鳍 4310 | 琮 4311 | 讹 4312 | 蛙 4313 | 纽 4314 | 谭 4315 | 酸 4316 | 兔 4317 | 莒 4318 | 睇 4319 | 伟 4320 | 觑 4321 | 羲 4322 | 嗜 4323 | 宜 4324 | 褐 4325 | 旎 4326 | 辛 4327 | 卦 4328 | 诘 4329 | 筋 4330 | 鎏 4331 | 溪 4332 | 挛 4333 | 熔 4334 | 阜 4335 | 晰 4336 | 鳅 4337 | 丢 4338 | 奚 4339 | 灸 4340 | 呱 4341 | 献 4342 | 陉 4343 | 黛 4344 | 鸪 4345 | 甾 4346 | 萨 4347 | 疮 4348 | 拯 4349 | 洲 4350 | 疹 4351 | 辑 4352 | 叙 4353 | 恻 4354 | 谒 4355 | 允 4356 | 柔 4357 | 烂 4358 | 氏 4359 | 逅 4360 | 漆 4361 | 拎 4362 | 惋 4363 | 扈 4364 | 湟 4365 | 纭 4366 | 啕 4367 | 掬 4368 | 擞 4369 | 哥 4370 | 忽 4371 | 涤 4372 | 鸵 4373 | 靡 4374 | 郗 4375 | 瓷 4376 | 扁 4377 | 廊 4378 | 怨 4379 | 雏 4380 | 钮 4381 | 敦 4382 | E 4383 | 懦 4384 | 憋 4385 | 汀 4386 | 拚 4387 | 啉 4388 | 腌 4389 | 岸 4390 | f 4391 | 痼 4392 | 瞅 4393 | 尊 4394 | 咀 4395 | 眩 4396 | 飙 4397 | 忌 4398 | 仝 4399 | 迦 4400 | 熬 4401 | 毫 4402 | 胯 4403 | 篑 4404 | 茄 4405 | 腺 4406 | 凄 4407 | 舛 4408 | 碴 4409 | 锵 4410 | 诧 4411 | 羯 4412 | 後 4413 | 漏 4414 | 汤 4415 | 宓 4416 | 仞 4417 | 蚁 4418 | 壶 4419 | 谰 4420 | 皑 4421 | 铄 4422 | 棰 4423 | 罔 4424 | 辅 4425 | 晶 4426 | 苦 4427 | 牟 4428 | 闽 4429 | \ 4430 | 烃 4431 | 饮 4432 | 聿 4433 | 丙 4434 | 蛳 4435 | 朱 4436 | 煤 4437 | 涔 4438 | 鳖 4439 | 犁 4440 | 罐 4441 | 荼 4442 | 砒 4443 | 淦 4444 | 妤 4445 | 黏 4446 | 戎 4447 | 孑 4448 | 婕 4449 | 瑾 4450 | 戢 4451 | 钵 4452 | 枣 4453 | 捋 4454 | 砥 4455 | 衩 4456 | 狙 4457 | 桠 4458 | 稣 4459 | 阎 4460 | 肃 4461 | 梏 4462 | 诫 4463 | 孪 4464 | 昶 4465 | 婊 4466 | 衫 4467 | 嗔 4468 | 侃 4469 | 塞 4470 | 蜃 4471 | 樵 4472 | 峒 4473 | 貌 4474 | 屿 4475 | 欺 4476 | 缫 4477 | 阐 4478 | 栖 4479 | 诟 4480 | 珞 4481 | 荭 4482 | 吝 4483 | 萍 4484 | 嗽 4485 | 恂 4486 | 啻 4487 | 蜴 4488 | 磬 4489 | 峋 4490 | 俸 4491 | 豫 4492 | 谎 4493 | 徊 4494 | 镍 4495 | 韬 4496 | 魇 4497 | 晴 4498 | U 4499 | 囟 4500 | 猜 4501 | 蛮 4502 | 坐 4503 | 囿 4504 | 伴 4505 | 亭 4506 | 肝 4507 | 佗 4508 | 蝠 4509 | 妃 4510 | 胞 4511 | 滩 4512 | 榴 4513 | 氖 4514 | 垩 4515 | 苋 4516 | 砣 4517 | 扪 4518 | 馏 4519 | 姓 4520 | 轩 4521 | 厉 4522 | 夥 4523 | 侈 4524 | 禀 4525 | 垒 4526 | 岑 4527 | 赏 4528 | 钛 4529 | 辐 4530 | 痔 4531 | 披 4532 | 纸 4533 | 碳 4534 | “ 4535 | 坞 4536 | 蠓 4537 | 挤 4538 | 荥 4539 | 沅 4540 | 悔 4541 | 铧 4542 | 帼 4543 | 蒌 4544 | 蝇 4545 | a 4546 | p 4547 | y 4548 | n 4549 | g 4550 | 哀 4551 | 浆 4552 | 瑶 4553 | 凿 4554 | 桶 4555 | 馈 4556 | 皮 4557 | 奴 4558 | 苜 4559 | 佤 4560 | 伶 4561 | 晗 4562 | 铱 4563 | 炬 4564 | 优 4565 | 弊 4566 | 氢 4567 | 恃 4568 | 甫 4569 | 攥 4570 | 端 4571 | 锌 4572 | 灰 4573 | 稹 4574 | 炝 4575 | 曙 4576 | 邋 4577 | 亥 4578 | 眶 4579 | 碾 4580 | 拉 4581 | 萝 4582 | 绔 4583 | 捷 4584 | 浍 4585 | 腋 4586 | 姑 4587 | 菖 4588 | 凌 4589 | 涞 4590 | 麽 4591 | 锢 4592 | 桨 4593 | 潢 4594 | 绎 4595 | 镰 4596 | 殆 4597 | 锑 4598 | 渝 4599 | 铬 4600 | 困 4601 | 绽 4602 | 觎 4603 | 匈 4604 | 糙 4605 | 暑 4606 | 裹 4607 | 鸟 4608 | 盔 4609 | 肽 4610 | 迷 4611 | 綦 4612 | 『 4613 | 亳 4614 | 佝 4615 | 俘 4616 | 钴 4617 | 觇 4618 | 骥 4619 | 仆 4620 | 疝 4621 | 跪 4622 | 婶 4623 | 郯 4624 | 瀹 4625 | 唉 4626 | 脖 4627 | 踞 4628 | 针 4629 | 晾 4630 | 忒 4631 | 扼 4632 | 瞩 4633 | 叛 4634 | 椒 4635 | 疟 4636 | 嗡 4637 | 邗 4638 | 肆 4639 | 跆 4640 | 玫 4641 | 忡 4642 | 捣 4643 | 咧 4644 | 唆 4645 | 艄 4646 | 蘑 4647 | 潦 4648 | 笛 4649 | 阚 4650 | 沸 4651 | 泻 4652 | 掊 4653 | 菽 4654 | 贫 4655 | 斥 4656 | 髂 4657 | 孢 4658 | 镂 4659 | 赂 4660 | 麝 4661 | 鸾 4662 | 屡 4663 | 衬 4664 | 苷 4665 | 恪 4666 | 叠 4667 | 希 4668 | 粤 4669 | 爻 4670 | 喝 4671 | 茫 4672 | 惬 4673 | 郸 4674 | 绻 4675 | 庸 4676 | 撅 4677 | 碟 4678 | 宄 4679 | 妹 4680 | 膛 4681 | 叮 4682 | 饵 4683 | 崛 4684 | 嗲 4685 | 椅 4686 | 冤 4687 | 搅 4688 | 咕 4689 | 敛 4690 | 尹 4691 | 垦 4692 | 闷 4693 | 蝉 4694 | 霎 4695 | 勰 4696 | 败 4697 | 蓑 4698 | 泸 4699 | 肤 4700 | 鹌 4701 | 幌 4702 | 焦 4703 | 浠 4704 | 鞍 4705 | 刁 4706 | 舰 4707 | 乙 4708 | 竿 4709 | 裔 4710 | 。 4711 | 茵 4712 | 函 4713 | 伊 4714 | 兄 4715 | 丨 4716 | 娜 4717 | 匍 4718 | 謇 4719 | 莪 4720 | 宥 4721 | 似 4722 | 蝽 4723 | 翳 4724 | 酪 4725 | 翠 4726 | 粑 4727 | 薇 4728 | 祢 4729 | 骏 4730 | 赠 4731 | 叫 4732 | Q 4733 | 噤 4734 | 噻 4735 | 竖 4736 | 芗 4737 | 莠 4738 | 潭 4739 | 俊 4740 | 羿 4741 | 耜 4742 | O 4743 | 郫 4744 | 趁 4745 | 嗪 4746 | 囚 4747 | 蹶 4748 | 芒 4749 | 洁 4750 | 笋 4751 | 鹑 4752 | 敲 4753 | 硝 4754 | 啶 4755 | 堡 4756 | 渲 4757 | 揩 4758 | 』 4759 | 携 4760 | 宿 4761 | 遒 4762 | 颍 4763 | 扭 4764 | 棱 4765 | 割 4766 | 萜 4767 | 蔸 4768 | 葵 4769 | 琴 4770 | 捂 4771 | 饰 4772 | 衙 4773 | 耿 4774 | 掠 4775 | 募 4776 | 岂 4777 | 窖 4778 | 涟 4779 | 蔺 4780 | 瘤 4781 | 柞 4782 | 瞪 4783 | 怜 4784 | 匹 4785 | 距 4786 | 楔 4787 | 炜 4788 | 哆 4789 | 秦 4790 | 缎 4791 | 幼 4792 | 茁 4793 | 绪 4794 | 痨 4795 | 恨 4796 | 楸 4797 | 娅 4798 | 瓦 4799 | 桩 4800 | 雪 4801 | 嬴 4802 | 伏 4803 | 榔 4804 | 妥 4805 | 铿 4806 | 拌 4807 | 眠 4808 | 雍 4809 | 缇 4810 | ‘ 4811 | 卓 4812 | 搓 4813 | 哌 4814 | 觞 4815 | 噩 4816 | 屈 4817 | 哧 4818 | 髓 4819 | 咦 4820 | 巅 4821 | 娑 4822 | 侑 4823 | 淫 4824 | 膳 4825 | 祝 4826 | 勾 4827 | 姊 4828 | 莴 4829 | 胄 4830 | 疃 4831 | 薛 4832 | 蜷 4833 | 胛 4834 | 巷 4835 | 芙 4836 | 芋 4837 | 熙 4838 | 闰 4839 | 勿 4840 | 窃 4841 | 狱 4842 | 剩 4843 | 钏 4844 | 幢 4845 | 陟 4846 | 铛 4847 | 慧 4848 | 靴 4849 | 耍 4850 | k 4851 | 浙 4852 | 浇 4853 | 飨 4854 | 惟 4855 | 绗 4856 | 祜 4857 | 澈 4858 | 啼 4859 | 咪 4860 | 磷 4861 | 摞 4862 | 诅 4863 | 郦 4864 | 抹 4865 | 跃 4866 | 壬 4867 | 吕 4868 | 肖 4869 | 琏 4870 | 颤 4871 | 尴 4872 | 剡 4873 | 抠 4874 | 凋 4875 | 赚 4876 | 泊 4877 | 津 4878 | 宕 4879 | 殷 4880 | 倔 4881 | 氲 4882 | 漫 4883 | 邺 4884 | 涎 4885 | 怠 4886 | $ 4887 | 垮 4888 | 荬 4889 | 遵 4890 | 俏 4891 | 叹 4892 | 噢 4893 | 饽 4894 | 蜘 4895 | 孙 4896 | 筵 4897 | 疼 4898 | 鞭 4899 | 羧 4900 | 牦 4901 | 箭 4902 | 潴 4903 | c 4904 | 眸 4905 | 祭 4906 | 髯 4907 | 啖 4908 | 坳 4909 | 愁 4910 | 芩 4911 | 驮 4912 | 倡 4913 | 巽 4914 | 穰 4915 | 沃 4916 | 胚 4917 | 怒 4918 | 凤 4919 | 槛 4920 | 剂 4921 | 趵 4922 | 嫁 4923 | v 4924 | 邢 4925 | 灯 4926 | 鄢 4927 | 桐 4928 | 睽 4929 | 檗 4930 | 锯 4931 | 槟 4932 | 婷 4933 | 嵋 4934 | 圻 4935 | 诗 4936 | 蕈 4937 | 颠 4938 | 遭 4939 | 痢 4940 | 芸 4941 | 怯 4942 | 馥 4943 | 竭 4944 | 锗 4945 | 徜 4946 | 恭 4947 | 遍 4948 | 籁 4949 | 剑 4950 | 嘱 4951 | 苡 4952 | 龄 4953 | 僧 4954 | 桑 4955 | 潸 4956 | 弘 4957 | 澶 4958 | 楹 4959 | 悲 4960 | 讫 4961 | 愤 4962 | 腥 4963 | 悸 4964 | 谍 4965 | 椹 4966 | 呢 4967 | 桓 4968 | 葭 4969 | 攫 4970 | 阀 4971 | 翰 4972 | 躲 4973 | 敖 4974 | 柑 4975 | 郎 4976 | 笨 4977 | 橇 4978 | 呃 4979 | 魁 4980 | 燎 4981 | 脓 4982 | 葩 4983 | 磋 4984 | 垛 4985 | 玺 4986 | 狮 4987 | 沓 4988 | 砜 4989 | 蕊 4990 | 锺 4991 | 罹 4992 | 蕉 4993 | 翱 4994 | 虐 4995 | 闾 4996 | 巫 4997 | 旦 4998 | 茱 4999 | 嬷 5000 | 枯 5001 | 鹏 5002 | 贡 5003 | 芹 5004 | 汛 5005 | 矫 5006 | 绁 5007 | 拣 5008 | 禺 5009 | 佃 5010 | 讣 5011 | 舫 5012 | 惯 5013 | 乳 5014 | 趋 5015 | 疲 5016 | 挽 5017 | 岚 5018 | 虾 5019 | 衾 5020 | 蠹 5021 | 蹂 5022 | 飓 5023 | 氦 5024 | 铖 5025 | 孩 5026 | 稞 5027 | 瑜 5028 | 壅 5029 | 掀 5030 | 勘 5031 | 妓 5032 | 畅 5033 | 髋 5034 | W 5035 | 庐 5036 | 牲 5037 | 蓿 5038 | 榕 5039 | 练 5040 | 垣 5041 | 唱 5042 | 邸 5043 | 菲 5044 | 昆 5045 | 婺 5046 | 穿 5047 | 绡 5048 | 麒 5049 | 蚱 5050 | 掂 5051 | 愚 5052 | 泷 5053 | 涪 5054 | 漳 5055 | 妩 5056 | 娉 5057 | 榄 5058 | 讷 5059 | 觅 5060 | 旧 5061 | 藤 5062 | 煮 5063 | 呛 5064 | 柳 5065 | 腓 5066 | 叭 5067 | 庵 5068 | 烷 5069 | 阡 5070 | 罂 5071 | 蜕 5072 | 擂 5073 | 猖 5074 | 咿 5075 | 媲 5076 | 脉 5077 | 【 5078 | 沏 5079 | 貅 5080 | 黠 5081 | 熏 5082 | 哲 5083 | 烁 5084 | 坦 5085 | 酵 5086 | 兜 5087 | × 5088 | 潇 5089 | 撒 5090 | 剽 5091 | 珩 5092 | 圹 5093 | 乾 5094 | 摸 5095 | 樟 5096 | 帽 5097 | 嗒 5098 | 襄 5099 | 魂 5100 | 轿 5101 | 憬 5102 | 锡 5103 | 〕 5104 | 喃 5105 | 皆 5106 | 咖 5107 | 隅 5108 | 脸 5109 | 残 5110 | 泮 5111 | 袂 5112 | 鹂 5113 | 珊 5114 | 囤 5115 | 捆 5116 | 咤 5117 | 误 5118 | 徨 5119 | 闹 5120 | 淙 5121 | 芊 5122 | 淋 5123 | 怆 5124 | 囗 5125 | 拨 5126 | 梳 5127 | 渤 5128 | R 5129 | G 5130 | 绨 5131 | 蚓 5132 | 婀 5133 | 幡 5134 | 狩 5135 | 麾 5136 | 谢 5137 | 唢 5138 | 裸 5139 | 旌 5140 | 伉 5141 | 纶 5142 | 裂 5143 | 驳 5144 | 砼 5145 | 咛 5146 | 澄 5147 | 樨 5148 | 蹈 5149 | 宙 5150 | 澍 5151 | 倍 5152 | 貔 5153 | 操 5154 | 勇 5155 | 蟠 5156 | 摈 5157 | 砧 5158 | 虬 5159 | 够 5160 | 缁 5161 | 悦 5162 | 藿 5163 | 撸 5164 | 艹 5165 | 摁 5166 | 淹 5167 | 豇 5168 | 虎 5169 | 榭 5170 | ˉ 5171 | 吱 5172 | d 5173 | ° 5174 | 喧 5175 | 荀 5176 | 踱 5177 | 侮 5178 | 奋 5179 | 偕 5180 | 饷 5181 | 犍 5182 | 惮 5183 | 坑 5184 | 璎 5185 | 徘 5186 | 宛 5187 | 妆 5188 | 袈 5189 | 倩 5190 | 窦 5191 | 昂 5192 | 荏 5193 | 乖 5194 | K 5195 | 怅 5196 | 撰 5197 | 鳙 5198 | 牙 5199 | 袁 5200 | 酞 5201 | X 5202 | 痿 5203 | 琼 5204 | 闸 5205 | 雁 5206 | 趾 5207 | 荚 5208 | 虻 5209 | 涝 5210 | 《 5211 | 杏 5212 | 韭 5213 | 偈 5214 | 烤 5215 | 绫 5216 | 鞘 5217 | 卉 5218 | 症 5219 | 遢 5220 | 蓥 5221 | 诋 5222 | 杭 5223 | 荨 5224 | 匆 5225 | 竣 5226 | 簪 5227 | 辙 5228 | 敕 5229 | 虞 5230 | 丹 5231 | 缭 5232 | 咩 5233 | 黟 5234 | m 5235 | 淤 5236 | 瑕 5237 | 咂 5238 | 铉 5239 | 硼 5240 | 茨 5241 | 嶂 5242 | 痒 5243 | 畸 5244 | 敬 5245 | 涿 5246 | 粪 5247 | 窘 5248 | 熟 5249 | 叔 5250 | 嫔 5251 | 盾 5252 | 忱 5253 | 裘 5254 | 憾 5255 | 梵 5256 | 赡 5257 | 珙 5258 | 咯 5259 | 娘 5260 | 庙 5261 | 溯 5262 | 胺 5263 | 葱 5264 | 痪 5265 | 摊 5266 | 荷 5267 | 卞 5268 | 乒 5269 | 髦 5270 | 寐 5271 | 铭 5272 | 坩 5273 | 胗 5274 | 枷 5275 | 爆 5276 | 溟 5277 | 嚼 5278 | 羚 5279 | 砬 5280 | 轨 5281 | 惊 5282 | 挠 5283 | 罄 5284 | 竽 5285 | 菏 5286 | 氧 5287 | 浅 5288 | 楣 5289 | 盼 5290 | 枢 5291 | 炸 5292 | 阆 5293 | 杯 5294 | 谏 5295 | 噬 5296 | 淇 5297 | 渺 5298 | 俪 5299 | 秆 5300 | 墓 5301 | 泪 5302 | 跻 5303 | 砌 5304 | 痰 5305 | 垡 5306 | 渡 5307 | 耽 5308 | 釜 5309 | 讶 5310 | 鳎 5311 | 煞 5312 | 呗 5313 | 韶 5314 | 舶 5315 | 绷 5316 | 鹳 5317 | 缜 5318 | 旷 5319 | 铊 5320 | 皱 5321 | 龌 5322 | 檀 5323 | 霖 5324 | 奄 5325 | 槐 5326 | 艳 5327 | 蝶 5328 | 旋 5329 | 哝 5330 | 赶 5331 | 骞 5332 | 蚧 5333 | 腊 5334 | 盈 5335 | 丁 5336 | ` 5337 | 蜚 5338 | 矸 5339 | 蝙 5340 | 睨 5341 | 嚓 5342 | 僻 5343 | 鬼 5344 | 醴 5345 | 夜 5346 | 彝 5347 | 磊 5348 | 笔 5349 | 拔 5350 | 栀 5351 | 糕 5352 | 厦 5353 | 邰 5354 | 纫 5355 | 逭 5356 | 纤 5357 | 眦 5358 | 膊 5359 | 馍 5360 | 躇 5361 | 烯 5362 | 蘼 5363 | 冬 5364 | 诤 5365 | 暄 5366 | 骶 5367 | 哑 5368 | 瘠 5369 | 」 5370 | 臊 5371 | 丕 5372 | 愈 5373 | 咱 5374 | 螺 5375 | 擅 5376 | 跋 5377 | 搏 5378 | 硪 5379 | 谄 5380 | 笠 5381 | 淡 5382 | 嘿 5383 | 骅 5384 | 谧 5385 | 鼎 5386 | 皋 5387 | 姚 5388 | 歼 5389 | 蠢 5390 | 驼 5391 | 耳 5392 | 胬 5393 | 挝 5394 | 涯 5395 | 狗 5396 | 蒽 5397 | 孓 5398 | 犷 5399 | 凉 5400 | 芦 5401 | 箴 5402 | 铤 5403 | 孤 5404 | 嘛 5405 | 坤 5406 | V 5407 | 茴 5408 | 朦 5409 | 挞 5410 | 尖 5411 | 橙 5412 | 诞 5413 | 搴 5414 | 碇 5415 | 洵 5416 | 浚 5417 | 帚 5418 | 蜍 5419 | 漯 5420 | 柘 5421 | 嚎 5422 | 讽 5423 | 芭 5424 | 荤 5425 | 咻 5426 | 祠 5427 | 秉 5428 | 跖 5429 | 埃 5430 | 吓 5431 | 糯 5432 | 眷 5433 | 馒 5434 | 惹 5435 | 娼 5436 | 鲑 5437 | 嫩 5438 | 讴 5439 | 轮 5440 | 瞥 5441 | 靶 5442 | 褚 5443 | 乏 5444 | 缤 5445 | 宋 5446 | 帧 5447 | 删 5448 | 驱 5449 | 碎 5450 | 扑 5451 | 俩 5452 | 俄 5453 | 偏 5454 | 涣 5455 | 竹 5456 | 噱 5457 | 皙 5458 | 佰 5459 | 渚 5460 | 唧 5461 | 斡 5462 | # 5463 | 镉 5464 | 刀 5465 | 崎 5466 | 筐 5467 | 佣 5468 | 夭 5469 | 贰 5470 | 肴 5471 | 峙 5472 | 哔 5473 | 艿 5474 | 匐 5475 | 牺 5476 | 镛 5477 | 缘 5478 | 仡 5479 | 嫡 5480 | 劣 5481 | 枸 5482 | 堀 5483 | 梨 5484 | 簿 5485 | 鸭 5486 | 蒸 5487 | 亦 5488 | 稽 5489 | 浴 5490 | { 5491 | 衢 5492 | 束 5493 | 槲 5494 | j 5495 | 阁 5496 | 揍 5497 | 疥 5498 | 棋 5499 | 潋 5500 | 聪 5501 | 窜 5502 | 乓 5503 | 睛 5504 | 插 5505 | 冉 5506 | 阪 5507 | 苍 5508 | 搽 5509 | 「 5510 | 蟾 5511 | 螟 5512 | 幸 5513 | 仇 5514 | 樽 5515 | 撂 5516 | 慢 5517 | 跤 5518 | 幔 5519 | 俚 5520 | 淅 5521 | 覃 5522 | 觊 5523 | 溶 5524 | 妖 5525 | 帛 5526 | 侨 5527 | 曰 5528 | 妾 5529 | 泗 5530 | 5531 | · 5532 | -------------------------------------------------------------------------------- /run-benchmark.bat: -------------------------------------------------------------------------------- 1 | chcp 65001 2 | :: Set Param 3 | @ECHO OFF 4 | @SETLOCAL 5 | echo "Setting the Number of Threads=%NUMBER_OF_PROCESSORS% Using an OpenMP Environment Variable" 6 | set OMP_NUM_THREADS=%NUMBER_OF_PROCESSORS% 7 | 8 | echo "请输入循环次数:" 9 | set /p LOOP_COUNT= 10 | 11 | SET TARGET_IMG=./images/1.jpg 12 | if not exist %TARGET_IMG% ( 13 | echo "找不到待识别的目标图片:%TARGET_IMG%,请打开本文件并编辑TARGET_IMG" 14 | PAUSE 15 | exit 16 | ) 17 | 18 | :: run Windows 19 | build\benchmark.exe --version 20 | build\benchmark.exe --models models ^ 21 | --det dbnet.mnn ^ 22 | --cls angle_net.mnn ^ 23 | --rec crnn_lite_lstm.mnn ^ 24 | --keys keys.txt ^ 25 | --image %TARGET_IMG% ^ 26 | --numThread %NUMBER_OF_PROCESSORS% ^ 27 | --padding 50 ^ 28 | --maxSideLen 1024 ^ 29 | --boxScoreThresh 0.6 ^ 30 | --boxThresh 0.3 ^ 31 | --unClipRatio 2.0 ^ 32 | --doAngle 1 ^ 33 | --mostAngle 1 ^ 34 | --loopCount %LOOP_COUNT% 35 | PAUSE 36 | @ENDLOCAL 37 | -------------------------------------------------------------------------------- /run-benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sysOS=`uname -s` 4 | NUM_THREADS=1 5 | if [ $sysOS == "Darwin" ];then 6 | #echo "I'm MacOS" 7 | NUM_THREADS=$(sysctl -n hw.ncpu) 8 | elif [ $sysOS == "Linux" ];then 9 | #echo "I'm Linux" 10 | NUM_THREADS=$(grep ^processor /proc/cpuinfo | wc -l) 11 | else 12 | echo "Other OS: $sysOS" 13 | fi 14 | 15 | echo "Setting the Number of Threads=$NUM_THREADS Using an OpenMP Environment Variable" 16 | set OMP_NUM_THREADS=$NUM_THREADS 17 | 18 | echo "请输入循环次数:" 19 | read -p "" LOOP_COUNT 20 | 21 | TARGET_IMG=./images/1.jpg 22 | if [ ! -f "$TARGET_IMG" ]; then 23 | echo "找不到待识别的目标图片:${TARGET_IMG},请打开本文件并编辑TARGET_IMG" 24 | exit 25 | fi 26 | 27 | ##### run test on MacOS or Linux 28 | ./build/benchmark --version 29 | ./build/benchmark --models models \ 30 | --det dbnet.mnn \ 31 | --cls angle_net.mnn \ 32 | --rec crnn_lite_lstm.mnn \ 33 | --keys keys.txt \ 34 | --image $TARGET_IMG \ 35 | --numThread $NUM_THREADS \ 36 | --padding 50 \ 37 | --maxSideLen 1024 \ 38 | --boxScoreThresh 0.6 \ 39 | --boxThresh 0.3 \ 40 | --unClipRatio 2.0 \ 41 | --doAngle 1 \ 42 | --mostAngle 1 \ 43 | --loopCount $LOOP_COUNT -------------------------------------------------------------------------------- /run-test.bat: -------------------------------------------------------------------------------- 1 | chcp 65001 2 | :: Set Param 3 | @ECHO OFF 4 | @SETLOCAL 5 | echo "Setting the Number of Threads=%NUMBER_OF_PROCESSORS% Using an OpenMP Environment Variable" 6 | set OMP_NUM_THREADS=%NUMBER_OF_PROCESSORS% 7 | 8 | SET TARGET_IMG=./images/1.jpg 9 | if not exist %TARGET_IMG% ( 10 | echo "找不到待识别的目标图片:%TARGET_IMG%,请打开本文件并编辑TARGET_IMG" 11 | PAUSE 12 | exit 13 | ) 14 | 15 | :: run Windows 16 | build\OcrLiteMnn.exe --version 17 | build\OcrLiteMnn.exe --models models ^ 18 | --det dbnet.mnn ^ 19 | --cls angle_net.mnn ^ 20 | --rec crnn_lite_lstm.mnn ^ 21 | --keys keys.txt ^ 22 | --image %TARGET_IMG% ^ 23 | --numThread %NUMBER_OF_PROCESSORS% ^ 24 | --padding 50 ^ 25 | --maxSideLen 1024 ^ 26 | --boxScoreThresh 0.6 ^ 27 | --boxThresh 0.3 ^ 28 | --unClipRatio 2.0 ^ 29 | --doAngle 1 ^ 30 | --mostAngle 1 31 | PAUSE 32 | @ENDLOCAL 33 | -------------------------------------------------------------------------------- /run-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sysOS=`uname -s` 4 | NUM_THREADS=1 5 | if [ $sysOS == "Darwin" ];then 6 | #echo "I'm MacOS" 7 | NUM_THREADS=$(sysctl -n hw.ncpu) 8 | elif [ $sysOS == "Linux" ];then 9 | #echo "I'm Linux" 10 | NUM_THREADS=$(grep ^processor /proc/cpuinfo | wc -l) 11 | else 12 | echo "Other OS: $sysOS" 13 | fi 14 | 15 | TARGET_IMG=./images/1.jpg 16 | if [ ! -f "$TARGET_IMG" ]; then 17 | echo "找不到待识别的目标图片:${TARGET_IMG},请打开本文件并编辑TARGET_IMG" 18 | exit 19 | fi 20 | 21 | ##### run test on MacOS or Linux 22 | ./build/OcrLiteMnn --version 23 | ./build/OcrLiteMnn --models models \ 24 | --det dbnet.mnn \ 25 | --cls angle_net.mnn \ 26 | --rec crnn_lite_lstm.mnn \ 27 | --keys keys.txt \ 28 | --image $TARGET_IMG \ 29 | --numThread $NUM_THREADS \ 30 | --padding 50 \ 31 | --maxSideLen 1024 \ 32 | --boxScoreThresh 0.6 \ 33 | --boxThresh 0.3 \ 34 | --unClipRatio 2.0 \ 35 | --doAngle 1 \ 36 | --mostAngle 1 -------------------------------------------------------------------------------- /src/AngleNet.cpp: -------------------------------------------------------------------------------- 1 | #include "AngleNet.h" 2 | #include "OcrUtils.h" 3 | #include 4 | #include 5 | #include 6 | 7 | AngleNet::AngleNet() {} 8 | 9 | AngleNet::~AngleNet() { 10 | } 11 | 12 | void AngleNet::setNumThread(int numOfThread) { 13 | numThread = numOfThread; 14 | //===session options=== 15 | // Sets the number of threads used to parallelize the execution within nodes 16 | // A value of 0 means ORT will pick a default 17 | //sessionOptions.SetIntraOpNumThreads(numThread); 18 | //set OMP_NUM_THREADS=16 19 | } 20 | 21 | void AngleNet::initModel(const std::string &pathStr) { 22 | 23 | net.reset(MNN::Interpreter::createFromFile(pathStr.c_str())); 24 | MNN::ScheduleConfig config; 25 | config.type = MNN_FORWARD_CPU; 26 | config.numThread = numThread; 27 | session = net->createSession(config); 28 | } 29 | 30 | Angle scoreToAngle(const std::vector &outputData) { 31 | int maxIndex = 0; 32 | float maxScore = -1000.0f; 33 | for (int i = 0; i < outputData.size(); i++) { 34 | if (i == 0)maxScore = outputData[i]; 35 | else if (outputData[i] > maxScore) { 36 | maxScore = outputData[i]; 37 | maxIndex = i; 38 | } 39 | } 40 | return {maxIndex, maxScore}; 41 | } 42 | 43 | Angle AngleNet::getAngle(cv::Mat &src) { 44 | std::vector inputTensorValues = substractMeanNormalize(src, meanValues, normValues); 45 | std::vectorinputShape = {1, src.channels(), src.rows, src.cols}; 46 | auto input = net->getSessionInput(session, NULL); 47 | auto output = net->getSessionOutput(session, NULL); 48 | auto shape = input->shape(); 49 | shape[0] = 1; 50 | shape[2] = src.rows; 51 | shape[3] = src.cols; 52 | net->resizeTensor(input, shape); 53 | net->resizeSession(session); 54 | auto nchwTensor = MNN::Tensor::create(inputShape,halide_type_of(),&inputTensorValues[0],MNN::Tensor::CAFFE); 55 | input->copyFromHostTensor(nchwTensor); 56 | delete nchwTensor; 57 | net->runSession(session); 58 | 59 | std::shared_ptr outputUser(new MNN::Tensor(output, output->getDimensionType())); //nchw 60 | output->copyToHostTensor(outputUser.get()); 61 | auto values = outputUser->host(); 62 | int size = outputUser->elementSize(); 63 | 64 | std::vector outputData(values, values + size); 65 | return scoreToAngle(outputData); 66 | } 67 | 68 | std::vector AngleNet::getAngles(std::vector &partImgs, const char *path, 69 | const char *imgName, bool doAngle, bool mostAngle) { 70 | int size = partImgs.size(); 71 | std::vector angles(size); 72 | if (doAngle) { 73 | for (int i = 0; i < size; ++i) { 74 | double startAngle = getCurrentTime(); 75 | auto angleImg = adjustTargetImg(partImgs[i], dstWidth, dstHeight); 76 | Angle angle = getAngle(angleImg); 77 | double endAngle = getCurrentTime(); 78 | angle.time = endAngle - startAngle; 79 | 80 | angles[i] = angle; 81 | 82 | //OutPut AngleImg 83 | if (isOutputAngleImg) { 84 | std::string angleImgFile = getDebugImgFilePath(path, imgName, i, "-angle-"); 85 | saveImg(angleImg, angleImgFile.c_str()); 86 | } 87 | } 88 | } else { 89 | for (int i = 0; i < size; ++i) { 90 | angles[i] = Angle{-1, 0.f}; 91 | } 92 | } 93 | //Most Possible AngleIndex 94 | if (doAngle && mostAngle) { 95 | auto angleIndexes = getAngleIndexes(angles); 96 | double sum = std::accumulate(angleIndexes.begin(), angleIndexes.end(), 0.0); 97 | double halfPercent = angles.size() / 2.0f; 98 | int mostAngleIndex; 99 | if (sum < halfPercent) {//all angle set to 0 100 | mostAngleIndex = 0; 101 | } else {//all angle set to 1 102 | mostAngleIndex = 1; 103 | } 104 | printf("Set All Angle to mostAngleIndex(%d)\n", mostAngleIndex); 105 | for (int i = 0; i < angles.size(); ++i) { 106 | Angle angle = angles[i]; 107 | angle.index = mostAngleIndex; 108 | angles.at(i) = angle; 109 | } 110 | } 111 | 112 | return angles; 113 | } -------------------------------------------------------------------------------- /src/CrnnNet.cpp: -------------------------------------------------------------------------------- 1 | #include "CrnnNet.h" 2 | #include "OcrUtils.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | CrnnNet::CrnnNet() {} 9 | 10 | CrnnNet::~CrnnNet() { 11 | } 12 | 13 | void CrnnNet::setNumThread(int numOfThread) { 14 | numThread = numOfThread; 15 | } 16 | 17 | void CrnnNet::initModel(const std::string &pathStr, const std::string &keysPath) { 18 | net.reset(MNN::Interpreter::createFromFile(pathStr.c_str())); 19 | MNN::ScheduleConfig config; 20 | config.type = MNN_FORWARD_CPU; 21 | config.numThread = numThread; 22 | session = net->createSession(config); 23 | //load keys 24 | std::ifstream in(keysPath.c_str()); 25 | std::string line; 26 | if (in) { 27 | while (getline(in, line)) {// line中不包括每行的换行符 28 | keys.push_back(line); 29 | } 30 | } else { 31 | printf("The keys.txt file was not found\n"); 32 | return; 33 | } 34 | if (keys.size() != 5531) { 35 | fprintf(stderr, "missing keys\n"); 36 | } 37 | printf("total keys size(%lu)\n", keys.size()); 38 | 39 | } 40 | 41 | template 42 | inline static size_t argmax(ForwardIterator first, ForwardIterator last) { 43 | return std::distance(first, std::max_element(first, last)); 44 | } 45 | 46 | TextLine CrnnNet::scoreToTextLine(const std::vector &outputData, int h, int w) { 47 | int keySize = keys.size(); 48 | std::string strRes; 49 | std::vector scores; 50 | int lastIndex = 0; 51 | int maxIndex; 52 | float maxValue; 53 | 54 | for (int i = 0; i < h; i++) { 55 | maxIndex = 0; 56 | maxValue = -1000.f; 57 | //do softmax 58 | std::vector exps(w); 59 | for (int j = 0; j < w; j++) { 60 | float expSingle = exp(outputData[i * w + j]); 61 | exps.at(j) = expSingle; 62 | } 63 | float partition = accumulate(exps.begin(), exps.end(), 0.0);//row sum 64 | maxIndex = int(argmax(exps.begin(), exps.end())); 65 | maxValue = float(*std::max_element(exps.begin(), exps.end())) / partition; 66 | if (maxIndex > 0 && maxIndex < keySize && (!(i > 0 && maxIndex == lastIndex))) { 67 | scores.emplace_back(maxValue); 68 | strRes.append(keys[maxIndex - 1]); 69 | } 70 | lastIndex = maxIndex; 71 | } 72 | return {strRes, scores}; 73 | } 74 | 75 | TextLine CrnnNet::getTextLine(const cv::Mat &src) { 76 | float scale = (float) dstHeight / (float) src.rows; 77 | int dstWidth = int((float) src.cols * scale); 78 | cv::Mat srcResize; 79 | resize(src, srcResize, cv::Size(dstWidth, dstHeight)); 80 | std::vector inputTensorValues = substractMeanNormalize(srcResize, meanValues, normValues); 81 | std::vectorinputShape = {1, srcResize.channels(), srcResize.rows, srcResize.cols}; 82 | auto input = net->getSessionInput(session, "input"); 83 | auto output = net->getSessionOutput(session, "out"); 84 | auto shape = input->shape(); 85 | shape[0] = 1; 86 | shape[2] = srcResize.rows; 87 | shape[3] = srcResize.cols; 88 | net->resizeTensor(input, shape); 89 | net->resizeSession(session); 90 | auto nchwTensor = MNN::Tensor::create(inputShape,halide_type_of(),&inputTensorValues[0],MNN::Tensor::CAFFE); 91 | input->copyFromHostTensor(nchwTensor); 92 | delete nchwTensor; 93 | net->runSession(session); 94 | 95 | std::shared_ptr outputUser(new MNN::Tensor(output, output->getDimensionType())); //nchw 96 | output->copyToHostTensor(outputUser.get()); 97 | auto values = outputUser->host(); 98 | int size = outputUser->elementSize(); 99 | 100 | std::vector outputData(values, values + size); 101 | return scoreToTextLine(outputData, output->shape()[0], output->shape()[2]); 102 | } 103 | 104 | std::vector CrnnNet::getTextLines(std::vector &partImg, const char *path, const char *imgName) { 105 | int size = partImg.size(); 106 | std::vector textLines(size); 107 | for (int i = 0; i < size; ++i) { 108 | //OutPut DebugImg 109 | if (isOutputDebugImg) { 110 | std::string debugImgFile = getDebugImgFilePath(path, imgName, i, "-debug-"); 111 | saveImg(partImg[i], debugImgFile.c_str()); 112 | } 113 | 114 | //getTextLine 115 | double startCrnnTime = getCurrentTime(); 116 | TextLine textLine = getTextLine(partImg[i]); 117 | double endCrnnTime = getCurrentTime(); 118 | textLine.time = endCrnnTime - startCrnnTime; 119 | textLines[i] = textLine; 120 | } 121 | return textLines; 122 | } -------------------------------------------------------------------------------- /src/DbNet.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "DbNet.h" 3 | #include "OcrUtils.h" 4 | #include 5 | #include 6 | 7 | DbNet::DbNet() {} 8 | 9 | DbNet::~DbNet() { 10 | } 11 | 12 | void DbNet::setNumThread(int numOfThread) { 13 | numThread = numOfThread; 14 | } 15 | 16 | void DbNet::initModel(const std::string &pathStr) { 17 | net.reset(MNN::Interpreter::createFromFile(pathStr.c_str())); 18 | MNN::ScheduleConfig config; 19 | config.type = MNN_FORWARD_CPU; 20 | config.numThread = numThread; 21 | session = net->createSession(config); 22 | } 23 | 24 | std::vector findRsBoxes(const cv::Mat &fMapMat, const cv::Mat &norfMapMat, ScaleParam &s, 25 | const float boxScoreThresh, const float unClipRatio) { 26 | float minArea = 3; 27 | std::vector rsBoxes; 28 | rsBoxes.clear(); 29 | std::vector> contours; 30 | findContours(norfMapMat, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); 31 | for (int i = 0; i < contours.size(); ++i) { 32 | float minSideLen, perimeter; 33 | std::vector minBox = getMinBoxes(contours[i], minSideLen, perimeter); 34 | if (minSideLen < minArea) 35 | continue; 36 | float score = boxScoreFast(fMapMat, contours[i]); 37 | if (score < boxScoreThresh) 38 | continue; 39 | //---use clipper start--- 40 | std::vector clipBox = unClip(minBox, perimeter, unClipRatio); 41 | std::vector clipMinBox = getMinBoxes(clipBox, minSideLen, perimeter); 42 | //---use clipper end--- 43 | 44 | if (minSideLen < minArea + 2) 45 | continue; 46 | 47 | for (int j = 0; j < clipMinBox.size(); ++j) { 48 | clipMinBox[j].x = (clipMinBox[j].x / s.ratioWidth); 49 | clipMinBox[j].x = (std::min)((std::max)(clipMinBox[j].x, 0), s.srcWidth); 50 | 51 | clipMinBox[j].y = (clipMinBox[j].y / s.ratioHeight); 52 | clipMinBox[j].y = (std::min)((std::max)(clipMinBox[j].y, 0), s.srcHeight); 53 | } 54 | 55 | rsBoxes.emplace_back(TextBox{clipMinBox, score}); 56 | } 57 | reverse(rsBoxes.begin(), rsBoxes.end()); 58 | return rsBoxes; 59 | } 60 | 61 | std::vector 62 | DbNet::getTextBoxes(cv::Mat &src, ScaleParam &s, float boxScoreThresh, float boxThresh, float unClipRatio) { 63 | cv::Mat srcResize; 64 | resize(src, srcResize, cv::Size(s.dstWidth, s.dstHeight)); // w*h 65 | 66 | std::vector inputTensorValues = substractMeanNormalize(srcResize, meanValues, normValues); 67 | 68 | auto input = net->getSessionInput(session, NULL); 69 | auto output = net->getSessionOutput(session, NULL); 70 | auto shape = input->shape(); 71 | shape[0] = 1; 72 | shape[2] = srcResize.rows; 73 | shape[3] = srcResize.cols; 74 | net->resizeTensor(input, shape); 75 | net->resizeSession(session); 76 | auto shapein = input->shape(); 77 | std::vector v = {1,(int)srcResize.channels(),srcResize.rows,srcResize.cols}; 78 | auto nchwTensor = MNN::Tensor::create(v,halide_type_of(),&inputTensorValues[0],MNN::Tensor::CAFFE); 79 | input->copyFromHostTensor(nchwTensor); 80 | delete nchwTensor; 81 | net->runSession(session); 82 | 83 | std::shared_ptr outputUser(new MNN::Tensor(output, output->getDimensionType())); //nchw 84 | output->copyToHostTensor(outputUser.get()); 85 | auto values = outputUser->host(); 86 | //-----Data preparation----- 87 | cv::Mat fMapMat(srcResize.rows, srcResize.cols, CV_32FC1); // h* w rows* cols 88 | ::memcpy(fMapMat.data, values, outputUser->stride(1) * sizeof(float)); // 只取第一个channel的数据 89 | //-----boxThresh----- 90 | cv::Mat norfMapMat; 91 | norfMapMat = fMapMat > boxThresh; 92 | return findRsBoxes(fMapMat, norfMapMat, s, boxScoreThresh, unClipRatio); 93 | } 94 | -------------------------------------------------------------------------------- /src/OcrLite.cpp: -------------------------------------------------------------------------------- 1 | #include "OcrLite.h" 2 | #include "OcrUtils.h" 3 | #include //windows&linux 4 | 5 | OcrLite::OcrLite() {} 6 | 7 | OcrLite::~OcrLite() { 8 | if (isOutputResultTxt) { 9 | fclose(resultTxt); 10 | } 11 | } 12 | 13 | void OcrLite::setNumThread(int numOfThread) { 14 | dbNet.setNumThread(numOfThread); 15 | angleNet.setNumThread(numOfThread); 16 | crnnNet.setNumThread(numOfThread); 17 | } 18 | 19 | void OcrLite::initLogger(bool isConsole, bool isPartImg, bool isResultImg) { 20 | isOutputConsole = isConsole; 21 | isOutputPartImg = isPartImg; 22 | isOutputResultImg = isResultImg; 23 | } 24 | 25 | void OcrLite::enableResultTxt(const char *path, const char *imgName) { 26 | isOutputResultTxt = true; 27 | std::string resultTxtPath = getResultTxtFilePath(path, imgName); 28 | printf("resultTxtPath(%s)\n", resultTxtPath.c_str()); 29 | resultTxt = fopen(resultTxtPath.c_str(), "w"); 30 | } 31 | 32 | void OcrLite::initModels(const std::string &detPath, const std::string &clsPath, 33 | const std::string &recPath, const std::string &keysPath) { 34 | Logger("=====Init Models=====\n"); 35 | Logger("--- Init DbNet ---\n"); 36 | dbNet.initModel(detPath); 37 | 38 | Logger("--- Init AngleNet ---\n"); 39 | angleNet.initModel(clsPath); 40 | 41 | Logger("--- Init CrnnNet ---\n"); 42 | crnnNet.initModel(recPath, keysPath); 43 | 44 | Logger("Init Models Success!\n"); 45 | } 46 | 47 | void OcrLite::Logger(const char *format, ...) { 48 | if (!(isOutputConsole || isOutputResultTxt)) return; 49 | char *buffer = (char *) malloc(8192); 50 | va_list args; 51 | va_start(args, format); 52 | vsprintf(buffer, format, args); 53 | va_end(args); 54 | if (isOutputConsole) printf("%s", buffer); 55 | if (isOutputResultTxt) fprintf(resultTxt, "%s", buffer); 56 | free(buffer); 57 | } 58 | 59 | cv::Mat makePadding(cv::Mat &src, const int padding) { 60 | if (padding <= 0) return src; 61 | cv::Scalar paddingScalar = {255, 255, 255}; 62 | cv::Mat paddingSrc; 63 | cv::copyMakeBorder(src, paddingSrc, padding, padding, padding, padding, cv::BORDER_ISOLATED, paddingScalar); 64 | return paddingSrc; 65 | } 66 | 67 | OcrResult OcrLite::detect(const char *path, const char *imgName, 68 | const int padding, const int maxSideLen, 69 | float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle) { 70 | std::string imgFile = getSrcImgFilePath(path, imgName); 71 | 72 | cv::Mat bgrSrc = imread(imgFile, cv::IMREAD_COLOR);//default : BGR 73 | cv::Mat originSrc; 74 | cvtColor(bgrSrc, originSrc, cv::COLOR_BGR2RGB);// convert to RGB 75 | int originMaxSide = (std::max)(originSrc.cols, originSrc.rows); 76 | int resize; 77 | if (maxSideLen <= 0 || maxSideLen > originMaxSide) { 78 | resize = originMaxSide; 79 | } else { 80 | resize = maxSideLen; 81 | } 82 | resize += 2*padding; 83 | cv::Rect paddingRect(padding, padding, originSrc.cols, originSrc.rows); 84 | cv::Mat paddingSrc = makePadding(originSrc, padding); 85 | ScaleParam scale = getScaleParam(paddingSrc, resize); 86 | OcrResult result; 87 | result = detect(path, imgName, paddingSrc, paddingRect, scale, 88 | boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle); 89 | return result; 90 | } 91 | 92 | std::vector OcrLite::getPartImages(cv::Mat &src, std::vector &textBoxes, 93 | const char *path, const char *imgName) { 94 | std::vector partImages; 95 | for (int i = 0; i < textBoxes.size(); ++i) { 96 | cv::Mat partImg = getRotateCropImage(src, textBoxes[i].boxPoint); 97 | partImages.emplace_back(partImg); 98 | //OutPut DebugImg 99 | if (isOutputPartImg) { 100 | std::string debugImgFile = getDebugImgFilePath(path, imgName, i, "-part-"); 101 | printf("debugImgFile:%s",debugImgFile.c_str()); 102 | saveImg(partImg, debugImgFile.c_str()); 103 | } 104 | } 105 | return partImages; 106 | } 107 | 108 | OcrResult OcrLite::detect(const char *path, const char *imgName, 109 | cv::Mat &src, cv::Rect &originRect, ScaleParam &scale, 110 | float boxScoreThresh, float boxThresh, float unClipRatio, bool doAngle, bool mostAngle) { 111 | 112 | cv::Mat textBoxPaddingImg = src.clone(); 113 | int thickness = getThickness(src); 114 | 115 | Logger("=====Start detect=====\n"); 116 | Logger("ScaleParam(sw:%d,sh:%d,dw:%d,dh:%d,%f,%f)\n", scale.srcWidth, scale.srcHeight, 117 | scale.dstWidth, scale.dstHeight, 118 | scale.ratioWidth, scale.ratioHeight); 119 | 120 | Logger("---------- step: dbNet getTextBoxes ----------\n"); 121 | double startTime = getCurrentTime(); 122 | std::vector textBoxes = dbNet.getTextBoxes(src, scale, boxScoreThresh, boxThresh, unClipRatio); 123 | 124 | double endDbNetTime = getCurrentTime(); 125 | double dbNetTime = endDbNetTime - startTime; 126 | Logger("dbNetTime(%fms)\n", dbNetTime); 127 | 128 | for (int i = 0; i < textBoxes.size(); ++i) { 129 | Logger("TextBox[%d](+padding)[score(%f),[x: %d, y: %d], [x: %d, y: %d], [x: %d, y: %d], [x: %d, y: %d]]\n", i, 130 | textBoxes[i].score, 131 | textBoxes[i].boxPoint[0].x, textBoxes[i].boxPoint[0].y, 132 | textBoxes[i].boxPoint[1].x, textBoxes[i].boxPoint[1].y, 133 | textBoxes[i].boxPoint[2].x, textBoxes[i].boxPoint[2].y, 134 | textBoxes[i].boxPoint[3].x, textBoxes[i].boxPoint[3].y); 135 | } 136 | 137 | Logger("---------- step: drawTextBoxes ----------\n"); 138 | drawTextBoxes(textBoxPaddingImg, textBoxes, thickness); 139 | 140 | //---------- getPartImages ---------- 141 | std::vector partImages = getPartImages(src, textBoxes, path, imgName); 142 | 143 | Logger("---------- step: angleNet getAngles ----------\n"); 144 | std::vector angles; 145 | angles = angleNet.getAngles(partImages, path, imgName, doAngle, mostAngle); 146 | 147 | //Log Angles 148 | for (int i = 0; i < angles.size(); ++i) { 149 | Logger("angle[%d][index(%d), score(%f), time(%fms)]\n", i, angles[i].index, angles[i].score, angles[i].time); 150 | } 151 | 152 | //Rotate partImgs 153 | for (int i = 0; i < partImages.size(); ++i) { 154 | if (angles[i].index == 0) { 155 | partImages.at(i) = matRotateClockWise180(partImages[i]); 156 | } 157 | } 158 | 159 | Logger("---------- step: crnnNet getTextLine ----------\n"); 160 | std::vector textLines = crnnNet.getTextLines(partImages, path, imgName); 161 | //Log TextLines 162 | for (int i = 0; i < textLines.size(); ++i) { 163 | Logger("textLine[%d](%s)\n", i, textLines[i].text.c_str()); 164 | std::ostringstream txtScores; 165 | for (int s = 0; s < textLines[i].charScores.size(); ++s) { 166 | if (s == 0) { 167 | txtScores << textLines[i].charScores[s]; 168 | } else { 169 | txtScores << " ," << textLines[i].charScores[s]; 170 | } 171 | } 172 | Logger("textScores[%d]{%s}\n", i, std::string(txtScores.str()).c_str()); 173 | Logger("crnnTime[%d](%fms)\n", i, textLines[i].time); 174 | } 175 | 176 | std::vector textBlocks; 177 | for (int i = 0; i < textLines.size(); ++i) { 178 | std::vector boxPoint = std::vector(4); 179 | int padding = originRect.x;//padding conversion 180 | boxPoint[0] = cv::Point(textBoxes[i].boxPoint[0].x - padding, textBoxes[i].boxPoint[0].y - padding); 181 | boxPoint[1] = cv::Point(textBoxes[i].boxPoint[1].x - padding, textBoxes[i].boxPoint[1].y - padding); 182 | boxPoint[2] = cv::Point(textBoxes[i].boxPoint[2].x - padding, textBoxes[i].boxPoint[2].y - padding); 183 | boxPoint[3] = cv::Point(textBoxes[i].boxPoint[3].x - padding, textBoxes[i].boxPoint[3].y - padding); 184 | TextBlock textBlock{boxPoint, textBoxes[i].score, angles[i].index, angles[i].score, 185 | angles[i].time, textLines[i].text, textLines[i].charScores, textLines[i].time, 186 | angles[i].time + textLines[i].time}; 187 | textBlocks.emplace_back(textBlock); 188 | } 189 | 190 | double endTime = getCurrentTime(); 191 | double fullTime = endTime - startTime; 192 | Logger("=====End detect=====\n"); 193 | Logger("FullDetectTime(%fms)\n", fullTime); 194 | 195 | //cropped to original size 196 | cv::Mat rgbBoxImg, textBoxImg; 197 | 198 | if (originRect.x > 0 && originRect.y > 0) { 199 | textBoxPaddingImg(originRect).copyTo(rgbBoxImg); 200 | } else { 201 | rgbBoxImg = textBoxPaddingImg; 202 | } 203 | cvtColor(rgbBoxImg, textBoxImg, cv::COLOR_RGB2BGR);//convert to BGR for Output Result Img 204 | 205 | //Save result.jpg 206 | if (isOutputResultImg) { 207 | std::string resultImgFile = getResultImgFilePath(path, imgName); 208 | imwrite(resultImgFile, textBoxImg); 209 | } 210 | 211 | std::string strRes; 212 | for (int i = 0; i < textBlocks.size(); ++i) { 213 | strRes.append(textBlocks[i].text); 214 | strRes.append("\n"); 215 | } 216 | 217 | return OcrResult{dbNetTime, textBlocks, textBoxImg, fullTime, strRes}; 218 | } -------------------------------------------------------------------------------- /src/OcrLiteJni.cpp: -------------------------------------------------------------------------------- 1 | #ifdef __JNI__ 2 | 3 | #include "version.h" 4 | #include 5 | #include "OcrLite.h" 6 | #include "OcrResultUtils.h" 7 | #include "OcrUtils.h" 8 | 9 | static OcrLite *ocrLite; 10 | 11 | JNIEXPORT jint JNICALL 12 | JNI_OnLoad(JavaVM *vm, void *reserved){ 13 | ocrLite = new OcrLite(); 14 | return JNI_VERSION_1_4; 15 | } 16 | 17 | JNIEXPORT void JNICALL 18 | JNI_OnUnload(JavaVM *vm, void *reserved){ 19 | //printf("JNI_OnUnload\n"); 20 | delete ocrLite; 21 | } 22 | 23 | #ifdef _WIN32 24 | char *jstringToChar(JNIEnv *env, jstring jstr) { 25 | char *rtn = NULL; 26 | jclass clsstring = env->FindClass("java/lang/String"); 27 | jstring strencode = env->NewStringUTF("gbk"); 28 | jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B"); 29 | jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode); 30 | jsize alen = env->GetArrayLength(barr); 31 | jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE); 32 | if (alen > 0) { 33 | rtn = (char *) malloc(alen + 1); 34 | memcpy(rtn, ba, alen); 35 | rtn[alen] = 0; 36 | } 37 | env->ReleaseByteArrayElements(barr, ba, 0); 38 | return rtn; 39 | } 40 | #else 41 | 42 | char *jstringToChar(JNIEnv *env, jstring input) { 43 | char *str = NULL; 44 | jclass clsstring = env->FindClass("java/lang/String"); 45 | jstring strencode = env->NewStringUTF("utf-8"); 46 | jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B"); 47 | jbyteArray barr = (jbyteArray) env->CallObjectMethod(input, mid, strencode); 48 | jsize alen = env->GetArrayLength(barr); 49 | jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE); 50 | if (alen > 0) { 51 | str = (char *) malloc(alen + 1); 52 | memcpy(str, ba, alen); 53 | str[alen] = 0; 54 | } 55 | env->ReleaseByteArrayElements(barr, ba, 0); 56 | return str; 57 | } 58 | 59 | #endif 60 | 61 | extern "C" JNIEXPORT jstring JNICALL 62 | Java_com_benjaminwan_ocrlibrary_OcrEngine_getVersion(JNIEnv *env, jobject thiz) { 63 | jstring ver = env->NewStringUTF(VERSION); 64 | return ver; 65 | } 66 | 67 | extern "C" JNIEXPORT jboolean JNICALL 68 | Java_com_benjaminwan_ocrlibrary_OcrEngine_setNumThread(JNIEnv *env, jobject thiz, jint numThread) { 69 | ocrLite->setNumThread(numThread); 70 | printf("numThread=%d\n", numThread); 71 | return JNI_TRUE; 72 | } 73 | 74 | extern "C" JNIEXPORT void JNICALL 75 | Java_com_benjaminwan_ocrlibrary_OcrEngine_initLogger(JNIEnv *env, jobject thiz, jboolean isConsole, 76 | jboolean isPartImg, jboolean isResultImg) { 77 | ocrLite->initLogger(isConsole,//isOutputConsole 78 | isPartImg,//isOutputPartImg 79 | isResultImg);//isOutputResultImg 80 | } 81 | 82 | extern "C" JNIEXPORT void JNICALL 83 | Java_com_benjaminwan_ocrlibrary_OcrEngine_enableResultText(JNIEnv *env, jobject thiz, jstring input) { 84 | std::string imgPath = jstringToChar(env, input); 85 | std::string imgDir = imgPath.substr(0, imgPath.find_last_of('/') + 1); 86 | std::string imgName = imgPath.substr(imgPath.find_last_of('/') + 1); 87 | ocrLite->enableResultTxt(imgDir.c_str(), imgName.c_str()); 88 | } 89 | 90 | extern "C" JNIEXPORT jboolean JNICALL 91 | Java_com_benjaminwan_ocrlibrary_OcrEngine_initModels(JNIEnv *env, jobject thiz, jstring path, 92 | jstring det, jstring cls, jstring rec, jstring keys) { 93 | std::string modelsDir = jstringToChar(env, path); 94 | std::string detName = jstringToChar(env, det); 95 | std::string clsName = jstringToChar(env, cls); 96 | std::string recName = jstringToChar(env, rec); 97 | std::string keysName = jstringToChar(env, keys); 98 | std::string modelDetPath = modelsDir + "/" + detName; 99 | std::string modelClsPath = modelsDir + "/" + clsName; 100 | std::string modelRecPath = modelsDir + "/" + recName; 101 | std::string keysPath = modelsDir + "/" + keysName; 102 | printf("modelsDir=%s\ndet=%s\ncls=%s\nrec=%s\nkeys=%s\n", modelsDir.c_str(), detName.c_str(), clsName.c_str(), 103 | recName.c_str(), keysName.c_str()); 104 | bool hasModelDetFile = isFileExists(modelDetPath); 105 | if (!hasModelDetFile) { 106 | fprintf(stderr, "Model det file not found: %s\n", modelDetPath.c_str()); 107 | return false; 108 | } 109 | bool hasModelClsFile = isFileExists(modelClsPath); 110 | if (!hasModelClsFile) { 111 | fprintf(stderr, "Model cls file not found: %s\n", modelClsPath.c_str()); 112 | return false; 113 | } 114 | bool hasModelRecFile = isFileExists(modelRecPath); 115 | if (!hasModelRecFile) { 116 | fprintf(stderr, "Model rec file not found: %s\n", modelRecPath.c_str()); 117 | return false; 118 | } 119 | bool hasKeysFile = isFileExists(keysPath); 120 | if (!hasKeysFile) { 121 | fprintf(stderr, "keys file not found: %s\n", keysPath.c_str()); 122 | return false; 123 | } 124 | ocrLite->initModels(modelDetPath, modelClsPath, modelRecPath, keysPath); 125 | return true; 126 | } 127 | 128 | extern "C" JNIEXPORT jobject JNICALL 129 | Java_com_benjaminwan_ocrlibrary_OcrEngine_detect(JNIEnv *env, jobject thiz, jstring input, jint padding, 130 | jint maxSideLen, 131 | jfloat boxScoreThresh, jfloat boxThresh, jfloat unClipRatio, 132 | jboolean doAngle, jboolean mostAngle 133 | ) { 134 | std::string imgPath = jstringToChar(env, input); 135 | bool hasTargetImgFile = isFileExists(imgPath); 136 | if (!hasTargetImgFile) { 137 | fprintf(stderr, "Target image not found: %s\n", imgPath.c_str()); 138 | OcrResult result{}; 139 | return OcrResultUtils(env, result).getJObject(); 140 | } 141 | std::string imgDir = imgPath.substr(0, imgPath.find_last_of('/') + 1); 142 | std::string imgName = imgPath.substr(imgPath.find_last_of('/') + 1); 143 | printf("imgDir=%s, imgName=%s\n", imgDir.c_str(), imgName.c_str()); 144 | OcrResult result = ocrLite->detect(imgDir.c_str(), imgName.c_str(), padding, maxSideLen, 145 | boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle); 146 | return OcrResultUtils(env, result).getJObject(); 147 | } 148 | #endif -------------------------------------------------------------------------------- /src/OcrResultUtils.cpp: -------------------------------------------------------------------------------- 1 | #ifdef __JNI__ 2 | #include 3 | #include "OcrResultUtils.h" 4 | 5 | OcrResultUtils::OcrResultUtils(JNIEnv *env, OcrResult &ocrResult) { 6 | jniEnv = env; 7 | 8 | jclass jOcrResultClass = env->FindClass("com/benjaminwan/ocrlibrary/OcrResult"); 9 | 10 | if (jOcrResultClass == NULL) { 11 | printf("OcrResult class is null\n"); 12 | } 13 | 14 | jmethodID jOcrResultConstructor = env->GetMethodID(jOcrResultClass, "", 15 | "(DLjava/util/ArrayList;DLjava/lang/String;)V"); 16 | 17 | jobject textBlocks = getTextBlocks(ocrResult.textBlocks); 18 | jdouble dbNetTime = (jdouble) ocrResult.dbNetTime; 19 | jdouble detectTime = (jdouble) ocrResult.detectTime; 20 | jstring jStrRest = jniEnv->NewStringUTF(ocrResult.strRes.c_str()); 21 | 22 | jOcrResult = env->NewObject(jOcrResultClass, jOcrResultConstructor, dbNetTime, 23 | textBlocks, detectTime, jStrRest); 24 | } 25 | 26 | OcrResultUtils::~OcrResultUtils() { 27 | jniEnv = NULL; 28 | } 29 | 30 | jobject OcrResultUtils::getJObject() { 31 | return jOcrResult; 32 | } 33 | 34 | jclass OcrResultUtils::newJListClass() { 35 | jclass clazz = jniEnv->FindClass("java/util/ArrayList"); 36 | if (clazz == NULL) { 37 | printf("ArrayList class is null\n"); 38 | return NULL; 39 | } 40 | return clazz; 41 | } 42 | 43 | jmethodID OcrResultUtils::getListConstructor(jclass clazz) { 44 | jmethodID constructor = jniEnv->GetMethodID(clazz, "", "()V"); 45 | return constructor; 46 | } 47 | 48 | jobject OcrResultUtils::newJPoint(cv::Point &point) { 49 | jclass clazz = jniEnv->FindClass("com/benjaminwan/ocrlibrary/Point"); 50 | if (clazz == NULL) { 51 | printf("Point class is null\n"); 52 | return NULL; 53 | } 54 | jmethodID constructor = jniEnv->GetMethodID(clazz, "", "(II)V"); 55 | jobject obj = jniEnv->NewObject(clazz, constructor, point.x, point.y); 56 | return obj; 57 | } 58 | 59 | jobject OcrResultUtils::newJBoxPoint(std::vector &boxPoint) { 60 | jclass jListClass = newJListClass(); 61 | jmethodID jListConstructor = getListConstructor(jListClass); 62 | jobject jList = jniEnv->NewObject(jListClass, jListConstructor); 63 | jmethodID jListAdd = jniEnv->GetMethodID(jListClass, "add", "(Ljava/lang/Object;)Z"); 64 | 65 | for (auto point : boxPoint) { 66 | jobject jPoint = newJPoint(point); 67 | jniEnv->CallBooleanMethod(jList, jListAdd, jPoint); 68 | } 69 | return jList; 70 | } 71 | 72 | jobject OcrResultUtils::getTextBlock(TextBlock &textBlock) { 73 | jobject jBoxPint = newJBoxPoint(textBlock.boxPoint); 74 | jfloat jBoxScore = (jfloat) textBlock.boxScore; 75 | jfloat jAngleScore = (jfloat) textBlock.angleScore; 76 | jdouble jAngleTime = (jdouble) textBlock.angleTime; 77 | jstring jText = jniEnv->NewStringUTF(textBlock.text.c_str()); 78 | jobject jCharScores = newJScoreArray(textBlock.charScores); 79 | jdouble jCrnnTime = (jdouble) textBlock.crnnTime; 80 | jdouble jBlockTime = (jdouble) textBlock.blockTime; 81 | jclass clazz = jniEnv->FindClass("com/benjaminwan/ocrlibrary/TextBlock"); 82 | if (clazz == NULL) { 83 | printf("TextBlock class is null\n"); 84 | return NULL; 85 | } 86 | jmethodID constructor = jniEnv->GetMethodID(clazz, "", 87 | "(Ljava/util/ArrayList;FIFDLjava/lang/String;[FDD)V"); 88 | jobject obj = jniEnv->NewObject(clazz, constructor, jBoxPint, jBoxScore, textBlock.angleIndex, 89 | jAngleScore, jAngleTime, jText, jCharScores, jCrnnTime, 90 | jBlockTime); 91 | return obj; 92 | } 93 | 94 | jobject OcrResultUtils::getTextBlocks(std::vector &textBlocks) { 95 | jclass jListClass = newJListClass(); 96 | jmethodID jListConstructor = getListConstructor(jListClass); 97 | jobject jList = jniEnv->NewObject(jListClass, jListConstructor); 98 | jmethodID jListAdd = jniEnv->GetMethodID(jListClass, "add", "(Ljava/lang/Object;)Z"); 99 | 100 | for (int i = 0; i < textBlocks.size(); ++i) { 101 | auto textBlock = textBlocks[i]; 102 | jobject jTextBlock = getTextBlock(textBlock); 103 | jniEnv->CallBooleanMethod(jList, jListAdd, jTextBlock); 104 | } 105 | return jList; 106 | } 107 | 108 | jfloatArray OcrResultUtils::newJScoreArray(std::vector &scores) { 109 | jfloatArray jScores = jniEnv->NewFloatArray(scores.size()); 110 | jniEnv->SetFloatArrayRegion(jScores, 0, scores.size(), (jfloat *) scores.data()); 111 | return jScores; 112 | } 113 | 114 | #endif -------------------------------------------------------------------------------- /src/OcrUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "OcrUtils.h" 5 | #include "clipper.hpp" 6 | 7 | double getCurrentTime() { 8 | return (static_cast(cv::getTickCount())) / cv::getTickFrequency() * 1000;//单位毫秒 9 | } 10 | 11 | std::wstring strToWstr(std::string str) { 12 | if (str.length() == 0) 13 | return L""; 14 | std::wstring wstr; 15 | wstr.assign(str.begin(), str.end()); 16 | return wstr; 17 | } 18 | 19 | ScaleParam getScaleParam(cv::Mat &src, const float scale) { 20 | int srcWidth = src.cols; 21 | int srcHeight = src.rows; 22 | int dstWidth = int((float) srcWidth * scale); 23 | int dstHeight = int((float) srcHeight * scale); 24 | if (dstWidth % 32 != 0) { 25 | dstWidth = (dstWidth / 32 - 1) * 32; 26 | dstWidth = (std::max)(dstWidth, 32); 27 | } 28 | if (dstHeight % 32 != 0) { 29 | dstHeight = (dstHeight / 32 - 1) * 32; 30 | dstHeight = (std::max)(dstHeight, 32); 31 | } 32 | float scaleWidth = (float) dstWidth / (float) srcWidth; 33 | float scaleHeight = (float) dstHeight / (float) srcHeight; 34 | return {srcWidth, srcHeight, dstWidth, dstHeight, scaleWidth, scaleHeight}; 35 | } 36 | 37 | ScaleParam getScaleParam(cv::Mat &src, const int targetSize) { 38 | int srcWidth, srcHeight, dstWidth, dstHeight; 39 | srcWidth = dstWidth = src.cols; 40 | srcHeight = dstHeight = src.rows; 41 | 42 | float ratio = 1.f; 43 | if (srcWidth > srcHeight) { 44 | ratio = float(targetSize) / float(srcWidth); 45 | } else { 46 | ratio = float(targetSize) / float(srcHeight); 47 | } 48 | dstWidth = int(float(srcWidth) * ratio); 49 | dstHeight = int(float(srcHeight) * ratio); 50 | if (dstWidth % 32 != 0) { 51 | dstWidth = (dstWidth / 32) * 32; 52 | dstWidth = (std::max)(dstWidth, 32); 53 | } 54 | if (dstHeight % 32 != 0) { 55 | dstHeight = (dstHeight / 32) * 32; 56 | dstHeight = (std::max)(dstHeight, 32); 57 | } 58 | float ratioWidth = (float) dstWidth / (float) srcWidth; 59 | float ratioHeight = (float) dstHeight / (float) srcHeight; 60 | return {srcWidth, srcHeight, dstWidth, dstHeight, ratioWidth, ratioHeight}; 61 | } 62 | 63 | std::vector getBox(const cv::RotatedRect &rect) { 64 | cv::Point2f vertices[4]; 65 | rect.points(vertices); 66 | //std::vector ret(4); 67 | std::vector ret2(vertices, vertices + sizeof(vertices) / sizeof(vertices[0])); 68 | //memcpy(vertices, &ret[0], ret.size() * sizeof(ret[0])); 69 | return ret2; 70 | } 71 | 72 | int getThickness(cv::Mat &boxImg) { 73 | int minSize = boxImg.cols > boxImg.rows ? boxImg.rows : boxImg.cols; 74 | int thickness = minSize / 1000 + 2; 75 | return thickness; 76 | } 77 | 78 | void drawTextBox(cv::Mat &boxImg, cv::RotatedRect &rect, int thickness) { 79 | cv::Point2f vertices[4]; 80 | rect.points(vertices); 81 | for (int i = 0; i < 4; i++) 82 | cv::line(boxImg, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 0, 255), thickness); 83 | //cv::polylines(srcmat, textpoint, true, cv::Scalar(0, 255, 0), 2); 84 | } 85 | 86 | void drawTextBox(cv::Mat &boxImg, const std::vector &box, int thickness) { 87 | auto color = cv::Scalar(255, 0, 0);// R(255) G(0) B(0) 88 | cv::line(boxImg, box[0], box[1], color, thickness); 89 | cv::line(boxImg, box[1], box[2], color, thickness); 90 | cv::line(boxImg, box[2], box[3], color, thickness); 91 | cv::line(boxImg, box[3], box[0], color, thickness); 92 | } 93 | 94 | void drawTextBoxes(cv::Mat &boxImg, std::vector &textBoxes, int thickness) { 95 | for (int i = 0; i < textBoxes.size(); ++i) { 96 | drawTextBox(boxImg, textBoxes[i].boxPoint, thickness); 97 | } 98 | } 99 | 100 | cv::Mat matRotateClockWise180(cv::Mat src) { 101 | flip(src, src, 0); 102 | flip(src, src, 1); 103 | return src; 104 | } 105 | 106 | cv::Mat matRotateClockWise90(cv::Mat src) { 107 | transpose(src, src); 108 | flip(src, src, 1); 109 | return src; 110 | } 111 | 112 | cv::Mat getRotateCropImage(const cv::Mat &src, std::vector box) { 113 | cv::Mat image; 114 | src.copyTo(image); 115 | std::vector points = box; 116 | 117 | int collectX[4] = {box[0].x, box[1].x, box[2].x, box[3].x}; 118 | int collectY[4] = {box[0].y, box[1].y, box[2].y, box[3].y}; 119 | int left = int(*std::min_element(collectX, collectX + 4)); 120 | int right = int(*std::max_element(collectX, collectX + 4)); 121 | int top = int(*std::min_element(collectY, collectY + 4)); 122 | int bottom = int(*std::max_element(collectY, collectY + 4)); 123 | 124 | cv::Mat imgCrop; 125 | image(cv::Rect(left, top, right - left, bottom - top)).copyTo(imgCrop); 126 | 127 | for (int i = 0; i < points.size(); i++) { 128 | points[i].x -= left; 129 | points[i].y -= top; 130 | } 131 | 132 | int imgCropWidth = int(sqrt(pow(points[0].x - points[1].x, 2) + 133 | pow(points[0].y - points[1].y, 2))); 134 | int imgCropHeight = int(sqrt(pow(points[0].x - points[3].x, 2) + 135 | pow(points[0].y - points[3].y, 2))); 136 | 137 | cv::Point2f ptsDst[4]; 138 | ptsDst[0] = cv::Point2f(0., 0.); 139 | ptsDst[1] = cv::Point2f(imgCropWidth, 0.); 140 | ptsDst[2] = cv::Point2f(imgCropWidth, imgCropHeight); 141 | ptsDst[3] = cv::Point2f(0.f, imgCropHeight); 142 | 143 | cv::Point2f ptsSrc[4]; 144 | ptsSrc[0] = cv::Point2f(points[0].x, points[0].y); 145 | ptsSrc[1] = cv::Point2f(points[1].x, points[1].y); 146 | ptsSrc[2] = cv::Point2f(points[2].x, points[2].y); 147 | ptsSrc[3] = cv::Point2f(points[3].x, points[3].y); 148 | 149 | cv::Mat M = cv::getPerspectiveTransform(ptsSrc, ptsDst); 150 | 151 | cv::Mat partImg; 152 | cv::warpPerspective(imgCrop, partImg, M, 153 | cv::Size(imgCropWidth, imgCropHeight), 154 | cv::BORDER_REPLICATE); 155 | 156 | if (float(partImg.rows) >= float(partImg.cols) * 1.5) { 157 | cv::Mat srcCopy = cv::Mat(partImg.rows, partImg.cols, partImg.depth()); 158 | cv::transpose(partImg, srcCopy); 159 | cv::flip(srcCopy, srcCopy, 0); 160 | return srcCopy; 161 | } else { 162 | return partImg; 163 | } 164 | } 165 | 166 | cv::Mat adjustTargetImg(cv::Mat &src, int dstWidth, int dstHeight) { 167 | cv::Mat srcResize; 168 | float scale = (float) dstHeight / (float) src.rows; 169 | int angleWidth = int((float) src.cols * scale); 170 | cv::resize(src, srcResize, cv::Size(angleWidth, dstHeight)); 171 | cv::Mat srcFit = cv::Mat(dstHeight, dstWidth, CV_8UC3, cv::Scalar(255, 255, 255)); 172 | if (angleWidth < dstWidth) { 173 | cv::Rect rect(0, 0, srcResize.cols, srcResize.rows); 174 | srcResize.copyTo(srcFit(rect)); 175 | } else { 176 | cv::Rect rect(0, 0, dstWidth, dstHeight); 177 | srcResize(rect).copyTo(srcFit); 178 | } 179 | return srcFit; 180 | } 181 | 182 | bool cvPointCompare(const cv::Point &a, const cv::Point &b) { 183 | return a.x < b.x; 184 | } 185 | 186 | std::vector getMinBoxes(const std::vector &inVec, float &minSideLen, float &allEdgeSize) { 187 | std::vector minBoxVec; 188 | cv::RotatedRect textRect = cv::minAreaRect(inVec); 189 | cv::Mat boxPoints2f; 190 | cv::boxPoints(textRect, boxPoints2f); 191 | 192 | float *p1 = (float *) boxPoints2f.data; 193 | std::vector tmpVec; 194 | for (int i = 0; i < 4; ++i, p1 += 2) { 195 | tmpVec.emplace_back(int(p1[0]), int(p1[1])); 196 | } 197 | 198 | std::sort(tmpVec.begin(), tmpVec.end(), cvPointCompare); 199 | 200 | minBoxVec.clear(); 201 | 202 | int index1, index2, index3, index4; 203 | if (tmpVec[1].y > tmpVec[0].y) { 204 | index1 = 0; 205 | index4 = 1; 206 | } else { 207 | index1 = 1; 208 | index4 = 0; 209 | } 210 | 211 | if (tmpVec[3].y > tmpVec[2].y) { 212 | index2 = 2; 213 | index3 = 3; 214 | } else { 215 | index2 = 3; 216 | index3 = 2; 217 | } 218 | 219 | minBoxVec.clear(); 220 | 221 | minBoxVec.push_back(tmpVec[index1]); 222 | minBoxVec.push_back(tmpVec[index2]); 223 | minBoxVec.push_back(tmpVec[index3]); 224 | minBoxVec.push_back(tmpVec[index4]); 225 | 226 | minSideLen = (std::min)(textRect.size.width, textRect.size.height); 227 | allEdgeSize = 2.f * (textRect.size.width + textRect.size.height); 228 | 229 | return minBoxVec; 230 | } 231 | 232 | float boxScoreFast(const cv::Mat &inMat, const std::vector &inBox) { 233 | std::vector box = inBox; 234 | int width = inMat.cols; 235 | int height = inMat.rows; 236 | int maxX = -1, minX = 1000000, maxY = -1, minY = 1000000; 237 | for (int i = 0; i < box.size(); ++i) { 238 | if (maxX < box[i].x) 239 | maxX = box[i].x; 240 | if (minX > box[i].x) 241 | minX = box[i].x; 242 | if (maxY < box[i].y) 243 | maxY = box[i].y; 244 | if (minY > box[i].y) 245 | minY = box[i].y; 246 | } 247 | maxX = (std::min)((std::max)(maxX, 0), width - 1); 248 | minX = (std::max)((std::min)(minX, width - 1), 0); 249 | maxY = (std::min)((std::max)(maxY, 0), height - 1); 250 | minY = (std::max)((std::min)(minY, height - 1), 0); 251 | 252 | for (int i = 0; i < box.size(); ++i) { 253 | box[i].x = box[i].x - minX; 254 | box[i].y = box[i].y - minY; 255 | } 256 | 257 | std::vector> maskBox; 258 | maskBox.push_back(box); 259 | cv::Mat maskMat(maxY - minY + 1, maxX - minX + 1, CV_8UC1, cv::Scalar(0, 0, 0)); 260 | cv::fillPoly(maskMat, maskBox, cv::Scalar(1, 1, 1), 1); 261 | 262 | // cv::Mat normat; 263 | // cv::normalize(maskMat, normat, 255, 0, cv::NORM_MINMAX); 264 | // 265 | // cv::Mat maskbinmat; 266 | // normat.convertTo(maskbinmat, CV_8UC1, 1); 267 | // imwrite("subbin.jpg", maskbinmat); 268 | 269 | //std::cout << inMat << std::endl; 270 | 271 | return cv::mean(inMat(cv::Rect(cv::Point(minX, minY), cv::Point(maxX + 1, maxY + 1))).clone(), 272 | maskMat).val[0]; 273 | } 274 | 275 | // use clipper 276 | std::vector unClip(const std::vector &inBox, float perimeter, float unClipRatio) { 277 | std::vector outBox; 278 | ClipperLib::Path poly; 279 | 280 | for (int i = 0; i < inBox.size(); ++i) { 281 | poly.push_back(ClipperLib::IntPoint(inBox[i].x, inBox[i].y)); 282 | } 283 | 284 | double distance = unClipRatio * ClipperLib::Area(poly) / (double) perimeter; 285 | 286 | ClipperLib::ClipperOffset clipperOffset; 287 | clipperOffset.AddPath(poly, ClipperLib::JoinType::jtRound, ClipperLib::EndType::etClosedPolygon); 288 | ClipperLib::Paths polys; 289 | polys.push_back(poly); 290 | clipperOffset.Execute(polys, distance); 291 | 292 | outBox.clear(); 293 | std::vector rsVec; 294 | for (int i = 0; i < polys.size(); ++i) { 295 | ClipperLib::Path tmpPoly = polys[i]; 296 | for (int j = 0; j < tmpPoly.size(); ++j) { 297 | outBox.emplace_back(tmpPoly[j].X, tmpPoly[j].Y); 298 | } 299 | } 300 | return outBox; 301 | } 302 | 303 | std::vector substractMeanNormalize(cv::Mat &src, const float *meanVals, const float *normVals) { 304 | auto inputTensorSize = src.cols * src.rows * src.channels(); 305 | std::vector inputTensorValues(inputTensorSize); 306 | size_t numChannels = src.channels(); 307 | size_t imageSize = src.cols * src.rows; 308 | for (size_t pid = 0; pid < imageSize; pid++) { 309 | for (size_t ch = 0; ch < numChannels; ++ch) { 310 | float data = (float) (src.data[pid * numChannels + ch] * normVals[ch] - meanVals[ch] * normVals[ch]); 311 | inputTensorValues[ch * imageSize + pid] = data; // 这个赋值方式,相当于从nhwc-> nchw? 312 | } 313 | } 314 | return inputTensorValues; 315 | } 316 | 317 | 318 | std::vector getAngleIndexes(std::vector &angles) { 319 | std::vector angleIndexes; 320 | angleIndexes.reserve(angles.size()); 321 | for (int i = 0; i < angles.size(); ++i) { 322 | angleIndexes.push_back(angles[i].index); 323 | } 324 | return angleIndexes; 325 | } 326 | 327 | void saveImg(cv::Mat &img, const char *imgPath) { 328 | cv::imwrite(imgPath, img); 329 | } 330 | 331 | std::string getSrcImgFilePath(const char *path, const char *imgName) { 332 | std::string filePath; 333 | filePath.append(path).append(imgName); 334 | return filePath; 335 | } 336 | 337 | std::string getResultTxtFilePath(const char *path, const char *imgName) { 338 | std::string filePath; 339 | filePath.append(path).append(imgName).append("-result.txt"); 340 | return filePath; 341 | } 342 | 343 | std::string getResultImgFilePath(const char *path, const char *imgName) { 344 | std::string filePath; 345 | filePath.append(path).append(imgName).append("-result.jpg"); 346 | return filePath; 347 | } 348 | 349 | std::string getDebugImgFilePath(const char *path, const char *imgName, int i, const char *tag) { 350 | std::string filePath; 351 | filePath.append(path).append(imgName).append(tag).append(std::to_string(i)).append(".jpg"); 352 | return filePath; 353 | } -------------------------------------------------------------------------------- /src/getopt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * getopt - POSIX like getopt for Windows console Application 3 | * 4 | * win-c - Windows Console Library 5 | * Copyright (c) 2015 Koji Takami 6 | * Released under the MIT license 7 | * https://github.com/takamin/win-c/blob/master/LICENSE 8 | */ 9 | #include 10 | #include 11 | #include "getopt.h" 12 | 13 | char *optarg = 0; 14 | int optind = 1; 15 | int opterr = 1; 16 | int optopt = 0; 17 | 18 | int postpone_count = 0; 19 | int nextchar = 0; 20 | 21 | static void postpone(int argc, char *const argv[], int index) { 22 | char **nc_argv = (char **) argv; 23 | char *p = nc_argv[index]; 24 | int j = index; 25 | for (; j < argc - 1; j++) { 26 | nc_argv[j] = nc_argv[j + 1]; 27 | } 28 | nc_argv[argc - 1] = p; 29 | } 30 | 31 | static int postpone_noopt(int argc, char *const argv[], int index) { 32 | int i = index; 33 | for (; i < argc; i++) { 34 | if (*(argv[i]) == '-') { 35 | postpone(argc, argv, index); 36 | return 1; 37 | } 38 | } 39 | return 0; 40 | } 41 | 42 | static int _getopt_(int argc, char *const argv[], 43 | const char *optstring, 44 | const struct option *longopts, int *longindex) { 45 | while (1) { 46 | int c; 47 | const char *optptr = 0; 48 | if (optind >= argc - postpone_count) { 49 | c = 0; 50 | optarg = 0; 51 | break; 52 | } 53 | c = *(argv[optind] + nextchar); 54 | if (c == '\0') { 55 | nextchar = 0; 56 | ++optind; 57 | continue; 58 | } 59 | if (nextchar == 0) { 60 | if (optstring[0] != '+' && optstring[0] != '-') { 61 | while (c != '-') { 62 | /* postpone non-opt parameter */ 63 | if (!postpone_noopt(argc, argv, optind)) { 64 | break; /* all args are non-opt param */ 65 | } 66 | ++postpone_count; 67 | c = *argv[optind]; 68 | } 69 | } 70 | if (c != '-') { 71 | if (optstring[0] == '-') { 72 | optarg = argv[optind]; 73 | nextchar = 0; 74 | ++optind; 75 | return 1; 76 | } 77 | break; 78 | } else { 79 | if (strcmp(argv[optind], "--") == 0) { 80 | optind++; 81 | break; 82 | } 83 | ++nextchar; 84 | if (longopts != 0 && *(argv[optind] + 1) == '-') { 85 | char const *spec_long = argv[optind] + 2; 86 | char const *pos_eq = strchr(spec_long, '='); 87 | int spec_len = (pos_eq == NULL ? strlen(spec_long) : pos_eq - spec_long); 88 | int index_search = 0; 89 | int index_found = -1; 90 | const struct option *optdef = 0; 91 | while (longopts->name != 0) { 92 | if (strncmp(spec_long, longopts->name, spec_len) == 0) { 93 | if (optdef != 0) { 94 | if (opterr) { 95 | fprintf(stderr, "ambiguous option: %s\n", spec_long); 96 | } 97 | return '?'; 98 | } 99 | optdef = longopts; 100 | index_found = index_search; 101 | } 102 | longopts++; 103 | index_search++; 104 | } 105 | if (optdef == 0) { 106 | if (opterr) { 107 | fprintf(stderr, "no such a option: %s\n", spec_long); 108 | } 109 | return '?'; 110 | } 111 | switch (optdef->has_arg) { 112 | case no_argument: 113 | optarg = 0; 114 | if (pos_eq != 0) { 115 | if (opterr) { 116 | fprintf(stderr, "no argument for %s\n", optdef->name); 117 | } 118 | return '?'; 119 | } 120 | break; 121 | case required_argument: 122 | if (pos_eq == NULL) { 123 | ++optind; 124 | optarg = argv[optind]; 125 | } else { 126 | optarg = (char *) pos_eq + 1; 127 | } 128 | break; 129 | } 130 | ++optind; 131 | nextchar = 0; 132 | if (longindex != 0) { 133 | *longindex = index_found; 134 | } 135 | if (optdef->flag != 0) { 136 | *optdef->flag = optdef->val; 137 | return 0; 138 | } 139 | return optdef->val; 140 | } 141 | continue; 142 | } 143 | } 144 | optptr = strchr(optstring, c); 145 | if (optptr == NULL) { 146 | optopt = c; 147 | if (opterr) { 148 | fprintf(stderr, 149 | "%s: invalid option -- %c\n", 150 | argv[0], c); 151 | } 152 | ++nextchar; 153 | return '?'; 154 | } 155 | if (*(optptr + 1) != ':') { 156 | nextchar++; 157 | if (*(argv[optind] + nextchar) == '\0') { 158 | ++optind; 159 | nextchar = 0; 160 | } 161 | optarg = 0; 162 | } else { 163 | nextchar++; 164 | if (*(argv[optind] + nextchar) != '\0') { 165 | optarg = argv[optind] + nextchar; 166 | } else { 167 | ++optind; 168 | if (optind < argc - postpone_count) { 169 | optarg = argv[optind]; 170 | } else { 171 | optopt = c; 172 | if (opterr) { 173 | fprintf(stderr, 174 | "%s: option requires an argument -- %c\n", 175 | argv[0], c); 176 | } 177 | if (optstring[0] == ':' || 178 | (optstring[0] == '-' || optstring[0] == '+') && 179 | optstring[1] == ':') { 180 | c = ':'; 181 | } else { 182 | c = '?'; 183 | } 184 | } 185 | } 186 | ++optind; 187 | nextchar = 0; 188 | } 189 | return c; 190 | } 191 | 192 | /* end of option analysis */ 193 | 194 | /* fix the order of non-opt params to original */ 195 | while ((argc - optind - postpone_count) > 0) { 196 | postpone(argc, argv, optind); 197 | ++postpone_count; 198 | } 199 | 200 | nextchar = 0; 201 | postpone_count = 0; 202 | return -1; 203 | } 204 | 205 | int getopt(int argc, char *const argv[], 206 | const char *optstring) { 207 | return _getopt_(argc, argv, optstring, 0, 0); 208 | } 209 | 210 | int getopt_long(int argc, char *const argv[], 211 | const char *optstring, 212 | const struct option *longopts, int *longindex) { 213 | return _getopt_(argc, argv, optstring, longopts, longindex); 214 | } 215 | /******************************************************** 216 | int getopt_long_only(int argc, char* const argv[], 217 | const char* optstring, 218 | const struct option* longopts, int* longindex) 219 | { 220 | return -1; 221 | } 222 | ********************************************************/ 223 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #ifndef __JNI__ 2 | #include 3 | #include 4 | #include "main.h" 5 | #include "version.h" 6 | #include "OcrLite.h" 7 | #include "OcrUtils.h" 8 | 9 | void printHelp(FILE *out, char *argv0) { 10 | fprintf(out, " ------- Usage -------\n"); 11 | fprintf(out, "%s %s", argv0, usageMsg); 12 | fprintf(out, " ------- Required Parameters -------\n"); 13 | fprintf(out, "%s", requiredMsg); 14 | fprintf(out, " ------- Optional Parameters -------\n"); 15 | fprintf(out, "%s", optionalMsg); 16 | fprintf(out, " ------- Other Parameters -------\n"); 17 | fprintf(out, "%s", otherMsg); 18 | fprintf(out, " ------- Examples -------\n"); 19 | fprintf(out, example1Msg, argv0); 20 | fprintf(out, example2Msg, argv0); 21 | } 22 | 23 | int main(int argc, char **argv) { 24 | if (argc <= 1) { 25 | printHelp(stderr, argv[0]); 26 | return -1; 27 | } 28 | std::string modelsDir, modelDetPath, modelClsPath, modelRecPath, keysPath; 29 | std::string imgPath, imgDir, imgName; 30 | int numThread = 4; 31 | int padding = 50; 32 | int maxSideLen = 1024; 33 | float boxScoreThresh = 0.6f; 34 | float boxThresh = 0.3f; 35 | float unClipRatio = 2.0f; 36 | bool doAngle = true; 37 | int flagDoAngle = 1; 38 | bool mostAngle = true; 39 | int flagMostAngle = 1; 40 | 41 | int opt; 42 | int optionIndex = 0; 43 | while ((opt = getopt_long(argc, argv, "d:1:2:3:4:i:t:p:s:b:o:u:a:A:v:h", long_options, &optionIndex)) != -1) { 44 | //printf("option(-%c)=%s\n", opt, optarg); 45 | switch (opt) { 46 | case 'd': 47 | modelsDir = optarg; 48 | printf("modelsPath=%s\n", modelsDir.c_str()); 49 | break; 50 | case '1': 51 | modelDetPath = modelsDir + "/" + optarg; 52 | printf("model dbnet path=%s\n", modelDetPath.c_str()); 53 | break; 54 | case '2': 55 | modelClsPath = modelsDir + "/" + optarg; 56 | printf("model angle path=%s\n", modelClsPath.c_str()); 57 | break; 58 | case '3': 59 | modelRecPath = modelsDir + "/" + optarg; 60 | printf("model crnn path=%s\n", modelRecPath.c_str()); 61 | break; 62 | case '4': 63 | keysPath = modelsDir + "/" + optarg; 64 | printf("keys path=%s\n", keysPath.c_str()); 65 | break; 66 | case 'i': 67 | imgPath.assign(optarg); 68 | imgDir.assign(imgPath.substr(0, imgPath.find_last_of('/') + 1)); 69 | imgName.assign(imgPath.substr(imgPath.find_last_of('/') + 1)); 70 | printf("imgDir=%s, imgName=%s\n", imgDir.c_str(), imgName.c_str()); 71 | break; 72 | case 't': 73 | numThread = (int) strtol(optarg, NULL, 10); 74 | //printf("numThread=%d\n", numThread); 75 | break; 76 | case 'p': 77 | padding = (int) strtol(optarg, NULL, 10); 78 | //printf("padding=%d\n", padding); 79 | break; 80 | case 's': 81 | maxSideLen = (int) strtol(optarg, NULL, 10); 82 | //printf("maxSideLen=%d\n", maxSideLen); 83 | break; 84 | case 'b': 85 | boxScoreThresh = strtof(optarg, NULL); 86 | //printf("boxScoreThresh=%f\n", boxScoreThresh); 87 | break; 88 | case 'o': 89 | boxThresh = strtof(optarg, NULL); 90 | //printf("boxThresh=%f\n", boxThresh); 91 | break; 92 | case 'u': 93 | unClipRatio = strtof(optarg, NULL); 94 | //printf("unClipRatio=%f\n", unClipRatio); 95 | break; 96 | case 'a': 97 | flagDoAngle = (int) strtol(optarg, NULL, 10); 98 | if (flagDoAngle == 0) { 99 | doAngle = false; 100 | } else { 101 | doAngle = true; 102 | } 103 | //printf("doAngle=%d\n", doAngle); 104 | break; 105 | case 'A': 106 | flagMostAngle = (int) strtol(optarg, NULL, 10); 107 | if (flagMostAngle == 0) { 108 | mostAngle = false; 109 | } else { 110 | mostAngle = true; 111 | } 112 | //printf("mostAngle=%d\n", mostAngle); 113 | break; 114 | case 'v': 115 | printf("%s\n", VERSION); 116 | return 0; 117 | case 'h': 118 | printHelp(stdout, argv[0]); 119 | return 0; 120 | default: 121 | printf("other option %c :%s\n", opt, optarg); 122 | } 123 | } 124 | if (modelDetPath.empty()) { 125 | modelDetPath = modelsDir + "/" + "dbnet.mnn"; 126 | } 127 | if (modelClsPath.empty()) { 128 | modelClsPath = modelsDir + "/" + "angle_net.mnn"; 129 | } 130 | if (modelRecPath.empty()) { 131 | modelRecPath = modelsDir + "/" + "crnn_lite_lstm.mnn"; 132 | } 133 | if (keysPath.empty()) { 134 | keysPath = modelsDir + "/" + "keys.txt"; 135 | } 136 | bool hasTargetImgFile = isFileExists(imgPath); 137 | if (!hasTargetImgFile) { 138 | fprintf(stderr, "Target image not found: %s\n", imgPath.c_str()); 139 | return -1; 140 | } 141 | bool hasModelDetFile = isFileExists(modelDetPath); 142 | if (!hasModelDetFile) { 143 | fprintf(stderr, "Model dbnet file not found: %s\n", modelDetPath.c_str()); 144 | return -1; 145 | } 146 | bool hasModelClsFile = isFileExists(modelClsPath); 147 | if (!hasModelClsFile) { 148 | fprintf(stderr, "Model angle file not found: %s\n", modelClsPath.c_str()); 149 | return -1; 150 | } 151 | bool hasModelRecFile = isFileExists(modelRecPath); 152 | if (!hasModelRecFile) { 153 | fprintf(stderr, "Model crnn file not found: %s\n", modelRecPath.c_str()); 154 | return -1; 155 | } 156 | bool hasKeysFile = isFileExists(keysPath); 157 | if (!hasKeysFile) { 158 | fprintf(stderr, "keys file not found: %s\n", keysPath.c_str()); 159 | return -1; 160 | } 161 | omp_set_num_threads(numThread); 162 | OcrLite ocrLite; 163 | ocrLite.setNumThread(numThread); 164 | ocrLite.initLogger( 165 | true,//isOutputConsole 166 | false,//isOutputPartImg 167 | true);//isOutputResultImg 168 | 169 | ocrLite.enableResultTxt(imgDir.c_str(), imgName.c_str()); 170 | ocrLite.Logger("=====Input Params=====\n"); 171 | ocrLite.Logger( 172 | "numThread(%d),padding(%d),maxSideLen(%d),boxScoreThresh(%f),boxThresh(%f),unClipRatio(%f),doAngle(%d),mostAngle(%d)\n", 173 | numThread, padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle); 174 | 175 | ocrLite.initModels(modelDetPath, modelClsPath, modelRecPath, keysPath); 176 | 177 | OcrResult result = ocrLite.detect(imgDir.c_str(), imgName.c_str(), padding, maxSideLen, 178 | boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle); 179 | ocrLite.Logger("%s\n", result.strRes.c_str()); 180 | return 0; 181 | } 182 | 183 | #endif -------------------------------------------------------------------------------- /valgrind-memcheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ## script for 内存泄露检查 3 | # ========== macOS ========== 4 | # https://github.com/LouisBrunner/valgrind-macos 5 | # brew tap LouisBrunner/valgrind 6 | # brew install --HEAD LouisBrunner/valgrind/valgrind 7 | # ========== linux ========== 8 | # https://www.valgrind.org/ 9 | # apt install valgrind 10 | 11 | NUM_THREADS=1 12 | 13 | set OMP_NUM_THREADS=$NUM_THREADS 14 | 15 | TARGET_IMG=images/1.jpg 16 | if [ ! -f "$TARGET_IMG" ]; then 17 | echo "找不到待识别的目标图片:${TARGET_IMG},请打开本文件并编辑TARGET_IMG" 18 | exit 19 | fi 20 | 21 | ##### run test on MacOS or Linux 22 | valgrind --tool=memcheck --leak-check=full --leak-resolution=med --track-origins=yes --vgdb=no --log-file=valgrind-memcheck.txt \ 23 | ./build/OcrLiteMnn --models models \ 24 | --det dbnet.mnn \ 25 | --cls angle_net.mnn \ 26 | --rec crnn_lite_lstm.mnn \ 27 | --keys keys.txt \ 28 | --image $TARGET_IMG \ 29 | --numThread $NUM_THREADS \ 30 | --padding 50 \ 31 | --maxSideLen 1024 \ 32 | --boxScoreThresh 0.6 \ 33 | --boxThresh 0.3 \ 34 | --unClipRatio 2.0 \ 35 | --doAngle 1 \ 36 | --mostAngle 1 37 | -------------------------------------------------------------------------------- /valgrind-memcheck.txt: -------------------------------------------------------------------------------- 1 | ==13885== Memcheck, a memory error detector 2 | ==13885== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. 3 | ==13885== Using Valgrind-3.17.0.GIT-lbmacos and LibVEX; rerun with -h for copyright info 4 | ==13885== Command: ./build/OcrLiteMnn --models models --det dbnet.mnn --cls angle_net.mnn --rec crnn_lite_lstm.mnn --keys keys.txt --image images/1.jpg --numThread 1 --padding 50 --maxSideLen 1024 --boxScoreThresh 0.6 --boxThresh 0.3 --unClipRatio 2.0 --doAngle 1 --mostAngle 1 5 | ==13885== Parent PID: 13884 6 | ==13885== 7 | --13885-- run: /usr/bin/dsymutil "./build/OcrLiteMnn" 8 | ==13885== Conditional jump or move depends on uninitialised value(s) 9 | ==13885== at 0x10028D8F3: _platform_memcmp (in /usr/local/Cellar/valgrind/HEAD-adaae87/lib/valgrind/vgpreload_memcheck-amd64-darwin.so) 10 | ==13885== by 0x1002FC6AD: MNN::GeometryComputer::Context::getCachedTensor(MNN::Tensor*) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 11 | ==13885== by 0x1002FBEDE: MNN::GeometryComputer::Context::getRasterCacheCreate(MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 12 | ==13885== by 0x100300380: MNN::GeometryComputerUtils::makeRaster(MNN::CommandBuffer const&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 13 | ==13885== by 0x1002FF378: MNN::GeometryComputerUtils::shapeComputeAndGeometryTransform(std::__1::vector >&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&, std::__1::shared_ptr, bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 14 | ==13885== by 0x1002B88BA: MNN::Pipeline::encode(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 15 | ==13885== by 0x1002E0B8A: MNN::Session::resize(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 16 | ==13885== by 0x1002A3826: MNN::Interpreter::createMultiPathSession(std::__1::vector > const&, std::__1::pair, std::__1::less, std::__1::allocator > > >, std::__1::shared_ptr > const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 17 | ==13885== by 0x1002A3ED1: MNN::Interpreter::createSession(MNN::ScheduleConfig const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 18 | ==13885== by 0x100018782: DbNet::initModel(std::__1::basic_string, std::__1::allocator > const&) (src/DbNet.cpp:21) 19 | ==13885== by 0x1000201DC: OcrLite::initModels(std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&) (src/OcrLite.cpp:36) 20 | ==13885== by 0x100063ED9: main (src/main.cpp:175) 21 | ==13885== Uninitialised value was created by a stack allocation 22 | ==13885== at 0x1002F5FFD: MNN::ConvertUtils::compute(MNN::Tensor*, MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 23 | ==13885== 24 | ==13885== Conditional jump or move depends on uninitialised value(s) 25 | ==13885== at 0x10028D924: _platform_memcmp (in /usr/local/Cellar/valgrind/HEAD-adaae87/lib/valgrind/vgpreload_memcheck-amd64-darwin.so) 26 | ==13885== by 0x1002FC6AD: MNN::GeometryComputer::Context::getCachedTensor(MNN::Tensor*) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 27 | ==13885== by 0x1002FBEDE: MNN::GeometryComputer::Context::getRasterCacheCreate(MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 28 | ==13885== by 0x100300380: MNN::GeometryComputerUtils::makeRaster(MNN::CommandBuffer const&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 29 | ==13885== by 0x1002FF378: MNN::GeometryComputerUtils::shapeComputeAndGeometryTransform(std::__1::vector >&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&, std::__1::shared_ptr, bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 30 | ==13885== by 0x1002B88BA: MNN::Pipeline::encode(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 31 | ==13885== by 0x1002E0B8A: MNN::Session::resize(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 32 | ==13885== by 0x1002A3826: MNN::Interpreter::createMultiPathSession(std::__1::vector > const&, std::__1::pair, std::__1::less, std::__1::allocator > > >, std::__1::shared_ptr > const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 33 | ==13885== by 0x1002A3ED1: MNN::Interpreter::createSession(MNN::ScheduleConfig const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 34 | ==13885== by 0x100018782: DbNet::initModel(std::__1::basic_string, std::__1::allocator > const&) (src/DbNet.cpp:21) 35 | ==13885== by 0x1000201DC: OcrLite::initModels(std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&) (src/OcrLite.cpp:36) 36 | ==13885== by 0x100063ED9: main (src/main.cpp:175) 37 | ==13885== Uninitialised value was created by a stack allocation 38 | ==13885== at 0x10032CA10: MNN::GeometryReshape::onCompute(MNN::Op const*, std::__1::vector > const&, std::__1::vector > const&, MNN::GeometryComputer::Context&, MNN::CommandBuffer&) const (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 39 | ==13885== 40 | ==13885== Conditional jump or move depends on uninitialised value(s) 41 | ==13885== at 0x1002FC6D2: MNN::GeometryComputer::Context::getCachedTensor(MNN::Tensor*) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 42 | ==13885== by 0x1002FBEDE: MNN::GeometryComputer::Context::getRasterCacheCreate(MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 43 | ==13885== by 0x100300380: MNN::GeometryComputerUtils::makeRaster(MNN::CommandBuffer const&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 44 | ==13885== by 0x1002FF378: MNN::GeometryComputerUtils::shapeComputeAndGeometryTransform(std::__1::vector >&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&, std::__1::shared_ptr, bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 45 | ==13885== by 0x1002B88BA: MNN::Pipeline::encode(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 46 | ==13885== by 0x1002E0B8A: MNN::Session::resize(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 47 | ==13885== by 0x1002A3826: MNN::Interpreter::createMultiPathSession(std::__1::vector > const&, std::__1::pair, std::__1::less, std::__1::allocator > > >, std::__1::shared_ptr > const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 48 | ==13885== by 0x1002A3ED1: MNN::Interpreter::createSession(MNN::ScheduleConfig const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 49 | ==13885== by 0x100018782: DbNet::initModel(std::__1::basic_string, std::__1::allocator > const&) (src/DbNet.cpp:21) 50 | ==13885== by 0x1000201DC: OcrLite::initModels(std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&) (src/OcrLite.cpp:36) 51 | ==13885== by 0x100063ED9: main (src/main.cpp:175) 52 | ==13885== Uninitialised value was created by a stack allocation 53 | ==13885== at 0x10032CA10: MNN::GeometryReshape::onCompute(MNN::Op const*, std::__1::vector > const&, std::__1::vector > const&, MNN::GeometryComputer::Context&, MNN::CommandBuffer&) const (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 54 | ==13885== 55 | ==13885== Conditional jump or move depends on uninitialised value(s) 56 | ==13885== at 0x10028D8F3: _platform_memcmp (in /usr/local/Cellar/valgrind/HEAD-adaae87/lib/valgrind/vgpreload_memcheck-amd64-darwin.so) 57 | ==13885== by 0x1002FC6AD: MNN::GeometryComputer::Context::getCachedTensor(MNN::Tensor*) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 58 | ==13885== by 0x1002FBEDE: MNN::GeometryComputer::Context::getRasterCacheCreate(MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 59 | ==13885== by 0x1002FBE3E: MNN::GeometryComputer::Context::getRasterCacheCreateRecurrse(MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 60 | ==13885== by 0x100300380: MNN::GeometryComputerUtils::makeRaster(MNN::CommandBuffer const&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 61 | ==13885== by 0x1002FF378: MNN::GeometryComputerUtils::shapeComputeAndGeometryTransform(std::__1::vector >&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&, std::__1::shared_ptr, bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 62 | ==13885== by 0x1002B88BA: MNN::Pipeline::encode(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 63 | ==13885== by 0x1002E0B8A: MNN::Session::resize(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 64 | ==13885== by 0x1002A3826: MNN::Interpreter::createMultiPathSession(std::__1::vector > const&, std::__1::pair, std::__1::less, std::__1::allocator > > >, std::__1::shared_ptr > const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 65 | ==13885== by 0x1002A3ED1: MNN::Interpreter::createSession(MNN::ScheduleConfig const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 66 | ==13885== by 0x100018782: DbNet::initModel(std::__1::basic_string, std::__1::allocator > const&) (src/DbNet.cpp:21) 67 | ==13885== by 0x1000201DC: OcrLite::initModels(std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&) (src/OcrLite.cpp:36) 68 | ==13885== Uninitialised value was created by a stack allocation 69 | ==13885== at 0x1002F5FFD: MNN::ConvertUtils::compute(MNN::Tensor*, MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 70 | ==13885== 71 | ==13885== Conditional jump or move depends on uninitialised value(s) 72 | ==13885== at 0x10028D924: _platform_memcmp (in /usr/local/Cellar/valgrind/HEAD-adaae87/lib/valgrind/vgpreload_memcheck-amd64-darwin.so) 73 | ==13885== by 0x1002FC6AD: MNN::GeometryComputer::Context::getCachedTensor(MNN::Tensor*) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 74 | ==13885== by 0x1002FBEDE: MNN::GeometryComputer::Context::getRasterCacheCreate(MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 75 | ==13885== by 0x1002FBE3E: MNN::GeometryComputer::Context::getRasterCacheCreateRecurrse(MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 76 | ==13885== by 0x100300380: MNN::GeometryComputerUtils::makeRaster(MNN::CommandBuffer const&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 77 | ==13885== by 0x1002FF378: MNN::GeometryComputerUtils::shapeComputeAndGeometryTransform(std::__1::vector >&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&, std::__1::shared_ptr, bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 78 | ==13885== by 0x1002B88BA: MNN::Pipeline::encode(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 79 | ==13885== by 0x1002E0B8A: MNN::Session::resize(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 80 | ==13885== by 0x1002A3826: MNN::Interpreter::createMultiPathSession(std::__1::vector > const&, std::__1::pair, std::__1::less, std::__1::allocator > > >, std::__1::shared_ptr > const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 81 | ==13885== by 0x1002A3ED1: MNN::Interpreter::createSession(MNN::ScheduleConfig const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 82 | ==13885== by 0x100018782: DbNet::initModel(std::__1::basic_string, std::__1::allocator > const&) (src/DbNet.cpp:21) 83 | ==13885== by 0x1000201DC: OcrLite::initModels(std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&) (src/OcrLite.cpp:36) 84 | ==13885== Uninitialised value was created by a stack allocation 85 | ==13885== at 0x1002F5FFD: MNN::ConvertUtils::compute(MNN::Tensor*, MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 86 | ==13885== 87 | ==13885== Conditional jump or move depends on uninitialised value(s) 88 | ==13885== at 0x1002FC6D2: MNN::GeometryComputer::Context::getCachedTensor(MNN::Tensor*) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 89 | ==13885== by 0x1002FBEDE: MNN::GeometryComputer::Context::getRasterCacheCreate(MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 90 | ==13885== by 0x1002FBE3E: MNN::GeometryComputer::Context::getRasterCacheCreateRecurrse(MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 91 | ==13885== by 0x100300380: MNN::GeometryComputerUtils::makeRaster(MNN::CommandBuffer const&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 92 | ==13885== by 0x1002FF378: MNN::GeometryComputerUtils::shapeComputeAndGeometryTransform(std::__1::vector >&, MNN::CommandBuffer&, MNN::GeometryComputer::Context&, std::__1::shared_ptr, bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 93 | ==13885== by 0x1002B88BA: MNN::Pipeline::encode(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 94 | ==13885== by 0x1002E0B8A: MNN::Session::resize(bool) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 95 | ==13885== by 0x1002A3826: MNN::Interpreter::createMultiPathSession(std::__1::vector > const&, std::__1::pair, std::__1::less, std::__1::allocator > > >, std::__1::shared_ptr > const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 96 | ==13885== by 0x1002A3ED1: MNN::Interpreter::createSession(MNN::ScheduleConfig const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 97 | ==13885== by 0x100018782: DbNet::initModel(std::__1::basic_string, std::__1::allocator > const&) (src/DbNet.cpp:21) 98 | ==13885== by 0x1000201DC: OcrLite::initModels(std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&, std::__1::basic_string, std::__1::allocator > const&) (src/OcrLite.cpp:36) 99 | ==13885== by 0x100063ED9: main (src/main.cpp:175) 100 | ==13885== Uninitialised value was created by a stack allocation 101 | ==13885== at 0x1002F5FFD: MNN::ConvertUtils::compute(MNN::Tensor*, MNN::Tensor*, MNN::CommandBuffer&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 102 | ==13885== 103 | UNKNOWN workq_ops option 1024 104 | ==13885== Thread 5: 105 | ==13885== Invalid read of size 4 106 | ==13885== at 0x103856C10: _pthread_wqthread_setup (in /usr/lib/system/libsystem_pthread.dylib) 107 | ==13885== by 0x103856942: _pthread_wqthread (in /usr/lib/system/libsystem_pthread.dylib) 108 | ==13885== by 0x103855B76: start_wqthread (in /usr/lib/system/libsystem_pthread.dylib) 109 | ==13885== Address 0x18 is not stack'd, malloc'd or (recently) free'd 110 | ==13885== 111 | ==13885== 112 | ==13885== Process terminating with default action of signal 11 (SIGSEGV) 113 | ==13885== Access not within mapped region at address 0x18 114 | ==13885== at 0x103856C10: _pthread_wqthread_setup (in /usr/lib/system/libsystem_pthread.dylib) 115 | ==13885== by 0x103856942: _pthread_wqthread (in /usr/lib/system/libsystem_pthread.dylib) 116 | ==13885== by 0x103855B76: start_wqthread (in /usr/lib/system/libsystem_pthread.dylib) 117 | ==13885== If you believe this happened as a result of a stack 118 | ==13885== overflow in your program's main thread (unlikely but 119 | ==13885== possible), you can try to increase the size of the 120 | ==13885== main thread stack using the --main-stacksize= flag. 121 | ==13885== The main thread stack size used in this run was 8388608. 122 | 123 | valgrind: m_scheduler/scheduler.c:1028 (void run_thread_for_a_while(HWord *, Int *, ThreadId, HWord, Bool)): Assertion 'VG_(in_generated_code) == False' failed. 124 | 125 | host stacktrace: 126 | ==13885== at 0x2580427BB: ??? 127 | ==13885== by 0x258042B2F: ??? 128 | ==13885== by 0x258042B12: ??? 129 | ==13885== by 0x2580B7478: ??? 130 | ==13885== by 0x2580B5547: ??? 131 | ==13885== by 0x2580C6695: ??? 132 | ==13885== by 0x2580C693D: ??? 133 | 134 | sched status: 135 | running_tid=2 136 | 137 | Thread 1: status = VgTs_Yielding (lwpid 771) 138 | ==13885== at 0x103841DF0: _platform_bzero$VARIANT$Haswell (in /usr/lib/system/libsystem_platform.dylib) 139 | ==13885== by 0x1003D31E5: std::__1::__function::__func > const&, std::__1::vector > const&)::$_0, std::__1::allocator > const&, std::__1::vector > const&)::$_0>, void (int)>::operator()(int&&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 140 | ==13885== by 0x1003D3906: std::__1::__function::__func > const&, std::__1::vector > const&)::$_1, std::__1::allocator > const&, std::__1::vector > const&)::$_1>, void (int)>::operator()(int&&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 141 | ==13885== by 0x1003B71B6: MNN::ThreadPool::enqueueInternal(std::__1::pair, int>&&, int) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 142 | ==13885== by 0x1003D2BD6: MNN::ConvolutionTiledExecutorBasic::onExecute(std::__1::vector > const&, std::__1::vector > const&) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 143 | ==13885== by 0x1002B97F5: MNN::Pipeline::execute() (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 144 | ==13885== by 0x1002E09C7: MNN::Session::run() const (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 145 | ==13885== by 0x100019678: DbNet::getTextBoxes(cv::Mat&, ScaleParam&, float, float, float) (src/DbNet.cpp:81) 146 | ==13885== by 0x100020AB4: OcrLite::detect(char const*, char const*, cv::Mat&, cv::Rect_&, ScaleParam&, float, float, float, bool, bool) (src/OcrLite.cpp:122) 147 | ==13885== by 0x100020783: OcrLite::detect(char const*, char const*, int, int, float, float, float, bool, bool) (src/OcrLite.cpp:87) 148 | ==13885== by 0x100063F5C: main (src/main.cpp:177) 149 | client stack range: [0x10427D000 0x104A7CFFF] client SP: 0x104A7A9F0 150 | valgrind stack range: [0x700006BB6000 0x700006CB5FFF] top usage: 11648 of 1048576 151 | 152 | Thread 2: status = VgTs_Runnable (lwpid 3331) 153 | ==13885== at 0x103855B68: start_wqthread (in /usr/lib/system/libsystem_pthread.dylib) 154 | client stack range: ??????? client SP: 0x70000E135000 155 | valgrind stack range: [0x70000D4FF000 0x70000D5FEFFF] top usage: 11232 of 1048576 156 | 157 | Thread 3: status = VgTs_WaitSys syscall unix:305 (lwpid 2819) 158 | ==13885== at 0x1037F8882: __psynch_cvwait (in /usr/lib/system/libsystem_kernel.dylib) 159 | ==13885== by 0x10385A424: _pthread_cond_wait (in /usr/lib/system/libsystem_pthread.dylib) 160 | ==13885== by 0x10328D591: std::__1::condition_variable::wait(std::__1::unique_lock&) (in /usr/lib/libc++.1.dylib) 161 | ==13885== by 0x1003B7654: void* std::__1::__thread_proxy >, MNN::ThreadPool::ThreadPool(int)::$_1> >(void*) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 162 | ==13885== by 0x10385A108: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib) 163 | ==13885== by 0x103855B8A: thread_start (in /usr/lib/system/libsystem_pthread.dylib) 164 | client stack range: [0x70000DD1E000 0x70000DD9DFFF] client SP: 0x70000DD9DEB8 165 | valgrind stack range: [0x70000D603000 0x70000D702FFF] top usage: 3160 of 1048576 166 | 167 | Thread 4: status = VgTs_WaitSys syscall unix:305 (lwpid 3843) 168 | ==13885== at 0x1037F8882: __psynch_cvwait (in /usr/lib/system/libsystem_kernel.dylib) 169 | ==13885== by 0x10385A424: _pthread_cond_wait (in /usr/lib/system/libsystem_pthread.dylib) 170 | ==13885== by 0x10328D591: std::__1::condition_variable::wait(std::__1::unique_lock&) (in /usr/lib/libc++.1.dylib) 171 | ==13885== by 0x1003B7654: void* std::__1::__thread_proxy >, MNN::ThreadPool::ThreadPool(int)::$_1> >(void*) (in /Users/xiaomi/java/OcrLiteMnn/mnn-shared/macos/libMNN.dylib) 172 | ==13885== by 0x10385A108: _pthread_start (in /usr/lib/system/libsystem_pthread.dylib) 173 | ==13885== by 0x103855B8A: thread_start (in /usr/lib/system/libsystem_pthread.dylib) 174 | client stack range: [0x70000DDA1000 0x70000DE20FFF] client SP: 0x70000DE20EB8 175 | valgrind stack range: [0x70000D707000 0x70000D806FFF] top usage: 2912 of 1048576 176 | 177 | Thread 5: status = VgTs_Yielding (lwpid 2575) 178 | ==13885== at 0x103856C10: _pthread_wqthread_setup (in /usr/lib/system/libsystem_pthread.dylib) 179 | ==13885== by 0x103856942: _pthread_wqthread (in /usr/lib/system/libsystem_pthread.dylib) 180 | ==13885== by 0x103855B76: start_wqthread (in /usr/lib/system/libsystem_pthread.dylib) 181 | client stack range: ??????? client SP: 0x70000DFABF90 182 | valgrind stack range: [0x700011B14000 0x700011C13FFF] top usage: 9680 of 1048576 183 | 184 | 185 | Note: see also the FAQ in the source distribution. 186 | It contains workarounds to several common problems. 187 | In particular, if Valgrind aborted or crashed after 188 | identifying problems in your program, there's a good chance 189 | that fixing those problems will prevent Valgrind aborting or 190 | crashing, especially if it happened in m_mallocfree.c. 191 | 192 | If that doesn't help, please report this bug to: www.valgrind.org 193 | 194 | In the bug report, send all the above text, the valgrind 195 | version, and what OS and version you are using. Thanks. 196 | 197 | --------------------------------------------------------------------------------