OpenCV в Android

Автор: | 19.10.2018

Инсталляция  OpenCV в  Android Studio
Захват видео с камеры
Отслеживание лица из видео-потока, используя каскад Хаара
Полезные ссылки

Инсталляция  OpenCV в  Android Studio

Скачиваю с сайта OpenCV архив opencv-3.4.3-android-sdk.zip, распаковываю его и размещаю папку из распакованного архива в корень диска C.

Создаю в в  Android Studio проект: File -> New -> New Project. Даю проекту имя opencv_project. Нажимаю Next -> Next -> Next -> Finish.

Выбираю меню File -> New -> Import Module… и указываю путь sdk/java из распакованного SDK архива:

В окне «Android» должен появиться модуль openCVLibrary343:

При этом еще откроется файл import_summary.txt. В нем предлагается вручную загрузить необходимые для проекта файлы. Закройте его. В этом проекте ничего догружать не нужно. Возможно это понадобится в других проектах.

В окне «Android» можно увидеть 3 файла с именем build.gradle, один из них принадлежит модулю openCVLibrary343:

Открываю этот файл и обновляю в нем параметры compileSdkVersionbuildToolsVersionminSdkVersion и targetSdkVersion, чтобы они совпадали с соответствующими параметрами из файла build.gradle (Module:app).

После того, как модуль OpenCV был добавлен, его нужно присоединить в качестве зависимости к модулю приложения. Выбираю меню File -> Project Structure…  В открывшемся окне выбираю app -> Dependencies -> + -> Module dependency -> OpenCVLibrary343 -> OK.

Последнее, что осталось сделать — добавить двоичные библиотеки OpenCV в проект, чтобы при сборке они были упакованы в .apk приложения. Для этого копирую папку sdk/native/libs из OpenCV SDK в папку проекта opencv_project/app/src/main. Переименовываю скопированную в проект папку libs в jniLibs.

В общем инсталляция   OpenCV закончена. Сейчас можно проверить, что ничего в  проекте не повреждено и по прежнему запускается «Hello World». Дополнительные установки и подключения для конкретных задач рассмотрены в примерах ниже.

Захват видео с камеры

Заменяю код в исходных файлах activity_main.xml и Main_Activity.java . Запускаю программу. Получаю вот такой результат:

«It seems that your device does not support camera (or it is locked). Application will be locked.»
«Кажется, Ваше устройство не поддерживает камеру (или она заблокирована). Приложение будет закрыто.»

Для устранения этой ошибки выполняю следующее:

Первое.   Ввожу в файл AndroidManifest.xml  перед тегом application следующую строку:

<uses-permission android:name="android.permission.CAMERA"/>
<application
    android:allowBackup="true"
...

Второе.    В Android устройстве последовательно нажимаю выделенные красным прямоугольником кнопки

 

 

 

 

 

Кнопка напротив «Camera» должна быть активной при запуске проекта приложения, которое работает с камерой.

Третье.    Вызываю AVD Manager кнопкой в правом верхнем углу Android Studio

открывается окно редактирования эмуляторов (у меня их 2), редактирую тот, что активный

 

В открывшемся окне нажимаю кнопку ShowAdvancedSettings и в блоке Camera выбираю Webcam0 для  Front и Back.

 

Запускаю приложение и получаю ожидаемый результат:

Файлы приложения «Capture video from the camera»

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:opencv="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<org.opencv.android.JavaCameraView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:visibility="gone"
    android:id="@+id/view"
    opencv:camera_id="any" />

</FrameLayout>

 

Main_Activity.java 

package com.example.sv.opencv_project;

import android.app.Activity;
import android.os.Bundle;
import android.view.SurfaceView;
import android.view.WindowManager;

import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;


public class MainActivity extends Activity implements CvCameraViewListener2 {
    private CameraBridgeViewBase mOpenCvCameraView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_main);
        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.view);
        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
        mOpenCvCameraView.setCvCameraViewListener(this);
    }

    @Override
    public void onPause()
    {
        super.onPause();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        OpenCVLoader.initDebug();
        mOpenCvCameraView.enableView();
    }

    public void onDestroy() {
        super.onDestroy();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    public void onCameraViewStarted(int width, int height) {
    }

    public void onCameraViewStopped() {
    }

    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
        return inputFrame.rgba();
    }
}

