RapidAI / RapidOcrAndroidOnnx

RapidOcr onnxruntime推理 for Android
Apache License 2.0
62 stars 10 forks source link

能不能加一个注销功能,自己做插件,有时候初始化多次会乱码 #9

Closed dicallc closed 4 months ago

dicallc commented 5 months ago

测试 ocrEngine = new OcrEngine(this.getApplicationContext()) 调用多次会得到乱码的识别的结果,最好能有一个反注册功能去释放,在第二次调用又可以初始化

benjaminwan commented 5 months ago

在同一个线程中不能多次调用初始化。 每次新建一个线程再进行调用。 最好不要在主线程中使用。

dicallc commented 5 months ago

我按照demo的代码 每次新建线程初始化一次,依然会乱码,还是提供一个注销方法吧

private Disposable detect(Bitmap img, int reSize) {
        return Single.fromCallable(new Callable<OcrResult>() {
                    @Override
                    public OcrResult call() throws Exception {
                       //初始化
                        ocrEngine = new OcrEngine(mActivity.getApplicationContext());
                        Bitmap boxImg = Bitmap.createBitmap(img.getWidth(), img.getHeight(), Bitmap.Config.RGB_565);
                        return ocrEngine.detect(img, boxImg, reSize);
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Throwable {
                        showLoading();
                        binding.detectBtn.setEnabled(false);
                        binding.stopBtn.setEnabled(true);
                    }
                })
                .doOnDispose(new Action() {
                    @Override
                    public void run() throws Throwable {
                        binding.detectBtn.setEnabled(true);
                        binding.stopBtn.setEnabled(false);
                        clearLastResult();
                    }
                })
                .doFinally(new Action() {
                    @Override
                    public void run() throws Throwable {
                        binding.detectBtn.setEnabled(true);
                        binding.stopBtn.setEnabled(false);
                    }
                })
                .subscribe(new Consumer<OcrResult>() {
                    @Override
                    public void accept(OcrResult ocrResult) throws Throwable {
                        String time = String.format("识别时间:%d ms", (int) ocrResult.getDetectTime());
                        binding.timeTV.setText(time);
                        Logger.i(ocrResult.toString());
                        ToastUtils.showToast(MainActivity.this, ocrResult.getStrRes(), Toast.LENGTH_SHORT);
                    }
                });

    }
benjaminwan commented 5 months ago

Schedulers.io()换成Schedulers.newThread() io是线程池,随机挑一个空闲的,有可能发生同一个线程重复调用。

new OcrEngine()只是普通的实例化对象,与一般的实例化比如new StringBuilder()没什么区别。 OcrEngine不是线程安全的,大部分java对象也都不是线程安全的。 关于java对象的手动销毁,可以自己搜索相关的文章。

dicallc commented 5 months ago

多次实例化的问题,在C++代码里面改一下就行了,我C++得功底不强,安卓应用开发倒是干10年了 CrnnNet.cpp

void CrnnNet::initModel(AAssetManager *mgr, const std::string &name, const std::string &keysName) {
    int dbModelDataLength = 0;
    void *dbModelData = getModelDataFromAssets(mgr, name.c_str(), dbModelDataLength);
    session = new Ort::Session(ortEnv, dbModelData, dbModelDataLength,
                               sessionOptions);
    free(dbModelData);
    inputNamesPtr = getInputNames(session);
    outputNamesPtr = getOutputNames(session);
    //----------------------------这里把keys清空就可以了
    keys.clear();
    //load keys
    char *buffer = readKeysFromAssets(mgr, keysName);
    if (buffer != NULL) {
        std::istringstream inStr(buffer);
        std::string line;
        while (getline(inStr, line)) {
            keys.emplace_back(line);
        }
        free(buffer);
    } else {
        LOGE(" txt file not found");
        return;
    }
    keys.insert(keys.begin(),
                "#"); // blank char for ctc
    keys.emplace_back(" ");
    LOGI("keys size(%d)", keys.size());
}