├── .github
└── workflows
│ └── android.yml
├── .gitignore
├── BUILD.md
├── INSTRUCTIONS.md
├── LICENSE
├── OcrLibrary
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── benjaminwan
│ │ └── ocrlibrary
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── angle_net.onnx
│ │ ├── crnn_lite_lstm.onnx
│ │ ├── dbnet.onnx
│ │ └── keys.txt
│ ├── cpp
│ │ ├── CMakeLists.txt
│ │ ├── include
│ │ │ ├── AngleNet.h
│ │ │ ├── BitmapUtils.h
│ │ │ ├── CrnnNet.h
│ │ │ ├── DbNet.h
│ │ │ ├── OcrLite.h
│ │ │ ├── OcrResultUtils.h
│ │ │ ├── OcrStruct.h
│ │ │ ├── OcrUtils.h
│ │ │ └── clipper.hpp
│ │ └── src
│ │ │ ├── AngleNet.cpp
│ │ │ ├── BitmapUtils.cpp
│ │ │ ├── CrnnNet.cpp
│ │ │ ├── DbNet.cpp
│ │ │ ├── OcrLite.cpp
│ │ │ ├── OcrResultUtils.cpp
│ │ │ ├── OcrUtils.cpp
│ │ │ ├── clipper.cpp
│ │ │ └── main.cpp
│ └── java
│ │ └── com
│ │ └── benjaminwan
│ │ └── ocrlibrary
│ │ ├── OcrEngine.kt
│ │ └── OcrResult.kt
│ └── test
│ └── java
│ └── com
│ └── benjaminwan
│ └── ocrlibrary
│ └── ExampleUnitTest.kt
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── benjaminwan
│ │ └── ocr
│ │ └── onnx
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── benjaminwan
│ │ │ └── ocr
│ │ │ └── onnx
│ │ │ ├── CameraActivity.kt
│ │ │ ├── GalleryActivity.kt
│ │ │ ├── IdCardFrontActivity.kt
│ │ │ ├── ImeiActivity.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── PlateActivity.kt
│ │ │ ├── app
│ │ │ └── App.kt
│ │ │ ├── dialog
│ │ │ ├── BaseDialog.kt
│ │ │ ├── DebugDialog.kt
│ │ │ └── TextResultDialog.kt
│ │ │ ├── models
│ │ │ ├── DbNetTimeItemView.kt
│ │ │ ├── DebugItemView.kt
│ │ │ └── IdCardFront.kt
│ │ │ └── utils
│ │ │ ├── BitmapUtils.kt
│ │ │ ├── ClipboardUtils.kt
│ │ │ ├── DecimalFormatUtils.kt
│ │ │ ├── IdCardMatchUtils.kt
│ │ │ ├── ImeiMatchUtils.kt
│ │ │ ├── PlateMatchUtils.kt
│ │ │ ├── RecyclerViewUtils.kt
│ │ │ ├── SoftInputUtils.kt
│ │ │ └── ToastUtils.kt
│ └── res
│ │ ├── anim
│ │ ├── window_close_down.xml
│ │ ├── window_close_up.xml
│ │ ├── window_enter_anim.xml
│ │ ├── window_exit_anim.xml
│ │ ├── window_fade_in.xml
│ │ ├── window_fade_out.xml
│ │ ├── window_show_down.xml
│ │ └── window_show_up.xml
│ │ ├── color
│ │ ├── btn_blue3_to_blue5.xml
│ │ ├── btn_blue5_to_blue7.xml
│ │ ├── btn_grey3_to_grey5.xml
│ │ ├── btn_grey5_to_grey7.xml
│ │ ├── btn_pink5_to_pink7.xml
│ │ └── btn_white_to_grey.xml
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── bg_blue3_to_blue5.xml
│ │ ├── bg_blue5_to_blue7.xml
│ │ ├── bg_edittext.xml
│ │ ├── bg_edittext_focused.xml
│ │ ├── bg_edittext_normal.xml
│ │ ├── bg_transparent_to_transparent_half.xml
│ │ ├── ic_close.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_loading.xml
│ │ ├── ic_ocr.xml
│ │ └── loading_anim.xml
│ │ ├── layout
│ │ ├── activity_camera.xml
│ │ ├── activity_gallery.xml
│ │ ├── activity_idcard_front.xml
│ │ ├── activity_imei.xml
│ │ ├── activity_main.xml
│ │ ├── activity_plate.xml
│ │ ├── dialog_debug.xml
│ │ ├── dialog_text_result.xml
│ │ ├── rv_dbnet_time_item.xml
│ │ ├── rv_debug_item_content.xml
│ │ └── rv_debug_view_item.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── colors_material.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── benjaminwan
│ └── ocr
│ └── onnx
│ └── ExampleUnitTest.kt
├── appjava
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── benjaminwan
│ │ └── ocr
│ │ └── java
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── benjaminwan
│ │ │ └── ocr
│ │ │ └── java
│ │ │ ├── MainActivity.java
│ │ │ ├── app
│ │ │ └── App.java
│ │ │ └── utils
│ │ │ ├── BitmapUtils.java
│ │ │ └── ToastUtils.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_loading.xml
│ │ └── loading_anim.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-anydpi-v33
│ │ └── ic_launcher.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── benjaminwan
│ └── ocr
│ └── java
│ └── ExampleUnitTest.java
├── build.gradle
├── capture
├── detect_IMEI.gif
├── detect_id_card.gif
└── detect_plate.gif
├── common-aar
└── IdCardView-1.0.aar
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── keystore
└── ocrlite.keystore
├── scripts
├── build-onnxruntime-android.sh
├── build-opencv3-android.sh
└── build-opencv3-static-android.sh
└── settings.gradle
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | tags:
7 | - '*.*.*'
8 |
9 | jobs:
10 | build-and-release:
11 | runs-on: ubuntu-latest
12 |
13 | env:
14 | ONNX_VERSION: 1.14.0
15 | ONNX_PKG_NAME: onnxruntime-1.14.0-android-shared
16 |
17 | steps:
18 | # 检出代码
19 | - uses: actions/checkout@v3
20 |
21 | - name: Unshallow
22 | run: git fetch --prune --unshallow
23 |
24 | # 设置JDK版本
25 | - name: set up JDK 11
26 | uses: actions/setup-java@v3
27 | with:
28 | java-version: '11'
29 | distribution: 'adopt'
30 |
31 | # 缓存依赖项
32 | # https://docs.github.com/cn/actions/guides/building-and-testing-java-with-gradle#caching-dependencies
33 | - name: Cache Gradle packages
34 | uses: actions/cache@v3
35 | with:
36 | path: |
37 | ~/.gradle/caches
38 | ~/.gradle/wrapper
39 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
40 | restore-keys: |
41 | ${{ runner.os }}-gradle-
42 |
43 | # 下载opencv-mobile-3.4.15-android.zip并解压到OcrLibrary/src
44 | - name: Download opencv-mobile-3.4.15-android.zip
45 | run: |
46 | wget https://github.com/benjaminwan/OcrLiteAndroidNcnn/releases/download/1.0.0.20201007/opencv-mobile-3.4.15-android.7z -O opencv-mobile-3.4.15-android.7z
47 | 7z x opencv-mobile-3.4.15-android.7z -aoa
48 | mv opencv-mobile-3.4.15-android/sdk OcrLibrary/src
49 |
50 | # 下载onnxruntime并解压到OcrLibrary/src/main
51 | - name: Download onnxruntime
52 | run: |
53 | wget https://github.com/RapidAI/OnnxruntimeBuilder/releases/download/${{ env.ONNX_VERSION }}/${{ env.ONNX_PKG_NAME }}.7z -O ${{ env.ONNX_PKG_NAME }}.7z
54 | 7z x ${{ env.ONNX_PKG_NAME }}.7z -aoa
55 | mv onnxruntime-shared OcrLibrary/src/main
56 |
57 | # Assemble Release apk
58 | - name: Build with Gradle
59 | run: chmod +x gradlew &&./gradlew assembleRelease
60 |
61 | # 清除部分Gradle缓存
62 | - name: Cleanup Gradle Cache
63 | run: |
64 | rm -f ~/.gradle/caches/modules-2/modules-2.lock
65 | rm -f ~/.gradle/caches/modules-2/gc.properties
66 |
67 | # 上传apk 到action(需要定制)
68 | # https://github.com/marketplace/actions/upload-a-build-artifact
69 | - name: Upload APK/AAR
70 | uses: actions/upload-artifact@v3
71 | with:
72 | name: outputs
73 | path: |
74 | app/build/outputs/apk/release/*.apk
75 | OcrLibrary/build/outputs/aar/*-release.aar
76 |
77 | # 获取 aar路径(需要定制)
78 | - name: Get aar path
79 | id: aar-path
80 | run: |
81 | path=$(find OcrLibrary/build/outputs/aar -name '*release.aar' -type f | head -1)
82 | echo "::set-output name=path::$path"
83 |
84 | # 获取demo apk路径
85 | - name: Get apk path
86 | id: apk-path
87 | run: |
88 | path=$(find app/build/outputs/apk/release -name '*.apk' -type f | head -1)
89 | echo "::set-output name=path::$path"
90 |
91 | # 获取apk版本号
92 | # https://github.com/marketplace/actions/apk-info-action
93 | - name: Get apk info
94 | id: apk-info
95 | uses: hkusu/apk-info-action@v1
96 | with:
97 | apk-path: ${{ steps.apk-path.outputs.path }}
98 |
99 | # 获取指定时区的时间
100 | # https://github.com/marketplace/actions/get-time-action
101 | - name: Get Time
102 | id: time
103 | uses: JantHsueh/get-time-action@master
104 | with:
105 | timeZone: 8
106 |
107 | # 获取git log 从 previousTag 到 lastTag
108 | - name: Get git log
109 | id: git-log
110 | run: |
111 | previousTag=$(git describe --abbrev=0 --tags `git rev-list --tags --skip=1 --max-count=1`)
112 | lastTag=$(git describe --abbrev=0 --tags)
113 | echo "previousTag:$previousTag ~ lastTag:$lastTag"
114 | log=$(git log $previousTag..$lastTag --pretty=format:'- %cd %an: %s\n' --date=format:'%Y-%m-%d %H:%M:%S')
115 | echo "$log"
116 | echo "::set-output name=log::"$log""
117 |
118 | # 显示信息(需要定制)
119 | - name: Show info
120 | if: always()
121 | run: |
122 | echo '${{ steps.aar-path.outputs.path }}'
123 | echo '${{ steps.apk-path.outputs.path }}'
124 | echo '${{ steps.apk-info.outputs.result }}' # get apk info success or failure
125 | echo '${{ steps.time.outputs.time }}'
126 | echo '${{ steps.git-log.outputs.log }}'
127 | echo '${{ steps.apk-info.outputs.application-name }}'
128 | echo '${{ steps.apk-info.outputs.application-id }}'
129 | echo '${{ steps.apk-info.outputs.version-code }}'
130 | echo '${{ steps.apk-info.outputs.version-name }}'
131 | echo '${{ steps.apk-info.outputs.min-sdk-version }}'
132 | echo '${{ steps.apk-info.outputs.target-sdk-version }}'
133 | echo '${{ steps.apk-info.outputs.compile-sdk-version }}'
134 | echo '${{ steps.apk-info.outputs.uses-permissions }}'
135 | echo '${{ steps.apk-info.outputs.debuggable }}'
136 | echo '${{ steps.apk-info.outputs.allow-backup }}'
137 | echo '${{ steps.apk-info.outputs.supports-rtl }}'
138 | echo '${{ steps.apk-info.outputs.file-size }}'
139 | echo '${{ steps.apk-info.outputs.readable-file-size }}'
140 |
141 | # 向钉钉发送消息
142 | # https://github.com/marketplace/actions/web-request-action
143 | - name: dingtalk
144 | uses: satak/webrequest-action@master
145 | with:
146 | url: ${{ secrets.DINGTALK_WEBHOOK }}
147 | method: POST
148 | payload: '{"msgtype": "text", "text": {"content": "版本更新: ${{ steps.apk-info.outputs.application-name }}-版本号: ${{ steps.apk-info.outputs.version-name }} \n 编译时间: ${{ steps.time.outputs.time }} \n 距上个正式版的更新记录: \n${{ steps.git-log.outputs.log }}"}}'
149 | headers: '{"Content-Type": "application/json"}'
150 |
151 | # 创建Changelog文件 triggered by git tag push
152 | - name: Generate Changelog
153 | if: startsWith(github.ref, 'refs/tags/')
154 | run: |
155 | echo -e '${{ steps.git-log.outputs.log }}' > Release.txt
156 |
157 | # Cat Changelog triggered by git tag push
158 | - name: Cat Changelog
159 | if: startsWith(github.ref, 'refs/tags/')
160 | run: |
161 | cat Release.txt
162 |
163 | # 创建Release triggered by git tag push(需要定制)
164 | # https://github.com/marketplace/actions/gh-release
165 | - name: Release
166 | uses: softprops/action-gh-release@v1
167 | if: startsWith(github.ref, 'refs/tags/')
168 | with:
169 | body_path: Release.txt
170 | draft: false
171 | files: |
172 | ${{ steps.apk-path.outputs.path }}
173 | ${{ steps.aar-path.outputs.path }}
174 | env:
175 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
176 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | #*.apk
3 | *.ap_
4 | *.aab
5 |
6 | # Files for the ART/Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Android Studio Navigation editor temp files
31 | .navigation/
32 |
33 | # Android Studio captures folder
34 | captures/
35 |
36 | # IntelliJ
37 | *.iml
38 | .idea
39 | .idea/workspace.xml
40 | .idea/tasks.xml
41 | .idea/gradle.xml
42 | .idea/assetWizardSettings.xml
43 | .idea/dictionaries
44 | .idea/libraries
45 | .idea/caches
46 | .idea/modules.xml
47 | .idea/caches/build_file_checksums.ser
48 | .idea/encodings.xml
49 | .idea/vcs.xml
50 | .idea/misc.xml
51 | .idea/codeStyles
52 |
53 | # Keystore files
54 | # Uncomment the following lines if you do not want to check your keystore files in.
55 | #*.jks
56 | #*.keystore
57 |
58 | # External native build folder generated in Android Studio 2.2 and later
59 | .externalNativeBuild
60 |
61 | # Google Services (e.g. APIs or Firebase)
62 | # google-services.json
63 |
64 | # Freeline
65 | freeline.py
66 | freeline/
67 | freeline_project_description.json
68 |
69 | # fastlane
70 | fastlane/report.xml
71 | fastlane/Preview.html
72 | fastlane/screenshots
73 | fastlane/test_output
74 | fastlane/readme.md
75 |
76 | # Version control
77 | vcs.xml
78 |
79 | # lint
80 | lint/intermediates/
81 | lint/generated/
82 | lint/outputs/
83 | lint/tmp/
84 | # lint/reports/
85 |
86 | .DS_Store
87 | ~*.xlsx
88 | other/~*.xlsx
--------------------------------------------------------------------------------
/BUILD.md:
--------------------------------------------------------------------------------
1 | # 编译说明
2 |
3 | 1. AndroidStudio 2022.1.1或以上;
4 | 2. NDK下载,在SDK Tools中下载,版本选最新版;
5 | 3. cmake 3.22.1,在SDK Tools中下载;
6 | 4. 原始模型来自https://github.com/DayBreak-u/chineseocr_lite/tree/onnx/models。
7 | 5. 模型目录结构为
8 |
9 | ```
10 | OcrLiteAndroidOnnx/OcrLibrary/src/main/assets
11 | ├── angle_net.onnx
12 | ├── crnn_lite_lstm.onnx
13 | ├── dbnet.onnx
14 | └── keys.txt
15 | ```
16 |
17 | 5.下载opencv-mobile-3.4.15-android.7z,[下载地址](https://gitee.com/benjaminwan/ocr-lite-android-ncnn/attach_files/843219/download/opencv-mobile-3.4.15-android.7z)
18 | 解压后目录结构为
19 |
20 | ```
21 | OcrLiteAndroidNcnn/OcrLibrary/src/sdk
22 | └── native
23 | ├── jni
24 | └── staticlibs
25 | ```
26 |
27 | 6. onnxruntime-1.14.0-android-shared.7z,[下载地址](https://github.com/RapidAI/OnnxruntimeBuilder/releases/tag/1.14.0)
28 |
29 | * 解压后目录结构为
30 |
31 | ```
32 | OcrLiteAndroidOnnx/OcrLibrary/src/main/onnxruntime-shared
33 | ├── OnnxRuntimeWrapper.cmake
34 | ├── arm64-v8a
35 | ├── armeabi-v7a
36 | ├── include
37 | ├── x86
38 | └── x86_64
39 | ```
40 |
41 | ### 编译Release包
42 |
43 | * mac/linux使用命令编译```./gradlew assembleRelease```
44 | * win使用命令编译```gradlew.bat assembleRelease```
45 | * 输出apk文件在app/build/outputs/apk
46 |
47 | ### 重新编译
48 |
49 | 删除项目根目录下的如下缓存文件夹
50 |
51 | ```
52 | .idea
53 | build
54 | app/build
55 | OcrLibrary/.cxx
56 | OcrLibrary/build
57 | ```
58 |
--------------------------------------------------------------------------------
/INSTRUCTIONS.md:
--------------------------------------------------------------------------------
1 | # 使用说明
2 |
3 | 1. 从Release下载OcrLibrary-版本-release.aar,放到项目的app/libs路径
4 |
5 | 1. 编辑app/build.gradle
6 |
7 | ```groovy
8 | dependencies {
9 | implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
10 | }
11 | ```
12 |
13 | 2. 实例化OcrEngine
14 |
15 | ```
16 | OcrEngine ocrEngine = new OcrEngine(this.getApplicationContext());
17 | ```
18 |
19 | 3. 调用detect方法
20 |
21 | ```
22 | OcrResult result = ocrEngine.detect(img, boxImg, reSize);
23 | ```
--------------------------------------------------------------------------------
/OcrLibrary/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /.cxx
3 | /src/main/sharedLibs
4 | /src/sdk
5 | /src/main/onnx
6 | /src/main/onnxruntime-shared
--------------------------------------------------------------------------------
/OcrLibrary/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-parcelize'
5 | }
6 |
7 | android {
8 | compileSdkVersion compile_sdk_version
9 |
10 | defaultConfig {
11 | minSdkVersion min_sdk_version
12 | targetSdk target_sdk_version
13 | versionCode project_version_code
14 | versionName project_version_name
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | consumerProguardFiles "consumer-rules.pro"
18 |
19 | externalNativeBuild {
20 | cmake {
21 | abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64', 'x86'
22 | }
23 | }
24 | }
25 |
26 | buildTypes {
27 | release {
28 | minifyEnabled false
29 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
30 | }
31 | }
32 | compileOptions {
33 | sourceCompatibility JavaVersion.VERSION_1_8
34 | targetCompatibility JavaVersion.VERSION_1_8
35 | }
36 | kotlinOptions {
37 | jvmTarget = '1.8'
38 | }
39 | externalNativeBuild {
40 | cmake {
41 | path "src/main/cpp/CMakeLists.txt"
42 | version "3.22.1"
43 | }
44 | }
45 |
46 | libraryVariants.all {
47 | variant ->
48 | variant.outputs.all {
49 | outputFileName = "${project.name}-${defaultConfig.versionName}-${variant.buildType.name}.aar"
50 | }
51 | }
52 | }
53 |
54 | dependencies {
55 | implementation fileTree(dir: "libs", include: ["*.jar"])
56 | //Test
57 | testImplementation 'junit:junit:4.13.2'
58 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
59 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
60 | //Kotlin
61 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
62 | //Android
63 | implementation 'androidx.core:core-ktx:1.9.0'
64 | implementation 'androidx.appcompat:appcompat:1.6.1'
65 | }
--------------------------------------------------------------------------------
/OcrLibrary/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/OcrLibrary/consumer-rules.pro
--------------------------------------------------------------------------------
/OcrLibrary/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/OcrLibrary/src/androidTest/java/com/benjaminwan/ocrlibrary/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocrlibrary
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.benjaminwan.ocrlibrary.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/OcrLibrary/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | /
5 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/assets/angle_net.onnx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/OcrLibrary/src/main/assets/angle_net.onnx
--------------------------------------------------------------------------------
/OcrLibrary/src/main/assets/crnn_lite_lstm.onnx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/OcrLibrary/src/main/assets/crnn_lite_lstm.onnx
--------------------------------------------------------------------------------
/OcrLibrary/src/main/assets/dbnet.onnx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/OcrLibrary/src/main/assets/dbnet.onnx
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.22.1)
2 |
3 | # OnnxRuntime
4 | include(${CMAKE_CURRENT_SOURCE_DIR}/../onnxruntime-shared/OnnxRuntimeWrapper.cmake)
5 | find_package(OnnxRuntime REQUIRED)
6 | if (OnnxRuntime_FOUND)
7 | message(STATUS "OnnxRuntime_LIBS: ${OnnxRuntime_LIBS}")
8 | message(STATUS "OnnxRuntime_INCLUDE_DIRS: ${OnnxRuntime_INCLUDE_DIRS}")
9 | else ()
10 | message(FATAL_ERROR "onnxruntime Not Found!")
11 | endif (OnnxRuntime_FOUND)
12 |
13 | ## opencv 库
14 | set(OpenCV_DIR "${CMAKE_SOURCE_DIR}/../../sdk/native/jni")
15 | find_package(OpenCV REQUIRED)
16 | if (OpenCV_FOUND)
17 | message(STATUS "OpenCV_LIBS: ${OpenCV_LIBS}")
18 | message(STATUS "OpenCV_INCLUDE_DIRS: ${OpenCV_INCLUDE_DIRS}")
19 | else ()
20 | message(FATAL_ERROR "opencv Not Found!")
21 | endif (OpenCV_FOUND)
22 |
23 | # openmp
24 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fopenmp")
25 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
26 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fopenmp")
27 |
28 | if (DEFINED ANDROID_NDK_MAJOR AND ${ANDROID_NDK_MAJOR} GREATER 20)
29 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-openmp")
30 | endif ()
31 |
32 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer -fstrict-aliasing -ffast-math")
33 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fomit-frame-pointer -fstrict-aliasing -ffast-math")
34 |
35 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
36 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden")
37 |
38 | # disable rtti and exceptions
39 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
40 |
41 | include_directories(include)
42 | file(GLOB OCR_SRC src/*.cpp)
43 | set(OCR_COMPILE_CODE ${OCR_SRC})
44 |
45 | add_library(OcrLite SHARED ${OCR_COMPILE_CODE})
46 |
47 | find_library( # Sets the name of the path variable.
48 | log-lib
49 | log)
50 |
51 | find_library(
52 | android-lib
53 | android
54 | )
55 |
56 | target_link_libraries(
57 | OcrLite
58 | ${OnnxRuntime_LIBS}
59 | ${OpenCV_LIBS}
60 | android
61 | z
62 | ${log-lib}
63 | ${android-lib}
64 | jnigraphics)
65 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/include/AngleNet.h:
--------------------------------------------------------------------------------
1 | #ifndef __OCR_ANGLENET_H__
2 | #define __OCR_ANGLENET_H__
3 |
4 | #include "OcrStruct.h"
5 | #include "onnxruntime/core/session/onnxruntime_cxx_api.h"
6 | #include
7 | #include
8 | #include
9 |
10 | class AngleNet {
11 | public:
12 | AngleNet();
13 |
14 | ~AngleNet();
15 |
16 | void setNumThread(int numOfThread);
17 |
18 | bool initModel(AAssetManager *mgr);
19 |
20 | std::vector getAngles(std::vector &partImgs, bool doAngle, bool mostAngle);
21 |
22 | private:
23 | Ort::Session *session;
24 | Ort::Env ortEnv = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "AngleNet");
25 | Ort::SessionOptions sessionOptions = Ort::SessionOptions();
26 | int numThread = 0;
27 |
28 | std::vector inputNamesPtr;
29 | std::vector outputNamesPtr;
30 |
31 | const float meanValues[3] = {127.5, 127.5, 127.5};
32 | const float normValues[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5};
33 | const int angleCols = 2;
34 | const int dstWidth = 192;
35 | const int dstHeight = 32;
36 |
37 | Angle getAngle(cv::Mat &src);
38 | };
39 |
40 |
41 | #endif //__OCR_ANGLENET_H__
42 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/include/BitmapUtils.h:
--------------------------------------------------------------------------------
1 | #ifndef __OCR_LITE_BITMAP_UTILS_H__
2 | #define __OCR_LITE_BITMAP_UTILS_H__
3 |
4 | #include
5 | #include "opencv2/core.hpp"
6 | #include "opencv2/imgproc.hpp"
7 |
8 | void bitmapToMat(JNIEnv *env, jobject bitmap, cv::Mat &dst);
9 |
10 | void matToBitmap(JNIEnv *env, cv::Mat &src, jobject bitmap);
11 |
12 |
13 | #endif //__OCR_LITE_BITMAP_UTILS_H__
14 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/include/CrnnNet.h:
--------------------------------------------------------------------------------
1 | #ifndef __OCR_CRNNNET_H__
2 | #define __OCR_CRNNNET_H__
3 |
4 | #include "OcrStruct.h"
5 | #include "onnxruntime/core/session/onnxruntime_cxx_api.h"
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | class CrnnNet {
12 | public:
13 |
14 | CrnnNet();
15 |
16 | ~CrnnNet();
17 |
18 | void setNumThread(int numOfThread);
19 |
20 | bool initModel(AAssetManager *mgr);
21 |
22 | std::vector getTextLines(std::vector &partImg);
23 |
24 | private:
25 | Ort::Session *session;
26 | Ort::Env ortEnv = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "CrnnNet");
27 | Ort::SessionOptions sessionOptions = Ort::SessionOptions();
28 | int numThread = 0;
29 |
30 | std::vector inputNamesPtr;
31 | std::vector outputNamesPtr;
32 |
33 | const float meanValues[3] = {127.5, 127.5, 127.5};
34 | const float normValues[3] = {1.0 / 127.5, 1.0 / 127.5, 1.0 / 127.5};
35 | const int dstHeight = 32;
36 | const int crnnCols = 5531;
37 |
38 | std::vector keys;
39 |
40 | TextLine scoreToTextLine(const float *srcData, int h, int w);
41 |
42 | TextLine getTextLine(cv::Mat &src);
43 | };
44 |
45 |
46 | #endif //__OCR_CRNNNET_H__
47 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/include/DbNet.h:
--------------------------------------------------------------------------------
1 | #ifndef __OCR_DBNET_H__
2 | #define __OCR_DBNET_H__
3 |
4 | #include "OcrStruct.h"
5 | #include "onnxruntime/core/session/onnxruntime_cxx_api.h"
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | class DbNet {
12 | public:
13 | DbNet();
14 |
15 | ~DbNet();
16 |
17 | void setNumThread(int numOfThread);
18 |
19 | bool initModel(AAssetManager *mgr);
20 |
21 | std::vector getTextBoxes(cv::Mat &src, ScaleParam &s, float boxScoreThresh,
22 | float boxThresh, float unClipRatio);
23 |
24 | private:
25 | Ort::Session *session;
26 | Ort::Env ortEnv = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "DbNet");
27 | Ort::SessionOptions sessionOptions = Ort::SessionOptions();
28 | int numThread = 0;
29 |
30 | std::vector inputNamesPtr;
31 | std::vector outputNamesPtr;
32 |
33 | const float meanValues[3] = {0.485 * 255, 0.456 * 255, 0.406 * 255};
34 | const float normValues[3] = {1.0 / 0.229 / 255.0, 1.0 / 0.224 / 255.0, 1.0 / 0.225 / 255.0};
35 | };
36 |
37 |
38 | #endif //__OCR_DBNET_H__
39 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/include/OcrLite.h:
--------------------------------------------------------------------------------
1 | #ifndef __OCR_LITE_H__
2 | #define __OCR_LITE_H__
3 |
4 | #include "opencv2/core.hpp"
5 | #include "onnxruntime/core/session/onnxruntime_cxx_api.h"
6 | #include "OcrStruct.h"
7 | #include "DbNet.h"
8 | #include "AngleNet.h"
9 | #include "CrnnNet.h"
10 |
11 | class OcrLite {
12 | public:
13 | OcrLite();
14 |
15 | ~OcrLite();
16 |
17 | void init(JNIEnv *jniEnv, jobject assetManager, int numOfThread);
18 |
19 | //void initLogger(bool isDebug);
20 |
21 | //void Logger(const char *format, ...);
22 |
23 | OcrResult detect(cv::Mat &src, cv::Rect &originRect, ScaleParam &scale,
24 | float boxScoreThresh, float boxThresh,
25 | float unClipRatio, bool doAngle, bool mostAngle);
26 |
27 | private:
28 | bool isLOG = true;
29 | DbNet dbNet;
30 | AngleNet angleNet;
31 | CrnnNet crnnNet;
32 | };
33 |
34 |
35 | #endif
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/include/OcrResultUtils.h:
--------------------------------------------------------------------------------
1 | #ifndef __OCR_RESULT_UTILS_H__
2 | #define __OCR_RESULT_UTILS_H__
3 |
4 | #include
5 | #include "OcrStruct.h"
6 |
7 | class OcrResultUtils {
8 | public:
9 | OcrResultUtils(JNIEnv *env, OcrResult &ocrResult, jobject boxImg);
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 |
35 |
36 | #endif //__OCR_RESULT_UTILS_H__
37 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/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 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/include/OcrUtils.h:
--------------------------------------------------------------------------------
1 | #ifndef __OCR_UTILS_H__
2 | #define __OCR_UTILS_H__
3 |
4 | #include
5 | #include "OcrStruct.h"
6 | #include "onnxruntime/core/session/onnxruntime_cxx_api.h"
7 | #include
8 | #include
9 | #include
10 |
11 | #define TAG "OcrLite"
12 | #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,TAG,__VA_ARGS__)
13 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__)
14 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
15 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG,__VA_ARGS__)
16 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
17 |
18 | #define __ENABLE_CONSOLE__ false
19 | #define Logger(format, ...) {\
20 | if(__ENABLE_CONSOLE__) LOGI(format,##__VA_ARGS__); \
21 | }
22 |
23 | template
24 | static std::unique_ptr makeUnique(Ts &&... params) {
25 | return std::unique_ptr(new T(std::forward(params)...));
26 | }
27 |
28 | template
29 | static double getMean(std::vector &input) {
30 | auto sum = accumulate(input.begin(), input.end(), 0.0);
31 | return sum / input.size();
32 | }
33 |
34 | template
35 | static double getStdev(std::vector &input, double mean) {
36 | if (input.size() <= 1) return 0;
37 | double accum = 0.0;
38 | for_each(input.begin(), input.end(), [&](const double d) {
39 | accum += (d - mean) * (d - mean);
40 | });
41 | double stdev = sqrt(accum / (input.size() - 1));
42 | return stdev;
43 | }
44 |
45 | double getCurrentTime();
46 |
47 | ScaleParam getScaleParam(cv::Mat &src, const float scale);
48 |
49 | ScaleParam getScaleParam(cv::Mat &src, const int targetSize);
50 |
51 | cv::RotatedRect getPartRect(std::vector &box, float scaleWidth, float scaleHeight);
52 |
53 | int getThickness(cv::Mat &boxImg);
54 |
55 | void drawTextBox(cv::Mat &boxImg, cv::RotatedRect &rect, int thickness);
56 |
57 | void drawTextBox(cv::Mat &boxImg, const std::vector &box, int thickness);
58 |
59 | void drawTextBoxes(cv::Mat &boxImg, std::vector &textBoxes, int thickness);
60 |
61 | cv::Mat matRotateClockWise180(cv::Mat src);
62 |
63 | cv::Mat matRotateClockWise90(cv::Mat src);
64 |
65 | cv::Mat getRotateCropImage(const cv::Mat &src, std::vector box);
66 |
67 | cv::Mat adjustTargetImg(cv::Mat &src, int dstWidth, int dstHeight);
68 |
69 | int getMiniBoxes(std::vector &inVec,
70 | std::vector &minBoxVec,
71 | float &minEdgeSize, float &allEdgeSize
72 | );
73 |
74 | float boxScoreFast(cv::Mat &mapmat, std::vector &_box);
75 |
76 | void unClip(std::vector &minBoxVec, float allEdgeSize, std::vector &outVec,
77 | float unClipRatio);
78 |
79 | std::vector
80 | substractMeanNormalize(cv::Mat &src, const float *meanVals, const float *normVals);
81 |
82 | std::vector getAngleIndexes(std::vector &angles);
83 |
84 | std::vector getInputNames(Ort::Session *session);
85 |
86 | std::vector getOutputNames(Ort::Session *session);
87 |
88 | void *getModelDataFromAssets(AAssetManager *mgr, const char *modelName, int &size);
89 |
90 | #endif //__OCR_UTILS_H__
91 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/src/AngleNet.cpp:
--------------------------------------------------------------------------------
1 | #include "AngleNet.h"
2 | #include "OcrUtils.h"
3 | #include
4 |
5 | AngleNet::AngleNet() {}
6 |
7 | AngleNet::~AngleNet() {
8 | delete session;
9 | inputNamesPtr.clear();
10 | outputNamesPtr.clear();
11 | }
12 |
13 | void AngleNet::setNumThread(int numOfThread) {
14 | numThread = numOfThread;
15 | //===session options===
16 | // Sets the number of threads used to parallelize the execution within nodes
17 | // A value of 0 means ORT will pick a default
18 | sessionOptions.SetIntraOpNumThreads(numThread);
19 | //set OMP_NUM_THREADS=16
20 |
21 | // Sets the number of threads used to parallelize the execution of the graph (across nodes)
22 | // If sequential execution is enabled this value is ignored
23 | // A value of 0 means ORT will pick a default
24 | sessionOptions.SetInterOpNumThreads(numThread);
25 |
26 | // Sets graph optimization level
27 | // ORT_DISABLE_ALL -> To disable all optimizations
28 | // ORT_ENABLE_BASIC -> To enable basic optimizations (Such as redundant node removals)
29 | // ORT_ENABLE_EXTENDED -> To enable extended optimizations (Includes level 1 + more complex optimizations like node fusions)
30 | // ORT_ENABLE_ALL -> To Enable All possible opitmizations
31 | sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
32 | }
33 |
34 | bool AngleNet::initModel(AAssetManager *mgr) {
35 | int dbModelDataLength = 0;
36 | void *dbModelData = getModelDataFromAssets(mgr, "angle_net.onnx", dbModelDataLength);
37 | session = new Ort::Session(ortEnv, dbModelData, dbModelDataLength,
38 | sessionOptions);
39 | free(dbModelData);
40 | inputNamesPtr = getInputNames(session);
41 | outputNamesPtr = getOutputNames(session);
42 | return true;
43 | }
44 |
45 | Angle scoreToAngle(const float *srcData, int w) {
46 | int angleIndex = 0;
47 | float maxValue = -1000.0f;
48 | for (int i = 0; i < w; i++) {
49 | if (i == 0)maxValue = srcData[i];
50 | else if (srcData[i] > maxValue) {
51 | angleIndex = i;
52 | maxValue = srcData[i];
53 | }
54 | }
55 | return {angleIndex, maxValue};
56 | }
57 |
58 | Angle AngleNet::getAngle(cv::Mat &src) {
59 |
60 | std::vector inputTensorValues = substractMeanNormalize(src, meanValues, normValues);
61 |
62 | std::array inputShape{1, src.channels(), src.rows, src.cols};
63 |
64 | auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
65 |
66 | Ort::Value inputTensor = Ort::Value::CreateTensor(memoryInfo, inputTensorValues.data(),
67 | inputTensorValues.size(), inputShape.data(),
68 | inputShape.size());
69 | assert(inputTensor.IsTensor());
70 | std::vector inputNames = {inputNamesPtr.data()->get()};
71 | std::vector outputNames = {outputNamesPtr.data()->get()};
72 | auto outputTensor = session->Run(Ort::RunOptions{nullptr}, inputNames.data(), &inputTensor,
73 | inputNames.size(), outputNames.data(), outputNames.size());
74 |
75 | assert(outputTensor.size() == 1 && outputTensor.front().IsTensor());
76 |
77 | size_t count = outputTensor.front().GetTensorTypeAndShapeInfo().GetElementCount();
78 | size_t rows = count / angleCols;
79 | float *floatArray = outputTensor.front().GetTensorMutableData();
80 |
81 | cv::Mat score(rows, angleCols, CV_32FC1);
82 | memcpy(score.data, floatArray, rows * angleCols * sizeof(float));
83 |
84 | return scoreToAngle((float *) score.data, angleCols);
85 | }
86 |
87 | std::vector AngleNet::getAngles(std::vector &partImgs,
88 | bool doAngle, bool mostAngle) {
89 | int size = partImgs.size();
90 | std::vector angles(size);
91 | if (doAngle) {
92 | for (int i = 0; i < size; ++i) {
93 | double startAngle = getCurrentTime();
94 | auto angleImg = adjustTargetImg(partImgs[i], dstWidth, dstHeight);
95 | Angle angle = getAngle(angleImg);
96 | double endAngle = getCurrentTime();
97 | angle.time = endAngle - startAngle;
98 | angles[i] = angle;
99 | }
100 | } else {
101 | for (int i = 0; i < size; ++i) {
102 | angles[i] = Angle{-1, 0.f};
103 | }
104 | }
105 | //Most Possible AngleIndex
106 | if (doAngle && mostAngle) {
107 | auto angleIndexes = getAngleIndexes(angles);
108 | double sum = std::accumulate(angleIndexes.begin(), angleIndexes.end(), 0.0);
109 | double halfPercent = angles.size() / 2.0f;
110 | int mostAngleIndex;
111 | if (sum < halfPercent) {//all angle set to 0
112 | mostAngleIndex = 0;
113 | } else {//all angle set to 1
114 | mostAngleIndex = 1;
115 | }
116 | Logger("Set All Angle to mostAngleIndex(%d)", mostAngleIndex);
117 | for (int i = 0; i < angles.size(); ++i) {
118 | Angle angle = angles[i];
119 | angle.index = mostAngleIndex;
120 | angles.at(i) = angle;
121 | }
122 | }
123 |
124 | return angles;
125 | }
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/src/BitmapUtils.cpp:
--------------------------------------------------------------------------------
1 | #include "BitmapUtils.h"
2 | #include
3 | #include
4 |
5 | using namespace cv;
6 |
7 | void bitmapToMat(JNIEnv *env, jobject bitmap, Mat &dst) {
8 | AndroidBitmapInfo info;
9 | void *pixels = 0;
10 |
11 | try {
12 | LOGI("nBitmapToMat");
13 | CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
14 | CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
15 | info.format == ANDROID_BITMAP_FORMAT_RGB_565);
16 | CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
17 | CV_Assert(pixels);
18 | dst.create(info.height, info.width, CV_8UC4);
19 | if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
20 | LOGI("nBitmapToMat: RGBA_8888 -> CV_8UC4");
21 | Mat tmp(info.height, info.width, CV_8UC4, pixels);
22 | //if (needUnPremultiplyAlpha) cvtColor(tmp, dst, COLOR_mRGBA2RGBA);
23 | //else
24 | tmp.copyTo(dst);
25 | } else {
26 | // info.format == ANDROID_BITMAP_FORMAT_RGB_565
27 | LOGI("nBitmapToMat: RGB_565 -> CV_8UC4");
28 | Mat tmp(info.height, info.width, CV_8UC2, pixels);
29 | cvtColor(tmp, dst, COLOR_BGR5652RGBA);
30 | }
31 | AndroidBitmap_unlockPixels(env, bitmap);
32 | return;
33 | } /*catch (const cv::Exception &e) {
34 | AndroidBitmap_unlockPixels(env, bitmap);
35 | LOGE("nBitmapToMat caught cv::Exception: %s", e.what());
36 | jclass je = env->FindClass("java/lang/Exception");
37 | if (!je) je = env->FindClass("java/lang/Exception");
38 | env->ThrowNew(je, e.what());
39 | return;
40 | }*/ catch (...) {
41 | AndroidBitmap_unlockPixels(env, bitmap);
42 | LOGE("nBitmapToMat caught unknown exception (...)");
43 | jclass je = env->FindClass("java/lang/Exception");
44 | env->ThrowNew(je, "Unknown exception in JNI code {nBitmapToMat}");
45 | return;
46 | }
47 | }
48 |
49 | void matToBitmap(JNIEnv *env, cv::Mat &src, jobject bitmap) {
50 | AndroidBitmapInfo info;
51 | void *pixels = 0;
52 |
53 | try {
54 | LOGI("nMatToBitmap");
55 | CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
56 | CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
57 | info.format == ANDROID_BITMAP_FORMAT_RGB_565);
58 | CV_Assert(src.dims == 2 && info.height == (uint32_t) src.rows &&
59 | info.width == (uint32_t) src.cols);
60 | CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4);
61 | CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
62 | CV_Assert(pixels);
63 | if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
64 | Mat tmp(info.height, info.width, CV_8UC4, pixels);
65 | if (src.type() == CV_8UC1) {
66 | LOGI("nMatToBitmap: CV_8UC1 -> RGBA_8888");
67 | cvtColor(src, tmp, COLOR_GRAY2RGBA);
68 | } else if (src.type() == CV_8UC3) {
69 | LOGI("nMatToBitmap: CV_8UC3 -> RGBA_8888");
70 | cvtColor(src, tmp, COLOR_RGB2RGBA);
71 | } else if (src.type() == CV_8UC4) {
72 | LOGI("nMatToBitmap: CV_8UC4 -> RGBA_8888");
73 | //if (needPremultiplyAlpha) cvtColor(src, tmp, COLOR_RGBA2mRGBA);
74 | //else
75 | src.copyTo(tmp);
76 | }
77 | } else {
78 | // info.format == ANDROID_BITMAP_FORMAT_RGB_565
79 | Mat tmp(info.height, info.width, CV_8UC2, pixels);
80 | if (src.type() == CV_8UC1) {
81 | LOGI("nMatToBitmap: CV_8UC1 -> RGB_565");
82 | cvtColor(src, tmp, COLOR_GRAY2BGR565);
83 | } else if (src.type() == CV_8UC3) {
84 | LOGI("nMatToBitmap: CV_8UC3 -> RGB_565");
85 | cvtColor(src, tmp, COLOR_RGB2BGR565);
86 | } else if (src.type() == CV_8UC4) {
87 | LOGI("nMatToBitmap: CV_8UC4 -> RGB_565");
88 | cvtColor(src, tmp, COLOR_RGBA2BGR565);
89 | }
90 | }
91 | AndroidBitmap_unlockPixels(env, bitmap);
92 | return;
93 | } /*catch (const cv::Exception &e) {
94 | AndroidBitmap_unlockPixels(env, bitmap);
95 | LOGE("nMatToBitmap caught cv::Exception: %s", e.what());
96 | jclass je = env->FindClass("java/lang/Exception");
97 | if (!je) je = env->FindClass("java/lang/Exception");
98 | env->ThrowNew(je, e.what());
99 | return;
100 | }*/ catch (...) {
101 | AndroidBitmap_unlockPixels(env, bitmap);
102 | LOGE("nMatToBitmap caught unknown exception (...)");
103 | jclass je = env->FindClass("java/lang/Exception");
104 | env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
105 | return;
106 | }
107 | }
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/src/DbNet.cpp:
--------------------------------------------------------------------------------
1 | #include "DbNet.h"
2 | #include "OcrUtils.h"
3 |
4 | DbNet::DbNet() {}
5 |
6 | DbNet::~DbNet() {
7 | delete session;
8 | inputNamesPtr.clear();
9 | outputNamesPtr.clear();
10 | }
11 |
12 | void DbNet::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 | // Sets the number of threads used to parallelize the execution of the graph (across nodes)
21 | // If sequential execution is enabled this value is ignored
22 | // A value of 0 means ORT will pick a default
23 | sessionOptions.SetInterOpNumThreads(numThread);
24 |
25 | // Sets graph optimization level
26 | // ORT_DISABLE_ALL -> To disable all optimizations
27 | // ORT_ENABLE_BASIC -> To enable basic optimizations (Such as redundant node removals)
28 | // ORT_ENABLE_EXTENDED -> To enable extended optimizations (Includes level 1 + more complex optimizations like node fusions)
29 | // ORT_ENABLE_ALL -> To Enable All possible opitmizations
30 | sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
31 | }
32 |
33 | bool DbNet::initModel(AAssetManager *mgr) {
34 | int dbModelDataLength = 0;
35 | void *dbModelData = getModelDataFromAssets(mgr, "dbnet.onnx", dbModelDataLength);
36 | session = new Ort::Session(ortEnv, dbModelData, dbModelDataLength, sessionOptions);
37 | free(dbModelData);
38 | inputNamesPtr = getInputNames(session);
39 | outputNamesPtr = getOutputNames(session);
40 | return true;
41 | }
42 |
43 | std::vector
44 | DbNet::getTextBoxes(cv::Mat &src, ScaleParam &s, float boxScoreThresh, float boxThresh,
45 | float unClipRatio) {
46 | float minArea = 3.0f;
47 | cv::Mat srcResize;
48 | resize(src, srcResize, cv::Size(s.dstWidth, s.dstHeight));
49 | std::vector inputTensorValues = substractMeanNormalize(srcResize, meanValues,
50 | normValues);
51 |
52 | std::array inputShape{1, srcResize.channels(), srcResize.rows, srcResize.cols};
53 |
54 | auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
55 |
56 | Ort::Value inputTensor = Ort::Value::CreateTensor(memoryInfo, inputTensorValues.data(),
57 | inputTensorValues.size(),
58 | inputShape.data(),
59 | inputShape.size());
60 | assert(inputTensor.IsTensor());
61 | std::vector inputNames = {inputNamesPtr.data()->get()};
62 | std::vector outputNames = {outputNamesPtr.data()->get()};
63 | auto outputTensor = session->Run(Ort::RunOptions{nullptr}, inputNames.data(), &inputTensor,
64 | inputNames.size(), outputNames.data(), outputNames.size());
65 |
66 | assert(outputTensor.size() == 1 && outputTensor.front().IsTensor());
67 |
68 | float *floatArray = outputTensor.front().GetTensorMutableData();
69 |
70 | cv::Mat fMapMat(srcResize.rows, srcResize.cols, CV_32FC1);
71 | memcpy(fMapMat.data, floatArray, srcResize.rows * srcResize.cols * sizeof(float));
72 |
73 | std::vector rsBoxes;
74 | cv::Mat norfMapMat;
75 | norfMapMat = fMapMat > boxThresh;
76 | rsBoxes.clear();
77 | std::vector> contours;
78 | findContours(norfMapMat, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
79 | for (int i = 0; i < contours.size(); ++i) {
80 | std::vector minBox;
81 | float minEdgeSize, allEdgeSize;
82 | getMiniBoxes(contours[i], minBox, minEdgeSize, allEdgeSize);
83 |
84 | if (minEdgeSize < minArea)
85 | continue;
86 | float score = boxScoreFast(fMapMat, contours[i]);
87 |
88 | if (score < boxScoreThresh)
89 | continue;
90 | //---use clipper start---
91 | std::vector newbox;
92 | unClip(minBox, allEdgeSize, newbox, unClipRatio);
93 |
94 | getMiniBoxes(newbox, minBox, minEdgeSize, allEdgeSize);
95 |
96 | if (minEdgeSize < minArea + 2)
97 | continue;
98 | //---use clipper end---
99 |
100 | for (int j = 0; j < minBox.size(); ++j) {
101 | minBox[j].x = (minBox[j].x / s.ratioWidth);
102 | minBox[j].x = (std::min)((std::max)(minBox[j].x, 0), s.srcWidth);
103 |
104 | minBox[j].y = (minBox[j].y / s.ratioHeight);
105 | minBox[j].y = (std::min)((std::max)(minBox[j].y, 0), s.srcHeight);
106 | }
107 |
108 | rsBoxes.emplace_back(TextBox{minBox, score});
109 | }
110 | reverse(rsBoxes.begin(), rsBoxes.end());
111 | return rsBoxes;
112 | }
113 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/src/OcrLite.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "OcrLite.h"
4 | #include "OcrUtils.h"
5 |
6 | OcrLite::OcrLite() {}
7 |
8 | OcrLite::~OcrLite() {}
9 |
10 | void OcrLite::init(JNIEnv *jniEnv, jobject assetManager, int numThread) {
11 | AAssetManager *mgr = AAssetManager_fromJava(jniEnv, assetManager);
12 | if (mgr == NULL) {
13 | LOGE(" %s", "AAssetManager==NULL");
14 | }
15 |
16 | Logger("--- Init DbNet ---\n");
17 | dbNet.setNumThread(numThread);
18 | dbNet.initModel(mgr);
19 |
20 | Logger("--- Init AngleNet ---\n");
21 | angleNet.setNumThread(numThread);
22 | angleNet.initModel(mgr);
23 |
24 | Logger("--- Init CrnnNet ---\n");
25 | crnnNet.setNumThread(numThread);
26 | crnnNet.initModel(mgr);
27 |
28 | LOGI("初始化完成!");
29 | }
30 |
31 | /*void OcrLite::initLogger(bool isDebug) {
32 | isLOG = isDebug;
33 | }
34 |
35 | void OcrLite::Logger(const char *format, ...) {
36 | if (!isLOG) return;
37 | char *buffer = (char *) malloc(8192);
38 | va_list args;
39 | va_start(args, format);
40 | vsprintf(buffer, format, args);
41 | va_end(args);
42 | if (isLOG) LOGI("%s", buffer);
43 | free(buffer);
44 | }*/
45 |
46 | std::vector getPartImages(cv::Mat &src, std::vector &textBoxes) {
47 | std::vector partImages;
48 | for (int i = 0; i < textBoxes.size(); ++i) {
49 | cv::Mat partImg = getRotateCropImage(src, textBoxes[i].boxPoint);
50 | partImages.emplace_back(partImg);
51 | }
52 | return partImages;
53 | }
54 |
55 | OcrResult OcrLite::detect(cv::Mat &src, cv::Rect &originRect, ScaleParam &scale,
56 | float boxScoreThresh, float boxThresh,
57 | float unClipRatio, bool doAngle, bool mostAngle) {
58 |
59 | cv::Mat textBoxPaddingImg = src.clone();
60 | int thickness = getThickness(src);
61 |
62 | Logger("=====Start detect=====");
63 | Logger("ScaleParam(sw:%d,sh:%d,dw:%d,dh:%d,%f,%f)", scale.srcWidth, scale.srcHeight,
64 | scale.dstWidth, scale.dstHeight,
65 | scale.ratioWidth, scale.ratioHeight);
66 |
67 | Logger("---------- step: dbNet getTextBoxes ----------");
68 | double startTime = getCurrentTime();
69 | std::vector textBoxes = dbNet.getTextBoxes(src, scale, boxScoreThresh, boxThresh,
70 | unClipRatio);
71 | Logger("TextBoxesSize(%ld)", textBoxes.size());
72 | double endDbNetTime = getCurrentTime();
73 | double dbNetTime = endDbNetTime - startTime;
74 | Logger("dbNetTime(%fms)", dbNetTime);
75 |
76 | for (int i = 0; i < textBoxes.size(); ++i) {
77 | Logger("TextBox[%d][score(%f),[x: %d, y: %d], [x: %d, y: %d], [x: %d, y: %d], [x: %d, y: %d]]",
78 | i,
79 | textBoxes[i].score,
80 | textBoxes[i].boxPoint[0].x, textBoxes[i].boxPoint[0].y,
81 | textBoxes[i].boxPoint[1].x, textBoxes[i].boxPoint[1].y,
82 | textBoxes[i].boxPoint[2].x, textBoxes[i].boxPoint[2].y,
83 | textBoxes[i].boxPoint[3].x, textBoxes[i].boxPoint[3].y);
84 | }
85 |
86 | Logger("---------- step: drawTextBoxes ----------");
87 | drawTextBoxes(textBoxPaddingImg, textBoxes, thickness);
88 |
89 | //---------- getPartImages ----------
90 | std::vector partImages = getPartImages(src, textBoxes);
91 |
92 | Logger("---------- step: angleNet getAngles ----------");
93 | std::vector angles;
94 | angles = angleNet.getAngles(partImages, doAngle, mostAngle);
95 |
96 | //Log Angles
97 | for (int i = 0; i < angles.size(); ++i) {
98 | Logger("angle[%d][index(%d), score(%f), time(%fms)]", i, angles[i].index, angles[i].score,
99 | angles[i].time);
100 | }
101 |
102 | //Rotate partImgs
103 | for (int i = 0; i < partImages.size(); ++i) {
104 | if (angles[i].index == 0) {
105 | partImages.at(i) = matRotateClockWise180(partImages[i]);
106 | }
107 | }
108 |
109 | Logger("---------- step: crnnNet getTextLine ----------");
110 | std::vector textLines = crnnNet.getTextLines(partImages);
111 | //Log TextLines
112 | for (int i = 0; i < textLines.size(); ++i) {
113 | Logger("textLine[%d](%s)", i, textLines[i].text.c_str());
114 | std::ostringstream txtScores;
115 | for (int s = 0; s < textLines[i].charScores.size(); ++s) {
116 | if (s == 0) {
117 | txtScores << textLines[i].charScores[s];
118 | } else {
119 | txtScores << " ," << textLines[i].charScores[s];
120 | }
121 | }
122 | Logger("textScores[%d]{%s}", i, std::string(txtScores.str()).c_str());
123 | Logger("crnnTime[%d](%fms)", i, textLines[i].time);
124 | }
125 |
126 | std::vector textBlocks;
127 | for (int i = 0; i < textLines.size(); ++i) {
128 | std::vector boxPoint = std::vector(4);
129 | int padding = originRect.x;//padding conversion
130 | boxPoint[0] = cv::Point(textBoxes[i].boxPoint[0].x - padding,
131 | textBoxes[i].boxPoint[0].y - padding);
132 | boxPoint[1] = cv::Point(textBoxes[i].boxPoint[1].x - padding,
133 | textBoxes[i].boxPoint[1].y - padding);
134 | boxPoint[2] = cv::Point(textBoxes[i].boxPoint[2].x - padding,
135 | textBoxes[i].boxPoint[2].y - padding);
136 | boxPoint[3] = cv::Point(textBoxes[i].boxPoint[3].x - padding,
137 | textBoxes[i].boxPoint[3].y - padding);
138 | TextBlock textBlock{boxPoint, textBoxes[i].score, angles[i].index, angles[i].score,
139 | angles[i].time, textLines[i].text, textLines[i].charScores,
140 | textLines[i].time,
141 | angles[i].time + textLines[i].time};
142 | textBlocks.emplace_back(textBlock);
143 | }
144 |
145 | double endTime = getCurrentTime();
146 | double fullTime = endTime - startTime;
147 | Logger("=====End detect=====");
148 | Logger("FullDetectTime(%fms)", fullTime);
149 |
150 | //cropped to original size
151 | cv::Mat textBoxImg;
152 | if (originRect.x > 0 && originRect.y > 0) {
153 | textBoxPaddingImg(originRect).copyTo(textBoxImg);
154 | } else {
155 | textBoxImg = textBoxPaddingImg;
156 | }
157 |
158 | std::string strRes;
159 | for (int i = 0; i < textBlocks.size(); ++i) {
160 | strRes.append(textBlocks[i].text);
161 | strRes.append("\n");
162 | }
163 |
164 | return OcrResult{dbNetTime, textBlocks, textBoxImg, fullTime, strRes};
165 | }
166 |
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/src/OcrResultUtils.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "OcrResultUtils.h"
3 |
4 | OcrResultUtils::OcrResultUtils(JNIEnv *env, OcrResult &ocrResult, jobject boxImg) {
5 | jniEnv = env;
6 |
7 | jclass jOcrResultClass = env->FindClass("com/benjaminwan/ocrlibrary/OcrResult");
8 |
9 | if (jOcrResultClass == NULL) {
10 | LOGE("OcrResult class is null");
11 | }
12 |
13 | jmethodID jOcrResultConstructor = env->GetMethodID(jOcrResultClass, "",
14 | "(DLjava/util/ArrayList;Landroid/graphics/Bitmap;DLjava/lang/String;)V");
15 |
16 | jobject textBlocks = getTextBlocks(ocrResult.textBlocks);
17 | jdouble dbNetTime = (jdouble) ocrResult.dbNetTime;
18 | jdouble detectTime = (jdouble) ocrResult.detectTime;
19 | jstring jStrRest = jniEnv->NewStringUTF(ocrResult.strRes.c_str());
20 |
21 | jOcrResult = env->NewObject(jOcrResultClass, jOcrResultConstructor, dbNetTime,
22 | textBlocks, boxImg, detectTime, jStrRest);
23 | }
24 |
25 | OcrResultUtils::~OcrResultUtils() {
26 | jniEnv = NULL;
27 | }
28 |
29 | jobject OcrResultUtils::getJObject() {
30 | return jOcrResult;
31 | }
32 |
33 | jclass OcrResultUtils::newJListClass() {
34 | jclass clazz = jniEnv->FindClass("java/util/ArrayList");
35 | if (clazz == NULL) {
36 | LOGE("ArrayList class is null");
37 | return NULL;
38 | }
39 | return clazz;
40 | }
41 |
42 | jmethodID OcrResultUtils::getListConstructor(jclass clazz) {
43 | jmethodID constructor = jniEnv->GetMethodID(clazz, "", "()V");
44 | return constructor;
45 | }
46 |
47 | jobject OcrResultUtils::newJPoint(cv::Point &point) {
48 | jclass clazz = jniEnv->FindClass("com/benjaminwan/ocrlibrary/Point");
49 | if (clazz == NULL) {
50 | LOGE("Point class is null");
51 | return NULL;
52 | }
53 | jmethodID constructor = jniEnv->GetMethodID(clazz, "", "(II)V");
54 | jobject obj = jniEnv->NewObject(clazz, constructor, point.x, point.y);
55 | return obj;
56 | }
57 |
58 | jobject OcrResultUtils::newJBoxPoint(std::vector &boxPoint) {
59 | jclass jListClass = newJListClass();
60 | jmethodID jListConstructor = getListConstructor(jListClass);
61 | jobject jList = jniEnv->NewObject(jListClass, jListConstructor);
62 | jmethodID jListAdd = jniEnv->GetMethodID(jListClass, "add", "(Ljava/lang/Object;)Z");
63 |
64 | for (auto point : boxPoint) {
65 | jobject jPoint = newJPoint(point);
66 | jniEnv->CallBooleanMethod(jList, jListAdd, jPoint);
67 | }
68 | return jList;
69 | }
70 |
71 | jobject OcrResultUtils::getTextBlock(TextBlock &textBlock) {
72 | jobject jBoxPint = newJBoxPoint(textBlock.boxPoint);
73 | jfloat jBoxScore = (jfloat) textBlock.boxScore;
74 | jfloat jAngleScore = (jfloat) textBlock.angleScore;
75 | jdouble jAngleTime = (jdouble) textBlock.angleTime;
76 | jstring jText = jniEnv->NewStringUTF(textBlock.text.c_str());
77 | jobject jCharScores = newJScoreArray(textBlock.charScores);
78 | jdouble jCrnnTime = (jdouble) textBlock.crnnTime;
79 | jdouble jBlockTime = (jdouble) textBlock.blockTime;
80 | jclass clazz = jniEnv->FindClass("com/benjaminwan/ocrlibrary/TextBlock");
81 | if (clazz == NULL) {
82 | LOGE("TextBlock class is null");
83 | return NULL;
84 | }
85 | jmethodID constructor = jniEnv->GetMethodID(clazz, "",
86 | "(Ljava/util/ArrayList;FIFDLjava/lang/String;[FDD)V");
87 | jobject obj = jniEnv->NewObject(clazz, constructor, jBoxPint, jBoxScore, textBlock.angleIndex,
88 | jAngleScore, jAngleTime, jText, jCharScores, jCrnnTime,
89 | jBlockTime);
90 | return obj;
91 | }
92 |
93 | jobject OcrResultUtils::getTextBlocks(std::vector &textBlocks) {
94 | jclass jListClass = newJListClass();
95 | jmethodID jListConstructor = getListConstructor(jListClass);
96 | jobject jList = jniEnv->NewObject(jListClass, jListConstructor);
97 | jmethodID jListAdd = jniEnv->GetMethodID(jListClass, "add", "(Ljava/lang/Object;)Z");
98 |
99 | for (int i = 0; i < textBlocks.size(); ++i) {
100 | auto textBlock = textBlocks[i];
101 | jobject jTextBlock = getTextBlock(textBlock);
102 | jniEnv->CallBooleanMethod(jList, jListAdd, jTextBlock);
103 | }
104 | return jList;
105 | }
106 |
107 | jfloatArray OcrResultUtils::newJScoreArray(std::vector &scores) {
108 | jfloatArray jScores = jniEnv->NewFloatArray(scores.size());
109 | jniEnv->SetFloatArrayRegion(jScores, 0, scores.size(), (jfloat *) scores.data());
110 | return jScores;
111 | }
--------------------------------------------------------------------------------
/OcrLibrary/src/main/cpp/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "OcrResultUtils.h"
2 | #include "BitmapUtils.h"
3 | #include "OcrLite.h"
4 | #include "OcrUtils.h"
5 | //#include "omp.h"
6 |
7 | static OcrLite *ocrLite;
8 |
9 | JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
10 | ocrLite = new OcrLite();
11 | return JNI_VERSION_1_4;
12 | }
13 |
14 | JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {
15 | LOGI("Goodbye OcrLite!");
16 | delete ocrLite;
17 | }
18 |
19 | extern "C" JNIEXPORT jboolean JNICALL
20 | Java_com_benjaminwan_ocrlibrary_OcrEngine_init(JNIEnv *env, jobject thiz, jobject assetManager,
21 | jint numThread) {
22 |
23 | ocrLite->init(env, assetManager, numThread);
24 | //omp_set_num_threads(numThread);
25 | //ocrLite->initLogger(false);
26 | return JNI_TRUE;
27 | }
28 |
29 | cv::Mat makePadding(cv::Mat &src, const int padding) {
30 | if (padding <= 0) return src;
31 | cv::Scalar paddingScalar = {255, 255, 255};
32 | cv::Mat paddingSrc;
33 | cv::copyMakeBorder(src, paddingSrc, padding, padding, padding, padding, cv::BORDER_ISOLATED,
34 | paddingScalar);
35 | return paddingSrc;
36 | }
37 |
38 | extern "C"
39 | JNIEXPORT jobject JNICALL
40 | Java_com_benjaminwan_ocrlibrary_OcrEngine_detect(JNIEnv *env, jobject thiz, jobject input, jobject output,
41 | jint padding, jint maxSideLen, jfloat boxScoreThresh, jfloat boxThresh,
42 | jfloat unClipRatio, jboolean doAngle, jboolean mostAngle) {
43 | Logger("padding(%d),maxSideLen(%d),boxScoreThresh(%f),boxThresh(%f),unClipRatio(%f),doAngle(%d),mostAngle(%d)",
44 | padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
45 | cv::Mat imgRGBA, imgRGB, imgOut;
46 | bitmapToMat(env, input, imgRGBA);
47 | cv::cvtColor(imgRGBA, imgRGB, cv::COLOR_RGBA2RGB);
48 | int originMaxSide = (std::max)(imgRGB.cols, imgRGB.rows);
49 | int resize;
50 | if (maxSideLen <= 0 || maxSideLen > originMaxSide) {
51 | resize = originMaxSide;
52 | } else {
53 | resize = maxSideLen;
54 | }
55 | resize += 2 * padding;
56 | cv::Rect paddingRect(padding, padding, imgRGB.cols, imgRGB.rows);
57 | cv::Mat paddingSrc = makePadding(imgRGB, padding);
58 | //按比例缩小图像,减少文字分割时间
59 | ScaleParam s = getScaleParam(paddingSrc, resize);//例:按长或宽缩放 src.cols=不缩放,src.cols/2=长度缩小一半
60 | OcrResult ocrResult = ocrLite->detect(paddingSrc, paddingRect, s, boxScoreThresh, boxThresh,
61 | unClipRatio, doAngle, mostAngle);
62 |
63 | cv::cvtColor(ocrResult.boxImg, imgOut, cv::COLOR_RGB2RGBA);
64 | matToBitmap(env, imgOut, output);
65 |
66 | return OcrResultUtils(env, ocrResult, output).getJObject();
67 | }
68 |
69 | extern "C" JNIEXPORT jdouble JNICALL
70 | Java_com_benjaminwan_ocrlibrary_OcrEngine_benchmark(JNIEnv *env, jobject thiz, jobject input,
71 | jint loop) {
72 | int padding = 50;
73 | int maxSideLen = 0;
74 | float boxScoreThresh = 0.6;
75 | float boxThresh = 0.3;
76 | float unClipRatio = 2.0;
77 | bool doAngle = true;
78 | bool mostAngle = true;
79 | LOGI("padding(%d),maxSideLen(%d),boxScoreThresh(%f),boxThresh(%f),unClipRatio(%f),doAngle(%d),mostAngle(%d)",
80 | padding, maxSideLen, boxScoreThresh, boxThresh, unClipRatio, doAngle, mostAngle);
81 | cv::Mat imgRGBA, imgRGB, imgOut;
82 | bitmapToMat(env, input, imgRGBA);
83 | cv::cvtColor(imgRGBA, imgRGB, cv::COLOR_RGBA2RGB);
84 | cv::Rect originRect(padding, padding, imgRGB.cols, imgRGB.rows);
85 | cv::Mat src = makePadding(imgRGB, padding);
86 | //按比例缩小图像,减少文字分割时间
87 | ScaleParam s = getScaleParam(src, src.cols);//例:按长或宽缩放 src.cols=不缩放,src.cols/2=长度缩小一半
88 |
89 | LOGI("=====warmup=====");
90 | OcrResult result = ocrLite->detect(src, originRect, s, boxScoreThresh, boxThresh,
91 | unClipRatio, doAngle, mostAngle);
92 | LOGI("dbNetTime(%f) detectTime(%f)\n", result.dbNetTime, result.detectTime);
93 | double dbTime = 0.0f;
94 | double detectTime = 0.0f;
95 | int loopCount = loop;
96 | for (int i = 0; i < loopCount; ++i) {
97 | LOGI("=====loop:%d=====", i + 1);
98 | OcrResult ocrResult = ocrLite->detect(src, originRect, s, boxScoreThresh, boxThresh,
99 | unClipRatio, doAngle, mostAngle);
100 | LOGI("dbNetTime(%f) detectTime(%f)\n", ocrResult.dbNetTime, ocrResult.detectTime);
101 | dbTime += ocrResult.dbNetTime;
102 | detectTime += ocrResult.detectTime;
103 | }
104 | LOGI("=====result=====\n");
105 | double averageTime = detectTime / loopCount;
106 | LOGI("average dbNetTime=%fms, average detectTime=%fms\n", dbTime / loopCount,
107 | averageTime);
108 | return (jdouble) averageTime;
109 | }
--------------------------------------------------------------------------------
/OcrLibrary/src/main/java/com/benjaminwan/ocrlibrary/OcrEngine.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocrlibrary
2 |
3 | import android.content.Context
4 | import android.content.res.AssetManager
5 | import android.graphics.Bitmap
6 |
7 | class OcrEngine(context: Context) {
8 | companion object {
9 | const val numThread: Int = 4
10 | }
11 |
12 | init {
13 | System.loadLibrary("OcrLite")
14 | val ret = init(context.assets, numThread)
15 | if (!ret) throw IllegalArgumentException()
16 | }
17 |
18 | var padding: Int = 50
19 | var boxScoreThresh: Float = 0.6f
20 | var boxThresh: Float = 0.3f
21 | var unClipRatio: Float = 2.0f
22 | var doAngle: Boolean = true
23 | var mostAngle: Boolean = true
24 |
25 | fun detect(input: Bitmap, output: Bitmap, maxSideLen: Int) =
26 | detect(
27 | input, output, padding, maxSideLen,
28 | boxScoreThresh, boxThresh,
29 | unClipRatio, doAngle, mostAngle
30 | )
31 |
32 | external fun init(assetManager: AssetManager, numThread: Int): Boolean
33 | external fun detect(
34 | input: Bitmap, output: Bitmap, padding: Int, maxSideLen: Int,
35 | boxScoreThresh: Float, boxThresh: Float,
36 | unClipRatio: Float, doAngle: Boolean, mostAngle: Boolean
37 | ): OcrResult
38 |
39 | external fun benchmark(input: Bitmap, loop: Int): Double
40 |
41 | }
--------------------------------------------------------------------------------
/OcrLibrary/src/main/java/com/benjaminwan/ocrlibrary/OcrResult.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocrlibrary
2 |
3 | import android.graphics.Bitmap
4 | import android.os.Parcelable
5 | import kotlinx.parcelize.Parcelize
6 |
7 | open class OcrOutput
8 |
9 | object OcrStop : OcrOutput()
10 | object OcrFailed : OcrOutput()
11 |
12 | @Parcelize
13 | data class OcrResult(
14 | val dbNetTime: Double,
15 | val textBlocks: ArrayList,
16 | var boxImg: Bitmap,
17 | var detectTime: Double,
18 | var strRes: String
19 | ) : Parcelable, OcrOutput()
20 |
21 | @Parcelize
22 | data class Point(var x: Int, var y: Int) : Parcelable
23 |
24 | @Parcelize
25 | data class TextBlock(
26 | val boxPoint: ArrayList, var boxScore: Float,
27 | val angleIndex: Int, val angleScore: Float, val angleTime: Double,
28 | val text: String, val charScores: FloatArray, val crnnTime: Double,
29 | val blockTime: Double
30 | ) : Parcelable {
31 | override fun equals(other: Any?): Boolean {
32 | if (this === other) return true
33 | if (javaClass != other?.javaClass) return false
34 |
35 | other as TextBlock
36 |
37 | if (boxPoint != other.boxPoint) return false
38 | if (boxScore != other.boxScore) return false
39 | if (angleIndex != other.angleIndex) return false
40 | if (angleScore != other.angleScore) return false
41 | if (angleTime != other.angleTime) return false
42 | if (text != other.text) return false
43 | if (!charScores.contentEquals(other.charScores)) return false
44 | if (crnnTime != other.crnnTime) return false
45 | if (blockTime != other.blockTime) return false
46 |
47 | return true
48 | }
49 |
50 | override fun hashCode(): Int {
51 | var result = boxPoint.hashCode()
52 | result = 31 * result + boxScore.hashCode()
53 | result = 31 * result + angleIndex
54 | result = 31 * result + angleScore.hashCode()
55 | result = 31 * result + angleTime.hashCode()
56 | result = 31 * result + text.hashCode()
57 | result = 31 * result + charScores.contentHashCode()
58 | result = 31 * result + crnnTime.hashCode()
59 | result = 31 * result + blockTime.hashCode()
60 | return result
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/OcrLibrary/src/test/java/com/benjaminwan/ocrlibrary/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocrlibrary
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OcrLiteAndroidOnnx
2 |
3 | [](https://github.com/benjaminwan/OcrLiteAndroidOnnx/issues)
4 | [](https://github.com/benjaminwan/OcrLiteAndroidOnnx)
5 |
6 |
7 | 目录
8 |
9 | - [OcrLiteAndroidOnnx](#OcrLiteAndroidOnnx)
10 | - [联系方式](#联系方式)
11 | - [项目完整源码](#项目完整源码)
12 | - [APK下载](#APK下载)
13 | - [简介](#简介)
14 | - [总体说明](#总体说明)
15 | - [更新说明](#更新说明)
16 | - [编译说明](#编译说明)
17 | - [使用说明](#使用说明)
18 | - [项目结构](#项目结构)
19 | - [常见问题](#常见问题)
20 | - [输入参数说明](#输入参数说明)
21 | - [关于作者](#关于作者)
22 | - [版权声明](#版权声明)
23 | - [示例图](#示例图)
24 | - [IMEI识别](#IMEI识别)
25 | - [身份证识别](#身份证识别)
26 | - [车牌识别](#车牌识别)
27 |
28 |
29 |
30 | ## 联系方式
31 |
32 | * QQ①群:994929053(满)
33 | * QQ②群:820132154(满)
34 | * QQ③群:904091319(满)
35 | * QQ④群:615877948(满)
36 | * QQ⑤群:185905924(满)
37 | * QQ⑥群:628010752
38 |
39 | ## 项目完整源码
40 |
41 | * 整合好源码和依赖库的完整工程项目,可到Q群共享内下载或Release下载,以Project开头的压缩包文件为源码工程,例:Project_OcrLiteAndroidOnnx-版本号.7z
42 | * 如果想自己折腾,则请继续阅读本说明
43 |
44 | ## APK下载
45 |
46 | * 编译好的demo apk,可以在release中下载,或者Q群共享内下载,文件名例:OcrLiteAndroidOnnx-版本号-release.apk
47 | * 或者[Github下载](https://github.com/benjaminwan/OcrLiteAndroidOnnx/releases)
48 |
49 | ## 简介
50 |
51 | Chineseocr Lite Android Onnx Demo,超轻量级中文OCR Android Demo,支持onnx推理 (DBNet+AngleNet+CRNN)
52 |
53 | **代码和模型均源自chineseocr lite的onnx分支**
54 |
55 | 详情请查看 [https://github.com/ouyanghuiyu/chineseocr_lite](https://github.com/ouyanghuiyu/chineseocr_lite)
56 |
57 | onnxruntime框架[https://github.com/microsoft/onnxruntime](https://github.com/microsoft/onnxruntime)
58 |
59 | 相似项目:https://github.com/RapidAI/RapidOcrAndroidOnnxCompose
60 |
61 | ## 总体说明
62 |
63 | 1. 封装为独立的Library,可以编译为aar,作为模块来调用;
64 | 2. Native层以C++编写;
65 | 3. Demo App以Kotlin-JVM编写;
66 | 4. Android版与其它版本不同,包含了几个应用场景,包括相册识别、摄像头识别、手机IMEI号识别、摄像头身份证识别这几个功能页面;
67 |
68 | ## 更新说明
69 |
70 | #### 2021-09-29 update 1.6.0
71 |
72 | * opencv 3.4.15(特别说明:4.5.3也可以支持,如果换成cv4,minSdkVersion必须改为24)
73 | * onnxruntime 1.9.0
74 | * 升级kotlin: 1.5.31
75 | * 升级gradle: 7.0.2
76 | * 升级各dependencies
77 | * 使用kotlin coroutines代替rxjava
78 |
79 | #### 2021-10-28 update 1.6.1
80 |
81 | * 编辑build.gradle,把版本定义放到root build.gradle
82 | * 编辑github workflow config,上传aar文件到release
83 |
84 | #### 2022-03-03 update 1.6.2
85 |
86 | * 升级gradle
87 | * 升级依赖库
88 |
89 | #### 2022-06-20 update 1.7.0
90 |
91 | * onnxruntime 1.11.1
92 | * 高版本的opencv会要求 Minimum required by OpenCV API level is android-24,所以目前仍停留在3.4.15
93 | * 如果不在意MinSdk,可自行[下载新版opencv](https://github.com/nihui/opencv-mobile/releases)
94 |
95 | #### 2022-02-15 update 1.8.0
96 |
97 | * 增加相册识别和相机识别停止按钮
98 | * 添加 Java demo
99 | * 适配onnxruntime 1.14.1
100 |
101 | ### [编译说明](./BUILD.md)
102 |
103 | ### [使用说明](./INSTRUCTIONS.md)
104 |
105 | ## 项目结构
106 |
107 | ```
108 | OcrLiteAndroidOnnx
109 | ├── app # demo app
110 | ├── capture # 截图
111 | ├── common-aar # app引用的aar库
112 | ├── keystore # app签名密钥文件
113 | ├── OcrLibrary # Ocr引擎库,包含Jni和C++代码
114 | └── scripts # 编译脚本
115 | ```
116 |
117 | ## 常见问题
118 |
119 | ### 输入参数说明
120 |
121 | 请参考[OcrLiteOnnx项目](https://github.com/ouyanghuiyu/chineseocr_lite/tree/onnx/cpp_projects/OcrLiteOnnx)
122 |
123 | ## 关于作者
124 |
125 | * Android demo编写:[benjaminwan](https://github.com/benjaminwan)
126 | * 模型开发:[DayBreak](https://github.com/DayBreak-u)
127 |
128 | ## 版权声明
129 |
130 | - OCR模型版权归[DayBreak](https://github.com/DayBreak-u)所有;
131 | - 其它工程代码版权归本仓库所有者所有;
132 |
133 | ## 示例图
134 |
135 | #### IMEI识别
136 |
137 | 
138 |
139 | #### 身份证识别
140 |
141 | 
142 |
143 | #### 车牌识别
144 |
145 | 
146 |
147 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'kotlin-parcelize'
5 | id 'kotlin-kapt'
6 | }
7 |
8 | android {
9 | signingConfigs {
10 | ocr {
11 | keyAlias 'ocrlite'
12 | keyPassword 'ocrlite'
13 | storeFile file('../keystore/ocrlite.keystore')
14 | storePassword 'ocrlite'
15 | }
16 | }
17 |
18 | compileSdkVersion compile_sdk_version
19 |
20 | defaultConfig {
21 | applicationId "com.benjaminwan.ocr.onnx"
22 | minSdkVersion min_sdk_version
23 | targetSdkVersion target_sdk_version
24 | versionCode project_version_code
25 | versionName project_version_name
26 | signingConfig signingConfigs.ocr
27 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
28 | }
29 |
30 | buildTypes {
31 | release {
32 | minifyEnabled false
33 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
34 | }
35 | }
36 |
37 | compileOptions {
38 | sourceCompatibility JavaVersion.VERSION_1_8
39 | targetCompatibility JavaVersion.VERSION_1_8
40 | }
41 |
42 | kotlinOptions {
43 | jvmTarget = JavaVersion.VERSION_1_8.toString()
44 | }
45 |
46 | kapt {
47 | correctErrorTypes = true
48 | }
49 |
50 | applicationVariants.all {
51 | variant ->
52 | variant.outputs.all {
53 | outputFileName = "${rootProject.name}-${defaultConfig.versionName}-${variant.buildType.name}.apk"
54 | }
55 | }
56 |
57 | viewBinding {
58 | enabled = true
59 | }
60 | }
61 |
62 | dependencies {
63 | implementation fileTree(dir: "libs", include: ["*.jar"])
64 | testImplementation 'junit:junit:4.13.2'
65 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
66 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
67 | //Kotlin
68 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
69 |
70 | //coroutines
71 | def coroutines_version = '1.6.1'
72 | //implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
73 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
74 |
75 | //Android
76 | implementation 'androidx.core:core-ktx:1.9.0'
77 | implementation 'androidx.appcompat:appcompat:1.6.1'
78 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
79 | implementation 'androidx.recyclerview:recyclerview:1.2.1'
80 |
81 | //lifecycle
82 | implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
83 |
84 | //glide
85 | implementation 'com.github.bumptech.glide:glide:4.13.2'
86 | implementation project(":OcrLibrary")
87 |
88 | implementation 'com.github.chrisbanes:PhotoView:2.3.0'
89 |
90 | def epoxyVersion = '5.0.0'
91 | implementation "com.airbnb.android:epoxy:$epoxyVersion"
92 | kapt "com.airbnb.android:epoxy-processor:$epoxyVersion"
93 |
94 | // CameraX core library
95 | def camerax_version = '1.2.1'
96 | implementation "androidx.camera:camera-core:$camerax_version"
97 | // CameraX Camera2 extensions
98 | implementation "androidx.camera:camera-camera2:$camerax_version"
99 | // CameraX Lifecycle library
100 | implementation "androidx.camera:camera-lifecycle:$camerax_version"
101 | // CameraX View class
102 | implementation "androidx.camera:camera-view:$camerax_version"
103 |
104 | //cameraMask 相机遮罩
105 | implementation 'jsc.kit.cameramask:camera-mask:0.3.0'
106 |
107 | //runWithPermissions 申请权限
108 | implementation 'com.afollestad.assent:core:3.0.0-RC4'
109 | implementation 'com.afollestad.assent:rationales:3.0.0-RC4'
110 |
111 | //Logger
112 | implementation 'com.orhanobut:logger:2.2.0'
113 |
114 | implementation(name: 'IdCardView-1.0', ext: 'aar')
115 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/benjaminwan/ocr/onnx/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.benjaminwan.ocr.onnx", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
33 |
36 |
39 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.view.View
6 | import androidx.appcompat.app.AppCompatActivity
7 | import com.benjaminwan.ocr.onnx.databinding.ActivityMainBinding
8 |
9 | class MainActivity : AppCompatActivity(), View.OnClickListener {
10 | private lateinit var binding: ActivityMainBinding
11 |
12 | private fun initViews() {
13 | binding.galleryBtn.setOnClickListener(this)
14 | binding.cameraBtn.setOnClickListener(this)
15 | binding.imeiBtn.setOnClickListener(this)
16 | binding.plateBtn.setOnClickListener(this)
17 | binding.idCardBtn.setOnClickListener(this)
18 | }
19 |
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | binding = ActivityMainBinding.inflate(layoutInflater)
23 | setContentView(binding.root)
24 | initViews()
25 | }
26 |
27 | override fun onClick(view: View?) {
28 | view ?: return
29 | when (view.id) {
30 | R.id.galleryBtn -> {
31 | startActivity(Intent(this, GalleryActivity::class.java))
32 | }
33 | R.id.cameraBtn -> {
34 | startActivity(Intent(this, CameraActivity::class.java))
35 | }
36 | R.id.imeiBtn -> {
37 | startActivity(Intent(this, ImeiActivity::class.java))
38 | }
39 | R.id.plateBtn -> {
40 | startActivity(Intent(this, PlateActivity::class.java))
41 | }
42 | R.id.idCardBtn -> {
43 | startActivity(Intent(this, IdCardFrontActivity::class.java))
44 | }
45 | else -> {
46 | }
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/app/App.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.app
2 |
3 | import android.app.Application
4 | import android.util.Log
5 | import com.benjaminwan.ocr.onnx.BuildConfig
6 | import com.benjaminwan.ocrlibrary.OcrEngine
7 | import com.orhanobut.logger.AndroidLogAdapter
8 | import com.orhanobut.logger.LogStrategy
9 | import com.orhanobut.logger.Logger
10 | import com.orhanobut.logger.PrettyFormatStrategy
11 |
12 | class App : Application() {
13 | companion object {
14 | lateinit var INSTANCE: App
15 | lateinit var ocrEngine: OcrEngine
16 | }
17 |
18 | override fun onCreate() {
19 | super.onCreate()
20 | INSTANCE = this
21 | initLogger()
22 | initOCREngine()
23 | }
24 | private fun initOCREngine() {
25 | ocrEngine = OcrEngine(this.applicationContext)
26 | }
27 |
28 | private fun initLogger() {
29 | val formatStrategy = PrettyFormatStrategy.newBuilder()
30 | .showThreadInfo(true)
31 | .tag("OcrLite")
32 | .logStrategy(LogCatStrategy())
33 | .build()
34 | Logger.addLogAdapter(object : AndroidLogAdapter(formatStrategy) {
35 | override fun isLoggable(priority: Int, tag: String?): Boolean = BuildConfig.DEBUG
36 | })
37 | }
38 |
39 | inner class LogCatStrategy : LogStrategy {
40 |
41 | private var last: Int = 0
42 |
43 | override fun log(priority: Int, tag: String?, message: String) {
44 | Log.println(priority, randomKey() + tag!!, message)
45 | }
46 |
47 | private fun randomKey(): String {
48 | var random = (10 * Math.random()).toInt()
49 | if (random == last) {
50 | random = (random + 1) % 10
51 | }
52 | last = random
53 | return random.toString()
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/dialog/BaseDialog.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.dialog
2 |
3 | import android.app.Dialog
4 | import android.util.DisplayMetrics
5 | import android.view.Gravity
6 | import android.view.ViewGroup
7 | import android.view.WindowManager
8 | import androidx.fragment.app.DialogFragment
9 |
10 | abstract class BaseDialog : DialogFragment() {
11 |
12 | private var mGravity = Gravity.CENTER//对话框的位置
13 | private var mCanceledOnTouchOutside = true//是否触摸外部关闭
14 | private var mCanceledBack = true//是否返回键关闭
15 | private var mAnimStyle: Int = 0//显示动画
16 |
17 | /*override fun onActivityCreated(savedInstanceState: Bundle?) {
18 | //修复DialogFragment内存泄漏
19 | if (showsDialog) {
20 | showsDialog = false
21 | }
22 | super.onActivityCreated(savedInstanceState)
23 | showsDialog = true
24 |
25 | val tmpView = view
26 | if (tmpView != null) {
27 | check(tmpView.parent == null) { "DialogFragment can not be attached to a container view" }
28 | dialog?.setContentView(tmpView)
29 | }
30 |
31 | activity?.let {
32 | dialog?.setOwnerActivity(it)
33 | }
34 |
35 | if (savedInstanceState != null) {
36 | val dialogState = savedInstanceState.getBundle("android:savedDialogState")
37 | if (dialogState != null) {
38 | dialog?.onRestoreInstanceState(dialogState)
39 | }
40 | }
41 | }*/
42 |
43 | fun setGravity(gravity: Int) {
44 | mGravity = gravity
45 | }
46 |
47 | fun setCanceledBack(canceledBack: Boolean) {
48 | mCanceledBack = canceledBack
49 | }
50 |
51 | fun setCanceledOnTouchOutside(canceledOnTouchOutsidek: Boolean) {
52 | mCanceledOnTouchOutside = canceledOnTouchOutsidek
53 | }
54 |
55 | fun setAnimStyle(animStyle: Int) {
56 | mAnimStyle = animStyle
57 | }
58 |
59 | override fun onStart() {
60 | val baseDialog = dialog
61 | if (baseDialog != null) {
62 | baseDialog.setCanceledOnTouchOutside(mCanceledOnTouchOutside)
63 | baseDialog.setCancelable(mCanceledBack)
64 | setDialogGravity(baseDialog)//设置对话框布局
65 | }
66 | // 全屏显示Dialog,重新测绘宽高
67 | if (dialog != null) {
68 | val dm = DisplayMetrics()
69 | activity?.windowManager?.defaultDisplay?.getMetrics(dm)
70 | val attributes = dialog!!.window!!.attributes
71 | attributes.gravity = Gravity.CENTER//对齐方式
72 | dialog?.window?.attributes = attributes
73 | dialog?.window?.setLayout(
74 | ViewGroup.LayoutParams.MATCH_PARENT,
75 | (dm.heightPixels * 0.9).toInt()
76 | )
77 | }
78 | super.onStart()
79 | }
80 |
81 | /**
82 | * 对话框配置
83 | *
84 | * @param dialog
85 | */
86 | private fun setDialogGravity(dialog: Dialog) {
87 | val window = dialog.window ?: return
88 | val wlp = window.attributes
89 | wlp.gravity = mGravity
90 | wlp.width = WindowManager.LayoutParams.MATCH_PARENT
91 | wlp.height = WindowManager.LayoutParams.WRAP_CONTENT
92 |
93 | window.attributes = wlp
94 | //动画
95 | if (mAnimStyle != 0) {
96 | window.setWindowAnimations(mAnimStyle)
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/dialog/DebugDialog.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.dialog
2 |
3 | import android.os.Bundle
4 | import android.view.Gravity
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.recyclerview.widget.DefaultItemAnimator
9 | import com.benjaminwan.ocr.onnx.R
10 | import com.benjaminwan.ocr.onnx.databinding.DialogDebugBinding
11 | import com.benjaminwan.ocr.onnx.models.dbNetTimeItemView
12 | import com.benjaminwan.ocr.onnx.models.debugItemView
13 | import com.benjaminwan.ocr.onnx.utils.format
14 | import com.benjaminwan.ocr.onnx.utils.hideSoftInput
15 | import com.benjaminwan.ocr.onnx.utils.setMarginItemDecoration
16 | import com.benjaminwan.ocrlibrary.OcrResult
17 | import com.benjaminwan.ocrlibrary.TextBlock
18 |
19 | class DebugDialog : BaseDialog(), View.OnClickListener {
20 | companion object {
21 | val instance: DebugDialog
22 | get() {
23 | val dialog = DebugDialog()
24 | dialog.setCanceledBack(true)
25 | dialog.setCanceledOnTouchOutside(false)
26 | dialog.setGravity(Gravity.CENTER)
27 | dialog.setAnimStyle(R.style.diag_top_down_up_animation)
28 | return dialog
29 | }
30 | }
31 |
32 | private var title: String = ""
33 | private var textBlocks: MutableList = mutableListOf()
34 | private var dbnetTime: Double = 0.0
35 |
36 | private var _binding: DialogDebugBinding? = null
37 | private val binding get() = _binding!!
38 |
39 | override fun onCreateView(
40 | inflater: LayoutInflater,
41 | viewGroup: ViewGroup?,
42 | savedInstanceState: Bundle?
43 | ): View {
44 | _binding = DialogDebugBinding.inflate(inflater, viewGroup, false)
45 | return binding.root
46 | }
47 |
48 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
49 | super.onViewCreated(view, savedInstanceState)
50 | initViews()
51 | }
52 |
53 | override fun dismiss() {
54 | hideSoftInput()
55 | super.dismiss()
56 | }
57 |
58 | private fun initViews() {
59 | binding.debugRV.setHasFixedSize(true)
60 | binding.debugRV.itemAnimator = DefaultItemAnimator()
61 | binding.debugRV.setMarginItemDecoration(2, 1, 2, 1)
62 |
63 | binding.debugRV.withModels {
64 | dbNetTimeItemView {
65 | id("dbnet time item")
66 | dbNetTimeStr(dbnetTime.format("#0.00") + "ms")
67 | }
68 | textBlocks.withIndex().forEach { (id, item) ->
69 | val boxPointStr = item.boxPoint.map { "[${it.x},${it.y}]" }.joinToString()
70 | val charScoresStr = item.charScores.map { it.format("#0.00") }.joinToString()
71 | debugItemView {
72 | id("debug view $id")
73 | index("$id")
74 | boxPoint(boxPointStr)
75 | boxScore(item.boxScore.format("#0.00"))
76 | angleIndex(item.angleIndex.toString())
77 | angleScore(item.angleScore.format("#0.00"))
78 | angleTime(item.angleTime.format("#0.00") + "ms")
79 | text(item.text)
80 | charScores(charScoresStr)
81 | crnnTime(item.crnnTime.format("#0.00") + "ms")
82 | blockTime(item.blockTime.format("#0.00") + "ms")
83 | }
84 | }
85 | }
86 |
87 | binding.negativeBtn.setOnClickListener(this)
88 | binding.positiveBtn.setOnClickListener(this)
89 | if (title.isNotEmpty()) {
90 | binding.titleTV.text = title
91 | }
92 |
93 | }
94 |
95 | fun setTitle(title: String): DebugDialog {
96 | this.title = title
97 | return this
98 | }
99 |
100 | fun setResult(result: OcrResult): DebugDialog {
101 | textBlocks.clear()
102 | textBlocks.addAll(result.textBlocks)
103 | dbnetTime = result.dbNetTime
104 | return this
105 | }
106 |
107 | override fun onClick(view: View) {
108 | val resId = view.id
109 | if (resId == R.id.negativeBtn) {
110 | dismiss()
111 | } else if (resId == R.id.positiveBtn) {
112 | this.dismiss()
113 | }
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/dialog/TextResultDialog.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.dialog
2 |
3 | import android.os.Bundle
4 | import android.view.Gravity
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import com.benjaminwan.ocr.onnx.R
9 | import com.benjaminwan.ocr.onnx.databinding.DialogTextResultBinding
10 | import com.benjaminwan.ocr.onnx.utils.hideSoftInput
11 | import com.benjaminwan.ocr.onnx.utils.toClipboard
12 |
13 | class TextResultDialog : BaseDialog(), View.OnClickListener {
14 | companion object {
15 | val instance: TextResultDialog
16 | get() {
17 | val dialog = TextResultDialog()
18 | dialog.setCanceledBack(true)
19 | dialog.setCanceledOnTouchOutside(false)
20 | dialog.setGravity(Gravity.CENTER)
21 | dialog.setAnimStyle(R.style.diag_top_down_up_animation)
22 | return dialog
23 | }
24 | }
25 |
26 | private var content: String = ""
27 | private var title: String = ""
28 |
29 | private var _binding: DialogTextResultBinding? = null
30 | private val binding get() = _binding!!
31 |
32 | override fun onCreateView(
33 | inflater: LayoutInflater,
34 | viewGroup: ViewGroup?,
35 | savedInstanceState: Bundle?
36 | ): View {
37 | _binding = DialogTextResultBinding.inflate(inflater, viewGroup, false)
38 | return binding.root
39 | }
40 |
41 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
42 | super.onViewCreated(view, savedInstanceState)
43 | initViews()
44 | }
45 |
46 | override fun dismiss() {
47 | hideSoftInput()
48 | super.dismiss()
49 | }
50 |
51 | private fun initViews() {
52 | binding.negativeBtn.setOnClickListener(this)
53 | binding.positiveBtn.setOnClickListener(this)
54 | binding.contentEdit.setText(content)
55 | if (title.isNotEmpty()) {
56 | binding.titleTV.text = title
57 | }
58 | }
59 |
60 | fun setTitle(title: String): TextResultDialog {
61 | this.title = title
62 | return this
63 | }
64 |
65 | fun setContent(textContent: String): TextResultDialog {
66 | content = textContent
67 | return this
68 | }
69 |
70 | override fun onClick(view: View) {
71 | val resId = view.id
72 | if (resId == R.id.negativeBtn) {
73 | dismiss()
74 | } else if (resId == R.id.positiveBtn) {
75 | requireContext().toClipboard(content)
76 | this.dismiss()
77 | }
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/models/DbNetTimeItemView.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.models
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.LayoutInflater
6 | import android.widget.LinearLayout
7 | import com.airbnb.epoxy.AfterPropsSet
8 | import com.airbnb.epoxy.ModelView
9 | import com.airbnb.epoxy.TextProp
10 | import com.benjaminwan.ocr.onnx.databinding.RvDbnetTimeItemBinding
11 |
12 | // The ModelView annotation is used on Views to have models generated from those views.
13 | // This is pretty straightforward with Kotlin, but properties need some special handling.
14 | @ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
15 | class DbNetTimeItemView @JvmOverloads constructor(
16 | context: Context,
17 | attrs: AttributeSet? = null,
18 | defStyleAttr: Int = 0
19 | ) : LinearLayout(context, attrs, defStyleAttr) {
20 | private val binding: RvDbnetTimeItemBinding =
21 | RvDbnetTimeItemBinding.inflate(LayoutInflater.from(this.context), this, true)
22 |
23 | init {
24 |
25 | }
26 |
27 | // 2. Or you can use lateinit
28 | @TextProp
29 | lateinit var dbNetTimeStr: CharSequence
30 |
31 | @AfterPropsSet
32 | fun useProps() {
33 | binding.dbNetTimeTv.text = dbNetTimeStr
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/models/DebugItemView.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.models
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.LayoutInflater
6 | import android.widget.LinearLayout
7 | import com.airbnb.epoxy.AfterPropsSet
8 | import com.airbnb.epoxy.ModelView
9 | import com.airbnb.epoxy.TextProp
10 | import com.benjaminwan.ocr.onnx.databinding.RvDebugViewItemBinding
11 |
12 | // The ModelView annotation is used on Views to have models generated from those views.
13 | // This is pretty straightforward with Kotlin, but properties need some special handling.
14 | @ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
15 | class DebugItemView @JvmOverloads constructor(
16 | context: Context,
17 | attrs: AttributeSet? = null,
18 | defStyleAttr: Int = 0
19 | ) : LinearLayout(context, attrs, defStyleAttr) {
20 |
21 | private val binding: RvDebugViewItemBinding =
22 | RvDebugViewItemBinding.inflate(LayoutInflater.from(this.context), this, true)
23 |
24 | init {
25 |
26 | }
27 |
28 | // 2. Or you can use lateinit
29 | @TextProp
30 | lateinit var index: CharSequence
31 |
32 | @TextProp
33 | lateinit var boxPoint: CharSequence
34 |
35 | @TextProp
36 | lateinit var boxScore: CharSequence
37 |
38 | @TextProp
39 | lateinit var angleIndex: CharSequence
40 |
41 | @TextProp
42 | lateinit var angleScore: CharSequence
43 |
44 | @TextProp
45 | lateinit var angleTime: CharSequence
46 |
47 | @TextProp
48 | lateinit var text: CharSequence
49 |
50 | @TextProp
51 | lateinit var charScores: CharSequence
52 |
53 | @TextProp
54 | lateinit var crnnTime: CharSequence
55 |
56 | @TextProp
57 | lateinit var blockTime: CharSequence
58 |
59 | @AfterPropsSet
60 | fun useProps() {
61 | binding.blockIndexTv.text = index
62 | binding.content.boxPointTv.text = boxPoint
63 | binding.content.boxScoreTv.text = boxScore
64 | binding.content.angleIndexTv.text = angleIndex
65 | binding.content.angleScoreTv.text = angleScore
66 | binding.content.angleTimeTv.text = angleTime
67 | binding.content.textTv.text = text
68 | binding.content.charScoresTv.text = charScores
69 | binding.content.crnnTimeTv.text = crnnTime
70 | binding.content.blockTimeTv.text = blockTime
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/models/IdCardFront.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.models
2 |
3 | import android.os.Parcelable
4 | import com.benjaminwan.ocrlibrary.OcrOutput
5 | import kotlinx.android.parcel.Parcelize
6 |
7 | @Parcelize
8 | data class IdCardFront(
9 | val name: String,//姓名
10 | val nation: String,//民族
11 | val address: String,//地址
12 | val number: String,//身份证号
13 | ) : Parcelable, OcrOutput() {
14 | //性别
15 | val gender: String
16 | get() {
17 | val genderNumber = number[16].toInt()
18 | return if (genderNumber % 2 == 1) "男" else "女"
19 | }
20 |
21 | //出生日期
22 | val birth: String
23 | get() {
24 | val year = number.substring(6..9)
25 | val month = number.substring(10..11)
26 | val date = number.substring(12..13)
27 | return "$year-$month-$date"
28 | }
29 |
30 | fun isEmpty(): Boolean =
31 | name.isEmpty() && nation.isEmpty() && address.isEmpty() && number.isEmpty()
32 |
33 |
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/utils/BitmapUtils.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.utils
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.graphics.BitmapFactory
6 | import android.net.Uri
7 | import java.io.FileNotFoundException
8 |
9 | @Throws(FileNotFoundException::class)
10 | fun Context.decodeUri(imgUri: Uri): Bitmap? {
11 | // Decode image size
12 | val options = BitmapFactory.Options()
13 | options.inJustDecodeBounds = false
14 | options.inMutable = true
15 | options.inPreferredConfig = Bitmap.Config.ARGB_8888
16 | return BitmapFactory.decodeStream(contentResolver.openInputStream(imgUri), null, options)
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/utils/ClipboardUtils.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.utils
2 |
3 | import android.content.ClipData
4 | import android.content.ClipboardManager
5 | import android.content.Context
6 |
7 | fun Context.toClipboard(text: String) {
8 | val clipboardManager =
9 | this.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
10 | // 创建普通字符型ClipData
11 | val mClipData = ClipData.newPlainText(packageName, text)
12 | // 将ClipData内容放到系统剪贴板里。
13 | clipboardManager.setPrimaryClip(mClipData)
14 | this.showToast("已复制到剪切板!")
15 | }
16 |
17 | fun Context.fromClipboard(): String? {
18 | val clipboardManager =
19 | this.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
20 | return if (clipboardManager.hasPrimaryClip()) {
21 | val clipData = clipboardManager.primaryClip
22 | if (clipData != null) {
23 | if (clipData.itemCount > 0) {
24 | clipData.getItemAt(0).text.toString()
25 | } else {
26 | null
27 | }
28 | } else {
29 | null
30 | }
31 | } else {
32 | null
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/utils/DecimalFormatUtils.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.utils
2 |
3 | import java.text.DecimalFormat
4 |
5 | /**
6 | * 数字格式化
7 | * @param pattern 格式
8 | * 例"#.000000" 保留6位小数
9 | * @return 返回格式化后的字符串
10 | */
11 | fun Double.format(pattern: String): String {
12 | if (pattern.isEmpty()) {
13 | return this.toString()
14 | }
15 | return DecimalFormat(pattern).format(this)
16 | }
17 |
18 | /**
19 | * 数字格式化
20 | * @param pattern 格式
21 | * @return 返回格式化后的字符串
22 | */
23 | fun Long.format(pattern: String): String {
24 | if (pattern.isEmpty()) {
25 | return this.toString()
26 | }
27 | return DecimalFormat(pattern).format(this)
28 | }
29 |
30 | /**
31 | * 数字格式化
32 | * @param pattern 格式
33 | * @return 返回格式化后的字符串
34 | */
35 | fun Int.format(pattern: String): String {
36 | if (pattern.isEmpty()) {
37 | return this.toString()
38 | }
39 | return DecimalFormat(pattern).format(this)
40 | }
41 |
42 | /**
43 | * 数字格式化
44 | * @param pattern 格式
45 | * @return 返回格式化后的字符串
46 | */
47 | fun Float.format(pattern: String): String {
48 | if (pattern.isEmpty()) {
49 | return this.toString()
50 | }
51 | return DecimalFormat(pattern).format(this)
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/utils/IdCardMatchUtils.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.utils
2 |
3 | import com.orhanobut.logger.Logger
4 | import java.util.regex.Matcher
5 | import java.util.regex.Pattern
6 |
7 | const val idCardNumberRegex =
8 | "^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}\$|^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)\$"
9 |
10 |
11 | fun getMatchIdCardNumberStr(text: String): String? {
12 | val matchALL = Regex(idCardNumberRegex).find(text)
13 | if (matchALL != null) {
14 | Logger.i("match结果 matchALL:${matchALL.value}")
15 | return matchALL.value
16 | }
17 | return null
18 | }
19 |
20 | fun String.trimSymbols(): String {
21 | var dest = ""
22 | if (this.isNotEmpty()) {
23 | val p: Pattern = Pattern.compile("\\p{P}|\\p{S}")
24 | val m: Matcher = p.matcher(this)
25 | dest = m.replaceAll("")
26 | }
27 | return dest
28 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/utils/ImeiMatchUtils.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.utils
2 |
3 | import com.orhanobut.logger.Logger
4 | import java.util.regex.Matcher
5 | import java.util.regex.Pattern
6 |
7 | const val imeiRegex = "\\d{15}|\\d{17}"
8 |
9 | fun getMatchImeiStr(text: String): String? {
10 | val matchALL = Regex(imeiRegex).find(text)
11 | if (matchALL != null) {
12 | Logger.i("match结果 matchALL:${matchALL.value}")
13 | return matchALL.value
14 | }
15 | return null
16 | }
17 |
18 | fun String.replaceBlank(): String {
19 | var dest = ""
20 | if (this.isNotEmpty()) {
21 | val p: Pattern = Pattern.compile("\\s*|\t|\r|\n")
22 | val m: Matcher = p.matcher(this)
23 | dest = m.replaceAll("")
24 | }
25 | return dest
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/utils/PlateMatchUtils.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.utils
2 |
3 | import com.orhanobut.logger.Logger
4 | import java.util.regex.Matcher
5 | import java.util.regex.Pattern
6 |
7 | const val plateRegex = "^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))\$"
8 |
9 | fun getMatchPlateStr(text: String): String? {
10 | val matchALL = Regex(plateRegex).find(text)
11 | if (matchALL != null) {
12 | Logger.i("match结果 matchALL:${matchALL.value}")
13 | return matchALL.value
14 | }
15 | return null
16 | }
17 |
18 | fun String.trimBlankAndSymbols(): String {
19 | var dest = ""
20 | if (this.isNotEmpty()) {
21 | val p: Pattern = Pattern.compile("\\p{P}|\\p{S}|\\s*|\t|\r|\n")
22 | val m: Matcher = p.matcher(this)
23 | dest = m.replaceAll("")
24 | }
25 | return dest
26 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/utils/RecyclerViewUtils.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.utils
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Color
6 | import android.graphics.Paint
7 | import android.graphics.Rect
8 | import android.view.View
9 | import androidx.recyclerview.widget.LinearLayoutManager
10 | import androidx.recyclerview.widget.RecyclerView
11 |
12 | /**
13 | * 设置RecyclerView的item四周间距
14 | * @param left 左边距
15 | * @param top 上边距
16 | * @param right 右边距
17 | * @param bottom 底边距
18 | */
19 | fun RecyclerView.setMarginItemDecoration(left: Int, top: Int, right: Int, bottom: Int) {
20 | addItemDecoration(object : RecyclerView.ItemDecoration() {
21 | override fun getItemOffsets(
22 | outRect: Rect,
23 | view: View,
24 | parent: RecyclerView,
25 | state: RecyclerView.State
26 | ) {
27 | //设置item间距
28 | outRect.left = dp2px(context, left)
29 | outRect.top = dp2px(context, top)
30 | outRect.right = dp2px(context, right)
31 | outRect.bottom = dp2px(context, bottom)
32 | }
33 | })
34 | }
35 |
36 | /**
37 | * 设置RecyclerView的item四周间距,并在item底部画分隔符
38 | * @param left 左边距
39 | * @param top 上边距
40 | * @param right 右边距
41 | * @param bottom 底边距
42 | */
43 | fun RecyclerView.setItemDecorationAndDrawBottom(
44 | left: Int, top: Int, right: Int, bottom: Int,
45 | bottomLine: Int
46 | ) {
47 | addItemDecoration(object : RecyclerView.ItemDecoration() {
48 | override fun getItemOffsets(
49 | outRect: Rect,
50 | view: View,
51 | parent: RecyclerView,
52 | state: RecyclerView.State
53 | ) {
54 | //设置item间距
55 | outRect.left = dp2px(context,left)
56 | outRect.top = dp2px(context,top)
57 | outRect.right = dp2px(context,right)
58 | outRect.bottom = dp2px(context,bottom)
59 | }
60 |
61 | override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
62 | super.onDraw(canvas, parent, state)
63 | //分隔符
64 | val paint = Paint()
65 | paint.color = Color.GRAY
66 |
67 | val left = parent.paddingLeft //不可以修改left等变量名,否则item底色会变成灰色
68 | val right = parent.measuredWidth - parent.paddingRight
69 | val childSize = parent.childCount
70 | for (i in 0 until childSize) {
71 | val child = parent.getChildAt(i)
72 | val layoutParams = child.layoutParams as RecyclerView.LayoutParams
73 | val top = child.bottom + layoutParams.bottomMargin
74 | val bottom = top + dp2px(context,bottomLine)
75 | canvas.drawRect(
76 | left.toFloat(), top.toFloat(),
77 | right.toFloat(), bottom.toFloat(), paint
78 | )
79 | }
80 | }
81 | })
82 | }
83 |
84 | fun RecyclerView.scrollToTop() {
85 | val layoutManager = this.layoutManager as LinearLayoutManager?
86 | layoutManager?.scrollToPositionWithOffset(0, 0)
87 | }
88 |
89 | fun RecyclerView.scrollToBottom() {
90 | val layoutManager = this.layoutManager as LinearLayoutManager?
91 | val itemCount = this.adapter?.itemCount ?: 0
92 | layoutManager?.scrollToPositionWithOffset(itemCount - 1, 0)
93 | }
94 |
95 | private fun dp2px(context: Context, value: Int): Int {
96 | val scale = context.resources.displayMetrics.density
97 | return (value.toFloat() * scale + 0.5f).toInt()
98 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/utils/SoftInputUtils.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.utils
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import android.view.inputmethod.InputMethodManager
6 | import android.widget.EditText
7 | import androidx.fragment.app.Fragment
8 |
9 | /**
10 | * 显示软建键盘
11 | */
12 | fun EditText.showSoftInput(){
13 | requestFocus()
14 | setSelection(text.toString().length)//将光标移至文字末尾
15 | val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
16 | imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
17 | }
18 |
19 | /**
20 | * 隐藏软键盘
21 | */
22 | fun Fragment.hideSoftInput() {
23 | val imm = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
24 | imm.hideSoftInputFromWindow(view?.windowToken, 0)
25 | }
26 |
27 | /**
28 | * 动态隐藏软键盘
29 | *
30 | * @param view 视图
31 | */
32 | fun View.hideSoftInput() {
33 | val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
34 | imm.hideSoftInputFromWindow(windowToken, 0)
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/benjaminwan/ocr/onnx/utils/ToastUtils.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx.utils
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.widget.Toast
6 | import androidx.annotation.StringRes
7 | import androidx.fragment.app.Fragment
8 |
9 | fun Context.showToast(msg: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
10 | Toast.makeText(this, msg, duration).show()
11 | }
12 |
13 | fun Context.showToast(@StringRes resId: Int, duration: Int = Toast.LENGTH_SHORT) {
14 | Toast.makeText(this, resId, duration).show()
15 | }
16 |
17 | /**
18 | * 显示Toast
19 | * @param msg
20 | */
21 | fun Activity.showToast(msg: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
22 | applicationContext.showToast(msg, duration)
23 | }
24 |
25 | /**
26 | * 显示Toast
27 | * @param msg
28 | */
29 | fun Activity.showToast(@StringRes msg: Int, duration: Int = Toast.LENGTH_SHORT) {
30 | applicationContext.showToast(msg, duration)
31 | }
32 |
33 | /**
34 | * 显示Toast
35 | * @param msg
36 | */
37 | fun Fragment.showToast(msg: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
38 | requireActivity().applicationContext.showToast(msg, duration)
39 | }
40 |
41 | /**
42 | * 显示Toast
43 | * @param msg
44 | */
45 | fun Fragment.showToast(@StringRes msg: Int, duration: Int = Toast.LENGTH_SHORT) {
46 | requireActivity().applicationContext.showToast(msg, duration)
47 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/window_close_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/window_close_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/window_enter_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/window_exit_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/window_fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/window_fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/window_show_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/window_show_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/color/btn_blue3_to_blue5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
15 |
20 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/color/btn_blue5_to_blue7.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
15 |
20 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/color/btn_grey3_to_grey5.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
15 |
20 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/color/btn_grey5_to_grey7.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
15 |
20 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/color/btn_pink5_to_pink7.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
15 |
20 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/color/btn_white_to_grey.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
15 |
20 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_blue3_to_blue5.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
14 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_blue5_to_blue7.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
13 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_edittext.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_edittext_focused.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_edittext_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_transparent_to_transparent_half.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close.xml:
--------------------------------------------------------------------------------
1 |
6 |
8 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_loading.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_ocr.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/loading_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_imei.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
18 |
19 |
36 |
37 |
54 |
55 |
73 |
74 |
88 |
89 |
107 |
108 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
21 |
22 |
27 |
28 |
33 |
34 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_plate.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
18 |
19 |
36 |
37 |
54 |
55 |
73 |
74 |
88 |
89 |
107 |
108 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_debug.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
24 |
25 |
26 |
27 |
31 |
32 |
41 |
42 |
43 |
44 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_text_result.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
29 |
30 |
31 |
32 |
36 |
37 |
46 |
47 |
48 |
49 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_dbnet_time_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_debug_item_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
18 |
19 |
25 |
26 |
27 |
28 |
32 |
33 |
38 |
39 |
44 |
45 |
46 |
47 |
52 |
53 |
59 |
60 |
67 |
68 |
74 |
75 |
82 |
83 |
89 |
90 |
97 |
98 |
99 |
100 |
104 |
105 |
110 |
111 |
117 |
118 |
119 |
120 |
124 |
125 |
131 |
132 |
139 |
140 |
141 |
142 |
146 |
147 |
153 |
154 |
161 |
162 |
163 |
164 |
168 |
169 |
175 |
176 |
183 |
184 |
185 |
186 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/rv_debug_view_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
23 |
24 |
33 |
34 |
35 |
36 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6200EE
4 | #3700B3
5 | #03DAC5
6 | #10000000
7 | #00000000
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | OcrLiteOnnx
3 |
4 | 框置信度门限
5 | 框大小倍率
6 | 获取相机权限
7 | 获取存储权限
8 | 文字方向检测
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
14 |
15 |
19 |
20 |
24 |
25 |
29 |
30 |
40 |
41 |
51 |
52 |
60 |
61 |
70 |
71 |
--------------------------------------------------------------------------------
/app/src/test/java/com/benjaminwan/ocr/onnx/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.onnx
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/appjava/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/appjava/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 |
5 | android {
6 | namespace 'com.benjaminwan.ocr.java'
7 | compileSdk compile_sdk_version
8 |
9 | defaultConfig {
10 | applicationId "com.benjaminwan.ocr.java"
11 | minSdk min_sdk_version
12 | targetSdk target_sdk_version
13 | versionCode project_version_code
14 | versionName project_version_name
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | viewBinding {
30 | enabled = true
31 | }
32 | }
33 |
34 | dependencies {
35 | testImplementation 'junit:junit:4.13.2'
36 | androidTestImplementation 'androidx.test.ext:junit:1.1.5'
37 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
38 | //Android
39 | implementation 'androidx.appcompat:appcompat:1.6.1'
40 | implementation 'com.google.android.material:material:1.8.0'
41 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
42 | //glide
43 | implementation 'com.github.bumptech.glide:glide:4.13.2'
44 |
45 | implementation 'com.github.chrisbanes:PhotoView:2.3.0'
46 |
47 | //申请权限
48 | implementation 'pub.devrel:easypermissions:3.0.0'
49 |
50 | //Logger
51 | implementation 'com.orhanobut:logger:2.2.0'
52 |
53 | //RxKotlin
54 | implementation 'io.reactivex.rxjava3:rxandroid:3.0.2'
55 | implementation 'io.reactivex.rxjava3:rxkotlin:3.0.1'
56 |
57 | implementation project(":OcrLibrary")
58 |
59 | }
--------------------------------------------------------------------------------
/appjava/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/appjava/src/androidTest/java/com/benjaminwan/ocr/java/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.java;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.benjaminwan.ocr.java", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/appjava/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/appjava/src/main/java/com/benjaminwan/ocr/java/app/App.java:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.java.app;
2 |
3 | import android.app.Application;
4 | import androidx.annotation.Nullable;
5 | import com.orhanobut.logger.AndroidLogAdapter;
6 | import com.orhanobut.logger.FormatStrategy;
7 | import com.orhanobut.logger.Logger;
8 | import com.orhanobut.logger.PrettyFormatStrategy;
9 | import com.benjaminwan.ocr.java.BuildConfig;
10 |
11 | public class App extends Application {
12 | @Override
13 | public void onCreate() {
14 | super.onCreate();
15 | initLogger();
16 | }
17 |
18 | private void initLogger() {
19 | FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder()
20 | .showThreadInfo(true)
21 | .tag("OcrLite")
22 | .build();
23 | Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy) {
24 | @Override
25 | public boolean isLoggable(int priority, @Nullable String tag) {
26 | return BuildConfig.DEBUG;
27 | }
28 | });
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/appjava/src/main/java/com/benjaminwan/ocr/java/utils/BitmapUtils.java:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.java.utils;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.net.Uri;
7 |
8 | import java.io.FileNotFoundException;
9 |
10 | public class BitmapUtils {
11 | public static Bitmap decodeUri(Context context, Uri imgUri) throws FileNotFoundException {
12 | // Decode image size
13 | BitmapFactory.Options options = new BitmapFactory.Options();
14 | options.inJustDecodeBounds = false;
15 | options.inMutable = true;
16 | options.inPreferredConfig = Bitmap.Config.ARGB_8888;
17 | return BitmapFactory.decodeStream(context.getContentResolver().openInputStream(imgUri), null, options);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/appjava/src/main/java/com/benjaminwan/ocr/java/utils/ToastUtils.java:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.java.utils;
2 |
3 | import android.app.Activity;
4 | import android.widget.Toast;
5 |
6 | public class ToastUtils {
7 | public static void showToast(Activity activity, CharSequence msg, int duration) {
8 | Toast.makeText(activity.getApplicationContext(), msg, duration).show();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/appjava/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/appjava/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/appjava/src/main/res/drawable/ic_loading.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/appjava/src/main/res/drawable/loading_anim.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/appjava/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
23 |
24 |
28 |
29 |
34 |
35 |
42 |
43 |
44 |
45 |
49 |
50 |
55 |
56 |
63 |
64 |
65 |
66 |
70 |
71 |
76 |
77 |
84 |
85 |
86 |
87 |
91 |
92 |
97 |
98 |
105 |
106 |
107 |
108 |
112 |
113 |
118 |
119 |
126 |
127 |
128 |
129 |
133 |
134 |
138 |
139 |
146 |
147 |
152 |
153 |
160 |
161 |
162 |
163 |
168 |
169 |
176 |
177 |
184 |
185 |
192 |
193 |
194 |
195 |
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-anydpi-v33/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/appjava/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/appjava/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/appjava/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/appjava/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | appjava
3 | 获取存储权限
4 |
--------------------------------------------------------------------------------
/appjava/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/appjava/src/test/java/com/benjaminwan/ocr/java/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.benjaminwan.ocr.java;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = "1.7.20"
4 | ext.compile_sdk_version = 33
5 | ext.min_sdk_version = 21
6 | ext.target_sdk_version = 33
7 | ext.project_version_code = 22
8 | ext.project_version_name = "1.8.0"
9 | }
10 |
11 | plugins {
12 | id 'com.android.application' version '7.4.1' apply false
13 | id 'com.android.library' version '7.4.1' apply false
14 | id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
15 | }
16 |
17 | task clean(type: Delete) {
18 | delete rootProject.buildDir
19 | }
--------------------------------------------------------------------------------
/capture/detect_IMEI.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/capture/detect_IMEI.gif
--------------------------------------------------------------------------------
/capture/detect_id_card.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/capture/detect_id_card.gif
--------------------------------------------------------------------------------
/capture/detect_plate.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/capture/detect_plate.gif
--------------------------------------------------------------------------------
/common-aar/IdCardView-1.0.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/common-aar/IdCardView-1.0.aar
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 | android.injected.testOnly=false
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Nov 19 08:49:30 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/keystore/ocrlite.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benjaminwan/OcrLiteAndroidOnnx/27c48c01ffbc10aec2f43f3292356e73cae5d6e0/keystore/ocrlite.keystore
--------------------------------------------------------------------------------
/scripts/build-onnxruntime-android.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # build onnxruntime 1.6~1.9 by benjaminwan
3 | # CMakeFiles/onnxruntime.dir/link.txt link lib*.a
4 |
5 | function cmakeParams(){
6 | ./build.sh --build_dir "$1_$2_$3" --parallel --config $1 --skip_tests \
7 | --build_shared_lib --cmake_extra_defines CMAKE_INSTALL_PREFIX=./install \
8 | --android --android_sdk_path /Users/mywork/android-sdk-macosx \
9 | --android_ndk_path /Users/mywork/android-sdk-macosx/ndk-bundle \
10 | --android_abi $2 \
11 | --android_api $3 \
12 | --target install
13 | }
14 |
15 | echo "请选择编译选项并回车: 1)Release,2)Debug"
16 | echo "Please Select Build Type: 1)Release,2)Debug"
17 | read -p "" BUILD_TYPE
18 | if [ $BUILD_TYPE == 0 ]; then
19 | echo
20 | elif [ $BUILD_TYPE == 1 ]; then
21 | cmakeParams "Release" "armeabi-v7a" 19
22 | cmakeParams "Release" "arm64-v8a" 21
23 | cmakeParams "Release" "x86" 19
24 | cmakeParams "Release" "x86_64" 21
25 | elif [ $BUILD_TYPE == 2 ]; then
26 | cmakeParams "Debug" "armeabi-v7a" 19
27 | cmakeParams "Debug" "arm64-v8a" 21
28 | cmakeParams "Debug" "x86" 19
29 | cmakeParams "Debug" "x86_64" 21
30 | else
31 | echo -e "输入错误!Input Error!"
32 | fi
--------------------------------------------------------------------------------
/scripts/build-opencv3-android.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # build opencv 3.5.x base on https://github.com/nihui/opencv-mobile/blob/master/opencv4_cmake_options.txt
3 |
4 | export ANDROID_NDK=/Users/mywork/android-sdk-macosx/ndk-bundle
5 |
6 | function cmakeParams() {
7 | mkdir -p "build-$1"
8 | pushd "build-$1"
9 | cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CONFIGURATION_TYPES=Release \
10 | -DCMAKE_INSTALL_PREFIX=install \
11 | -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK/build/cmake/android.toolchain.cmake" \
12 | -DANDROID_ABI="$1" -DANDROID_ARM_NEON=ON -DANDROID_CPP_FEATURES="no-rtti no-exceptions" \
13 | $(cat ../../opencv3_cmake_options.txt) -DBUILD_opencv_world=OFF \
14 | ..
15 | cmake --build . --config Release -j $NUM_THREADS
16 | cmake --build . --config Release --target install
17 | popd
18 | }
19 |
20 | sysOS=$(uname -s)
21 | NUM_THREADS=1
22 |
23 | if [ $sysOS == "Darwin" ]; then
24 | #echo "I'm MacOS"
25 | NUM_THREADS=$(sysctl -n hw.ncpu)
26 | elif [ $sysOS == "Linux" ]; then
27 | #echo "I'm Linux"
28 | NUM_THREADS=$(grep ^processor /proc/cpuinfo | wc -l)
29 | else
30 | echo "Other OS: $sysOS"
31 | fi
32 |
33 | # build
34 | cmakeParams "armeabi-v7a"
35 | cmakeParams "arm64-v8a"
36 | cmakeParams "x86"
37 | cmakeParams "x86_64"
38 |
39 | # pack
40 | mkdir opencv-mobile-3.4.15-android
41 | cp -rf build-x86/install/* opencv-mobile-3.4.15-android/
42 | cp -rf build-x86_64/install/* opencv-mobile-3.4.15-android/
43 | cp -rf build-armeabi-v7a/install/* opencv-mobile-3.4.15-android/
44 | cp -rf build-arm64-v8a/install/* opencv-mobile-3.4.15-android/
45 | rm -rf opencv-mobile-3.4.15-android/apk
46 | rm -rf opencv-mobile-3.4.15-android/sdk/etc
--------------------------------------------------------------------------------
/scripts/build-opencv3-static-android.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # build opencv 3.4.11 for android static (.a) by benjaminwan 2020.8.21
4 |
5 | export ANDROID_NDK=/path/to/your/ndk/17.2.4988734
6 |
7 | cmakeParams(){
8 | cmake -DCMAKE_BUILD_TYPE=RELEASE\
9 | -DANDROID_ABI=$1 \
10 | -DANDROID_ARM_NEON=ON \
11 | -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
12 | -DBUILD_ANDROID_PROJECTS=OFF \
13 | -DBUILD_ANDROID_EXAMPLES=OFF \
14 | -DBUILD_CUDA_STUBS=OFF \
15 | -DBUILD_DOCS=OFF \
16 | -DBUILD_EXAMPLES=OFF \
17 | -DBUILD_IPP_IW=OFF \
18 | -DBUILD_ITT=OFF \
19 | -DBUILD_JASPER=OFF \
20 | -DBUILD_JAVA=OFF \
21 | -DBUILD_JPEG=OFF \
22 | -DBUILD_LIST=OFF \
23 | -DBUILD_OPENEXR=OFF \
24 | -DBUILD_PACKAGE=OFF \
25 | -DBUILD_PERF_TESTS=OFF \
26 | -DBUILD_PNG=OFF \
27 | -DBUILD_PROTOBUF=OFF \
28 | -DBUILD_SHARED_LIBS=OFF \
29 | -DBUILD_TBB=OFF \
30 | -DBUILD_TESTS=OFF \
31 | -DBUILD_TIFF=OFF \
32 | -DBUILD_USE_SYMLINKS=OFF \
33 | -DBUILD_WEBP=OFF \
34 | -DBUILD_WITH_DEBUG_INFO=OFF \
35 | -DBUILD_WITH_DYNAMIC_IPP=OFF \
36 | -DBUILD_ZLIB=OFF \
37 | -DBUILD_opencv_apps=OFF \
38 | -DBUILD_opencv_calib3d=OFF \
39 | -DBUILD_opencv_core=ON \
40 | -DBUILD_opencv_dnn=OFF \
41 | -DBUILD_opencv_features2d=OFF \
42 | -DBUILD_opencv_flann=OFF \
43 | -DBUILD_opencv_highgui=ON \
44 | -DBUILD_opencv_imgcodecs=ON \
45 | -DBUILD_opencv_imgproc=ON \
46 | -DBUILD_opencv_java_bindings_generator=OFF \
47 | -DBUILD_opencv_js=OFF \
48 | -DBUILD_opencv_ml=OFF \
49 | -DBUILD_opencv_objdetect=OFF \
50 | -DBUILD_opencv_photo=OFF \
51 | -DBUILD_opencv_python2=OFF \
52 | -DBUILD_opencv_python_bindings_generator=OFF \
53 | -DBUILD_opencv_python_tests=OFF \
54 | -DBUILD_opencv_shape=OFF \
55 | -DBUILD_opencv_stitching=OFF \
56 | -DBUILD_opencv_superres=OFF \
57 | -DBUILD_opencv_ts=OFF \
58 | -DBUILD_opencv_video=OFF \
59 | -DBUILD_opencv_videoio=OFF \
60 | -DBUILD_opencv_videostab=OFF \
61 | -DBUILD_opencv_world=ON \
62 | -DWITH_1394=OFF \
63 | -DWITH_ARITH_DEC=OFF \
64 | -DWITH_ARITH_ENC=OFF \
65 | -DWITH_AVFOUNDATION=OFF \
66 | -DWITH_EIGEN=OFF \
67 | -DWITH_FFMPEG=OFF \
68 | -DWITH_GSTREAMER=OFF \
69 | -DWITH_IMGCODEC_HDR=OFF \
70 | -DWITH_IMGCODEC_PXM=OFF \
71 | -DWITH_IMGCODEC_SUNRASTER=OFF \
72 | -DWITH_IPP=OFF \
73 | -DWITH_ITT=OFF \
74 | -DWITH_JASPER=OFF \
75 | -DWITH_JPEG=OFF \
76 | -DWITH_LAPACK=OFF \
77 | -DWITH_OPENEXR=OFF \
78 | -DWITH_PNG=OFF \
79 | -DWITH_PROTOBUF=OFF \
80 | -DWITH_PTHREADS_PF=OFF \
81 | -DWITH_QUIRC=OFF \
82 | -DWITH_TIFF=OFF \
83 | -DWITH_VTK=OFF \
84 | -DWITH_WEBP=OFF \
85 | ..
86 | make -j8
87 | make install
88 | }
89 |
90 | ##### android armv7
91 | mkdir -p build-android-armv7
92 | pushd build-android-armv7
93 | cmakeParams "armeabi-v7a"
94 | popd
95 |
96 | ##### android arm64-v8a
97 | mkdir -p build-android-arm64v8
98 | pushd build-android-arm64v8
99 | cmakeParams "arm64-v8a"
100 | popd
101 |
102 | ##### android x86
103 | mkdir -p build-android-x86
104 | pushd build-android-x86
105 | cmakeParams "x86"
106 | popd
107 |
108 | ##### android x86_64
109 | mkdir -p build-android-x86_64
110 | pushd build-android-x86_64
111 | cmakeParams "x86_64"
112 | popd
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | maven { url "https://jitpack.io" }
14 | jcenter()
15 | flatDir {
16 | dirs 'common-aar'
17 | }
18 | }
19 | }
20 | rootProject.name = "OcrLiteAndroidOnnx"
21 | include ':app'
22 | include ':OcrLibrary'
23 | include ':appjava'
24 |
--------------------------------------------------------------------------------