Отслеживание лица, используя каскад Хаара

Заимствую пример из интернет. Создаю новый проект, заменяю код в файле Main_Activity.java.

Код незначительно отличается от примера из интернет. Изменения вызваны обновленной версией OpenCV.

Через контекстное меню создаю директорию raw в папке res.

Копирую в эту папку  файл lbpcascade_frontalface.xml из папки …\etc\lbpcascades установленного opencv-3.4.3-android-sdk:

В программу можно загружать и подключать разные каскады — в зависимости от ожидаемого результата (детектирование лица, глаз, кисти руки и т.п.). Часть каскадов находится в папке …\etc\… , другие можно поискать в интернет.

Запускаю программу. Получаю вот такой результат:

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

На сайте по ссылке описано, как можно решить эту проблему при работе с Android Studio в  различных  ОС (у меня Windows 10). Для инсталляции OpenCV Manager в  эмуляторе выполняю следующее:

Копирую APK файл из установленного у меня на компьютере пакета opencv-3.4.3-android-sdk в директорию …android\sdk\platform-tools:

Через кнопку поисковика запускаю окно командной строки Windows: cmd

В окне командной строки последовательно ввожу команды, которые обеспечивают выход на соответствующую директорию и инсталляцию apk файла:

Перебирал несколько файлов для установки, пока не добился успешного результата (Succces) с файлом OpenCV_3.4.3_Manager_3.43_x86.apk. Другие подгруженные apk файлы из директории …android\sdk\platform-tools можно удалить.

Запускаю приложение после выполненных настроек и получаю ожидаемый результат (квадраты отслеживают положение лиц):

В случае использования другого эмулятора инсталляцию OpenCV Manager  необходимо повторить, иначе снова будет появляться сообщение об ошибке «Package not found …»

Файл приложения face detection — Main_Activity.java 

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import org.opencv.android.*;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

public class MainActivity extends Activity
        implements CvCameraViewListener {

    private CameraBridgeViewBase openCvCameraView;
    private CascadeClassifier cascadeClassifier;
    private Mat grayscaleImage;
    private int absoluteFaceSize;

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                    initializeOpenCVDependencies();
                    break;
                default:
                    super.onManagerConnected(status);
                    break;
            }
        }
    };

    private void initializeOpenCVDependencies() {

        try {
            // Copy the resource into a temp file so OpenCV can load it
            InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
            File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
            File mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
            FileOutputStream os = new FileOutputStream(mCascadeFile);


            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            is.close();
            os.close();

            // Load the cascade classifier
            cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
        } catch (Exception e) {
            Log.e("OpenCVActivity", "Error loading cascade", e);
        }

        // And we are ready to go
        openCvCameraView.enableView();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        openCvCameraView = new JavaCameraView(this, -1);
        setContentView(openCvCameraView);
        openCvCameraView.setCvCameraViewListener(this);
    }

    @Override
    public void onCameraViewStarted(int width, int height) {
        grayscaleImage = new Mat(height, width, CvType.CV_8UC4);

        // The faces will be a 20% of the height of the screen
        absoluteFaceSize = (int) (height * 0.2);
    }

    @Override
    public void onCameraViewStopped() {
    }

    @Override
    public Mat onCameraFrame(Mat aInputFrame) {
        // Create a grayscale image
        Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);

        MatOfRect faces = new MatOfRect();

        // Use the classifier to detect faces
        if (cascadeClassifier != null) {
            cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2,
                    new Size(absoluteFaceSize, absoluteFaceSize), new Size());
        }

        // If there are any faces found, draw a rectangle around it
        Rect[] facesArray = faces.toArray();
        for (int i = 0; i <facesArray.length; i++)
            Imgproc.rectangle(aInputFrame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);

        Imgproc.circle(aInputFrame, new Point(10, 50), 50, new Scalar(255, 0,0));

        return aInputFrame;
    }

    @Override
    public void onResume() {
        super.onResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_4_0, this, mLoaderCallback);
    }
}

Полезные ссылки:

Face Detection без OpenCV:

Работа с камерой:

 

 

Автор: Николай Свирневский

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *