OpenCV no Android: Acesso a câmera usando C

On 15 de fevereiro de 2016 by Giovani Romani

opencv_logo

Esse tutorial é composto por duas partes, ambas partem do princípio que você já tenha seguido o tutorial Iniciando com OpenCV e Android Studio :

  1. Como utilizar um código nativo em OpenCV no Android Studio.
  2. Como capturar uma imagem da câmera e salvar na memória interna.

1. Como utilizar um código nativo em OpenCV no Android Studio

Configurando o Ambiente

Requisitos:

  1. Se não possuir a biblioteca do OpenCV para Android, faça o download no site.
  2. Faça o download do NDK no link.

Primeiramente devemos adicionar as ferramentas externas:

  1. javah: responsável por gerar os arquivos de cabeçalho .h a partir do arquivo .java
  2. ndk-build: responsável por compilar o código nativo.

Para adicionarmos as ferramentas, no Android Studio, devemos ir em Preferences->External Tools e adicionar a ferramenta externa javah, com as seguintes configurações:

  • Program: /usr/bin/javah ou o caminho onde o binário javah se encontra em seu computador, se seu sistema operacional for unix digite which javah
  • Parameters:
    -v -jni -d $ModuleFileDir$/src/main/jni $FileClass$

     

  • Working directory: $SourcepathEntry$

Captura de Tela 2016-02-15 às 03.53.19

 

Para adicionarmos a ferramenta externa ndk-build, devemos ir em Preferences->External Tools, com as seguintes configurações:

  • Program: /Users/user/android-ndk-r10e/ndk-build ou o caminho onde se encontra o ndk-build
  • Parameters:
    NDK_PROJECT_PATH=$ModuleFileDir$/build/intermediates/ndk 
    NDK_LIBS_OUT=$ModuleFileDir$/src/main/jniLibs 
    NDK_APPLICATION_MK=$ModuleFileDir$/src/main/jni/Application.mk 
    APP_BUILD_SCRIPT=$ModuleFileDir$/src/main/jni/Android.mk V=1

     

  • Working directory: $SourcepathEntry$

Captura de Tela 2016-02-15 às 04.00.12

 

Na classe MainActivity.java devemos indicar o nome das bibliotecas que serão geradas através da compilação do código nativo para que elas sejam carregadas.  Para isso devemos adicionar este trecho de código na classe MainActivity.java:

public class MainActivity extends AppCompatActivity implements CvCameraViewListener2, 
View.OnClickListener {
    //...
    static {
//O nome da biblioteca corresponde ao nome definido no arquivo Android.mk, que 
será visto posteriormente
        System.loadLibrary("NdkLib");
        System.loadLibrary("opencv_java3");
    }
//o nome da função é definido pelo programador
    public native int grayOpenCV(long matRgba, long matGray);
//...
}

 

Ao clicar com o botão direito na classe MainActivity.java, deverão aparecer as ferramentas que adicionamos anteriormente. Clique em javah para que seja criado o diretório jni  e gerado o arquivo de cabeçalho, nesse exemplo, com_example_giovaniromani_tutorialopencv_MainActivity.h em /src/main /jni:

Captura de Tela 2016-02-15 às 02.56.59

 

Uma vez criado o diretório /src/main/jni, devemos adicionar três arquivos, dois responsáveis pela compilação e um contendo o código nativo que queremos utilizar, são eles: Android.mk, Application.mk e nativeCodeSobel.cpp

Criando e Editando os Arquivos de Configuração para a Compilação do Código Nativo

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

#diretorio onde se encontra o sdk do OpenCV em seu computador
OPENCVROOT:= /Users/user/OpenCV-android-sdk
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include ${OPENCVROOT}/sdk/native/jni/OpenCV.mk

#arquivo contendo o código nativo
LOCAL_SRC_FILES := nativeCodeSobel.cpp
LOCAL_LDLIBS += -llog
LOCAL_MODULE := NdkLib

include $(BUILD_SHARED_LIBRARY)

 

Application.mk

APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a x86
APP_PLATFORM := android-16

 

nativeCodeGray.cpp

Neste arquivo se encontram as instruções que desejamos utilizar em código nativo.

#include "nativeCodeGray.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <nativeCodeGray.h>
//Atencao ao nome da biblioteca, ele deverá ser igual ao arquivo contido no diretório 
///src/main/libs
#include <com_example_giovaniromani_tutorialopencv_MainActivity.h>

using namespace cv;

/** @function main */

//Atenção ao nome do método, ele deverá ser igual ao nome contido no 
//com_example_giovaniromani_tutorialopencv_MainActivity.h
    JNIEXPORT jint
    JNICALL Java_com_example_giovaniromani_tutorialopencv_MainActivity_grayOpenCV
            (JNIEnv *, jobject, jlong matRgba, jlong matGray) {
        Mat &rgba = *(Mat *) matRgba;
        Mat &gray = *(Mat *) matGray;
        cvtColor(rgba, gray, CV_BGR2GRAY);
    }

 

Logo, teremos 5 arquivos no diretório src/main/jni.

Captura de Tela 2016-02-15 às 04.57.23

 

 

No arquivo build.gradle do app devemos adicionar o seguinte trecho de código:

//...
android{
//...
   sourceSets.main {
       jni.srcDirs = [] //desabilita chamada automática ao ndk-build
   }

 //Será necessário verificar e atualizar o caminho para o ndk-build
   task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
       commandLine "/Users/giovaniromani/MEGA/CodigoFonte/android-ndk-r10e/ndk-build",
               'NDK_PROJECT_PATH=build/intermediates/ndk',
               'NDK_LIBS_OUT=src/main/jniLibs',
               'APP_BUILD_SCRIPT=src/main/jni/Android.mk',
               'NDK_APPLICATION_MK=src/main/jni/Application.mk'
   }
   tasks.withType(JavaCompile) {
       compileTask -> compileTask.dependsOn ndkBuild 
   }
}
//....

 

