口算批改接入说明
文档修订记录
| 文档版本号 | 修订日期 | 修订原因 |
|---|---|---|
| V1.0 | 2022.6.21 | 创建文档 |
| V1.0.1 | 2022.7.7 | DocListener新增onEvent() 回调 |
概述
支持识别数学公式和符号,能识别分式、四则运算题型。
集成步骤
1. 添加依赖库
//必须依赖库
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation "org.java-websocket:Java-WebSocket:1.4.0"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.aliyun.dpa:oss-android-sdk:2.9.11'//SDKV2.4.1.25 以后需加入
// 口算批改
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
implementation "com.squareup.retrofit2:converter-moshi:2.6.0"
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"
implementation "androidx.work:work-runtime-ktx:2.7.1"
2. AndroidManifest配置
添加权限
<!--网络-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--文件读写-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--deviceID-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--绘本、指尖查词、坐姿、口算批改-->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<!-- 读取手机状态,获取IMEI -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<!-- android 10 在application节点添加以下适配高版本 -->
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"
3. 代码混淆
代码混淆文件proguard-project.txt,添加如下内容
-keep class com.turing.**{ *;}
-dontwarn com.turing.**
-keep class org.java_websocket.**{*;}
-dontwarn org.java_websocket.**
-keep class org.slf4j.**{*;}
-dontwarn org.slf4j.**
-keep class org.eclipse.** { *; }
-dontwarn org.eclipse.**
-keep class com.gl.glpigailib** { *;}
-keep class com.wyt.authentication** { *;}
-keep class a.** { *;}
-keep class b.** { *;}
-keep class c.** { *;}
4. SDK 初始化
使用口算批改功能前调用,请先调用SDK初始化代码。SDK初始化详情见《Android SDK接入指南说明文档》
TuringInitializer.getInstance().initV3XXX()
5. 开启功能集成
使用说明见下面【功能集成】描述。
实例化
TuringMathCorrection turingMath = TuringMathCorrection.getInstance(this);
功能集成
1. 使用口算批改
支持传入图片的文件地址 或 字节数据。
自行实现相机功能流程图
init=>start: 自行实现相机
take=>operation: 拍照
cut=>operation: 可自行裁剪图片
doc=>operation: 传入图片mathCorrection
deal=>operation: 处理回调onResult
release=>end: 释放资源stopMathCorrection
init->take->cut->doc->deal->release
方法
void mathCorrection(MathCorrectionRequestConfig config,MathCorrectionListener<MathCorrectionResult> listener);
输入说明
- MathCorrectionRequestConfig 说明
| 参数 | 类型 | 是否必须 | 取值范围 | 说明 |
|---|---|---|---|---|
| imagePath | String | Y | - | 图片文件绝对地址 (imagePath 和 imageData 二选一;两个都有值,优先选用 imageData) |
| imageData | byte[] | N | - | 图片字节数据 (imagePath 和 imageData 二选一;两个都有值,优先选用 imageData) |
- MathCorrectionListener 说明
接口回调为主线程
```java public interface MathCorrectionListener {
/**
* 识别结果
* @param result
*/
void onResult(MathCorrectionResult result);
/**
* 错误回调
* @param code
* @param msg
*/
void onError(int code, String msg);
} ```
输出说明
- MathCorrectionResult 说明
| 参数 | 类型 | 是否必返 | 取值范围 | 说明 |
|---|---|---|---|---|
| allAnswerRight | boolean | Y | - | 是否全部回答正确 |
| result | List |
Y | - | 识别结果 |
- MathCorrectionItem 参数说明
| 参数 | 类型 | 是否必返 | 取值范围 | 说明 |
|---|---|---|---|---|
| isAnswerRight | boolean | Y | - | 答案是否正确 |
| equationCoord | EquationCoord | Y | - | 坐标位置 |
| equationStr | String | Y | - | 识别出的算式,识别出的文本行字符串 |
- EquationCoord 参数说明
| 参数 | 类型 | 是否必返 | 取值范围 | 说明 |
|---|---|---|---|---|
| x | int | Y | - | 算式图的左上角横坐标 |
| y | int | Y | - | 算式图的左上角纵坐标 |
| width | int | Y | - | 算式图高度 |
| height | int | Y | - | 算式图宽度 |
请求示例
private fun math() {
showProgress()
var config = MathCorrectionRequestConfig.Builder()
.setImagePath(imagePath)
.build()
TuringMathCorrection.getInstance(this)
.mathCorrection(config, object : MathCorrectionListener<MathCorrectionResult> {
override fun onResult(mathCorrection: MathCorrectionResult?) {
hideProgress()
// mathCorrection.isAllAnswerRight true-全部回答正确,false-未全部回答正确
drawResult(mathCorrection?.result)
}
override fun onError(code: Int, msg: String?) {
hideProgress()
Log.e(TAG, "code=$code, msg=$msg")
}
})
}
2. 使用SDK内部相机获取图片
用于口算批改的图片可以是本地文件或相机。SDK封装了相机开发的方法,可直接使用。
使用SDK内部相机功能流程图
init=>start: 初始化相机initCamera
take=>operation: 拍照takePicture
cut=>operation: 可自行裁剪图片
doc=>operation: 传入图片mathCorrection
deal=>operation: 处理回调onResult
release=>end: 释放资源releaseCamera+stopMathCorrection
init->take->cut->doc->deal->release
方法
/**
* 1. 先初始化相机,并开启相机
*
* @param layout 装载预览界面的布局,建议使用 FrameLayout
* @param config 参数配置类
* @param listener 状态监听
*/
void initCamera(ViewGroup layout,DocRequestConfig config,@NotNull DocListener listener);
/**
* 2. 拍照
*/
void takePicture();
输入说明
- DocRequestConfig 参数说明
| 参数 | 类型 | 是否必须 | 说明 |
|---|---|---|---|
| dumpEnabled | boolean | N | 是否存储原始图片。默认:false |
| dumpCropEnabled | boolean | N | 是否存储裁切图片。默认:true |
| path | String | Y | 存储图片路径(原始图和裁切图) |
| viewSize | Size | N | 预览布局的大小。默认:MATCH_PARENT |
| previewSize | Size | Y | 预计图分辨率。 无默认值,必须设置 |
| picSize | Size | Y | 拍照图分辨率,图片格式JPEG。 无默认值,必须设置 |
| cameraId | String | N | 摄像头ID,"1"-前置,"0"-后置。默认:"0" |
| mirror | boolean | N | 是否镜像:一般前置摄像头使用。 使用反光镜-true,不使用反光镜-false |
| preMirror | boolean | N | 预览视图是否镜像 |
| photoDelayTime | int | N | 拍照延时,单位:s。默认:3s |
| preViewRotation | int | N | 预览视图旋转角度。默认:0 |
| preFrameRotation | int | N | 预览文档框的旋转角度。默认:90 |
| imageRotation | int | N | 图片旋转角度。默认:90 |
| drawPreDetectEnable | boolean | N | 是否绘制预览视图文档框。默认:true |
| preFrameColor | int | N | 绘制预览视图文档框的颜色。默认:绿色 |
| preFrameWidth | float | N | 绘制预览视图文档的边框大小。默认:5 |
| ifPad | boolean | N | true-平板;false-台灯 |
| ifCamera2 | boolean | N | true-Camera2;false-Camera1 默认true。 切换此值,重新调用initCamera()才生效。 |
配置 DocRequestConfig 参数,更改以下字段值时需要重新启动相机,会启动相机的方法:initCamera()、onResume()。
- viewSize
- previewSize
- picSize
- preViewRotation
- preFrameRotation
- cameradId
- ifCamera2
- ifPad
- DocListener 说明
接口回调为异步线程,如有更新 UI 操作,请切换至主线程。
```java public interface DocListener { /* * 成功回调 * @param path 裁切后图片路径 * @param jpg 裁切后的数据,jpg 格式 * @param width * @param height / void onResult(String path, byte[] jpg, int width, int height);
/**
* 拍照延时倒计时
* @param time 单位:s
*/
void onTimer(long time);
/**
* 开始拍照
*/
void startCaputure();
/**
* 拍照结束
* @param path 原始图片路径
*/
void endCaputure(String path);
/**
* 错误回调
* @param code
* @param msg
*/
void onError(int code, String msg);
/**
* 事件回调
*
* @param event
*/
void onEvent(MessageEvent event);
} ```
- MessageEvent 说明
```java public class MessageEvent { /* * 相机状态 * 时机:调用了开启相机方法 / public final static int CAMERA_STATES_OPENING = 1;
/**
* 相机状态
* 时机:CameraDevice.StateCallback#onOpened
*/
public final static int CAMERA_STATES_OPENED = 2;
/**
* 相机状态
* 时机:调用了关闭相机方法
*/
public final static int CAMERA_STATES_CLOSEING = 3;
/**
* 相机状态
* 时机:CameraDevice.StateCallback#onDisconnected
*/
public final static int CAMERA_STATES_DISCONNECTED = 4;
/**
* 相机状态
* 时机:CameraDevice.StateCallback#onClosed
*/
public final static int CAMERA_STATES_CLOSED = 5;
/**
* 相机状态
* 时机:CameraDevice.StateCallback#onError
*/
public final static int CAMERA_STATES_ERROR = 6;
/**
* 开始初始化
*/
public final static int INIT_START = 7;
/**
* 初始化成功
*/
public final static int INIT_SUCCESS = 8;
/**
* 初始化失败
*/
public final static int INIT_FAIL = 9;
} ```
输出说明
调用拍照方法 takePicture() 后,会回调 docListener。
请求示例
val requestConfig: DocRequestConfig by lazy {
DocRequestConfig.Builder()
.setPath(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).absolutePath + File.separator + "turingMath")
.setPhotoDelayTime(3)
.setImageRotation(0) //后置 横屏-0(图片为竖图)-90(图片为横图,预览的效果) 竖屏90; 前置
.setPreFrameRotation(0) //后置 横屏-0(图片为竖图)-90(图片为横图,预览的效果) 竖屏90;前置
.setPreViewRotation(90) // 后置 横屏90 竖屏-0; 前置
.setPreviewSize(Size(1920, 1080))
.setPicSize(Size(1920, 1080))
.setCameraId("1")
.setMirror(true)
.setDumpEnabled(true)
.build()
}
// 初始化相机
private fun init() {
turingMath = TuringMathCorrection.getInstance(this)
turingMath!!.initCamera(mainBinding.frameLayer, requestConfig, object : DocListener {
override fun onResult(result: DocResultBean?) {
hideProgressBar()
if (result == null) {
return
}
showUI("图片裁切成功")
// 跳转显示页
var intent = Intent(this@MathCorPhotoActivity, ShowImageActivity::class.java)
intent.putExtra(ShowImageActivity.EXTRA_IMAGE_ORIGIN_PATH, mOriginPath)
intent.putExtra(ShowImageActivity.EXTRA_IMAGE_CURL_PATH, result.path)
intent.putExtra(
ShowImageActivity.EXTRA_ACTIVITY_TYPE,
ShowImageActivity.ACTIVITY_TYPE_MATH
)
startActivity(intent)
finish()
}
override fun onTimer(time: Long) {
mUIHandler.post(
Runnable {
Log.e("TAG", "倒计时 $time")
if (time <= 0) {
mainBinding.tvTimer.setVisibility(View.GONE)
return@Runnable
}
mainBinding.tvTimer.setText(time.toString())
if (mainBinding.tvTimer.getVisibility() !== View.VISIBLE) {
mainBinding.tvTimer.setVisibility(View.VISIBLE)
}
}
)
}
override fun startCaputure() {
// 开始拍照回调
mUIHandler.post {
showProgressBar()
mainBinding.tvTimer.setVisibility(View.GONE)
}
}
override fun endCaputure(originalPath: String) {
mOriginPath = originalPath
mainBinding.dumpSwitch.setClickable(true)
mainBinding.facingfrontSwitch.setClickable(true)
// 跳转显示页
var intent = Intent(this@MathCorPhotoActivity, ShowImageActivity::class.java)
intent.putExtra(ShowImageActivity.EXTRA_IMAGE_ORIGIN_PATH, mOriginPath)
intent.putExtra(ShowImageActivity.EXTRA_IMAGE_CURL_PATH, mOriginPath)
intent.putExtra(
ShowImageActivity.EXTRA_ACTIVITY_TYPE,
ShowImageActivity.ACTIVITY_TYPE_MATH
)
startActivity(intent)
finish()
}
override fun onError(code: Int, msg: String) {
}
override fun onEvent(event: MessageEvent?) {
}
})
}
// 初始化相机后,合适的时机调用拍照方法
turingMath!!.takePicture()
3. 停止/启动 相机
使用SDK内部相机后,可以按实际需求调用停止、启动相机的方法。
方法
/**
* 在 Activity 生命周期方法 onPause() 中调用,SDK 内部会关闭相机
*/
void onPause();
/**
* 在 Activity 生命周期方法 onPause() 中调用,SDK 内部会开启相机
*/
void onResume();
4. 资源释放
- 相机资源释放
```java
/**
* 建议不使用用相机时,及时释放资源。
* 再次使用相机功能需要重新调用 initCamera()
*/
void releaseCamera();
```
- 批改资源释放
java
/**
* 建议在 Activity 的 onDestory() 中调用
*/
void stopMathCorrection();