반응형


ndk-build를 사용하여 안드로이드 프로젝트에 OpenCV 라이브러리를 추가하는 과정 및 OpenCV를 사용하여 카메라 영상을 그레이스케일로 변경하는 방법을 설명합니다.



테스트 환경은 다음과 같습니다. 


  • Windows 10

  • OpenCV 4.3.0

  • Android Studio 4.0

  • Android 10 (API 30)

  • NDK 21




다음 순서로 설명합니다. 




1. 안드로이드 프로젝트 생성


2. 프로젝트에 OpenCV 라이브러리 추가


3. ndk-build 사용한 NDK + OpenCV 카메라 예제


4. 참고





최초작성 2006. 5. 7

~~~~~~~~~~~~~~~

2020. 2. 16 OpenCV 4.2.0, Android 10.0 

2020. 6. 27 Android Studio 4.0, OpenCV 4.3.0, Android 10.0




1. 안드로이드 프로젝트 생성


1-1. Empty Activity를 선택합니다. 





1-2. Name 항목에 프로젝트 이름을 적고, Language는 Java,  Minimum API level은 API 21을 선택합니다.





2. 프로젝트에 OpenCV 라이브러리 추가

2-1. OpenCV를 위한 깃허브에서 opencv-4.3.0-android-sdk.zip 파일을 다운로드 합니다. 

https://github.com/opencv/opencv/releases 




압축을 풀어서 C:\에 복사해줍니다. 




2-2.  Android용 OpenCV가 다음 위치에 있는 것으로 가정하고 진행합니다.

C:\OpenCV-android-sdk





2-3. 앞에서 진행한 프로젝트 생성이 완료되기를 대기합니다. 안드로이드 스튜디오의 상태 표시줄에 작업중 메시지가 사라져야 합니다. 


OpenCV 라이브러리 모듈을 프로젝트로 가져오기 위해 메뉴에서 File > New > Import Module를 선택합니다. 


Source directory 입력란 옆에 있는 버튼을 클릭합니다.




OpenCV-android-sdk 디렉토리 하위에 있는 sdk 디렉토리를 선택하고 OK 버튼을 클릭합니다. 





Finish 버튼을 클릭한 후 sync가 끝나길 대기합니다.





2-4. app 모듈에서 opencv 라이브러리 모듈을 사용하도록 설정해줘야 합니다.

메뉴에서 File > Project structure를 선택한 후,  왼쪽에 보이는 리스트에서 Dependencies를 선택합니다. 





Modules에서  app을 선택한 후, Declared Dependencies에 보이는 +를 클릭하면 보이는 메뉴에서 Module Dependency를 선택합니다. 





앞에서 추가했던 opencv 모듈이 sdk 이름으로 보입니다. 체크한 후  OK버튼을 클릭합니다.





이제 sdk 모듈(opencv) app 모듈에서 사용할 수 있게 설정되었습니다. 

이제 OK 버튼을 클릭하여 Project Structure 창을 닫습니다.





2-5.  문제없이 sdk 모듈(opencv)이 추가되었다면 다음처럼 보입니다. 





3. ndk-build 사용한 NDK + OpenCV 카메라 예제

3-1.  안드로이드 스튜디오에서 ndk-build를 사용하여 C/C++ 코드를 컴파일 및 디버그하기 위해서는 다음 패키지가 필요합니다.


  • The Android Native Development Kit (NDK)

안드로이드에서 JAVA 코드와 C/C++ 코드를 같이 사용할 수 있게 해줍니다.



안드로이드 스튜디오 메뉴에서 Tools > SDK Manager를 선택합니다.



SDK Tools 탭에서  NDK를 선택하고 Apply 버튼을 클릭하면 다운로드 및 설치가 진행됩니다.

포스트 진행 과정에서 추가로 다른 버전의 NDK가 설치될 수 있습니다. 





3-2. AppCompatActivity 클래스를 사용한 액티비티에서 타이틀바를 없애기 위해서 styles.xml 파일에 다음 코드(노란색)를 추가합니다.



<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <!-- No Title Bar-->
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

</resources>




3-3. 레이아웃 파일 activity_main.xml 을 다음 코드로 대체합니다.



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >
   
    <org.opencv.android.JavaCameraView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/activity_surface_view" />

</LinearLayout>




3-4. 매니페스트 파일 AndroidManifest.xml 에  다음 코드(노란색)를 추가합니다. 



