feat: 增加ocr文字识别功能

This commit is contained in:
2023-03-23 15:48:24 +08:00
parent 506299b3a3
commit 12b870ea79
53 changed files with 9603 additions and 166 deletions

1
ocr/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

61
ocr/build.gradle Normal file
View File

@@ -0,0 +1,61 @@
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
}
android {
namespace 'com.navinfo.ocr'
compileSdk 31
defaultConfig {
minSdk 23
targetSdk 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
abiFilters "armeabi", "armeabi-v7a"
}
}
buildTypes {
debug {
packagingOptions {
doNotStrip '**/*.so' // 避免so资源文件编译提示可忽略
}
}
release {
packagingOptions {
doNotStrip '**/*.so' // 避免so资源文件编译提示可忽略
}
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'com.google.android.material:material:1.8.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
api files('libs/easyedge-sdk.jar')
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ocr/libs/easyedge-sdk.jar Normal file

Binary file not shown.

21
ocr/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,24 @@
package com.navinfo.ocr
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.navinfo.ocr", appContext.packageName)
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- <application-->
<!-- android:allowBackup="true"-->
<!-- />-->
</manifest>

View File

@@ -0,0 +1,26 @@
{
"version": 1,
"framework": "fluid",
"model_info": {
"n_type": 0,
"best_threshold": 0.1,
"model_kind": 100
},
"pre_process": {
"mean": [123.675, 116.28, 103.53],
"scale": [
0.01712475383166,
0.01750700280112,
0.01742919389978
],
"color_format": "BGR",
"channel_order": "CHW",
"resize": [960, 960],
"rescale_mode": "keep_ratio",
"max_size":960,
"ocr_rec_resize": [320,32]
},
"extra": {
"fluid": {"optType": "nb"}
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1659598895605" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3308" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
</style></defs><path d="M885.333333 938.666667H138.666667a53.393333 53.393333 0 0 1-53.333334-53.333334V138.666667a53.393333 53.393333 0 0 1 53.333334-53.333334h746.666666a53.393333 53.393333 0 0 1 53.333334 53.333334v746.666666a53.393333 53.393333 0 0 1-53.333334 53.333334zM138.666667 128a10.666667 10.666667 0 0 0-10.666667 10.666667v746.666666a10.666667 10.666667 0 0 0 10.666667 10.666667h746.666666a10.666667 10.666667 0 0 0 10.666667-10.666667V138.666667a10.666667 10.666667 0 0 0-10.666667-10.666667z" fill="#A1DBF5" p-id="3309"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,209 @@
package com.navinfo.ocr
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.os.Build
import android.text.TextUtils
import android.util.Log
import android.widget.Toast
import com.baidu.ai.edge.core.base.CallException
import com.baidu.ai.edge.core.base.Consts
import com.baidu.ai.edge.core.infer.InferConfig
import com.baidu.ai.edge.core.infer.InferManager
import com.baidu.ai.edge.core.ocr.OcrInterface
import com.baidu.ai.edge.core.ocr.OcrResultModel
import com.baidu.ai.edge.core.util.FileUtil
import com.navinfo.ocr.model.OcrViewResultModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import org.json.JSONException
import org.json.JSONObject
import java.util.*
class OCRManager {
private var mContext: Context? = null
private var modelName = ""
private val socList = ArrayList<String>()
private var modelType = 0
private var soc: String? = null
private var mOcrManager: OcrInterface? = null
private val CONFIDENCE = 0.3f
fun ocr(bitmap: Bitmap): List<OcrViewResultModel> {
Log.e("jingo", "OCRManager 线程名称3 ${Thread.currentThread().name}")
val list = ArrayList<OcrViewResultModel>()
if (mOcrManager != null) {
val modelList = mOcrManager!!.ocr(bitmap, CONFIDENCE)
for (i in modelList.indices) {
val mOcrResultModel: OcrResultModel = modelList[i]
val mOcrViewResultModel = OcrViewResultModel()
mOcrViewResultModel.colorId = mOcrResultModel.labelIndex
mOcrViewResultModel.index = i + 1
mOcrViewResultModel.confidence = mOcrResultModel.confidence
mOcrViewResultModel.name = mOcrResultModel.label
mOcrViewResultModel.bounds = mOcrResultModel.points
mOcrViewResultModel.isTextOverlay = true
list.add(mOcrViewResultModel)
}
}
return list
}
/**
* 原有的
*/
private fun initConfigFromDemoConfig(): Boolean {
val confJson =
FileUtil.readAssetsFileUTF8StringIfExists(mContext!!.assets, "demo/config.json")
if (TextUtils.isEmpty(confJson)) {
return false
}
try {
val confObj = JSONObject(confJson)
modelName = confObj.optString("modelName", "")
val str = confObj.optString("soc", Consts.SOC_ARM)
val socs = str.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
socList.addAll(listOf(*socs))
modelType = confObj.getInt("modelType")
} catch (e: JSONException) {
e.printStackTrace()
}
return true
}
/**
* 开放模型
*/
private fun initConfigFromDemoConf(): Boolean {
val confJson =
FileUtil.readAssetsFileUTF8StringIfExists(mContext!!.assets, "demo/conf.json")
if (TextUtils.isEmpty(confJson)) {
return false
}
try {
val confObj = JSONObject(confJson)
modelName = confObj.optString("modelName", "")
socList.add(Consts.SOC_ARM)
val inferCfgJson = FileUtil.readAssetsFileUTF8StringIfExists(
mContext!!.assets,
Consts.ASSETS_DIR_ARM + "/infer_cfg.json"
)
if (TextUtils.isEmpty(inferCfgJson)) {
return false
}
val inferCfgObj = JSONObject(inferCfgJson)
modelType = inferCfgObj.getJSONObject("model_info").getInt("model_kind")
} catch (e: JSONException) {
e.printStackTrace()
}
return true
}
private fun checkChip(): Boolean {
if (socList.contains(Consts.SOC_DSP) && Build.HARDWARE.equals("qcom", ignoreCase = true)) {
soc = Consts.SOC_DSP
return true
}
if (socList.contains(Consts.SOC_ADRENO_GPU) && Build.HARDWARE.equals(
"qcom",
ignoreCase = true
)
) {
soc = Consts.SOC_ADRENO_GPU
return true
}
if (socList.contains(Consts.SOC_NPU) && Build.HARDWARE.contains("kirin980")) {
soc = "npu200"
return true
}
if (socList.contains(Consts.SOC_NPU_VINCI)
&& (Build.HARDWARE.contains("kirin810") || Build.HARDWARE.contains("kirin820")
|| Build.HARDWARE.contains("kirin990") || Build.HARDWARE.contains("kirin985"))
) {
soc = Consts.SOC_NPU_VINCI
return true
}
if (socList.contains(Consts.SOC_ARM_GPU)) {
try {
if (InferManager.isSupportOpencl()) {
soc = Consts.SOC_ARM_GPU
return true
}
} catch (e: CallException) {
Toast.makeText(
mContext, e.errorCode.toString() + ", " + e.message,
Toast.LENGTH_SHORT
).show()
}
}
if (socList.contains(Consts.SOC_ARM)) {
soc = Consts.SOC_ARM
return true
}
return false
}
fun init(context: Context) {
mContext = context
if (initConfigFromDemoConfig()) {
return
}
if (initConfigFromDemoConf()) {
return
}
/* 从infer/读配置 */
var confJson = FileUtil.readAssetsFileUTF8StringIfExists(
mContext!!.applicationContext.assets,
Consts.ASSETS_DIR_ARM + "/conf.json"
)
if (!TextUtils.isEmpty(confJson)) {
try {
val confObj = JSONObject(confJson)
modelName = confObj.optString("modelName", "")
val str = confObj.optString("soc", Consts.SOC_ARM)
val socs = str.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
socList.addAll(listOf(*socs))
modelType = confObj.getInt("modelType")
} catch (e: JSONException) {
e.printStackTrace()
}
} else {
confJson = FileUtil.readAssetsFileUTF8StringIfExists(
mContext!!.applicationContext.assets,
Consts.ASSETS_DIR_ARM + "/infer_cfg.json"
)
try {
val confObj = JSONObject(confJson)
socList.add(Consts.SOC_ARM)
modelType = confObj.getJSONObject("model_info").getInt("model_kind")
} catch (e: JSONException) {
e.printStackTrace()
}
}
MainScope().launch(Dispatchers.IO) {
try {
Log.e("jingo", "OCRManager 线程名称 ${Thread.currentThread().name}")
/* 1. 准备配置类初始化Manager类。可以在onCreate或onResume中触发请在非UI线程里调用 */
val config = InferConfig(context.assets, "infer")
mOcrManager = InferManager(mContext, config, SERIAL_NUM)
// cancel()
} catch (e: Exception) {
Log.e("jingo", "OCRManager 线程名称 ${e.message}")
}
}
}
companion object {
val instance: OCRManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
OCRManager()
}
// 请替换为您的序列号
private const val SERIAL_NUM = "XXXX-XXXX-XXXX-XXXX"
}
}

View File

@@ -0,0 +1,209 @@
package com.navinfo.ocr.model;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
public class BasePolygonResultModel extends BaseResultModel implements Parcelable {
private int colorId;
private boolean isRect;
private boolean isTextOverlay;
private boolean isHasGroupColor = false;
private boolean isDrawPoints = false;
/**
* 姿态一个点会有多个pair
*/
private boolean multiplePairs = false;
protected BasePolygonResultModel(Parcel in) {
super(in);
colorId = in.readInt();
isRect = in.readByte() != 0;
isTextOverlay = in.readByte() != 0;
isHasGroupColor = in.readByte() != 0;
isDrawPoints = in.readByte() != 0;
multiplePairs = in.readByte() != 0;
in.readByteArray(mask);
semanticMask = in.readByte() != 0;
rect = in.readParcelable(Rect.class.getClassLoader());
bounds = in.createTypedArrayList(Point.CREATOR);
}
public static final Creator<BasePolygonResultModel> CREATOR = new Creator<BasePolygonResultModel>() {
@Override
public BasePolygonResultModel createFromParcel(Parcel in) {
return new BasePolygonResultModel(in);
}
@Override
public BasePolygonResultModel[] newArray(int size) {
return new BasePolygonResultModel[size];
}
};
public boolean isTextOverlay() {
return isTextOverlay;
}
public void setTextOverlay(boolean textOverlay) {
isTextOverlay = textOverlay;
}
public int getColorId() {
return colorId;
}
public void setColorId(int colorId) {
this.colorId = colorId;
}
private byte[] mask = {};
/**
* 是否是语义分割mask
*/
private boolean semanticMask;
private Rect rect;
BasePolygonResultModel() {
super();
}
BasePolygonResultModel(int index, String name, float confidence, Rect bounds) {
super(index, name, confidence);
parseFromRect(bounds);
}
BasePolygonResultModel(int index, String name, float confidence, List<Point> bounds) {
super(index, name, confidence);
this.bounds = bounds;
}
public Rect getRect() {
return rect;
}
public Rect getRect(float ratio, Point origin) {
return new Rect((int) (origin.x + rect.left * ratio),
(int) (origin.y + rect.top * ratio),
(int) (origin.x + rect.right * ratio),
(int) (origin.y + rect.bottom * ratio));
}
private void parseFromRect(Rect rect) {
Point ptTL = new Point(rect.left, rect.top);
Point ptTR = new Point(rect.right, rect.top);
Point ptRB = new Point(rect.right, rect.bottom);
Point ptLB = new Point(rect.left, rect.bottom);
this.bounds = new ArrayList<>();
this.bounds.add(ptTL);
this.bounds.add(ptTR);
this.bounds.add(ptRB);
this.bounds.add(ptLB);
this.rect = rect;
isRect = true;
}
public boolean isRect() {
return isRect;
}
public void setRect(boolean rect) {
isRect = rect;
}
public byte[] getMask() {
return mask;
}
public void setMask(byte[] mask) {
this.mask = mask;
}
public void setSemanticMask(boolean semanticMask) {
this.semanticMask = semanticMask;
}
public boolean isSemanticMask() {
return semanticMask;
}
private List<Point> bounds;
public List<Point> getBounds() {
return bounds;
}
public List<Point> getBounds(float ratio, Point origin) {
List<Point> pointList = new ArrayList<>();
for (Point pt : bounds) {
int nx = (int) (origin.x + pt.x * ratio);
int ny = (int) (origin.y + pt.y * ratio);
pointList.add(new Point(nx, ny));
}
return pointList;
}
public void setBounds(List<Point> bounds) {
this.bounds = bounds;
}
public void setBounds(Rect bounds) {
parseFromRect(bounds);
}
public boolean isHasMask() {
return (mask != null);
}
public boolean isHasGroupColor() {
return isHasGroupColor;
}
public void setHasGroupColor(boolean hasGroupColor) {
isHasGroupColor = hasGroupColor;
}
public boolean isDrawPoints() {
return isDrawPoints;
}
public void setDrawPoints(boolean drawPoints) {
isDrawPoints = drawPoints;
}
public void setMultiplePairs(boolean multiplePairs) {
this.multiplePairs = multiplePairs;
}
public boolean isMultiplePairs() {
return multiplePairs;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest,flags);
dest.writeInt(colorId);
dest.writeByte((byte) (isRect ? 1 : 0));
dest.writeByte((byte) (isTextOverlay ? 1 : 0));
dest.writeByte((byte) (isHasGroupColor ? 1 : 0));
dest.writeByte((byte) (isDrawPoints ? 1 : 0));
dest.writeByte((byte) (multiplePairs ? 1 : 0));
dest.writeByteArray(mask);
dest.writeByte((byte) (semanticMask ? 1 : 0));
dest.writeParcelable(rect, flags);
dest.writeTypedList(bounds);
}
}

View File

@@ -0,0 +1,95 @@
package com.navinfo.ocr.model;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by ruanshimin on 2018/5/16.
*/
public class BaseRectBoundResultModel extends BaseResultModel implements Parcelable {
private int colorId;
protected BaseRectBoundResultModel(Parcel in) {
super(in);
colorId = in.readInt();
in.readByteArray(mask);
bounds = in.readParcelable(Rect.class.getClassLoader());
}
public static final Creator<BaseRectBoundResultModel> CREATOR = new Creator<BaseRectBoundResultModel>() {
@Override
public BaseRectBoundResultModel createFromParcel(Parcel in) {
return new BaseRectBoundResultModel(in);
}
@Override
public BaseRectBoundResultModel[] newArray(int size) {
return new BaseRectBoundResultModel[size];
}
};
public int getColorId() {
return colorId;
}
public void setColorId(int colorId) {
this.colorId = colorId;
}
private byte[] mask = {};
BaseRectBoundResultModel() {
super();
}
BaseRectBoundResultModel(int index, String name, float confidence, Rect bounds) {
super(index, name, confidence);
this.bounds = bounds;
}
public byte[] getMask() {
return mask;
}
public void setMask(byte[] mask) {
this.mask = mask;
}
private Rect bounds;
public Rect getBounds() {
return bounds;
}
public Rect getBounds(float ratio, Point origin) {
return new Rect((int) (origin.x + bounds.left * ratio),
(int) (origin.y + bounds.top * ratio),
(int) (origin.x + bounds.right * ratio),
(int) (origin.y + bounds.bottom * ratio));
}
public void setBounds(Rect bounds) {
this.bounds = bounds;
}
public boolean isHasMask() {
return (mask != null);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(colorId);
dest.writeByteArray(mask);
dest.writeParcelable(bounds, flags);
}
}

View File

@@ -0,0 +1,80 @@
package com.navinfo.ocr.model;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
/**
* Created by ruanshimin on 2018/5/16.
*/
public class BaseResultModel implements Parcelable {
private int index = 0;
private String name = "";
private float confidence = 0;
protected BaseResultModel() {
}
protected BaseResultModel(int index, String name, float confidence) {
this.index = index;
this.name = name;
this.confidence = confidence;
}
protected BaseResultModel(Parcel in) {
index = in.readInt();
name = in.readString();
confidence = in.readFloat();
}
public static final Creator<BaseResultModel> CREATOR = new Creator<BaseResultModel>() {
@Override
public BaseResultModel createFromParcel(Parcel in) {
return new BaseResultModel(in);
}
@Override
public BaseResultModel[] newArray(int size) {
return new BaseResultModel[size];
}
};
public float getConfidence() {
return confidence;
}
public void setConfidence(float confidence) {
this.confidence = confidence;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(index);
dest.writeString(name);
dest.writeFloat(confidence);
}
}

View File

@@ -0,0 +1,22 @@
package com.navinfo.ocr.model;
import java.io.Serializable;
/**
* Created by ruanshimin on 2018/5/13.
*/
public class ClassifyResultModel extends BaseResultModel {
public ClassifyResultModel() {
super();
}
public ClassifyResultModel(int index, String name, float confidence) {
super(index, name, confidence);
}
}

View File

@@ -0,0 +1,20 @@
package com.navinfo.ocr.model;
import android.graphics.Rect;
import java.io.Serializable;
/**
* Created by ruanshimin on 2018/5/13.
*/
public class DetectResultModel extends BasePolygonResultModel {
public DetectResultModel() {
super();
}
public DetectResultModel(int index, String name, float confidence, Rect bounds) {
super(index, name, confidence, bounds);
}
}

View File

@@ -0,0 +1,17 @@
package com.navinfo.ocr.model;
import android.graphics.Point;
import android.os.Parcelable;
import java.io.Serializable;
import java.util.List;
public class OcrViewResultModel extends BasePolygonResultModel{
public OcrViewResultModel() {
super();
}
public OcrViewResultModel(int index, String name, float confidence, List<Point> bounds) {
super(index, name, confidence, bounds);
}
}

View File

@@ -0,0 +1,14 @@
package com.navinfo.ocr.model;
import java.io.Serializable;
public class PoseViewResultModel extends BasePolygonResultModel {
public PoseViewResultModel() {
super();
setRect(false);
setTextOverlay(false);
setDrawPoints(true);
setMultiplePairs(true);
}
}

View File

@@ -0,0 +1,29 @@
package com.navinfo.ocr.model;
import android.graphics.Point;
import android.graphics.Rect;
import java.io.Serializable;
import java.util.List;
/**
* Created by ruanshimin on 2018/5/13.
*/
public class SegmentResultModel extends BasePolygonResultModel {
public SegmentResultModel() {
super();
}
public SegmentResultModel(int index, String name, float confidence, List<Point> bounds, byte[] mask) {
super(index, name, confidence, bounds);
this.setMask(mask);
}
public SegmentResultModel(int index, String name, float confidence, List<Point> bounds) {
super(index, name, confidence, bounds);
}
}

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.NavinfoCollect" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">ocr</string>
</resources>

View File

@@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.NavinfoCollect" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -0,0 +1,17 @@
package com.navinfo.ocr
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}