如何使用 Camera2 FaceDetection faces.getBound() 获取真实值?
How to get true values with Camera2 FaceDetection, faces.getBound()?
我正在 Android 中编写一些代码,我必须使用 camera2 API 进行人脸检测。我的代码基于 android-camera2-api-face-recon samples 我不知道为什么但是当我使用 face.getBound()
时,它的值 return不在视线范围内。
这是 Android studio 的,在 JAVA 中,这段代码应该在头部周围绘制一个矩形,并且它识别出有一个头部,但是矩形被绘制在任何地方并且不t跟头。
private void process(CaptureResult result) {
Integer mode = result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
Face[] faces = result.get(CaptureResult.STATISTICS_FACES);
mFaceDetectionMatrix=new Matrix();
if (faces != null && mode != null) {
if (faces.length ==1) {
for(int i = 0; i < faces.length; i++) {
if (faces[i].getScore() > 50) {
int left = faces[i].getBounds().left;
int top = faces[i].getBounds().top;
int right = faces[i].getBounds().right;
int bottom = faces[i].getBounds().bottom;
float points[] = {(float)bottom, (float)right, (float)top, (float)left};
Log.i("Test", "faces : " + faces.length + " , mode : " + mode + " left " + left + " top " + top + " right " + right);
Rect uRect = new Rect(left, top, right, bottom); //The function I'm supposed to use
//Rect uRect = new Rect(+2000-bottom, 1500-left, +1500-top, 3500-right) the function I'm using in order to fix this problem
当头部向下或向上移动时,矩形向左或向右移动,反之亦然。如您所见,我正在尝试一些无法使用的东西来修复它,我必须完全更改 Rect 中的主菜。
我想正确解决这个问题并理解为什么它不起作用,如果我不能,我想更改我放入 Rect 中的常量以便能够在所有设备上使用此代码。
你有什么想法吗?
为了控制传感器方向,我使用了这个代码:
int orientationOffset;
orientationOffset = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
Rect activeArraySizeRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
//Face Detection Matrix
//mFaceDetectionMatrix = new Matrix();
// TODO - I guess that is not enough if we have a landscape layout too...
mFaceDetectionMatrix.setRotate(orientationOffset);
Log.i("Test", "activeArraySizeRect1: (" + activeArraySizeRect + ") -> " + activeArraySizeRect.width() + ", " + activeArraySizeRect.height());
Log.i("Test", "activeArraySizeRect2: " + mPreviewSize.getWidth() + ", " + mPreviewSize.getHeight());
float s1 = mPreviewSize.getWidth() / (float)activeArraySizeRect.width();
float s2 = mPreviewSize.getHeight() / (float)activeArraySizeRect.height();
//float s1 = mOverlayView.getWidth();
//float s2 = mOverlayView.getHeight();
boolean mirror = true; // we always use front face camera
boolean weAreinPortrait = true;
mFaceDetectionMatrix.postScale(mirror ? -s1 : s1, s2);
//mFaceDetectionMatrix.postRotate(orientation);
if (mSwappedDimensions) {
mFaceDetectionMatrix.postTranslate(mPreviewSize.getHeight(), mPreviewSize.getWidth());
} else {
// TODO - ...
}
这就像...矩形是横向的,头部是纵向的。
谢谢
[编辑]
我找到了修复它的方法!在 OverlayView class、onDraw 中,我添加了这个:
canvas.scale(-1, 1, getWidth()/2, getHeight()/2);
我在 fragment_camera2_basic.xml 中修改了 OverlayView,同时添加了 android:rotation="90"
现在矩形像它必须的那样移动。
解决了问题,现在根据使用的设备,矩形的位置不一样。
我已经像这样修改了顶部、左侧、右侧和底部:
int left = (int)((float)(faces[i].getBounds().left)/MGpix.getWidth()*mTextureView.getHeight());
int top = (int)((float)(faces[i].getBounds().top)/MGpix.getHeight()*mTextureView.getWidth());
int right = (int)((float)(faces[i].getBounds().right)/MGpix.getWidth()*mTextureView.getHeight());
int bottom =(int)((float)(faces[i].getBounds().bottom)/MGpix.getHeight()*mTextureView.getWidth());
MGpix 等于 characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
现在快要工作了,但是根据设备的不同,矩形是在头部周围或旁边,但它会像现在一样跟随头部。
例如,在荣耀 5c 上,矩形的位置很好,但在 huawey p9 lite 上,矩形的左上角在鼻子上。
有什么办法可以解决吗?
如何将传感器 active array coordinate system 中的面部矩形坐标转换为预览视图的坐标?
您需要考虑传感器的 orientation 以及您的应用程序相对于设备的本机方向的当前方向。
编辑:
您当前计算的 s1/s2 对于竖屏设备(描述大多数手机)上的横向传感器是不正确的,即使您的应用程序被锁定为竖屏方向也是如此。
如果您的应用和传感器的方向不匹配,您需要在 s1/s2 计算之前交换 width/height 预览或 activeArray。
之后的旋转只会交换两个计算错误的坐标。
最稳健的选择是获取当前显示器的方向(相对于设备的本机方向),并使用该方向和传感器方向来确定传感器和您的应用程序的相对方向,以决定何时交换坐标。类似于:
int displayRotation = WindowManager.getDefaultDisplay().getRotation();
boolean displayIsRotated = (displayRotation == Surface#ROTATION_90) ||
(displayRotation == Surface#ROTATION_270)
int cameraOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)
boolean cameraIsRotated = (cameraRotation == 90) || (cameraRotation == 270)
boolean flipAxes = displayIsRotated ^ cameraIsRotated;
if (flipAxes) {
float s1 = mPreviewSize.getWidth() / (float)activeArraySizeRect.height();
float s2 = mPreviewSize.getHeight() / (float)activeArraySizeRect.width();
} else {
float s1 = mPreviewSize.getWidth() / (float)activeArraySizeRect.width();
float s2 = mPreviewSize.getHeight() / (float)activeArraySizeRect.height();
}
我正在 Android 中编写一些代码,我必须使用 camera2 API 进行人脸检测。我的代码基于 android-camera2-api-face-recon samples 我不知道为什么但是当我使用 face.getBound()
时,它的值 return不在视线范围内。
这是 Android studio 的,在 JAVA 中,这段代码应该在头部周围绘制一个矩形,并且它识别出有一个头部,但是矩形被绘制在任何地方并且不t跟头。
private void process(CaptureResult result) {
Integer mode = result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE);
Face[] faces = result.get(CaptureResult.STATISTICS_FACES);
mFaceDetectionMatrix=new Matrix();
if (faces != null && mode != null) {
if (faces.length ==1) {
for(int i = 0; i < faces.length; i++) {
if (faces[i].getScore() > 50) {
int left = faces[i].getBounds().left;
int top = faces[i].getBounds().top;
int right = faces[i].getBounds().right;
int bottom = faces[i].getBounds().bottom;
float points[] = {(float)bottom, (float)right, (float)top, (float)left};
Log.i("Test", "faces : " + faces.length + " , mode : " + mode + " left " + left + " top " + top + " right " + right);
Rect uRect = new Rect(left, top, right, bottom); //The function I'm supposed to use
//Rect uRect = new Rect(+2000-bottom, 1500-left, +1500-top, 3500-right) the function I'm using in order to fix this problem
当头部向下或向上移动时,矩形向左或向右移动,反之亦然。如您所见,我正在尝试一些无法使用的东西来修复它,我必须完全更改 Rect 中的主菜。
我想正确解决这个问题并理解为什么它不起作用,如果我不能,我想更改我放入 Rect 中的常量以便能够在所有设备上使用此代码。
你有什么想法吗?
为了控制传感器方向,我使用了这个代码:
int orientationOffset;
orientationOffset = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
Rect activeArraySizeRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
//Face Detection Matrix
//mFaceDetectionMatrix = new Matrix();
// TODO - I guess that is not enough if we have a landscape layout too...
mFaceDetectionMatrix.setRotate(orientationOffset);
Log.i("Test", "activeArraySizeRect1: (" + activeArraySizeRect + ") -> " + activeArraySizeRect.width() + ", " + activeArraySizeRect.height());
Log.i("Test", "activeArraySizeRect2: " + mPreviewSize.getWidth() + ", " + mPreviewSize.getHeight());
float s1 = mPreviewSize.getWidth() / (float)activeArraySizeRect.width();
float s2 = mPreviewSize.getHeight() / (float)activeArraySizeRect.height();
//float s1 = mOverlayView.getWidth();
//float s2 = mOverlayView.getHeight();
boolean mirror = true; // we always use front face camera
boolean weAreinPortrait = true;
mFaceDetectionMatrix.postScale(mirror ? -s1 : s1, s2);
//mFaceDetectionMatrix.postRotate(orientation);
if (mSwappedDimensions) {
mFaceDetectionMatrix.postTranslate(mPreviewSize.getHeight(), mPreviewSize.getWidth());
} else {
// TODO - ...
}
这就像...矩形是横向的,头部是纵向的。
谢谢
[编辑] 我找到了修复它的方法!在 OverlayView class、onDraw 中,我添加了这个:
canvas.scale(-1, 1, getWidth()/2, getHeight()/2);
我在 fragment_camera2_basic.xml 中修改了 OverlayView,同时添加了 android:rotation="90" 现在矩形像它必须的那样移动。
解决了问题,现在根据使用的设备,矩形的位置不一样。
我已经像这样修改了顶部、左侧、右侧和底部:
int left = (int)((float)(faces[i].getBounds().left)/MGpix.getWidth()*mTextureView.getHeight());
int top = (int)((float)(faces[i].getBounds().top)/MGpix.getHeight()*mTextureView.getWidth());
int right = (int)((float)(faces[i].getBounds().right)/MGpix.getWidth()*mTextureView.getHeight());
int bottom =(int)((float)(faces[i].getBounds().bottom)/MGpix.getHeight()*mTextureView.getWidth());
MGpix 等于 characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
现在快要工作了,但是根据设备的不同,矩形是在头部周围或旁边,但它会像现在一样跟随头部。 例如,在荣耀 5c 上,矩形的位置很好,但在 huawey p9 lite 上,矩形的左上角在鼻子上。 有什么办法可以解决吗?
如何将传感器 active array coordinate system 中的面部矩形坐标转换为预览视图的坐标?
您需要考虑传感器的 orientation 以及您的应用程序相对于设备的本机方向的当前方向。
编辑: 您当前计算的 s1/s2 对于竖屏设备(描述大多数手机)上的横向传感器是不正确的,即使您的应用程序被锁定为竖屏方向也是如此。
如果您的应用和传感器的方向不匹配,您需要在 s1/s2 计算之前交换 width/height 预览或 activeArray。
之后的旋转只会交换两个计算错误的坐标。
最稳健的选择是获取当前显示器的方向(相对于设备的本机方向),并使用该方向和传感器方向来确定传感器和您的应用程序的相对方向,以决定何时交换坐标。类似于:
int displayRotation = WindowManager.getDefaultDisplay().getRotation();
boolean displayIsRotated = (displayRotation == Surface#ROTATION_90) ||
(displayRotation == Surface#ROTATION_270)
int cameraOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)
boolean cameraIsRotated = (cameraRotation == 90) || (cameraRotation == 270)
boolean flipAxes = displayIsRotated ^ cameraIsRotated;
if (flipAxes) {
float s1 = mPreviewSize.getWidth() / (float)activeArraySizeRect.height();
float s2 = mPreviewSize.getHeight() / (float)activeArraySizeRect.width();
} else {
float s1 = mPreviewSize.getWidth() / (float)activeArraySizeRect.width();
float s2 = mPreviewSize.getHeight() / (float)activeArraySizeRect.height();
}