<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.tistory.webnautes.useopencvwithndk_build">


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

    <uses-feature android:name="android.hardware.camera" android:required="false"/>

    <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>

    <uses-feature android:name="android.hardware.camera.front" android:required="false"/>

    <uses-feature android:name="android.hardware.camera.front.autofocus"  android:required="false"/>


    <supports-screens android:resizeable="true"

        android:smallScreens="true"

        android:normalScreens="true"

        android:largeScreens="true"

        android:anyDensity="true" />

    

    <application

        android:allowBackup="true"

        android:icon="@mipmap/ic_launcher"

        android:label="@string/app_name"

        android:roundIcon="@mipmap/ic_launcher_round"

        android:supportsRtl="true"

        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity"

            android:screenOrientation="landscape"

            android:configChanges="keyboardHidden|orientation">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />


                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>


</manifest>



앱에서 안드로이드 디바이스의 카메라에 접근하기 위해서는 필요한  퍼미션 입니다.


<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front.autofocus"  android:required="false"/>



android:screenOrientation 속성을 landscape로 해주어야 OpenCV JAVA API를 사용하여  전체화면에  카메라 영상을 보여 줄 수 있습니다.


android:screenOrientation="landscape"




3-5. 카메라로부터 영상을 가져오는 것은 JAVA 코드에서 하며 JNI(Java Native Interface)를 사용하여 C/C++ 함수를 호출하여 영상처리를 진행합니다. 


자바코드 파일 MainActivity.java를 다음 코드로 대체합니다.

첫번째 줄에 있는 package는 남겨둬야 합니다. 



import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.DialogInterface;
import android.os.Bundle;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
import android.view.SurfaceView;
import android.view.WindowManager;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;

import java.util.Collections;
import java.util.List;

import static android.Manifest.permission.CAMERA;


public class MainActivity extends AppCompatActivity
        implements CameraBridgeViewBase.CvCameraViewListener2 {

    private static final String TAG = "opencv";
    private Mat matInput;
    private Mat matResult;

    private CameraBridgeViewBase mOpenCvCameraView;

    public native void ConvertRGBtoGray(long matAddrInput, long matAddrResult);


    static {
        System.loadLibrary("opencv_java4");
        System.loadLibrary("native-lib");
    }



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


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

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.activity_main);

        mOpenCvCameraView = (CameraBridgeViewBase)findViewById(R.id.activity_surface_view);
        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
        mOpenCvCameraView.setCvCameraViewListener(this);
        mOpenCvCameraView.setCameraIndex(0); // front-camera(1),  back-camera(0)
    }

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

    @Override
    public void onResume()
    {
        super.onResume();

        if (!OpenCVLoader.initDebug()) {
            Log.d(TAG, "onResume :: Internal OpenCV library not found.");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_2_0, this, mLoaderCallback);
        } else {
            Log.d(TAG, "onResum :: OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }
    }


    public void onDestroy() {
        super.onDestroy();

        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public void onCameraViewStarted(int width, int height) {

    }

    @Override
    public void onCameraViewStopped() {

    }

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

        matInput = inputFrame.rgba();

        if ( matResult == null )

            matResult = new Mat(matInput.rows(), matInput.cols(), matInput.type());

        ConvertRGBtoGray(matInput.getNativeObjAddr(), matResult.getNativeObjAddr());

        return matResult;
    }


    protected List<? extends CameraBridgeViewBase> getCameraViewList() {
        return Collections.singletonList(mOpenCvCameraView);
    }


    //여기서부턴 퍼미션 관련 메소드
    private static final int CAMERA_PERMISSION_REQUEST_CODE = 200;


    protected void onCameraPermissionGranted() {
        List<? extends CameraBridgeViewBase> cameraViews = getCameraViewList();
        if (cameraViews == null) {
            return;
        }
        for (CameraBridgeViewBase cameraBridgeViewBase: cameraViews) {
            if (cameraBridgeViewBase != null) {
                cameraBridgeViewBase.setCameraPermissionGranted();
            }
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        boolean havePermission = true;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(CAMERA) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
                havePermission = false;
            }
        }
        if (havePermission) {
            onCameraPermissionGranted();
        }
    }

    @Override
    @TargetApi(Build.VERSION_CODES.M)
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == CAMERA_PERMISSION_REQUEST_CODE && grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            onCameraPermissionGranted();
        }else{
            showDialogForPermission("앱을 실행하려면 퍼미션을 허가하셔야합니다.");
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }


    @TargetApi(Build.VERSION_CODES.M)
    private void showDialogForPermission(String msg) {

        AlertDialog.Builder builder = new AlertDialog.Builder( MainActivity.this);
        builder.setTitle("알림");
        builder.setMessage(msg);
        builder.setCancelable(false);
        builder.setPositiveButton("예", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id){
                requestPermissions(new String[]{CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
            }
        });
        builder.setNegativeButton("아니오", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface arg0, int arg1) {
                finish();
            }
        });
        builder.create().show();
    }


}




