Обнаружение лица на фото с помощью Android FaceDetector.Face API

1. Обзор

Начиная с версии  Google Play services 7.8, доступен новый Mobile Vision API, который обеспечивает новые интерфейсы   Android FaceDetector.Face API  для обнаружения человеческих лиц на изображениях и видео. Определение лиц было доступно в android и раньше, просто Face Detection API предлагает дополнительные возможности, такие как обнаружение лица в различных ориентациях, обнаружение черт лица и понимание мимики.
В этом уроке мы протестируем работу этого API и создадим простое приложение, которое загружает фотографию и определяет на ней человеческое лицо, обозначив его рамкой.

2. FaceDetector API

Android FaceDetector.Face API является развитием предыдущего API Android FaceDetector.  Он создан, чтобы лучше обнаружить человеческие лица на изображениях и видео для облегчения редактирования. Он достаточно умен, чтобы распознавать лица даже при различной ориентации – так что, если голова вашего субъекта повернута в сторону, он может обнаружить его лицо. Также могут быть обнаружены на лицах  глаза, нос и края губ.
Важно: Это не  API распознавания лиц. Вместо этого, новый API просто обнаруживает области изображения или видео, которые являются человеческими лицами. Он также определяет в последовательных кадрах видео одни и те же лица. Если лицо покидает поле зрения, и снова входит, оно не распознается как ранее обнаруженное лицо.

3. Предварительные условия

Для разработки приложения вам понадобятся:
  • Среда разработки Android Studio
  • Android устройство, которое работает на Android 4.2.2 или более поздней версии – или –  эмулятор Android (это доступно в Android Studio)
  • Последняя версия Android SDK, включая компонент средств SDK. Вы можете получить это от Android SDK Manager в Android Studio.
  • Google Play services SDK. Вы можете получить это в Android SDK Manager в Android Studio.

4. Создание приложения

В этом шаге вы создадите основной костяк приложения, которое вы сможете заполнить позже путем добавления кода.
Откройте Android Studio. При запуске Android Studio, выберите пункт «Создать новый проект Android Studio». Вы увидите диалоговое окно «Новый проект». Введите данные для вашего приложения.
Нажмите Next, и вы получите экран с выбором к целевых Android-устройств. Принимаем по умолчанию, и нажимаем Next в следующем окне.
Выберите шаблон ‘Empty Activity’ в следующем диалоге.
2016-08-28_16-18-14
Нажмите «Next», и вам будет предложено настроить активити. Просто примите значения по умолчанию и нажмите «Готово».

Обновление build.gradle

Далее нужно обновить ваш файл сборки build.gradle. В Android Studio откройте узел Gradle скрипты и выберите build.gradle (модуль App), как показано на рисунке:
2016-08-28_16-21-08
Это откроет ваш build.gradle файл, в нижней части которого будет такой код:
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])}

Теперь нам нужно добавить сюда библиотеку Play services самой новой версии.  Узнать последние версии всех библиотек можно по ссылке на нашем сайте fandroid.info. Найдите пункт “Gradle, please! Актуальные версии популярных библиотек”.

2016-08-28_16-25-31

Сейчас самая свежая версия библиотеки Play services 9.4.  Копируем и вставляем в секцию зависимостей файла сборки нашего проекта.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.2.0'
    compile 'com.google.android.gms:play-services:9.4.0'
}
Не забудьте выполнить синхронизацию gradle по ссылке справа. Это также можно  сделать с помощью кнопки синхронизации Gradle на панели инструментов, она выглядит следующим образом:

Image

Обновление Google Play Services

Google Play services часто обновляется, чтобы получить последнюю версию, нажмите в Android Studio Tools > Android > SDK Manager:

Image

Затем найдите запись для Google Play Services и убедитесь, что у вас стоит 26 или более поздней версии:

2016-08-28_16-36-45

Создаем базовый пользовательский интерфейс

