Как получить истинные значения с Camera2 FaceDetection, faces.getBound ()? - PullRequest
1 голос
/ 10 мая 2019

Я пишу некоторый код в Android, я должен сделать обнаружение лица с помощью camera2 API. Мой код основан на Android-Camera2-Api-Face-Recon образцов , и я не знаю, почему, но когда я использую face.getBound(), возвращаемые значения не видны.

Это для студии Android, в 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 - ...
                }

Это как ... прямоугольник в ландшафте, а голова в портрете.

Спасибо

[EDIT] Я нашел способ это исправить! В классе OverlayView, в onDraw, я добавляю это:


 canvas.scale(-1, 1, getWidth()/2, getHeight()/2);

и я изменил OverlayView в фрагменте_camera2_basic.xml при добавлении андроида: вращение = "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 совпадает с характеристиками.get (CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);

Теперь он близок к работе, но прямоугольник, в зависимости от устройства, либо вокруг головы, либо рядом, но он следует за головой, как и раньше. Например, на Honor 5c, прямоугольник хорошо расположен, но с huawey p9 lite верхний левый угол прямоугольника находится на носу. Есть идеи, чтобы это исправить?

1 Ответ

0 голосов
/ 11 мая 2019

Как конвертировать координаты прямоугольника грани, которые находятся в датчике активной системы координат массива , в координаты предварительного просмотра?

Необходимо учитывать ориентацию датчика , а также текущую ориентацию вашего приложения относительно исходной ориентации устройства.

Edit: Текущие расчеты s1 / s2 не верны для ландшафтного датчика на портретном устройстве (которое описывает большинство телефонов), даже в том случае, если ваше приложение заблокировано в портретной ориентации.

Вам необходимо поменять ширину / высоту в предпросмотре или активном массиве перед вычислением s1 / s2, если ориентация вашего приложения и датчика не совпадают.

Поворот после этого только поменяет две неверно рассчитанные координаты друг с другом.

Самый надежный вариант - получить текущую ориентацию дисплея (которая будет относительно исходной ориентации устройства) и использовать ее и ориентацию датчика, чтобы определить взаимную ориентацию датчика и вашего приложения, чтобы решить, когда менять местами. координаты. Что-то вроде:

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();
}
...