맥에서 OpenCV를 안드로이드 NDK 툴체인을 사용해서 빌드해 보기로 했다. 


1. 빌드 환경


빌드 환경은 아래와 같다. 다만, Java 같은 경우에는 brew cask로 설치하면 안된다. brew를 사용할 경우, JDK 10 이상의 최신 버전이 설치 되게 되는데, Android의 빌드툴인 Gradle 과 호환성 문제가 발생한다. 찾아보니, Gradle도 Gradle과 Gradle Wrapper의 두가지 버전이 존재하는데, Gradle 버전이 5.X 이상으로 높다고 하더라도 OpenCV 빌드시, 사용하는 Gradle Wrapper의 버전이 4.X로 낮게되면, JDK 10 이상의 환경을 지원하지 않는다고 한다. 따로 업데이트하는 방법도 존재하나, 몇번 시도해보고 안되서 최신버전으로 설치한 JDK 를 지우고,  Oracle 사이트에서 JDK8을 별도로 설치하였다. 참고로 했던, Java Wrapper로 ANT를 사용하기도 하는데, 최신 SDK에서는 더이상 지원하지도 않고, Gradle로 해도 별 무리없이 빌드되기 때문에, 따로 ANT를 설치하지는 않는다.

  • macOS Mojave 10.14.3
  • Android Studio 3.3.2,
  • Android SDK 28
  • Android NDK 19
  • Java JDK 8
  • CMake

위의 환경만 구축되어 있다면, NDK에서 제공하는 툴체인을 사용해서, 빌드하면 된다. 기본적으로 C++ 형태의 include 와 static lib.를 만들수 있다. 여기에다 Android Studio에서 사용하기 편하게 java로 wrapping하는 작업을 하게 되는데, 이를 위해서 Android SDK와 Java JDK가 필요하고, 이 작업을 Gradle이 수행하게 된다. 이 결과까지 나오면, 우리가 보통 사용하는 빌드된  OpenCV의 Android향 라이브러리를 볼 수 있다. 


2.CMake 기본 빌드 확인

OpenCV 홈페이지에서 source로된 openCV를 다운받는다. 적당한 디렉토리에 압축을 풀고, build 디렉토리를 만든 후에 바로 cmake 를 하면 된다. 이 경우에는 macOS용 툴체인으로 빌드되게 되고, make 까지해서, lib. 가 생성되면, macOS안에서 사용할수 있는 openCV 라이브러리가 만들어진다. 안드로이드향 openCV를 만드는게 목적이기 때문에 여기에서는 cmake가 잘먹는지 정도만 확인한다. 

