Обнаружение лица с помощью Google Vision API отображается через VideoView

Я использовал Vision API из Google Play Services в своем приложении, и все отлично работает на моих устройствах (Nexus 7 2012 с Android 5.1 и более дешевым планшетом с Android 4.2.2), но не на некоторых производственных устройствах,

У нас есть API видения с платформой распознавания лиц, работающей все время, пока наше приложение открыто, поэтому приложение меняет контент, когда распознавание лиц обнаруживает его.

Проблема в том, когда мы показываем видео с VideoView в то же время, что обнаружение лица работает, потому что мы заметили, что какой-то "призрак" появляется на вершине VideoView и мы видели, что этот "призрак" - это предварительный просмотр, который распознавание лица получает в реальном времени.

Это сложно объяснить, поэтому мы записали видео, которое лучше иллюстрирует проблему: Видео

В это время я попробовал этот материал:

  • Изменение размеров .setRequestedPreviewSize(int, int) и мы увидели, что на основе этих измерений "призрак" тоже меняет свое измерение, поэтому мы поняли, что размер предварительного просмотра - это тот, который вызывает проблему.

  • Удаление звонка .setRequestedPreviewSize(int, int) от CameraSource.Builder мы видели, что внутренне, он по умолчанию имеет размеры 1024x768, как вы можете видеть на CameraSource так что "призрак" заполняет весь экран этим.

  • Попытка другого фреймворка для воспроизведения видео, удаление VideoView и используя другой, основанный на TextureView тоже не помогает, призрак все еще показывает.

  • Использование разных форматов видео тоже не помогает

Я думаю, что это может быть какой-то проблемой, когда одновременно работает SurfaceView или SurfaceTexture, один поверх другого, но я впервые работаю с мультимедийным приложением.

У кого-то есть представление о том, в чем может быть проблема?

Заранее спасибо.

РЕДАКТИРОВАТЬ

Просто чтобы уточнить, я выкладываю код, который использую.

Этот метод, который я использую в приложении, показан на видео:

private void setupFaceDetector() {
        Log.d(TAG, "setupFaceDetector");
        faceDetector = new FaceDetector.Builder(this)
                .setProminentFaceOnly(true)
                .setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
                .build();
        if (!faceDetector.isOperational()) {
            retryIn(1000);
        } else {
            faceDetector.setProcessor(new LargestFaceFocusingProcessor(faceDetector, new FaceTracker(this)));
            if (BuildConfig.FLAVOR.equals("withPreview")) {
                mCameraSource = new CameraSource.Builder(this, faceDetector)
                        .setFacing(CameraSource.CAMERA_FACING_FRONT)
                        .setRequestedPreviewSize(320, 240)
                        .build();
            } else {
                mCameraSource = new CameraSource.Builder(this, faceDetector)
                        .setFacing(CameraSource.CAMERA_FACING_FRONT)
                        .build();
            }
        }

    }

Я использовал вкус, чтобы поиграть с разными вещами, этот проект был только для того, чтобы облегчить тестирование этой функции.

Когда onResume() метод вызывается, я загружаю видео с File и начиная CameraSource пример

private void initializeVideo() {
  mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mp) {
      mp.start();
    }
  });

  mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
      Log.d(TAG, "Error playing the video");
      return false;
    }
  });
  mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
    @Override
    public void onCompletion(MediaPlayer mp) {
      playVideo();
    }
  });
}

private void startCameraSource() {
  try {
    mCameraSource.start();
  } catch (IOException e) {
    e.printStackTrace();
  }
}

Просто для ясности:

  • Мы используем FaceTracker только для обнаружения лиц, и используя его public void onNewItem(int id, Face face) а также public void onMissing(Detector.Detections<Face> detections)

  • XML-макет, чтобы показать VideoView является:

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"/>
    
    <ScrollView
        android:id="@+id/scroll"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1">
    
        <TextView
            android:id="@+id/tv_log"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@android:color/white"/>
    </ScrollView>
    

1 ответ

Я не совсем уверен, но вот несколько советов, которые стоит попробовать:

Здесь есть версия CameraSource с открытым исходным кодом, которую вы можете использовать и изменять по мере необходимости в своем приложении:

https://github.com/googlesamples/android-vision/blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java

У него есть пара переменных экземпляра поверхности, mDummySurfaceView и mDummySurfaceTexture, которые используются при работе с предварительным просмотром камеры в случае, если для предварительного просмотра нет отображения. Они настроены здесь:

https://github.com/googlesamples/android-vision/blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java#L346

Я предполагаю, что в вашем приложении эти фиктивные поверхности как-то мешают вашему видео. Вы можете увидеть, может ли ваше приложение использовать альтернативную стратегию для работы с камерой, для которой не нужны эти фиктивные поверхности.

Вы также можете запустить источник камеры с указанным вами указанным SurfaceHolder, как указано здесь:

https://github.com/googlesamples/android-vision/blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java#L370

Вы можете попробовать поэкспериментировать с созданием альтернативных поверхностей и посмотреть, есть ли способ избежать вмешательства в ваше видео.

Если ничего из этого не работает, вы также можете попробовать самостоятельно написать код управления камерой, аналогично тому, что обеспечивает CameraSource, но с использованием более нового API "camera2" (мы поставили CameraSource с помощью API "camera1", потому что в то время этот API имел немного немного лучшая обратная совместимость со старыми камерами, но это улучшилось с камерой2). Если вы сделаете это, вы можете применить аналогичный подход к передаче изображений предварительного просмотра на детектор, как это сделано здесь:

https://github.com/googlesamples/android-vision/blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java#L1191

Другие вопросы по тегам