본문 바로가기
Android

Android openCv Mat to Array, 안드로이드 opencv 이미지 배열 얻기

by ahsung 2020. 9. 10.

 

 

안드로이드 스튜디오에 openCv sdk를 사용하여 이미지를 얻어내고

그 이미지를 굳이 file bytes를 사용하지 않고 openCv의 이미지 포맷인 Mat 자료구조 값을 그대로 서버로 전송하고 싶은데,  

 

뭔가 함수를 찾아봐도 Java의 캡슐화 원칙때문인지, 전체 Array값을 얻을 수 있는 인터페이스 함수를 제공하지는 않는 것 같고(제가 못 찾은 것일 수도..허허) ..

 

하지만 기본적으로 원래 cpp로 만들어진 openCv는 전체 Mat의 Array를 알 수 있는 방법이 있기 때문에,

 

직접 openCv cpp 코드를 추가하여 java로의 인터페이스 함수를 만들어봅시당~

정말 간단하니 겁먹을 필요는 없습니다!

 

- 이 포스팅은 이미 Android Studio와 OpenCv 연동이 완료된 상태를 가정합니다. -

webnautes.tistory.com/1054

 

Android NDK + CMake + OpenCV 카메라 예제 및 프로젝트 생성방법(Android Camera Example with NDK, OpenCV, CMake )

안녕하세요 : ) NDK를 지원하는 안드로이드 프로젝트를 생성한 후, OpenCV 라이브러리를 추가하여 사용하는 방법을 설명합니다. 간단한 예제로 OpenCV Java API에서 캡처한 영상을 OpenCV C++ API에서 그레�

webnautes.tistory.com

Android용 openCV 설치를 쉽게 알려주셨길래 링크 달아놨습니다~

 

 

 

 

 

Android OpenCv  Mat to Array

 

 

 

 

 

보통 OpenCv를 안드로이드 스튜디오에 연결하고나면 이런 디렉토리 구조를 갖게 될텐데요.

저희가 알아야 할 부분은 cpp 디렉토리 부분으로, 간단하게 설명하자면

 

하위 폴더 inlcudes는 실제로 cpp 안에 있는 폴더는 아니고 opencv에 있는 라이브러리와 Ndk입니다.

그리고 CMakeLists.txt, native-lib.cpp가 실제 하위에 있는 file들인데

 

cMake는 빌드 스크립트를 만드는 툴로서, CMakeLists.txt에 어떻게 cpp file과 오브젝트 file들을 빌드업하고 include할지 선언 되어있습니다.

 

CMakeLists.txt의 내부 선언을 보면 native-lib.cpp를 끌어오는 부분도 있습니다. 저희는 이쪽에 코드를 추가해서

Java에서도 openCv cpp-library 로직을 사용할 수 있는 인터페이스가 되는 함수를 만들 것 입니다!

 

cMakeLists.txt

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

set(pathPROJECT C:/Users/asung/Documents/vision) # 프로젝트 경로로 수정!
set(pathOPENCV ${pathPROJECT}/opencv) # opencv 모듈 이름,경로 수정!
set(pathLIBOPENCV_JAVA ${pathOPENCV}/native/libs/${ANDROID_ABI}/libopencv_java4.so)

set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

include_directories(${pathOPENCV}/native/jni/include)


# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        ${pathPROJECT}/app/src/main/cpp/native-lib.cpp )



add_library( lib_opencv SHARED IMPORTED )

set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${pathLIBOPENCV_JAVA})


# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-lib

        lib_opencv

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib} )

이미 openCv 연동에 성공하셨다면 이미 코드 설정이 잘 되있으시겠지만, 참고용입니다.

경로는 자체 프로젝트에 맞게 잘 설정해주세요.

 

 

 

 

 

Android Activity java

 

그 다음 원하는 Class에서 인터페이스가 될 함수를 선언합니다.

처음 선언당시 당연히 converToArray() 함수와 같이 정의 부분이 없기 때문에 빨간 경고가 올라 올 것입니다.

마우스를 가져다 대고  Create JNI funtion을 누르거나, Alt + Shift + Enter로 생성합시다!

함수는 첫번째 인자에 Mat 객체의 주소를 넣으면, 두번째 인자 byte array에 값을 넣는 방식입니다!

 

 

 

native-lib.cpp에 그 내용이 추가되었습니다

 

 

 

 

native-lib.cpp

#include <jni.h>
#include <string>
#include <opencv2/opencv.hpp>
using namespace cv;



extern "C"
JNIEXPORT void JNICALL
Java_com_example_vision_CameraActivity_converToArray(JNIEnv *env, jobject thiz, jlong mat_addr,
                                                     jbyteArray array) {
    // TODO: implement converToArray()
    Mat &mat = *(Mat *)mat_addr;
    env->SetByteArrayRegion(array,0,mat.total(),(const jbyte *)mat.data);
}

 

처음 인터페이스가 되는 함수를 설계할 때처럼  mat의 주소를 받았으니, 해당 Mat.data는 cpp에서 배열의 값을 가지고 있기 때문에 그대로 SetByteArrayRegion 함수를 사용하여 array에 복사해 줍시다!

 

참고로 java의 타입들은 Ndk cpp에서 jbyte, jint 식으로 j가 붙어 표현됩니다.

 

이렇게 사용하면 끄읕~~

 

 

이제 부터 converToArray함수를 통해 java의 byte Array로 변환할 수 있습니다~!

사용 예시

 

함수 이름을 생각없이 짓다보니,, Mat2Array 정도면 좋았겠네요!

 

 

아마 제 기억에는 mat data가 1차원 데이터이다보니 그냥 쭉 빼왔는데,

실제로는 여러차원 데이터를 평탄화 한거라,  Array의 의미는 잘 해석하셔야 할듯 합니다!

일단 가로, 세로 길이에 따라 2차원으로 구분될거고, RGB에 무슨값 하나더해서 색으로 4차원이 또 있던 것 같습니다!

예전에 사용하고 포스팅을 너무 늦게해서 저도 기억이 가물가물 하네요

 

참고하시는 분들은 알아내는 과정도 즐거우니 알아서 잘하시길~

 

 

'Android' 카테고리의 다른 글

Android android9 API 28 이상 network 연결 오류  (0) 2020.01.09

댓글