我正在Android中编写一些代码,我必须使用camera2 API进行面部检测。我的代码基于 android-camera2-api-face-recon samples,我不知道为什么,但是当我使用
face.getBound()
时,它返回的值不在视图中。
这是针对Android studio的,在JAVA中,这段代码应该在头部周围绘制一个矩形,并且它识别出有一个头部,但是矩形被绘制在任何地方并且不跟随头部。
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 类的 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 等于 features.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
现在它已经接近工作了,但是根据设备的不同,矩形要么围绕头部,要么靠近头部,但它会像以前一样跟随头部。 例如,在荣耀 5c 上,矩形位置很好,但在华为 p9 lite 上,矩形的左上角位于鼻子上。 有什么想法可以修复它吗?
如何将传感器活动阵列坐标系中的面部矩形坐标转换为预览视图的坐标?
您需要考虑传感器的方向以及应用程序相对于设备本机方向的当前方向。
编辑: 对于纵向设备(描述大多数手机)上的横向传感器,您当前的 s1/s2 计算不正确,即使您的应用程序被锁定为纵向方向也是如此。
如果您的应用程序和传感器的方向不匹配,您需要在 s1/s2 计算之前交换预览或 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();
}