-- General configuration for OpenCV 4.0.1 =====================================
--   Version control:               unknown
--
--   Platform:
--     Timestamp:                   2019-03-16T10:53:51Z
--     Host:                        Darwin 18.2.0 x86_64
--     CMake:                       3.13.4
--     CMake generator:             Unix Makefiles
--     CMake build tool:            /usr/bin/make
--     Configuration:               Release
--
--   CPU/HW features:
--     Baseline:                    SSE SSE2 SSE3 SSSE3 SSE4_1
--       requested:                 DETECT
--     Dispatched code generation:  SSE4_2 FP16 AVX AVX2 AVX512_SKX
--       requested:                 SSE4_1 SSE4_2 AVX FP16 AVX2 AVX512_SKX
--       SSE4_2 (2 files):          + POPCNT SSE4_2
--       FP16 (1 files):            + POPCNT SSE4_2 FP16 AVX
--       AVX (5 files):             + POPCNT SSE4_2 AVX
--       AVX2 (13 files):           + POPCNT SSE4_2 FP16 FMA3 AVX AVX2
--       AVX512_SKX (1 files):      + POPCNT SSE4_2 FP16 FMA3 AVX AVX2 AVX_512F AVX512_SKX
--
--   C/C++:
--     Built as dynamic libs?:      YES
--     C++ Compiler:                /Library/Developer/CommandLineTools/usr/bin/c++  (ver 10.0.0.10001044)
--     C++ flags (Release):         -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -fdiagnostics-show-option -Wno-long-long -Qunused-arguments -Wno-semicolon-before-method-body -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
--     C++ flags (Debug):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -fdiagnostics-show-option -Wno-long-long -Qunused-arguments -Wno-semicolon-before-method-body -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
--     C Compiler:                  /Library/Developer/CommandLineTools/usr/bin/cc
--     C flags (Release):           -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -fdiagnostics-show-option -Wno-long-long -Qunused-arguments -Wno-semicolon-before-method-body -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG
--     C flags (Debug):             -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -fdiagnostics-show-option -Wno-long-long -Qunused-arguments -Wno-semicolon-before-method-body -ffunction-sections -fdata-sections  -fvisibility=hidden -fvisibility-inlines-hidden -g  -O0 -DDEBUG -D_DEBUG
--     Linker flags (Release):
--     Linker flags (Debug):
--     ccache:                      NO
--     Precompiled headers:         NO
--     Extra dependencies:
--     3rdparty dependencies:
--
--   OpenCV modules:
--     To be built:                 calib3d core dnn features2d flann gapi highgui imgcodecs imgproc java_bindings_generator ml objdetect photo python2 python_bindings_generator stitching ts video videoio
--     Disabled:                    world
--     Disabled by dependency:      -
--     Unavailable:                 java js python3
--     Applications:                tests perf_tests apps
--     Documentation:               NO
--     Non-free algorithms:         NO
--
--   GUI:
--     Cocoa:                       YES
--     VTK support:                 NO
--
--   Media I/O:
--     ZLib:                        build (ver 1.2.11)
--     JPEG:                        build-libjpeg-turbo (ver 1.5.3-62)
--     WEBP:                        build (ver encoder: 0x020e)
--     PNG:                         build (ver 1.6.35)
--     TIFF:                        build (ver 42 - 4.0.9)
--     JPEG 2000:                   build (ver 1.900.1)
--     OpenEXR:                     build (ver 1.7.1)
--     HDR:                         YES
--     SUNRASTER:                   YES
--     PXM:                         YES
--     PFM:                         YES
--
--   Video I/O:
--     DC1394:                      NO
--     FFMPEG:                      NO
--       avcodec:                   NO
--       avformat:                  NO
--       avutil:                    NO
--       swscale:                   NO
--       avresample:                NO
--     GStreamer:                   NO
--     AVFoundation:                YES
--
--   Parallel framework:            GCD
--
--   Trace:                         YES (with Intel ITT)
--
--   Other third-party libraries:
--     Intel IPP:                   2019.0.0 Gold [2019.0.0]
--            at:                   /Users/injookim/Project/opencv-4.0.1/.build/Release/3rdparty/ippicv/ippicv_mac/icv
--     Intel IPP IW:                sources (2019.0.0)
--               at:                /Users/injookim/Project/opencv-4.0.1/.build/Release/3rdparty/ippicv/ippicv_mac/iw
--     Lapack:                      YES (/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Accelerate.framework /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/Accelerate.framework)
--     Eigen:                       NO
--     Custom HAL:                  NO
--     Protobuf:                    build (3.5.1)
--
--   OpenCL:                        YES (no extra features)
--     Include path:                NO
--     Link libraries:              -framework OpenCL
--
--   Python 2:
--     Interpreter:                 /usr/bin/python2.7 (ver 2.7.10)
--     Libraries:                   /usr/lib/libpython2.7.dylib (ver 2.7.10)
--     numpy:                       /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/core/include (ver 1.8.0rc1)
--     install path:                lib/python2.7/site-packages/cv2/python-2.7
--
--   Python (for build):            /usr/bin/python2.7
--
--   Java:
--     ant:                         NO
--     JNI:                         /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/JavaVM.framework/Headers /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/JavaVM.framework/Headers /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks/JavaVM.framework/Headers
--     Java wrappers:               NO
--     Java tests:                  NO
--
--   Install to:                    /usr/local
-- -----------------------------------------------------------------
--
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/injookim/Project/opencv-4.0.1/.build/Release
 Configuring done. Generating done. 이 뜬걸로 보아, cmake가 잘되었음을 확인할 수 있다.


3.안드로이드용 CMake 

안드로이드 용으로 빌드하려면, 여러가지 옵션이 필요하기 때문에 간단히,  아래와 같이 script 파일을 만들어서 이를 활용한다. NDK 디렉토리, SDK 디렉토리, OpenCV source가 있는 디렉토리, OpenCV lib.를 인스톨할 디렉토리, SDK API 레벨, 툴체인이 있는 디렉토리, 대상 Android Machine의 Architecture까지 설정해 주면 된다.

툴체인이 있는 디렉토리를 보면,  NDK에서 사전설정된 android toolchain을 사용하고 있음을 확인할 수 있다. Architecture의 경우에는 32bit를 사용하면, armeabi-v7a, 64bit를 사용하면 arm64-v8a를 선택하면 된다.

SDK_ROOT="/Users/injookim/Library/Android/sdk"
NDK_ROOT="~/Library/Android/sdk/ndk-bundle"
WD="/Users/injookim/Project"
OPENCV_ROOT="${WD}/opencv-4.0.1"
INSTALL_DIR="${WD}/android_opencv/opencv"
API_LEVEL=28
TOOLCHAIN="~/Library/Android/sdk/ndk-bundle/build/cmake/android.toolchain.cmake"
#ARCH="arm64-v8a"
ARCH="armeabi-v7a"
cmake  ../.. \
-DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
-DANDROID_SDK="$SDK_ROOT" \
-DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN}" \
-DANDROID_NDK="${NDK_ROOT}" \
-DANDROID_SDK_TARGET="${API_LEVEL}" \
-DANDROID_ABI="${ARCH}" \
-DBUILD_EXAMPLES=OFF \
-DBUILD_ANDROID_PROJECTS=ON \
-DBUILD_TESTS=OFF \
-DBUILD_PERF_TESTS=OFF \
-DBUILD_JAVA=ON \
-DBUILD_opencv_java=ON \
-DBUILD_SHARED_LIBS=OFF \
-DBUILD_FAT_JAVA_LIB=ON \
-DBUILD_PYTHON=OFF \
-DINSTALL_ANDROID_EXAMPLES=OFF \
-DANDROID_EXAMPLES_WITH_LIBS=OFF \
-DBUILD_DOCS=OFF \
-DWITH_OPENCL=OFF \
-DANDROID_NDK_HOST_X64=ON \ 
-DANDROID_TOOLCHAIN=clang \
-DANDROID_STL=c++_static \
-DANDROID_ARM_NEON=ON \
-DANDROID_NDK_HOST_X64=ON


SDK 폴더를 지정할 때는,  full path를 사용해 주는 게 필요하다. 그러하지 않을 경우, 지정 위치를 찾지 못하며, 아래와 같은 error message가 나타난다.

CMake Error at cmake/android/OpenCVDetectAndroidSDK.cmake:51 (message):
  Android SDK: specified path doesn't exist: ~/Library/Android/sdk
Call Stack (most recent call first):
  cmake/android/OpenCVDetectAndroidSDK.cmake:171 (ocv_detect_android_sdk)
  CMakeLists.txt:780 (include)

cmake가 잘 되었을 경우에는 아래와 같은 메시지가 나오게 된다.

-- General configuration for OpenCV 4.0.1 =====================================
--   Version control:               unknown
--
--   Platform:
--     Timestamp:                   2019-03-17T11:14:56Z
--     Host:                        Darwin 18.2.0 x86_64
--     Target:                      Android 1 armv7-a
--     CMake:                       3.13.4
--     CMake generator:             Unix Makefiles
--     CMake build tool:            /usr/bin/make
--     Configuration:               Release
--
--   CPU/HW features:
--     Baseline:                    NEON
--       requested:                 DETECT
--
--   C/C++:
--     Built as dynamic libs?:      NO
--     C++ Compiler:                /Users/injookim/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++  (ver 8.0)
--     C++ flags (Release):         -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -mfpu=vfpv3-d16 -fno-addrsig -march=armv7-a -mthumb -mfpu=neon -Wa,--noexecstack -Wformat -Werror=format-security -stdlib=libc++    -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Winconsistent-missing-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -fdiagnostics-show-option -Qunused-arguments  -fvisibility=hidden -fvisibility-inlines-hidden  -Oz -DNDEBUG   -DNDEBUG
--     C++ flags (Debug):           -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -mfpu=vfpv3-d16 -fno-addrsig -march=armv7-a -mthumb -mfpu=neon -Wa,--noexecstack -Wformat -Werror=format-security -stdlib=libc++    -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Winconsistent-missing-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -fdiagnostics-show-option -Qunused-arguments  -fvisibility=hidden -fvisibility-inlines-hidden  -O0 -fno-limit-debug-info   -DDEBUG -D_DEBUG -g
--     C Compiler:                  /Users/injookim/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang
--     C flags (Release):           -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -mfpu=vfpv3-d16 -fno-addrsig -march=armv7-a -mthumb -mfpu=neon -Wa,--noexecstack -Wformat -Werror=format-security    -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Winconsistent-missing-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -fdiagnostics-show-option -Qunused-arguments  -fvisibility=hidden -fvisibility-inlines-hidden  -Oz -DNDEBUG   -DNDEBUG
--     C flags (Debug):             -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -mfpu=vfpv3-d16 -fno-addrsig -march=armv7-a -mthumb -mfpu=neon -Wa,--noexecstack -Wformat -Werror=format-security    -fsigned-char -W -Wall -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -Wformat -Werror=format-security -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Winit-self -Winconsistent-missing-override -Wno-narrowing -Wno-delete-non-virtual-dtor -Wno-unnamed-type-template-args -Wno-comment -fdiagnostics-show-option -Qunused-arguments  -fvisibility=hidden -fvisibility-inlines-hidden  -O0 -fno-limit-debug-info   -DDEBUG -D_DEBUG -g
--     Linker flags (Release):      -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
--     Linker flags (Debug):        -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
--     ccache:                      NO
--     Precompiled headers:         NO
--     Extra dependencies:          /Users/injookim/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/arm-linux-androideabi/libz.a dl m log
--     3rdparty dependencies:       libcpufeatures libprotobuf libjpeg-turbo libwebp libpng libtiff libjasper IlmImf quirc tegra_hal
--
--   OpenCV modules:
--     To be built:                 calib3d core dnn features2d flann highgui imgcodecs imgproc java java_bindings_generator ml objdetect photo stitching video videoio
--     Disabled:                    world
--     Disabled by dependency:      -
--     Unavailable:                 gapi js python2 python3 ts
--     Applications:                -
--     Documentation:               NO
--     Non-free algorithms:         NO
--
--   Android NDK:                   /Users/injookim/Library/Android/sdk/ndk-bundle (ver 19.1.5304403)
--     Android ABI:                 armeabi-v7a
--     NDK toolchain:               arm-linux-androideabi-clang
--     STL type:                    c++_static
--     Native API level:            16
--   Android SDK:                   /Users/injookim/Library/Android/sdk (tools: 26.1.1 build tools: 28.0.3)
--
--   GUI:
--
--   Media I/O:
--     ZLib:                        /Users/injookim/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/arm-linux-androideabi/libz.a (ver 1.2.7)
--     JPEG:                        build-libjpeg-turbo (ver 1.5.3-62)
--     WEBP:                        build (ver encoder: 0x020e)
--     PNG:                         build (ver 1.6.35)
--     TIFF:                        build (ver 42 - 4.0.9)
--     JPEG 2000:                   build (ver 1.900.1)
--     OpenEXR:                     build (ver 1.7.1)
--     HDR:                         YES
--     SUNRASTER:                   YES
--     PXM:                         YES
--     PFM:                         YES
--
--   Video I/O:
--
--   Parallel framework:            pthreads
--
--   Trace:                         YES (built-in)
--
--   Other third-party libraries:
--     Custom HAL:                  YES (carotene (ver 0.0.1))
--     Protobuf:                    build (3.5.1)
--
--   Python (for build):            /usr/bin/python2.7
--
--   Java:                          export all functions
--     ant:                         NO
--     Java wrappers:               YES
--     Java tests:                  NO
--
--   Install to:                    /Users/injookim/Project/android_opencv/opencv
-- -----------------------------------------------------------------
--
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/injookim/Project/opencv-4.0.1/.build/Release_Android


4. 빌드(make or ninja)

 cmake가 완료되면, 아래와 같이 make -j4 명령을 수행해주면 빌드된다.

make -j4

make시에, 아래와 같은  error message가 나올 경우가 있는데, 이 경우에는 ANDROID_HOME 환경변수를 terminal 환경에 추가해줘야 된다. zsh는 .zshrc, bash이면 .bashrc

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':15-puzzle'.
> SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.
.zshrc
export ANDROID_HOME=/Users/injookim/Library/Android/sdk

cmake 옵션 중에, -GNinja 옵션을 추가해 주면,  아래와 같이 ninja를 사용할 수도 있다. 물론, 그전에 brew를 사용해 ninja를 설치해 주어야 한다.

ninja -j4

빌드 중에, Gradle 관련, error가 뜬다면, JDK  버전이 8인지 확인이 필요하다.
최종적으로 아래와 같은 메시지가 나오면 빌드가 완료된 것이다.

BUILD SUCCESSFUL in 18s
96 actionable tasks: 59 executed, 37 up-to-date
AAPT2 aapt2-3.2.1-4818971-osx Daemon #0: shutdown
AAPT2 aapt2-3.2.1-4818971-osx Daemon #1: shutdown
AAPT2 aapt2-3.2.1-4818971-osx Daemon #2: shutdown
VCS Checkout Cache (/Users/injookim/Project/opencv-4.0.1/.build/Release_Android/opencv_android/.gradle/vcsWorkingDirs) has not been cleaned up in 0 days
[100%] Built target android_sample_tutorial-2-mixedprocessing


5. Install

make install 해주면, 지정된 디렉토리에 lib.를 복사해 주고, libopencv_java4.so 파일이 생성되어 있는 것을 확인해 주면 된다.

make install


*
생성된 파일로 실제 안드로이드 머신에서 돌려 보지는 않아, 동작 확인이 된 건 아니다.
그리고, Java Wrapper가 꼭 필요한 지에 대한 의문도 있어서, Java Wrapper를 사용하지 않을 경우의 사용법도 구현해 볼 예정이다.
cmake 옵션 중에 아래 옵션을 OFF로 하게 되면, Java Wrapper가 돌아가지 않고, inlcude와  static lib. 만이 생성된다.

-DBUILD_ANDROID_PROJECTS=OFF


6. Reference



NDK에 빌드된 OpenCV를 연동해보는 것도 복잡하지는 않다. 스텝바이스텝으로 자세히 설명하는 블로그들이 많다. 여기에서는 전체 구조 정도만 다루어 보겠다.

1 MainActivity.java (Java) - main loop
  • Java로 작성된 main loop가 있고, 여기에서 C++ 관련된 내용은 해당 lib.를 load하는 방식으로 사용한다. NDK를 사용하면, 기본적으로 native-lib를 load한다. OpenCV를 사용하게 되면, opencv lib.도 같이 load해주면 된다.
  • main loop는 main(){} 함수 구조를 사용하지 않고, 이벤트 기반의 callback 구조를 사용한다. 해당 procedure에 맞게 code를 상속받아 작성해 넣어주면 된다. (아래 그림 참조)

2. native-lib.cpp(C++) - c++ code 작성

  • 위의 Java Main loop에서 call하는 함수를 implementation 해준다.
  • CMakelists.txt도 여기에서 작성하면서, 필요한 lib.를 불러와서 사용한다.

Java로는 기기 제어와 일반적인 진행 procedure를 작성하여, 카메라 영상 등 입력 소스를 제어한다. C++에서는 입력 소스를 처리하는 routine을 lib.화하여 만들어 두면, 이 함수를 Java에서 call해서 사용하는 구조로 사용 가능하다.

** 아래 그림과 같이 안드로이드 App이 동작하고, onCreate(), onStart()등의 함수에 적당한 초기화 내용을 넣어준다.
     실제 main loop는 while() 대신에 event callback을 사용하게 되는데, callback 함수에 연동된 함수에 앱 동작시 실행되는 내용을 넣어준다.

<안드로이드 App 동작 순서>




안드로이드 스튜디오 내에서 NDK를 이용하여 Hello World를 빌드해 보는 것도 간단하다.

가이드대로 클릭만 하면 된다.


그러나, SDK를 사용하는것과의 가장 큰 차이점은 경로 내에서 white space를 허용하지 않는다는 것이다.

SDK 설치 디렉토리와 Application 디렉토리에 white space가 포함된다면,

SDK를 이용해서 빌드할 경우에는 별 문제없이 빌드되었던게

NDK를 이용해서 빌드하게 되면 여러가지 error가 발생한다.


안드로이드 스튜디오를 설치하고, 안내를 따라가면, Hello World까지는 클릭으로 빌드 가능하다. 스마트폰에 다운로드해서 앱에서 Hello World를 보기 위해서는 하나의 벽이 있는데, 그게 '기기를 개발용으로 설정하기' 이다.


Run 명령 실행 후, 스마트폰 디바이스가 보이지 않아, Troubleshoot 가이드를 봤음에도, 이게 필수라는 느낌이 들지 않아 진행하지 않았는데, 필수이다. 스마트폰내 설정에서 빌드넘버를 7회 클릭하여 개발자 모드를 활성화시키고, 활성화된 개발자 모드 안에서 USB 디버깅을 활성화해야 스마트폰 디바이스가 안드로이드 스튜디오 내에서 보이게 된다. 단순히, PC 내에서 스마트폰 내 폴더가 접근 가능하니, 위 설정이 필요하다는 사실을 간과했다.





'android' 카테고리의 다른 글

Android Studio(NDK)에 안드로이드 용으로 빌드된 OpenCV 연동  (0) 2019.03.02
안드로이드 스튜디오 NDK 기본  (0) 2019.02.18
AR SDK와 한계  (0) 2019.01.14
AR에 대한 잡생각  (0) 2019.01.08
prologue  (0) 2018.12.29

사용할 만한 SDK를 검색해보니, 역시나 구글과 Apple이 이미 가지고 있었다.

 * 구글 - ARCore

 * 애플 - ARKit


이외에 wikitude라는 업체에서도 SDK를 제공해주는데, 이건 free는 아니고, 월정액제로 제공된다.

참고할 만한 사이트는 아래.


https://thinkmobiles.com/blog/best-ar-sdk-review/


다시, 필요한 기술 및 기술적 한계로 돌아가게 되면,


 * 3D Reconstruction - 현실 데이터를 활용해서 3D 지도 생성: 있는 기술이다. 단지, 정확도와 속도 문제가 있을뿐.

 * 3D지도와 각종 위치를 매칭(SLAM): 마찬가지로 있는 기술이다. 정확도와 속도 문제가 있다.

 * 가상물체의 모델링: 3D애니메이션에서 사용하는 것처럼 모션캡쳐 장비를 사용해서 모델링하면, 실사와 유사한 가상물체를 만들수 있다.


위 두가지가 SDK들이 제공해주는 기능일 것이고, 가상물체의 모델링도 기술의 문제라기 보다는 자본의 문제일 것이다. 여기까지가 현수준의 AR이 해볼 수 있는 것들인 것 같다. 현수준에서, 궁극의 AR로 다가가기 위해서는 아래와 같은 문제가 해결되어야 하고, 생각해 본바로는 이게 AR의 가장 큰 기술적 한계일 것 같다. 이 두가지가 없다면, 사용자는 쉽게 AR환경 내에서 가상 물체를 눈치챌 수 있고, 플레이시에 이에 따른 위화감을 가져가게 될 것이다

 

 * 현실의 환경이 가상 물체(virtual object)에게 주는 영향을 반영하기

 * 가상 물체(virtual object)가 현실의 환경에게 주는 영향을 반영하기


* 현실의 환경이 가상 물체(virtual object)에게 주는 영향을 반영하기

가상 물체가 현실의 환경을 얼마나 잘 반영하는가의 대표적인 사례로 occlusion 문제를 생각해 볼 수 있다. 현실과 가상이 잘 섞이려면, 3차원으로 바라볼때, 위화감없이 얼마나 실제 환경에 의해 잘 가려지고, 실제 환경을 잘 가리는지가 중요하다. 이에 더해 가상 물체가 이동할 경우에 원근법이나 중력같은 자연법칙을 얼마나 잘 모사할 수 있는가에 따라 현실에 잘 섞여들어갈 것이다. 이에 대한 해답은 3D 지도와 위치인식, 몇가지 물리 법칙들을 반영한 가상물체의 이동 기술이 얼마나 잘 만들어지는가에 달려있다. 중요한건 어디에 위치해 있는가이므로. 하지만, 이것만으로는 충분하지 않다.


   - 실제 환경에서 투명 물체와 반투명 물체가 있는 경우

   - 실제 환경이 정적이지 않고 동적인 경우

   - 실제 환경에서, 광원이 있을 경우


위 세가지 경우만 보더라도 해답을 찾는게 쉽지는 않을 것이다. 투명 물체와 반투명 물체를 반영하려면 실제 환경에서 각 물체의 속성까지 파악해내야 하는데, 이건 다른 차원의 문제로 넘어가 버린다. 또한, 사전에 모델링된 실제 환경에서, 가상 물체를 정합하는 문제와 동적으로 변하는 실제 환경에서, 가상 물체를 정합하는 건 또 다른 문제이다. 이는, 위에서 얘기했던, 3D Reconstruction 같은 기술이 실시간으로 동작해야 함을 뜻한다. 일몰이나 일출같은 실제 환경의 광원까지 반영해야 된다면?


* 가상 물체(virtual object)가 현실의 환경에게 주는 영향을 반영하기

가장 큰 한계일 것 같다. 여기까지 고려해야 한다면, 사용자의 공간을 완전히 통제할 수 있는 VR같은 경우가 오히려 쉬울 수도 있다. AR에서 가상 물체가 현실의 소파에 앉게 된다면, 현재의 기술로는 정확한 위치에 앉는 것까지는 해볼 수 있을 것이다. 하지만, 현실 소파의 특성과 가상 물체의 특성에 따라 현실 소파의 눌림까지 표현할 수 있을까. 게다가 실제 소파는 눌리지 않는다. 이를 반영하게 되면, 현실 소파와 AR 내에서의 소파의 괴리가 발생하게 된다. 이러한 괴리를 허용해야 할까. 허용하지 않게 된다면, 가상 물체가 아무리 실사와 비슷하게 보이더라도 사용자는 이질감을 느낄 것이다. 어려운 문제다.


일단, 가상 물체가 현실의 환경에 주는 영향은 배제해야 될것 같고, 구글의 SDK를 써보면서, 현수준의 느낌을 봐야겠다.

1. trend

ETRI에서 2017년에 만든 자료가 있어서 참조했다. 시장은 2016년에 10억달러에서 2020년 1200억달러 수준(IDC 예상)으로 커진다고 한다. 참고로 자율주행 관련된 Waymo나 UBER같은 회사가 1000억달러 수준의 시장가치가 있다고 평가받고 있다. 예전부터 연구되고 있었긴 하지만, 본격적으로 시장이 커지고 있는건 2015년 부터인것 같다. 대표적으로 아래와 같은 일들이 2015년에서 2016년사이에 벌어졌다.

      • Google과 Nintendo의 Niantic 투자(2천만달러 수준)
      • Apple의 metaio, FlyBy Media(M&A)
      • Intel의 Vuzix 투자(2400만달러 투자)
      • Qualcomm Ventures의 Blippar 투자(4500만달러 투자)
      • Starbreeze Studios의 ePawn(M&A 400만유로)
      • Horizon Ventures의 Meta 투자(2300만달러 투자)
      • The Hive의 Augmented Pixels 투자(100만달러 투자)  


2. device와 contents

중요한건 AR을 표현할 수 있는 device와 그 device에 표현될 contents이다. device는 크게 아래와 같이 3가지 정도로 나눠볼 수 있다.

      • AR의 현실 환경을 모델링 할 수 있는 카메라(2D, 3D, scanner)
      • AR 환경을 표현 할 수 있는 디스플레이
      • AR 환경 내에서 사용자의 움직임을 반영할 수 있는 입력장치

Microsoft의 Hololens 같은것이 카메라와 디스플레이를 HMD 스타일로 표현된 장치라고 볼 수 있다. 현재, 가격은 5천불 정도로 가격 저항이 있어 보인다. 구글에서 얼마전 나왔던, Google Glass 같은 것도 위 2가지의 역할을 하지만, 경량화된 만큼 배터리와 발열 문제를 해결하지 못해 단종되었다고 알고 있다. 드라마 알함브라나 영화 미션임파서블에서 나왔던, 스마트 렌즈가 위 device의 궁극적인 goal이라고 볼 수 있겠지만, 외계인이 만들지 않는 이상 물리적으로 불가능하고, 따로 제작한다면 현실적으로는 문제가 해결된 Google Glass 정도를 목표로 해야되지 않을까 한다.


아니면, 관점을 바꾸어 모바일폰을 활용하는 방법도 있다. 이미, 포켓몬고에서 사용한 방법이지만, 모바일폰에 사용된 2D 카메라의 한계로 실제 AR 성능은 재미 수준을 넘어서지는 못한다. 하지만, 모바일폰에 3D카메라가 달리기 시작하면 얘기는 달라질 수 있다. 아이폰X의 경우에도 전방 카메라이긴 하지만 face id를 위해서 3D 카메라가 장착되었고, 화웨이에서도 3D카메라가 후면에 달린다는 얘기가 들린다. TV의 경우에는 3D가 제 역할을 하지 못했지만, 정체된 모바일폰 시장의 경우에는 이를 한번정도 breakthrough 해볼 컨텐츠가 AR이지 않을까. 카메라 화소 경쟁에서 카메라 개수 경쟁으로, 마지막으로 3D카메라 quality 경쟁으로. 단, 3D 카메라로 만들어 낼 수 있는 컨텐츠가 갤럭시S9의 이모지콘? 수준이라면 곤란할 것이고, 정말 그럴듯한 AR quality가 나와줘야 할 것이다.


모바일폰에 3D카메라가 달리기 시작하면, 집내부같은 공간을 3D카메라로 모델링하여 3D 지도를 만들고, 여기에서 AR 맵핑을 시도해 볼 수 있다. 단순, 2D카메라를 사용한 AR보다는 훨씬 괜찮은 quality가 나올 것이다. 이를 나타내는 것은 모바일폰의 display를 그대로 써도 되고, google 식으로 모바일폰을 넣을 수 있는 맞춤형 박스를 하나 만들어서 VR 스타일로 나타나게 해볼 수도 있다.


게임 등 액티브한 활동을 위해서는 별도의 입력 장치가 필요하다. 기본적으로는 모바일폰의 디스플레이를 터치하면서 진행할 수도 있겠지만, 별도의 장치로 Bluetooth를 통해 통신하고, Play Station의 dual shock처럼 진동정도 추가해주면 괜찮을 것 같다. 음성인식과 제스쳐인식 기술이 발전해서 적용해보는 것도 괜찮아 보인다.


3. SDK

이런 생각을 남들도 이미 다했고, 좀 찾아보니 AR을 구현해 볼 수 있는 SDK도 많이 나와있다. Apple만 해도 arkit2가 있고, placenote, sturfee라는 것도 있고, intel도 있다. 결국 문제는 AR의 수준인 것 같다. 그런면에서, AR은 여전히 발전해 나갈 여지가 많다. 최종적으로는 드라마 알함브라처럼, 무엇이 현실이고, 무엇이 AR인지 알수없는 경지까지 가지 않을까. 그리고, 이를 위해서는 algorithm도 중요하지만, 3D 카메라의 성능도 중요하다.


4. 개발을 한다면 아래와 같은게 필요할 것 같다.

   이것들이 없는 건 아니고, 단지 정교하고 빠르며 여러케이스에 대응되는게 없을 뿐이다. 물론, 사람들이 바보라서 정교하고 빠른걸 못만든 것도 아니다.

    • 정교한 3d 카메라(indoor, outdoor)
    • 정교한 3d map reconstruction algorithm
    • 정교한 localization algorithm(3d 지도와 나의 위치를 맵핑)
    • 정교한 display(VR처럼 3d로 표현하려면)
    • 정교한 interaction 장치(음성인식, 제스쳐 인식, 혹은 입력 장치)


5. application

위와 같은게 엔진 수준으로 나와 준다면, 이를 활용한 application은 무궁무진할 것 같다. 이외로 1~2년 안에 쓸만한 엔진이 나올수도 있을것 같고, 그러면 AR 시장은 3가지로 나뉠 것 같다.

    • AR을 구현할 수 있는 장치 시장(유력해 보이는건 모바일폰에 센서추가): 대기업과의 경쟁
    • AR 구현 엔진: 기술적 장벽
    • 엔진을 활용한 2차 application 시장: 기회선점, 아이디어선점, 특허선점
    • - 대부분 2차 application 시장으로 갈텐데, 여기는 기술적 장벽보다는 아이디어와 자본으로 들어갈 수 있는 영역이라 치열할 것 같다.


6. plan

* 쓸만한 엔진을 만드는데 주력하다가

* 비어있는 application이 있다면 특허로 선점?. 조사해보지는 않았지만 여기도 이미 쓸만한건 대부분 선점되어 있을것 같긴 하다.


* 일단, 먼저 시중에 나와있는 SDK를 사용해보면서, 수준을 확인해봐야겠다. 필요하면 3D카메라도 구입해보고.










   


드라마 '알함브라의추억'을 보다보니, AR의 현재 trend와 수준이 궁금해져서 일들을 좀 진행시켜 보기로 했다. 기간은 6개월에서 1년정도로 예상한다. 아래 정도로 짬날때마다 진행해 볼려고 하는데, 언뜻 생각해보면, 이슈라고 할만한 것은 VR 기기 착용에 따른 어지러움, 착용자의 신체와 착용자가 바라보는 대상과의 위치를 추정하는 방법과 그 정확도일 것 같은데, 치명적인 한계가 없었으면 좋겠다.


 1. 현수준 확인

 2. 이슈, 한계 확인

 3. Open Source를 최대한 활용한 proto 제작


일단, 이정도로 해보면 재밌을것 같다.

 

+ Recent posts