我正在使用Android firebase-ml-vision使用SurfaceView扫描条形码和连续的ByteBuffer图片帧。我用ML kit quickstart project作为起点,效果很好。
我的项目的目标是识别与条形码相关的产品并将其添加到扫描项目列表中。
相机对焦后,条形码处理器会多次检测到相同的条形码,因此您可以在一秒内扫描20个而不是1个条形码。
这是来自CamereSource.FrameProcessingRunnable.run的javadoc
* As long as the processing thread is active, this executes detection on frames continuously. * The next pending frame is either immediately available or hasn't been received yet. Once it * is available, we transfer the frame info to local variables and run detection on that frame. * It immediately loops back for the next frame without pausing.
我试图在FrameProcessingRunnable中添加一个“暂停”检查,但我仍然得到至少两次识别相同的条形码,因为下一帧/帧已经被输入进行检测:
private class FrameProcessingRunnable implements Runnable {
private volatile boolean paused = false;
.
.
.
public void pause() {
synchronized (lock) {
this.paused = true;
lock.notifyAll();
}
}
public void resume() {
synchronized (lock) {
this.paused = false;
lock.notifyAll();
}
}
public void run() {
.
.
.
synchronized (processorLock) {
if (!paused) {
Log.d(TAG, "Process an image");
frameProcessor.process(...
因为我无法暂停,所以当从缓冲区检测到条形码时,我选择停止并启动:
private CameraSourcePreview preview;
public void pauseImageProcessing() {
preview.stop();
try {
preview.start(cameraSource, graphicOverlay);
} catch (IOException e) {
}
}
这有效,但在再次启动之前有大约1秒的延迟,相机开始聚焦并且可以检测到下一个条形码。毫无疑问,这种方法也消耗了不必要的资源。你可能会说这很好,但在this video you'll see the difference between the camera scanner with Stop&Start and a Bluetooth scanner:
我正在寻找一种解决方案,只需在成功检测到并重新启动之后立即丢弃任何帧,但到目前为止我都失败了。我每秒使用20帧。
VissionProcessorBase确实有限制代码
// Whether we should ignore process(). This is usually caused by feeding input data faster than
// the model can handle.
private final AtomicBoolean shouldThrottle = new AtomicBoolean(false);
但是对我的需求来说还不够远:(
相机对焦后,条形码处理器会多次检测到相同的条形码,因此您可以在一秒内扫描20个而不是1个条形码。
vision processor base.Java
private void detectInVisionImage(
FirebaseVisionImage image,
final FrameMetadata metadata) {
detectInImage(image)
.addOnSuccessListener(
new OnSuccessListener<T>() {
@Override
public void onSuccess(final T results) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
shouldThrottle.set(false);
}
},1000);
VisionProcessorBase.this.onSuccess(results, metadata);
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
shouldThrottle.set(false);
}
},1000);
VisionProcessorBase.this.onFailure(e);
}
});
// Begin throttling until this frame of input has been processed, either in onSuccess or
// onFailure.
shouldThrottle.set(true);
}