Utilizando o Código Nativo

Por fim,  para que seja exibida a imagem, devemos chamar o método passando como parâmetro duas matrizes:

    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {

        Mat rgba = inputFrame.rgba();
        Mat gray = new Mat();

        grayOpenCV(rgba.getNativeObjAddr(), gray.getNativeObjAddr());
//retorna o objeto Mat que está em escala de cinza ao View para que seja exibida na tela
        return gray;
    }

 

2. Como capturar uma imagem da câmera e salvar na memória interna

Implementando o tratamento do evento OnClick

Devemos, inicialmente, implementar a interface View.OnClickListener, ela será responsável por obter e tratar o evento, que no nosso caso, será um toque na tela:

public class MainActivity extends AppCompatActivity implements CvCameraViewListener2, View.OnClickListener {

Você notará que a assinatura estará sublinhada de vermelho, isso acontece porque devemos, obrigatoriamente, sobrescrever o método OnClick.

@Override
public void onClick(View v) {
}

Para que a View possa capturar o evento, temos que ativar o seu listener, assim, devemos colocar a seguinte linha de código no método OnCreate da classe MainActivity:

mOpenCvCameraView.setOnClickListener(this);

Salvando a Imagem

Será necessário criar um atributo do tipo Mat que armazenará a imagem em escala de cinza, conforme nosso objetivo. Dessa forma teremos a declaração do atributo no início da classe e atribuiremos o objeto gray do tipo Mat ao atributo matGray dentro do método OnCameraFrame, conforme código abaixo:

public class MainActivity extends AppCompatActivity implements CvCameraViewListener2, View.OnClickListener {
//...
    private Mat matGray;
//...
    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
        Mat rgba = inputFrame.rgba();
        Mat gray = new Mat();
        grayOpenCV(rgba.getNativeObjAddr(), gray.getNativeObjAddr());
        matGray=gray;
        return gray;
    }
//...
}

Para que a imagem seja salva ao clicarmos na tela, devemos inserir as seguintes linhas de código no método OnClick:

@Override
public void onClick(View v) {
//Armazena uma cópia da matriz matGray na matriz src
    Mat src = matGray.clone();
//Realiza a cnoversão de Mat para Bitmap
    Bitmap bitmap = Bitmap.createBitmap(src.cols(), src.rows(), Bitmap.Config.ARGB_8888);
    Utils.matToBitmap(src, bitmap);
    ContentValues contentValues = new ContentValues();
    Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
 contentValues);
    OutputStream outputStream;
    try {
//Salva a imagem
        outputStream = getContentResolver().openOutputStream(uri);
        boolean compressed = bitmap.compress(Bitmap.CompressFormat.PNG, 0, 
outputStream);
        outputStream.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Atenção

O Aplicativo deve ter permissão para pode acessar a memória externa do aparelho, para isso, devemos inserir as seguintes linhas no arquivo AndroidManifest.xml

[sourcecode language=”xml”]
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
[/sourcecode]

droid

Para mais detalhes, o código está disponível no GitHub.

Referência:

[1] http://hujiaweibujidao.github.io/blog/2014/10/22/android-ndk-and-opencv-development-with-android-studio/

Summary
OpenCV no Android: Acesso a câmera usando C
Article Name
OpenCV no Android: Acesso a câmera usando C
Description
Aprenda como compilar código nativo NDK e utilizar o OpenCV para capturar imagens da câmera.
Author
Publisher Name
iMobilis
Publisher Logo

7 Responses to “OpenCV no Android: Acesso a câmera usando C”

  • Boa noite,
    copiei e colei o código logo abaixo da mensagem:

    ” No arquivo build.gradle do app devemos adicionar o seguinte trecho de código:”

    Verifiquei o caminho para ndk-build e mesmo assim ocorre um erro no programa. Poderia me ajudar?

    Grato.

    • Boa noite André,

      há um problema de formatação no código.

      A linha
      compileTask – & g t; compileTask.dependsOn ndkBuild
      deverá ser substituída por
      compileTask -> compileTask.dependsOn ndkBuild

      Caso tenha dúvidas sobre o código, ele está disponível no GitHub.

      Se o problema persistir, nos comunique novamente indicando o erro.

      • Boa tarde,
        o erro ainda continua, aparece a seguinte mensagem.

        Error:Execution failed for task ‘:app:ndkBuild’.
        > A problem occurred starting process ‘command ‘/C:/Users/andre/Downloads/android-ndk-r10e/ndk-build”

  • Boa tarde.
    Tem algum desenvolvedor para um aplicativo android que interligue a captura de imagens do celular( OPENCV/TESSERAT… ) com um banco de dados e o sinesp cidadão. Seria usado embarcado em um veiculo visando o combate de ilícitos penais.
    Aguardo maiores informações.
    Obrigado.
    rb.moc.liamgnull@livadlaicilop

  • Olá pessoal. Alguém consegue montar programar um aplicativo para android utilizando a tecnologia para obter placas de veículos e pesquisar no Senasp cidadão?
    Caso afirmativo entre em contato no email moc.liamgnull@alivadlaicilop

  • Ei lá só queria dar-lhe um rápida heads-սp e qսe você saiba aⅼguns do imagens não estão carregando corretamente.
    Nã᧐ sei porquê, mas еu acho qᥙe é սma գuestão dе
    vinculaçãߋ. Já tentei em dois diferentes navegadores internet е ambos mostram a mesma resultado.

Trackbacks & Pings

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *