OpenCV 와함께하는컴퓨터비전프로그래밍캠프 Appx. 안드로이드 OpenCV 프로그래밍 Last Update: 2018/06/07 Visual C++ 영상처리프로그래밍 저자 황선규 / 공학박사 sunkyoo.hwang@gmail.com
모바일컴퓨터비전프로그래밍 목차 Android 개요 Android 개발환경구축 Android Studio 설치 OpenCV Android SDK 설치 OpenCV Java API 사용방법 JNI를이용한 OpenCV 사용방법 2017 년 4 월 Android Studio 2.3.x & Android KitKat 기반으로최초작성된문서를 2018 년 6 월기준최신버전으로업데이트하면서예전그림이일부사용되었습니다. - 2 -
Android 개요 안드로이드 (Android) 구글 (Google) 에서개발하고배포하는모바일운영체제 리눅스기반 + Java UI 개발정보 개발자사이트 : https://developer.android.com/ ( 공식 ) 개발도구 : Android Studio 개발언어 : Java, C/C++, Go, Kotlin image from https://en.wikipedia.org/wiki/android_(operating_system) - 3 -
Android 개요 모바일 OS 점유율 https://www.statista.com/statistics/266136/global-market-share-held-by-smartphone-operating-systems/ - 4 -
Android 개요 안드로이드 OS 버전별점유율 (Apr. 2017) - 5 -
Android 개요 안드로이드 OS 버전별점유율 (Jun. 2018) - 6 -
Android Framework 앱개발자 Java 구글 JNI C/C++ 제조사 C/ASM - 7 -
Android Studio 설치 Android Studio 다운로드 설치파일다운로드 : https://developer.android.com/studio/ - 8 -
Android Studio 설치 Android Studio 설치 - 9 -
Android 개발환경구축 Android SDK 설치 Android Studio 첫화면하단 Configure 버튼을누르고, [SDK Manager] 선택 필요한 SDK Platform 설치확인 - 10 -
Android 개발환경구축 NDK(JNI) 빌드위한 SDK 툴설치 [SDK Tools] 탭에서 CMake, LLDB, NDK 추가설치 - 11 -
OpenCV Android SDK 설치 OpenCV Android SDK 다운로드 http://opencv.org/releases.html OpenCV-3.4.0-android-sdk.zip 다운로드 C:\opencv\ 폴더에압축해제 - 12 -
OpenCV Java API 사용하기 OcvTest1 프로젝트생성 Android Studio 시작화면에서 Start a new Android Studio project: 선택 ( 또는 [File] [New] [New Project ] 메뉴선택 ) Application name : OcvTest1 이후설정은디폴트값사용 ([Next] & [Next] & & [Finish]) 프로젝트위치는가급적한글또는공백이없는폴더로지정 - 13 -
OpenCV Java API 사용하기 OpenCV 3.4.0 모듈추가 [File] [New] [Import Module ] 메뉴선택 Source Directory 항목에서 C:\opencv\OpenCV-androidsdk\sdk\java 폴더선택 Module name 항목은자동으로 opencvlibrary340 입력됨 이후 [Next] [Finish] 버튼클릭 - 14 -
OpenCV Java API 사용하기 빌드설정파일수정 1 2 3 좌측상단탭을 [Android] 에서 [Project] 로변경 <Project>\OcvTest1\app\build.gradle 파일을참조하여 <Project>\OcvTest1\openCVLibrary340\build.gradle 파일을수정 (compilesdkversion, buildtoolsversion, minsdkversion, targetsdkversion 등의숫자값을동일하게수정 ) [Tools] [Android] [Sync Project with Gradle Files] 메뉴선택 1 3 2 copy - 15 -
OpenCV Java API 사용하기 모듈의존성설정 [File] [Project Structure ] 메뉴선택 2 3 1 4-16 -
OpenCV Java API 사용하기 모듈의존성설정 [File] [Project Structure ] 메뉴선택 (Con t) 5-17 -
OpenCV Java API 사용하기 OpenCV so 파일복사 <Project>\OcvTest1\app 아래에 JNI Folder 생성 Change Folder Location 선택하고 src/main/jnilibs/ 입력 - 18 -
OpenCV Java API 사용하기 OpenCV so 파일복사 (Con t) C:\opencv\OpenCV-android-sdk\sdk\native\libs 아래모든파일을복사하여 <Project>\OcvTest1\app\src\main\jniLibs\ 폴더에붙여넣기! 실제로는각하위폴더에서 *.so 파일만필요하며, *.a 파일은삭제해도무방함. - 19 -
OpenCV Java API 사용하기 activity_main.xml 파일편집 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.kkokkal.ocvtest1.mainactivity"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/imageview1" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="load Image" android:id="@+id/button1" android:onclick="onbutton1clicked" android:layout_alignparentbottom="true" /> </RelativeLayout> - 20 -
OpenCV Java API 사용하기 MainActivity.java 파일편집 loadlibrary("opencv_java3") - 21 -
public class MainActivity extends AppCompatActivity {... OpenCV Java API 사용하기 @Override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!haspermissions(permissions)) { requestpermissions(permissions, PERMISSIONS_REQUEST_CODE); imageview1 = findviewbyid(r.id.imageview1); @Override protected void ondestroy() { bitmap1.recycle(); bitmap1 = null; super.ondestroy(); public void onbutton1clicked(view view) { Intent intent = new Intent(Intent.ACTION_PICK); intent.settype(android.provider.mediastore.images.media.content_type); intent.setdata(android.provider.mediastore.images.media.external_content_uri); startactivityforresult(intent, REQ_CODE_SELECT_IMAGE); OpenCV와함께하는컴퓨터비전프로그래밍 - 22 -
@Override protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == REQ_CODE_SELECT_IMAGE) { OpenCV if (resultcode Java == Activity.RESULT_OK) API 사용하기 { try { String path = getimagepathfromuri(data.getdata()); BitmapFactory.Options options = new BitmapFactory.Options(); options.insamplesize = 4; bitmap1 = BitmapFactory.decodeFile(path, options); if (bitmap1!= null) { detectedge(); imageview1.setimagebitmap(bitmap1); catch (Exception e) { e.printstacktrace(); public String getimagepathfromuri(uri contenturi) { String[] proj = {MediaStore.Images.Media.DATA; Cursor cursor = getcontentresolver().query(contenturi, proj, null, null, null); if (cursor == null) { return contenturi.getpath(); else { int idx = cursor.getcolumnindexorthrow(mediastore.images.media.data); cursor.movetofirst(); String imgpath = cursor.getstring(idx); cursor.close(); return imgpath; OpenCV와함께하는컴퓨터비전프로그래밍 - 23 -
OpenCV Java API 사용하기 static final int PERMISSIONS_REQUEST_CODE = 1000; String[] PERMISSIONS = {"android.permission.read_external_storage"; private boolean haspermissions(string[] permissions) { int result; for (String perms : permissions){ result = ContextCompat.checkSelfPermission(this, perms); if (result == PackageManager.PERMISSION_DENIED){ return false; return true; public void detectedge() { Mat src = new Mat(); Utils.bitmapToMat(bitmap1, src); Mat edge = new Mat(); Imgproc.Canny(src, edge, 50, 150); Utils.matToBitmap(edge, bitmap1); OpenCV Java API 사용코드 src.release(); edge.release(); - 24 -
c:\opencv\opencv-android-sdk\sdk\java\src\org\opencv\android\utils.java OpenCV Java API 사용하기 OpenCV와함께하는컴퓨터비전프로그래밍 <opencv-src>\modules\java\generator\src\cpp\util.cpp - 25 -
OpenCV Java API 사용하기 AndroidManifest.xml 파일편집 - 26 -
OpenCV Java API 사용하기 gradle.properties 파일편집 android.usedeprecatedndk = true 문장추가한후, 우측상단의 Sync Now 클릭! - 27 -
OpenCV Java API 사용하기 실행결과 - 28 -
OpenCV Java API 사용하기 만약실행시아래와같은에러가발생한다면, <OcvTest1-src>\app\Build.gradle 파일에서 sourcesets 부분을수정 - 29 -
OpenCV Java API 사용하기 OpenCV Java API 도움말 http://docs.opencv.org/java/3.0.0/ - 30 -
JNI 를이용한 OpenCV 사용방법 OcvTest2 프로젝트생성 Android Studio 시작화면에서 Start a new Android Studio project: 선택 ( 또는 [File] [New] [New Project ] 메뉴선택 ) Application name : OcvTest2 Inlucde C++ Support 항목선택 이후설정은디폴트값사용 ([Next] & [Next] & & [Finish]) - 31 -
JNI 를이용한 OpenCV 사용방법 OpenCV 사용을위한기본설정하기 OcvTest1 프로젝트생성할때와마찬가지로 OcvTest2 프로젝트에서도 OpenCV 관련설정하기 (pp. 14 ~ 19 참고 ) OpenCV 3.4.0 모듈추가 빌드설정파일수정 모듈의존성설정 OpenCV so 파일복사 - 32 -
JNI 를이용한 OpenCV 사용방법 activity_main.xml 파일편집 - 33 -
JNI 를이용한 OpenCV 사용방법 MainActivity.java 파일편집 - 34 -
@Override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!haspermissions(permissions)) { requestpermissions(permissions, PERMISSIONS_REQUEST_CODE); mjavacameraview = (JavaCameraView) findviewbyid(r.id.java_camera_view); if (mjavacameraview!= null) { mjavacameraview.setvisibility(surfaceview.visible); mjavacameraview.setcvcameraviewlistener(this); else { Log.e(TAG, "oncreate: mjavacameraview is null!"); @Override public void oncameraviewstarted(int width, int height) { Log.d(TAG, "oncameraviewstarted: width = " + width + ", height = " + height); mrgba = new Mat(); @Override public void oncameraviewstopped() { Log.d(TAG, "oncameraviewstopped:"); mrgba.release(); - 35 -
@Override public Mat oncameraframe(camerabridgeviewbase.cvcameraviewframe inputframe) { mrgba = inputframe.rgba(); nativedetectanddisplay(mrgba.getnativeobjaddr()); return mrgba; @Override protected void ondestroy() { super.ondestroy(); if (mjavacameraview!= null) mjavacameraview.disableview(); @Override protected void onpause() { super.onpause(); if (mjavacameraview!= null) mjavacameraview.disableview(); @Override protected void onresume() { super.onresume(); mjavacameraview.enableview(); - 36 -
static final int PERMISSIONS_REQUEST_CODE = 1000; String[] PERMISSIONS = {"android.permission.read_external_storage", "android.permission.camera"; private boolean haspermissions(string[] permissions) { int result; for (String perms : permissions){ result = ContextCompat.checkSelfPermission(this, perms); if (result == PackageManager.PERMISSION_DENIED){ return false; return true; /** * A native method that is implemented by the 'native-lib' native library, * which is packaged with this application. */ public native String stringfromjni(); public native void nativedetectanddisplay(long addrmat); - 37 -
JNI 를이용한 OpenCV 사용방법 native-lib.cpp 파일편집 - 38 -
void Java_com_example_sunkyoo_ocvtest2_MainActivity_nativeDetectAndDisplay( JNIEnv *env, jobject, jlong addrmat) { if (cascade.empty()) { cascade.load("/sdcard/haarcascade_frontalface.xml ); if (cascade.empty()) { return; Mat &src = *(Mat *) addrmat; Mat gray, gray2; cvtcolor(src, gray, COLOR_BGRA2GRAY); resize(gray, gray2, Size(640, 360)); // Screen Size: 1920x1080 vector<rect> faces; cascade.detectmultiscale(gray2, faces, 1.2, 3, 0, Size(40, 40)); for (size_t i = 0; i < faces.size(); i++) { Rect rc = faces[i]; rc.x *= 3; rc.y *= 3; rc.width *= 3; rc.height *= 3; rectangle(src, rc, Scalar(255, 0, 255), 2); - 39 -
JNI 를이용한 OpenCV 사용방법 CMakeLists.txt 파일편집 - 40 -
JNI 를이용한 OpenCV 사용방법 <OcvTest2-src>\app\Build.gradle 파일에서빌드방법수정 최신 android studio 의 NDK 에서 libc++ 을사용하기때문에발생한문제! (See https://stackoverflow.com/a/50320876) - 41 -
JNI 를이용한 OpenCV 사용방법 AndroidManifest.xml 파일편집 - 42 -
JNI 를이용한 OpenCV 사용방법 style.xml 파일편집 - 43 -
JNI 를이용한 OpenCV 사용방법 얼굴검출을위한 XML 파일을안드로이드폰에복사 c:\opencv\build\install\etc\haarcascades\ 폴더에있는 haarcascade_frontalface_default.xml 파일을안드로이드기기 sdcard 최상위폴더에복사 - 44 -
JNI 를이용한 OpenCV 사용방법 - 45 -
break - 46 -