3-6.  javah를 사용하여 자바 코드에서 선언한 네이티브 메소드에 대응하는 C/C++ 함수가 선언되어 있는 헤더 파일을 jni 디렉토리에 자동으로 생성합니다.



우선 javah를 실행하기 편하게 안드로이드 스튜디오의 외부 도구로 등록합니다. 메뉴에서 File > Settings를 선택합니다.

Settings 창의 왼쪽 목록에서 Tools > External Tools를 선택하고  + 아이콘을 클릭합니다.





아래처럼  각 항목의 내용을 채웁니다.

Advanced Options를 클릭해야 모든 항목이 보입니다.


◼ Name

javah


◼ Description

Android Tool - javah


◼ Advanced Options를 클릭하고 다음 두 항목을 체크

Make console active on message in stdout

Make console active on message in stderr


◼ Program  

Android Studio에서 번들로 제공되는 OpenJDK를 사용하면 program에 다음처럼 입력합니다.

C:\Program Files\Android\Android Studio\jre\bin\javah.exe


Oracle의 JDK를 사용한다면 program에 다음처럼 입력합니다. 사용하는 jdk 버전에 따라 디렉토리 위치가 다를 수 있습니다. 

C:\Program Files\Java\jdk1.8.0_131\bin\javah.exe


◼ Arguments :

-v -jni -d $ProjectFileDir$/app/src/main/jni $FileClass$


◼ Working directory:

$SourcepathEntry$



다 입력하고나서 OK를 클릭하여 설정을 저장합니다. 





External Tools에 javah가 추가되었습니다.





 MainActivity를 선택하고 마우스 우클릭 후 보이는 메뉴에서 External Tools >  javah를 선택합니다.




문제 없이 진행되면 다음과 같은 메시지가  출력됩니다.


"C:\Program Files\Android\Android Studio\jre\bin\javah.exe" -v -jni -d C:\Users\webnautes\AndroidStudioProjects\UseOpenCVwithndkbuild/app/src/main/jni com.tistory.webnautes.useopencvwithndk_build.MainActivity

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

Error: unmappable character for encoding MS949

[Creating file RegularFileObject[C:\Users\webnautes\AndroidStudioProjects\UseOpenCVwithndkbuild\app\src\main\jni\com_tistory_webnautes_useopencvwithndk_build_MainActivity.h]]



코드에 한글이 포함된 경우 다음과 같은 메시지가 여러줄 같이 출력되는데 결과를 얻는데 상관없으므로 무시하셔도 됩니다.


Error: unmappable character for encoding MS949




app / src / main 디렉토리 아래에 jni 디렉토리가 생성되고 그 안에 패키지 이름이 포함된 헤더 파일(여기엔선 com_tistory_webnautes_useopencvwithndk_build_MainActivity.h)이 생성됩니다.

현재 android 뷰이기 때문에 app / cpp 디렉토리에 위치한 것처럼 보입니다. 


자바 코드의 패키지 이름(com.tistory.webnautes.useopencvwithndk_build)과  액티비티 이름(MainActivity)의 조합으로 헤더 파일의 이름이 결정됩니다. 






3-7. 자바에서 선언한 네이티브 메소드를 위한 C/C++ 구현을 cpp / main.cpp 파일에 작성합니다.

main.cpp는 공유 라이브러리 파일로 컴파일 되어 자바 코드에서 로드되어 사용됩니다. 


 cpp 디렉토리를 선택한 후, 마우스 우클릭하여 메뉴에서 New > File을 선택합니다.

 


 


새로 생성할 파일 이름으로  main.cpp를 적고 OK를 클릭합니다.




cpp에 main.cpp 파일이 생성됩니다. 



 

 

main.cpp  파일에 다음 헤더파일 2개를 추가합니다.

두 번째 헤더파일은 앞에서 생성한 헤더파일 이름을 적어줍니다.

 

#include <jni.h>
#include "com_tistory_webnautes_useopencvwithndk_build_MainActivity.h"



두번째 헤더파일을 열어보면  JAVA에서 선언한 네이티브 메소드에 대응하는 JNI 함수가 다음 처럼  정의되어 있습니다.


/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_tistory_webnautes_useopencvwithndk_build_MainActivity */