Теперь, когда ваше приложение полностью настроено, нужно построить пользовательский интерфейс, который позволяет пользователю обнаружить лицо
в изображении, а затем наложить на лицо рамку.
В Android Studio выберите папку «res» и откройте его в подпапку «layout». Здесь вы увидите «activity_main.xml».
Дважды щелкните, чтобы открыть его в редакторе и не забудьте выбрать вкладку «Текст» в нижней части редактора для получения текста XML-представление макета.
Android Studio должен выглядеть следующим образом:
Image
Вы можете видеть, что ваш макет содержит один узел <TextView>. Удалите его и  добавьте компонент ImageView, в который будет загружаться изображение.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="info.fandroid.facedetect.MainActivity">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/image"/>

</RelativeLayout>

Отредактируйте ваш AndroidManifest.xml

Вы должны отредактировать файл AndroidManifest.xml, добавив такие строки:

<meta-data 
android:name="com.google.android.gms.vision.DEPENDENCIES" 
android:value="face" />

Это гарантирует, что библиотеки для распознавания лиц будут доступны приложению.

Общий вид манифеста приложения:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.fandroid.facedetect">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:name="android.support.multidex.MultiDexApplication">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="com.google.android.gms.vision.DEPENDENCIES"
            android:value="face"/>
    </application>

</manifest>

Добавление распознавания лиц к вашему приложению

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

В этом уроке для простоты мы будем обработать изображение, которое уже присутствует в вашем приложении.
Скачайте Вот это изображение по ссылке в описании видео:
Image - "Woman and a chiwawa dog" by Peter van der Sluijs, available on the CC 3.0 license, downloaded from https://commons.wikimedia.org/wiki/File:Woman_and_chiwawa_dog.JPG
Источник: https://commons.wikimedia.org/wiki/File:Woman_and_chiwawa_dog.JPG

Назовите его test1.jpg и добавьте в каталог res/drawable в файловой системе. Android Studio делает файл доступным в качестве ресурса, с идентификатором: R.drawable.test1

5. Написание кода приложения

Вот полный набор импортов классов, используемых в главном активити:

import android.app.Activity;
import android.app.AlertDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.face.Face;
import com.google.android.gms.vision.face.FaceDetector;

Весь код пишем в методе onCreate. Это не совсем правильно с точки зрения архитектуры приложения, но для нашего упрощенного примера опустим эти условности.

Загрузим изображение

Начнем с загрузки изображения. Мы будем рисовать поверх изображения красный прямоугольник на любых обнаруженных лицах, поэтому мы должны убедиться, что растровое изображение является изменяемым. Сначала мы получаем дескриптор элемента  ImageView  для использования позже. Затем мы используем BitMapFactory для загрузки растрового изображения. Обратите внимание, что ресурс доступен с помощью ссылки R.drawable.test1. Если используется другое имя для изображения, нужно заменить test1 вашим именем.

ImageView myImageView = (ImageView) findViewById(R.id.imgview);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable=true;Bitmap myBitmap = BitmapFactory.decodeResource(
        getApplicationContext().getResources(), 
        R.drawable.test1, 
        options);

Создадим объект Paint

Далее создадим объект myRectPaint класса Paint, который мы будем использовать для рисования на изображении.
Это устанавливает штрих шириной 5 пикселей и стиль обводки, это означает, что когда он рисует фигуру, он только рисует контур, и не заполняет форму.
Paint myRectPaint = new Paint();
myRectPaint.setStrokeWidth(5);
myRectPaint.setColor(Color.RED);
myRectPaint.setStyle(Paint.Style.STROKE);

Создадим объект Canvas

Далее создадим объект tempBitmap из оригинальной картинки, которую мы используем. Из этого мы можем создать объект класса Canvas и нарисовать Bitmap на нем.

