В этом посте я хочу описать, как распознавать лица на изображении с помощью Android. Я использую камеру, чтобы получить изображение, а затем приложение нарисует прямоугольник вокруг лиц, обнаруженных на изображении. Для этого мы просто используем Android API, например:
- FaceDetector используется для обнаружения лица в растровом изображении
- Объект Face , содержащий информацию об обнаруженном лице
Поэтому мы должны сделать три шага в наших приложениях:
- Сделай снимок
- Определить лица на картинке
- Рисует прямоугольники вокруг обнаруженных лиц
Сделайте снимок на камеру с помощью Android
Этот шаг довольно прост, потому что мы должны просто вызвать намерение и подготовиться к получению результата. Намерение очень простое:
1
2
|
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(cameraIntent, CAMERA_RETURN_CODE); |
Чтобы получить результат (снимок сделан), мы должны переопределить метод в нашей деятельности:
1
2
3
4
5
6
|
@Override protected void onActivityResult( int requestCode, int resultCode, Intent data) { if (requestCode == CAMERA_RETURN_CODE) { Bitmap cameraBmp = (Bitmap) data.getExtras().get( "data" ); } } |
В строке 4 мы получаем наше изображение, используя дополнительные с ключом данных.
Определить лица на картинке
На этом этапе мы используем API, поставляемый с Android SDK начиная с уровня 1. Для реализации нашей логики мы создаем пользовательский компонент, который расширяет
ImageView , мы называем это FaceImageView .
1
2
3
|
public class FaceImageView extends ImageView { ... } |
Чтобы обнаружить лица, сначала нужно преобразовать изображение в растровое изображение в формат 556, иначе мы не сможем использовать изображение, как указано в API, поэтому имеем:
1
|
Bitmap tmpBmp = image.copy(Config.RGB_565, true ); |
Теперь у нас есть изображение в правильном формате, мы создаем экземпляр FaceDetector:
1
|
FaceDetector faceDet = new FaceDetector(tmpBmp.getWidth(), tmpBmp.getHeight(), MAX_FACES); |
передавая ширину и высоту изображения, а также количество лиц, которые мы хотим обнаружить (в нашем случае это просто константа). Теперь мы вызываем метод findFaces для обнаружения лиц, в результате чего мы ожидаем массив экземпляра Face, который должен иметь длину, равную количеству лиц, которые мы хотим обнаружить:
1
|
faceDet.findFaces(tmpBmp, faceList); |
где faceList — это наш массив.
Теперь мы должны проанализировать каждый элемент в нашем массиве и получить результат. Мы просто хотим получить среднюю точку лица и расстояние между глазами . Мы используем эти две информации, чтобы нарисовать прямоугольник для каждого обнаруженного лица:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
for ( int i= 0 ; i < faceList.length; i++) { Face face = faceList[i]; Log.d( "FaceDet" , "Face [" +face+ "]" ); if (face != null ) { Log.d( "FaceDet" , "Face [" +i+ "] - Confidence [" +face.confidence()+ "]" ); PointF pf = new PointF(); face.getMidPoint(pf); Log.d( "FaceDet" , "\t Eyes distance [" +face.eyesDistance()+ "] - Face midpoint [" +pf+ "]" ); RectF r = new RectF(); r.left = pf.x - face.eyesDistance() / 2 ; r.right = pf.x + face.eyesDistance() / 2 ; r.top = pf.y - face.eyesDistance() / 2 ; r.bottom = pf.y + face.eyesDistance() / 2 ; rects[i] = r; } } |
В строке (9-13) мы вычисляем вершину прямоугольника и сохраняем их в объекте RectF. Если мы хотим запустить приложение, мы можем использовать реальный смартфон или AVD, настроенный в нашей среде разработки. В этом случае убедитесь, что вы настроили камеру для использования:
Запустив пример и посмотрев журнал, мы имеем:
Мы замечаем, что приложение обнаружило одно лицо, в то время как другие равны нулю, поскольку на картинке больше нет лиц.
Нарисуйте прямоугольники вокруг обнаруженных лиц
Последний шаг — рисование прямоугольников вокруг обнаруженных лиц. В этом случае мы можем использовать полученную ранее информацию следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@Override protected void onDraw(Canvas canvas) { super .onDraw(canvas); Paint p = new Paint(); canvas.drawBitmap(image, 0 , 0 , p); Paint rectPaint = new Paint(); rectPaint.setStrokeWidth( 2 ); rectPaint.setColor(Color.BLUE); rectPaint.setStyle(Style.STROKE); for ( int i= 0 ; i < MAX_FACES; i++) { RectF r = rects[i]; if (r != null ) canvas.drawRect(r, rectPaint); } } |
- Доступен исходный код @ github