Closed dicallc closed 4 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);
}
});
}
Schedulers.io()换成Schedulers.newThread() io是线程池,随机挑一个空闲的,有可能发生同一个线程重复调用。
new OcrEngine()只是普通的实例化对象,与一般的实例化比如new StringBuilder()没什么区别。 OcrEngine不是线程安全的,大部分java对象也都不是线程安全的。 关于java对象的手动销毁,可以自己搜索相关的文章。
多次实例化的问题,在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());
}
测试 ocrEngine = new OcrEngine(this.getApplicationContext()) 调用多次会得到乱码的识别的结果,最好能有一个反注册功能去释放,在第二次调用又可以初始化