Bitmap tempBitmap = Bitmap.createBitmap(myBitmap.getWidth(), myBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
tempCanvas.drawBitmap(myBitmap, 0, 0, null);

Создадим  Face Detector

Нам нужно создать новый объект FaceDetector, используя его билдер.
Мы добавили зависимость AndroidManifest.xml так, чтобы библиотеки будут загружаться прежде, чем понадобятся в приложении. Но вполне возможно, что первый раз наш детектор лица cработает, когда служба Google Play еще не будет готова для обработки лица. Поэтому мы должны проверить, что наш детектор работает, прежде чем использовать его. Если нет, нам придется ждать загрузки для завершения или оповестить пользователей, что служба не готова.
FaceDetector faceDetector = new FaceDetector.Builder(getApplicationContext()).setTrackingEnabled(false).build();
if(!faceDetector.isOperational()){
   new AlertDialog.Builder(v.getContext()).setMessage("Could not set up the face detector!").show();
   return;}
Поскольку в этом примере просто обнаружение лица на стоп-кадр, нет необходимости отслеживания. Для реализации обнаружения лица в видео или на превью с камеры следует установить для trackingEnabled значение  «true».
Теперь мы готовы обнаружить лица. Создадим рамку с помощью Bitmap, затем вызовем метод detect класса FaceDetector, используя этот кадр, чтобы вернуть объекты массива SparseArray faces.
Frame frame = new Frame.Builder().setBitmap(myBitmap).build();
SparseArray<Face> faces = faceDetector.detect(frame);

Рисование прямоугольников на лицах

Таким образом,  мы получаем массив лиц SparseArray. Можно выполнить итерацию массива для получения координаты ограничивающего прямоугольника для лица. API возвращает x, y координаты левого верхнего угла, а также ширину и высоту. Для отрисовки прямоугольника требуется x, y верхнего левого и нижнего правого углов, получаем их в результате несложных вычислений.

for (int i = 0; i < faces.size(); i++) {
            Face thisFace = faces.valueAt(i);
            float x1 = thisFace.getPosition().x;
            float y1 = thisFace.getPosition().y;
            float x2 = x1 + thisFace.getWidth();
            float y2 = y1 + thisFace.getHeight();
            tempCanvas.drawRoundRect(new RectF(x1, y1, x2, y2), 2, 2, myRectPaint);
        }

И наконец, загружаем изображение в макет:

myImageView.setImageDrawable(new BitmapDrawable(getResources(), tempBitmap));

Результаты

Теперь все, что вам нужно сделать, это запустить приложение. На экране видим, что обнаружено лицо женщины, при этом морда собаки не определяется.

Image

В качестве домашнего задания поэкспериментируйте, попробуйте загрузить другие изображения, там где больше лиц, или там где лица повернуты под разными углами, и осмотрите, как  Face Detection API справится с задачей.

Исходный код этого приложения полностью:

package info.fandroid.facedetect;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.SparseArray;
import android.widget.ImageView;
import android.widget.Toast;

import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.face.Face;
import com.google.android.gms.vision.face.FaceDetector;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView myImageView = (ImageView) findViewById(R.id.image);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inMutable = true;
        Bitmap myBitmap = BitmapFactory.decodeResource(
                getApplicationContext().getResources(),
                R.drawable.test1,
                options);

        Paint myRectPaint = new Paint();
        myRectPaint.setStrokeWidth(5);
        myRectPaint.setColor(Color.RED);
        myRectPaint.setStyle(Paint.Style.STROKE);

        Bitmap tempBitmap = Bitmap.createBitmap(myBitmap.getWidth(), myBitmap.getHeight(), Bitmap.Config.RGB_565);
        Canvas tempCanvas = new Canvas(tempBitmap);
        tempCanvas.drawBitmap(myBitmap, 0, 0, null);

        FaceDetector faceDetector = new FaceDetector.Builder(getApplicationContext()).setTrackingEnabled(false).build();
        if (!faceDetector.isOperational()) {
            Toast.makeText(this, "Cold not set up the Face Detector!", Toast.LENGTH_LONG).show();
            return;
        }

        Frame frame = new Frame.Builder().setBitmap(myBitmap).build();
        SparseArray <Face> faces = faceDetector.detect(frame);

        for (int i = 0; i < faces.size(); i++) {
            Face thisFace = faces.valueAt(i);
            float x1 = thisFace.getPosition().x;
            float y1 = thisFace.getPosition().y;
            float x2 = x1 + thisFace.getWidth();
            float y2 = y1 + thisFace.getHeight();
            tempCanvas.drawRoundRect(new RectF(x1, y1, x2, y2), 2, 2, myRectPaint);
        }

        myImageView.setImageDrawable(new BitmapDrawable(getResources(), tempBitmap));
    }
}

Источник

Дополнительно:

<<<Предыдущий урок      Следующий урок>>>

Коментарі: 1
Додати коментар