使用后置摄像头的人脸检测无法使用 camera2 API 正常工作

Posted

技术标签:

【中文标题】使用后置摄像头的人脸检测无法使用 camera2 API 正常工作【英文标题】:Face detection with back camera is not working properly using camera2 API 【发布时间】:2020-06-07 07:29:39 【问题描述】:

我正在使用 camre2 api 进行人脸检测。这适用于前置摄像头,但不适用于后置摄像头。 谁能证明后置摄像头的人脸检测矩阵

前置摄像头人脸检测矩阵为

 if (facing == CameraCharacteristics.LENS_FACING_FRONT) 


                        StreamConfigurationMap map = mCameraCharacteristics.get(
                                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                        if (map == null) 
                            continue;
                        

                        // For still image captures, we use the largest available size.
                        Size largest = Collections.max(
                                Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
                                new CompareSizesByArea());
                        /*maxImages = mCameraCharacteristics.get(
                                CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT);*/
                        mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
                                ImageFormat.JPEG, 1);
                        mImageReader.setOnImageAvailableListener(
                                mOnImageAvailableListener, mBackgroundHandler);

                        // Find out if we need to swap dimension to get the preview size relative to sensor
                        // coordinate.
                        int displayRotation = this.getWindowManager().getDefaultDisplay().getRotation();
                        //noinspection ConstantConditions
                        mSensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
                        mSwappedDimensions = false;

                        switch (displayRotation) 
                            case Surface.ROTATION_0:
                            case Surface.ROTATION_180:
                                if (mSensorOrientation == 90 || mSensorOrientation == 270) 
                                    mSwappedDimensions = true;
                                
                                break;
                            case Surface.ROTATION_90:
                            case Surface.ROTATION_270:
                                if (mSensorOrientation == 0 || mSensorOrientation == 180) 
                                    mSwappedDimensions = true;
                                
                                break;
                            default:
                                Log.e(TAG, "Display rotation is invalid: " + displayRotation);
                        

                        Point displaySize = new Point();
                        this.getWindowManager().getDefaultDisplay().getSize(displaySize);
                        int rotatedPreviewWidth = width;
                        int rotatedPreviewHeight = height;
                        int maxPreviewWidth = displaySize.x;
                        int maxPreviewHeight = displaySize.y;

                        if (mSwappedDimensions) 
                            rotatedPreviewWidth = height;
                            rotatedPreviewHeight = width;
                            maxPreviewWidth = displaySize.y;
                            maxPreviewHeight = displaySize.x;
                        

                        if (maxPreviewWidth > MAX_PREVIEW_WIDTH) 
                            maxPreviewWidth = MAX_PREVIEW_WIDTH;
                        

                        if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) 
                            maxPreviewHeight = MAX_PREVIEW_HEIGHT;
                        

                        // Danger, W.R.! Attempting to use too large a preview size could  exceed the camera
                        // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
                        // garbage capture data.
                        mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                                rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
                                maxPreviewHeight, largest);

                        // We fit the aspect ratio of TextureView to the size of preview we picked.
                        int orientation = getResources().getConfiguration().orientation;
                        if (orientation == Configuration.ORIENTATION_LANDSCAPE) 
                            textureView.setAspectRatio(
                                    mPreviewSize.getWidth(), mPreviewSize.getHeight());
                         else 
                            textureView.setAspectRatio(
                                    mPreviewSize.getHeight(), mPreviewSize.getWidth());
                        

                        // Check if the flash is supported.
                        Boolean available = mCameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
                        FlashSupported = available == null ? false : available;

                        this.cameraId = "0";

                        int orientationOffset = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
                        Rect activeArraySizeRect = mCameraCharacteristics.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);
                        if (mSwappedDimensions) 
                            mFaceDetectionMatrix.postTranslate(mPreviewSize.getHeight(), mPreviewSize.getWidth());
                         else 
                            // TODO - ...

                           // here i am using same code just making mirror 
                           //value false.
                        

                    

这适用于前置摄像头。谁能有后置摄像头人脸检测矩阵的解决方案。

【问题讨论】:

任何人都可以解决这个问题 【参考方案1】:

在 if (face == CameraCharacteristics.LENS_FACING_FRONT) 中对 else 条件使用 boolean mirror = false

【讨论】:

以上是关于使用后置摄像头的人脸检测无法使用 camera2 API 正常工作的主要内容,如果未能解决你的问题,请参考以下文章

ML Kit iOS 人脸检测错误

使用 CameraX 时,前置摄像头的 Facebase MLKit 人脸检测失败

MLkit 人脸检测不适用于 android 的前置摄像头

camera2人脸检测回调

需要在使用 MLKit 和 Camera2 进行人脸检测期间捕获静止图像

android Camera如何判断当前使用的摄像头是前置还是后置