#ifndef _Included_com_tistory_webnautes_useopencvwithndk_build_MainActivity
#define _Included_com_tistory_webnautes_useopencvwithndk_build_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
#undef com_tistory_webnautes_useopencvwithndk_build_MainActivity_PERMISSIONS_REQUEST_CODE
#define com_tistory_webnautes_useopencvwithndk_build_MainActivity_PERMISSIONS_REQUEST_CODE 1000L
/*
* Class:     com_tistory_webnautes_useopencvwithndk_build_MainActivity
* Method:    ConvertRGBtoGray
* Signature: (JJ)V
*/
JNIEXPORT void JNICALL Java_com_tistory_webnautes_useopencvwithndk_1build_MainActivity_ConvertRGBtoGray
  (JNIEnv *, jobject, jlong, jlong);

#ifdef __cplusplus
}
#endif
#endif


 

생성된 JNI 함수를 main.cpp 파일에 복사해오고(파란색 부분) 추가로 필요한 코드를( 노란 부분) 추가합니다.

 

#include <jni.h>
#include "com_tistory_webnautes_useopencvwithndk_build_MainActivity.h"

#include <opencv2/opencv.hpp>


using namespace cv;



extern "C"{

    JNIEXPORT void JNICALL
  Java_com_tistory_webnautes_useopencvwithndk_1build_MainActivity_ConvertRGBtoGray(
            JNIEnv *env,
            jobject  instance,
            jlong matAddrInput,
            jlong matAddrResult){


        Mat &matInput = *(Mat *)matAddrInput;
        Mat &matResult = *(Mat *)matAddrResult;

        cvtColor(matInput, matResult, COLOR_RGBA2GRAY);


      }
}




3-8.  ndk-build를 사용하여 공유 라이브러리(.so)를 빌드하기 위해서는 Android.mk 파일과 Application.mk 파일을 작성해줘야 합니다. 

  


 cpp 디렉토리를 선택한 후, 마우스 우클릭하여 메뉴에서 New > File을 선택합니다.

새로 생성할 파일 이름으로 Android.mk를 적고 OK를 클릭합니다.




Text가 선택된 상태에서 OK를 클릭합니다. 


 


cpp 에 Android.mk 파일이 생성됩니다.




Android.mk 파일에 다음 내용을 추가합니다.


공유 라이브러리를 생성할 경우에는 사용되는 외부 라이브러리 정보와 직접 작성한 C/C++ 소스코드 관련 정보를 입력합니다.


machine-woong님이 지적해주셨습니다. 진행하실때  OPENCVROOT에서 노란색 경로가 현재 진행중인 프로젝트의 경로인지 확인하세요.


OpenCV 모듈이  프로젝트 폴더 내의 sdk 폴더에 존재합니다. 


LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

#opencv library
OPENCVROOT:= C:\Users\webnautes\AndroidStudioProjects\UseOpenCVwithndkbuild\sdk

OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include ${OPENCVROOT}\native\jni\OpenCV.mk


LOCAL_MODULE    := native-lib
LOCAL_SRC_FILES := main.cpp
LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)




 cpp 디렉토리를 선택한 후, 마우스 우클릭하여 메뉴에서 New > File을 선택합니다.

새로 생성할 파일 이름으로 Application.mk를 적고 OK를 클릭합니다.





cpp 에 Application.mk 파일이 생성됩니다.




 

Application.mk 파일에 다음 내용을 추가합니다. 컴파일시 사용되는 여러 변수들을 정의합니다. 

현재는 API 30을 사용하므로 APP_PLATFORM으로 android-30을 사용합니다.


APP_OPTIM := debug
APP_ABI := arm64-v8a armeabi-v7a x86 x86_64

APP_PLATFORM := android-30

APP_STL := c++_static
APP_CPPFLAGS := -frtti -fexceptions
NDK_TOOLCHAIN_VERSION := clang

APP_BUILD_SCRIPT := Android.mk



APP_ABI에는 프로젝트창 다음 위치에 있는 4개의 ABI를 적습니다. 

대부분의 경우 arm64-v8a를 사용할 겁니다. 





3-9. app 모듈의 build.gradle ndk-build를 사용하여 C/C++ 빌드가 이루어지기 위해 필요한 내용을 추가해줍니다. (노란색 줄)



apply plugin: 'com.android.application'


android {

    compileSdkVersion 30

    buildToolsVersion "30.0.0"


    defaultConfig {

        applicationId "com.tistory.webnautes.useopencvwithndk_build"

        minSdkVersion 21

        targetSdkVersion 30

        versionCode 1

        versionName "1.0"


        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

    }


    buildTypes {

        release {

            minifyEnabled false

            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

        }

    }


    externalNativeBuild {

        ndkBuild {

            path 'src/main/jni/Android.mk'

        }

    }

}




3-10. Sync Now를 클릭하거나 메뉴에서 File > Sync Project with Gradle Files를 선택하여 Gradle build를 시작합니다.




문제 없으면 왼쪽 아래에 다음과 같은  메시지가 보입니다.





빌드 후, 안드로이드 폰에 설치하여 실행시켜 보면  안드로이드폰의 방향에 따라  카메라 영상도 같이 회전합니다.  






4. 참고

Android Studio에서 안드로이드 프로젝트 생성시  Include C++ Support 체크박스를 설정한 경우 생성되는 소스 코드


https://developer.android.com/ndk/guides/index.html


https://developer.android.com/studio/projects/add-native-code.html


https://github.com/googlesamples/android-ndk


http://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html


http://docs.opencv.org/2.4/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.html




반응형

포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

여러분의 응원으로 좋은 컨텐츠가 만들어집니다.
지금 본 내용이 도움이 되었다면 유튜브 구독 부탁드립니다. 감사합니다 : )

유튜브 구독하기


제가 쓴 책도 한번 검토해보세요.

  1. 이전 댓글 더보기
  2. TomKong 2020.01.08 23:10

    드디어 성공했습니다! 감사합니다!

  3. ㅇㅇ 2020.03.02 03:41

    성공했습니다! 감사합니다.
    한가지 궁금한 점이 있는데요, 안드로이드 폰에서 실행했을 때, 휴대폰을 움직이면 조금 끊기는 감이 있습니다. 왜 이런걸까요? 다른 카메라 어플들은 흑백 화면 필터 넣어도 빠르게 나왔습니다.
    기종은 갤럭시 노트9 입니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.03.02 10:46 신고

      OpenCV 자바용 API에서 발생하는 현상 같습니다. 해결할수 있을지는 알수없네요

  4. MCP 2020.03.11 15:31

    대부분의 과정은 성공했는데 마지막 gradle sync에서 오류가 발생합니다.
    Gradle sync failed: executing external native build for ndkBuild
    NDK Resolution Outcome: Project settings: Gradle model version=5.4.1, NDK version is UNKNOWN
    NDK 경로는 C:\\Users\\홍길동\\AppData\\Local\Android\\Sdk\\ndk\\21.0.6113669 이렇게 설정했는데요 무엇이 문제일까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.03.11 15:35 신고

      안드로이드 SDK 경로에 한글이름이 포함되어있어 문제가 된듯 보입니다.

  5. MCP 2020.03.11 15:47

    앗 홍길동은 제가 임의로 수정한것이구요 영문으로 되어있어요

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.03.11 17:36 신고

      찾아보니 안드로이드 스튜디오를 최신버전으로 업데이트해서 해결한분이 있네요. 혹시 모르니 ndk도 업데이트해보세요

  6. MCP 2020.03.11 18:03

    흠...여기 말고 webnautes님의 다른 게시물에 있는대로 했더니 잘 되네요;;;

  7. Favicon of https://coding-tear.tistory.com BlogIcon 코딩의 눈물 2020.03.14 19:37 신고

    안녕하세요 개발자님 전자공학부 졸업을 앞둔 학부생입니다. 다름이 아니고 android studio, opencv, barcode reader 가 같이 움직일 수 있는지 궁금합니다!

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.03.15 00:04 신고

      안드로이드에 OpenCV를 같이 사용하는 것은 본 포스팅을 참고하시면 되고요..

      바코드 리더는 안드로이드용으로 구현된 라이브러리를 찾아보시면 될듯합니다.

  8. 옹삼 2020.03.18 02:33

    전부 설치가 되어서.. 안드로이드 스튜디오도 이상이 없다고 뜨는데
    핸드폰에 설치된 어플을 눌러보니 예상치못해 중지되었다고 계속 뜨네요;;
    어디서 문제인지 잘 모르겠습니다 ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.03.18 07:08 신고

      로그캣에서 에러 메시지를 찾아보세요

    • Ares 2020.06.23 23:22

      저도 동일한 문제가 생기는데 혹시 해결방법은 찾으셨나요? 어렵네요

  9. save77 2020.04.02 17:30

    항상 여기랑 유투브 강좌로 이것저것 도움만 받다 저도 도움이 될까 글 남깁니다.
    위에 사항대로 했을때 저는
    1. ABIs [arm64-v8a,armeabi-v7a,armeabi] set by 'android.injected.build.abi' gradle flag contained 'ARMEABI' not targeted by this project.
    2. java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
    3. Gradle sync failed: executing external native build for ndkBuild

    이런 세가지 에러때문에 진행이 안돼었는데 구글링으로 몇가지 에러 해결법을 찾고 추가하니 정상적으로 동작돼더라구요.
    >> build.gradle 에 ndk 버전과 armeabi를 제외하는 코드를 추가
    splits {
    abi {
    enable true
    reset()
    include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
    universalApk true //generate an additional APK that contains all the ABIs
    }
    }

    project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]

    android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
    output.versionCodeOverride =
    project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
    }
    }

    ndkVersion "21.0.6113669"

    >> Application.mk 에 static 부분을 shared로 수정하고 모든 문제가 해결되었습니다.
    APP_STL := c++_shared

  10. 2020.05.08 23:49

    안녕하세요! 카메라 예제 잘 따라해서 진행하고 있습니다.
    그런데 제가 카메라를 찍고, 이걸 비트맵으로 해서 다른 액티비티에 넘겨주고 카메라가 실행되던 액티비티는 실행을
    종료시키고 싶은데 카메라를 찍는 법을 모르겠습니다...
    카메라 캡쳐하는 방법이나 함수 등이 있을까요?
    카메라에서 이미지를 받아 같은 액티비티에서 띄우면 들어가긴 하는데 다른 액티비티로 넘어가는 인텐트 코드를 만들면 그냥 종료되버리네요..

    도움 부탁드립니다!

  11. minee 2020.05.11 10:50

    포스팅 잘 봤습니다.
    opencv카메라 캡쳐하는 방법 알 수 있을까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.11 10:55 신고

      opencv에서 어떤 카메라를 사용하는 경우인가요? 안드로이드에서 하려는 건가요?

    • minee 2020.05.11 11:16

      네 맞습니다. 안드로이드에서 하고싶습니다. 예제처럼 카메라 작동은 잘 됩니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.11 12:27 신고

      이 포스트에 있는 코드가 OpenCV의 API를 사용하여 카메라를 캡처하는건데 어떤걸 하고싶은 건가요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.11 12:28 신고

      카메라 영상을 파일로 저장하는걸 하려는 건가요?

    • minee 2020.05.11 16:25

      openCV 카메라 화면에 버튼을 하나 놓고, 그 버튼을 누르면 그 때의 화면을 저장하고 싶습니다. 따로 이미지 캡처가 되는 기능은 API에 따로 없는지 궁금합니다.

      답변 계속 감사합니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.11 21:11 신고

      다음 포스트의 "3. 캡쳐 버튼 추가하기"를 참고하세요

      https://webnautes.tistory.com/1087

  12. lee 2020.05.18 09:01

    오류는 없이 카메라가 까맣게 안나오는 증상 혹시 왜그런지 아시나요..??

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.18 09:05 신고

      혹시 로그캣에 관련 에러가 없나 확인해보세요

    • lee 2020.05.18 09:29

      E/OpenCV/StaticHelper: OpenCV error: Cannot load info library for OpenCV

      로그캣에 찍히는 오류는 이거뿐인데 이거 때문일까요..??

    • lee 2020.05.18 10:32

      해결 했습니다..ㅎ 간단한 실수였네요!

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.05.18 20:10 신고

      다행입니다.

  13. 만두 2020.06.10 02:50

    오류는 없으나 프로젝트 창에서 opencv 모듈이 나타나지 않습니다...ㅜㅜ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.10 06:04 신고

      프로젝트를 android 뷰에서 project뷰로 바꿔보세요

    • 만두 2020.06.10 10:58

      앗..찾았네요 감사합니다!!

    • 만두 2020.06.10 17:10

      Caused by: org.gradle.api.IllegalDependencyNotation: Supplied String module notation 'androidx.test.esp' is invalid. Example notations: 'org.gradle:gradle-core:2.2', 'org.mockito:mockito-core:1.9.5:javadoc'.

      똑같이 따라했는데 혹시 이 오류는 뭔지 아시나요..?? opencv가 처음입니다..

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.10 20:08 신고

      찾아서 다행입니다.

      androidx.test.esp 뒤에 보통 버전이 붙는데 없어서 문제가 생긴겁니다.


      아래 처럼요
      org.gradle:gradle-core:2.2

  14. 안스 2020.06.13 10:29

    (자바 코드의 패키지 이름(com.tistory.webnautes.useopencvwithndk_build)과 액티비티 이름(MainActivity)의 조합으로 헤더 파일의 이름이 결정됩니다. )

    project 뷰로 app/src/main/jni 폴더가 안생깁니다..

    external tools - javah 연결해줘도 없어요..

    저는 안스 4.0 버전이에요..

  15. 물만두 2020.06.23 13:21

    안녕하세요! 매번 친절히 답변 달아주셔서 감사합니다
    몇주째 시도해보는 중인데 왜 안되는걸까요...ㅠㅠ

    Unable to load class 'org.jetbrains.kotlin.annotation.plugin.ide.AnnotationBasedPluginModelBuilderService'.
    Possible causes for this unexpected error include:
    Gradle's dependency cache may be corrupt (this sometimes occurs after a network connection timeout.)
    Re-download dependencies and sync project (requires network)

    The state of a Gradle build process (daemon) may be corrupt. Stopping all Gradle daemons may solve this problem.
    Stop Gradle build processes (requires restart)

    Your project may be using a third-party plugin which is not compatible with the other plugins in the project or the version of Gradle requested by the project.

    In the case of corrupt Gradle processes, you can also try closing the IDE and then killing all Java processes.

    이런오류가 뜹니다

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.23 20:05 신고

      안드로이드 스튜디오를 삭제한 후.. 재설치해서 해결했다는 사람이 있네요. 새로 설치후. 기존에 설치되었던 설정을 로드하면 안된다네요 아래가 원본글 입니다.

      https://stackoverflow.com/questions/62392719/unable-to-load-class-org-jetbrains-kotlin-annotation-plugin-ide-annotationbased

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.27 12:22 신고

      다시 따라 해보시면 될겁니다. 이제서야 진행해보았네요

  16. mys 2020.06.23 22:08

    not configured. Download it with SDK manager. Preferred NDK version is '20.0.5594570'. Log: C:\Users\사용자이름\AndroidStudioProjects\test\opencv\.cxx\ndk_locator_record.json
    import module에서 finish누르고 싱크과정에서 위와 같은 에러가 뜹니다 ㅠ 왜 이럴까요?
    SDK매니저에서 체크할건 다 체크했는데

    해결했습니다
    프로젝트스트럭쳐 들어가서
    ndk 폴더 위치를 잡아주니까 되네요
    ndk폴더위치가 자동으로 안잡혀있었네요

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.06.27 12:22 신고

      이제서야 다시 진행해보았습니다. 이젠 잘 될겁니다.

  17. jyshin 2020.07.24 16:27

    Gradle sync fail이 되네요.. 하기에 작성한 Android.mk가 없다고 하는데..

    Gradle project ndkBuild.path is C:\Users\j.y.shin\AndroidStudioProjects\UniTILE\app\src\main\jni\Android.mk but that file doesn't exist
    Affected Modules: app

    정작 작성한 Android.mk는 하기처럼 이상한 path에 있네요.
    C:\Users\j.y.shin\AndroidStudioProjects\UniTILE\sdk\libcxx_helper

    어떻게 하지요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.24 16:56 신고

      해당 파일을 없다고 오류난 위치에 다시 생성해보세요

  18. jyshin 2020.07.27 11:01

    차근 차근 따라해 보니.. 빌드 성공했습니다.

    빌드 성공하면, .so파일이 생성되는거아닌가요? 어디에 .so가 있는지요? 그리고 .apk파일도 위치 알고 싶습니다.

  19. fpfpthd 2020.07.29 18:50

    혹시 현재도 질문 받으실진 모르겟지만 ㅠ
    External Tools에 javah 를 하면
    Exception in thread "main" java.lang.IllegalArgumentException: Not a valid class name:
    이런 오류가 나고 구글링 계속 해보고는 있는대 해결이 안나서요 ㅠㅠ
    알려주신 방법으로 내용을 다 채웟고 그중에
    어규먼트 부분에
    -v -jni -d $ModuleFileDir$/src/main/jni $FileClass$ -> $ModuleFileDir$ 이부분만 저한테 맞게 변경하였습니다.
    경로와 다른부분도 계속 바꿔가면서 해보는대 잘안되서 글남겨봅니다 ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.29 18:53 신고

      환경변수로 지정한 부분을 그대로 사용해봤나요?

    • BlogIcon fpfpthd 2020.07.29 18:56

      게시글 그대로 어규먼트 말씀이신가욤?? 넵 그대로도 해봤습니당 ㅠ

    • BlogIcon fpfpthd 2020.07.29 18:58

      혹시 환경변수로 지정한 부분 어떤부분을 말씀 하신건지 이해가 잘안가는대 예시 혹시 하나만 들어주실수있으신가요 ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.29 19:02 신고

      딸러 기호로 둘러싸인 이름들을 의미합니다.

    • BlogIcon fpfpthd 2020.07.29 19:09

      넵 ㅜ 그대로도 해보고 절대경로도 해봣지만 안되고잇네용 ㅠㅠ

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.29 19:14 신고

      안드로이드 스튜디오 버전이 어떻게 되나요?

    • BlogIcon fpfpthd 2020.07.29 19:16

      안드로이드 스튜디오 4.0 입니다!

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.07.29 23:47 신고

      혹시나해서 포스트대로 다시 해보니 잘됩니다. $로 둘러쌓인 문자열이 실제 실행시 변환된 값들을 참부하니 참고하여 다시 진행해보세요.

      실행결과를 비교해보세요

      "C:\Program Files\Android\Android Studio\jre\bin\javah.exe" -v -jni -d C:\Users\webnautes\AndroidStudioProjects\UseOpenCVwithndkbuild/app/src/main/jni com.tistory.webnautes.useopencvwithndk_build.MainActivity



      [Creating file RegularFileObject[C:\Users\webnautes\AndroidStudioProjects\UseOpenCVwithndkbuild\app\src\main\jni\com_tistory_webnautes_useopencvwithndk_build_MainActivity.h]]

    • BlogIcon fpfpthd 2020.07.31 12:22

      감사합니다!! 해보겠습니다!

  20. 이문규 2020.08.06 10:06

    안녕하세요. 예제 잘 따라해보았습니다.

    스마트폰에 탑재해서 gray로 잘 실행되는 것 까지 확인하였는데요.

    다시 안드로이드 스튜디오를 실행시켜보았더니, 소스코드창이 하나도 보이지 않고,

    High number of internal exceptions has been detected. This indicates a serious problem with the IDE. Please consider clean reinstall of Android Studio. If the problem persists, please report a bug by following the link below.

    라고 우측하단에 뜨네요.

    혹시 재설치 그냥 하면 되는걸까요?
    재설치는 완전 삭제로 해야될까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.06 10:08 신고

      완전히 삭제후 재설치해보는게 나을듯합니다

    • BlogIcon 이문규 2020.08.06 11:09

      네 일단 해결되었습니다. 감사합니다.

    • BlogIcon 이문규 2020.08.06 11:12

      이 이후에 다른 함수 사용하는 글도 혹시 게시하실 예정이신가요??

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.08.06 13:44 신고

      아직은 없습니다.. 요청을 하셔도 시간이 오래걸릴 수 있습니다

    • BlogIcon 이문규 2020.08.06 14:55

      네 알겠습니다.
      좋은 글 항상 감사합니다.

  21. Favicon of https://qufdl4134.tistory.com BlogIcon 쿠루루루루앙 2020.11.18 20:52 신고

    javac -h (jni 폴더위치) (path/mainactivty.java) 이렇게 external tool로 작업하니까 mainactivity의 모든 import문에서 package xxxx does not exist랑 이외코드에서 symbol 에러가 생기는데 혹시 무엇때문인지 알수있을까요?
    그리고 헤더파일을 만드는 이유가 궁금합니다. 템플릿을 native c++로 작성하고 native-lib.cpp에 mainactivty와 연결할 함수 선언하면 차이가 없는데 별도로 선언하는 이유가 있을까요?

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.11.18 20:55 신고

      cmake 방식이 아닌 ndk-build 방식을 사용하려면 수동으로 헤더파일을 생성해줘야 합니다.

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.11.18 20:56 신고

      직접 명령어를 실행했나요?

    • Favicon of https://qufdl4134.tistory.com BlogIcon 쿠루루루루앙 2020.11.19 13:45 신고

      external tool 설정에서 올려주신 Arguments 대신에 javac -h (jni 폴더위치) (mainactivity.java)로 대신하여 실행하였습니다. 안드로이드 스튜디오상 터미널로도 동일하게 위 명령어로 실행했을때도 동일한 오류가 뜨네요. 처음엔 한글을 인식못해서 에러가 났고 한글을 다 지우고 다시 실행하니 mainactivy의 모든 import문에서 package xxxxx does not exist에러와 이외 코드에선 symbol 에러가 발생합니다..

    • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2020.11.19 14:11 신고

      터미널에서 직접 명령어로는 해보지 않아서 확답이 어렵습니다. 포스트 대로 해보셨나요?

+ Recent posts