跳转至

口算批改接入说明

文档修订记录

文档版本号 修订日期 修订原因
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();