我想在应用程序中使用视觉API提供的新面部检测功能,并结合额外的帧处理。为此,我需要访问经人脸检测器处理的相机帧,并使用检测到的人脸数据连接处理器。
正如我在示例中所看到的,CameraSource抽象了检测和相机访问,我无法访问正在处理的帧。这个API中有没有获取相机帧的示例,或者创建并连接一个接收相机帧的检测器?至少有可能吗?
谢谢, Lucio
我想在应用程序中使用视觉API提供的新面部检测功能,并结合额外的帧处理。为此,我需要访问经人脸检测器处理的相机帧,并使用检测到的人脸数据连接处理器。
正如我在示例中所看到的,CameraSource抽象了检测和相机访问,我无法访问正在处理的帧。这个API中有没有获取相机帧的示例,或者创建并连接一个接收相机帧的检测器?至少有可能吗?
谢谢, Lucio
是的,这是可能的。您需要创建自己的Detector子类,它包装FaceDetector并在detect方法中执行额外的帧处理代码。它应该类似于这样:
class MyFaceDetector extends Detector<Face> {
private Detector<Face> mDelegate;
MyFaceDetector(Detector<Face> delegate) {
mDelegate = delegate;
}
public SparseArray<Face> detect(Frame frame) {
// *** add your custom frame processing code here
return mDelegate.detect(frame);
}
public boolean isOperational() {
return mDelegate.isOperational();
}
public boolean setFocus(int id) {
return mDelegate.setFocus(id);
}
}
您需要将人脸检测器与您的类一起包装,并将您的类传入相机源。代码大致如下:
FaceDetector faceDetector = new FaceDetector.Builder(context)
.build();
MyFaceDetector myFaceDetector = new MyFaceDetector(faceDetector);
myFaceDetector.setProcessor(/* include your processor here */);
mCameraSource = new CameraSource.Builder(context, myFaceDetector)
.build();
您的检测器将首先使用原始帧数据进行调用。
请注意,如果设备旋转,图像可能不会直立。您可以通过帧的metadata.getRotation方法获取方向。
一个警告:一旦detect方法返回,您就不应该访问帧像素数据。由于相机源重复使用图像缓冲区,一旦方法返回,帧对象的内容最终将被覆盖。
编辑:(额外说明) 您还可以使用MultiDetector避免的样板代码,如下所示:MultiDetector
MultiDetector multiDetector = new MultiDetector.Builder()
.add(new FaceDetector.Builder(context)
.build())
.add(new YourReallyOwnDetector())
.build();
还需要注意在那里描述了与MultiProcessor
一起使用的FaceTrackerFactory
的用法。
这是我最终确定的解决方案。它假设盒子在屏幕中心。
public class BoxDetector extends Detector {
private Detector mDelegate;
private int mBoxWidth, mBoxHeight;
public BoxDetector(Detector delegate, int boxWidth, int boxHeight) {
mDelegate = delegate;
mBoxWidth = boxWidth;
mBoxHeight = boxHeight;
}
public SparseArray detect(Frame frame) {
int width = frame.getMetadata().getWidth();
int height = frame.getMetadata().getHeight();
int right = (width / 2) + (mBoxHeight / 2);
int left = (width / 2) - (mBoxHeight / 2);
int bottom = (height / 2) + (mBoxWidth / 2);
int top = (height / 2) - (mBoxWidth / 2);
YuvImage yuvImage = new YuvImage(frame.getGrayscaleImageData().array(), ImageFormat.NV21, width, height, null);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(left, top, right, bottom), 100, byteArrayOutputStream);
byte[] jpegArray = byteArrayOutputStream.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length);
Frame croppedFrame =
new Frame.Builder()
.setBitmap(bitmap)
.setRotation(frame.getMetadata().getRotation())
.build();
return mDelegate.detect(croppedFrame);
}
public boolean isOperational() {
return mDelegate.isOperational();
}
public boolean setFocus(int id) {
return mDelegate.setFocus(id);
}
}
像这样将这个类包装在你的检测器中
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
BoxDetector boxDetector = new BoxDetector(barcodeDetector, heightPx, widthPx);
new BoxDetector(barcodeDetector, cameraView.getHeight()/3, cameraView.getWidth());
当我调用boxDetector.detect时,我不知道要传递什么框架。 - mikro098@MCR
BoxDetector类,然后按照以下步骤操作。我只是提供有关文本识别器的示例,所以您可以像这样设置。TextRecognizer mTextRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
BoxDetector boxDetector = new BoxDetector(mTextRecognizer, heightPx, widthPx);
boxDetector.setProcessor(new Detector.Processor<TextBlock>() {
@Override
public void release() {
}
@Override
public void receiveDetections(Detector.Detections<TextBlock> detections) {
SparseArray<TextBlock> items = detections.getDetectedItems();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < items.size(); ++i) {
TextBlock item = items.valueAt(i);
if (item != null && item.getValue() != null) {
stringBuilder.append(item.getValue() + " ");
}
}
final String fullText = stringBuilder.toString();
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
// here full string(fullText) you can get whatever is it scanned.
}
});
}
});