Обнаружение лица с помощью 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 с открытым исходным кодом, которую вы можете использовать и изменять по мере необходимости в своем приложении:
У него есть пара переменных экземпляра поверхности, mDummySurfaceView и mDummySurfaceTexture, которые используются при работе с предварительным просмотром камеры в случае, если для предварительного просмотра нет отображения. Они настроены здесь:
Я предполагаю, что в вашем приложении эти фиктивные поверхности как-то мешают вашему видео. Вы можете увидеть, может ли ваше приложение использовать альтернативную стратегию для работы с камерой, для которой не нужны эти фиктивные поверхности.
Вы также можете запустить источник камеры с указанным вами указанным SurfaceHolder, как указано здесь:
Вы можете попробовать поэкспериментировать с созданием альтернативных поверхностей и посмотреть, есть ли способ избежать вмешательства в ваше видео.
Если ничего из этого не работает, вы также можете попробовать самостоятельно написать код управления камерой, аналогично тому, что обеспечивает CameraSource, но с использованием более нового API "camera2" (мы поставили CameraSource с помощью API "camera1", потому что в то время этот API имел немного немного лучшая обратная совместимость со старыми камерами, но это улучшилось с камерой2). Если вы сделаете это, вы можете применить аналогичный подход к передаче изображений предварительного просмотра на детектор, как это сделано здесь: