[유니티/안드로이드/Visual Studio] 안드로이드apk에서 opencv so라이브러리 호출하기

프로그래밍/OpenCV2020. 9. 21. 20:42

시간 여유가 없어 간단하게 정리하려고 합니다.

 

안드로이드에서 apk를 실행했을 때 so파일을 못찾아 dllnotfound 에러가 뜨는 경우 so파일을 못찾은게 아니라 so파일에 문제가 있어 읽기에 실패했을 수도 있습니다. 다만 이런 경우라고 하더라도.. 비주얼 스튜디오 빌드시에 에러가 뜨지 않아 로그만 가지고 문제를 찾기가 쉽지 않습니다. 저의 경우 so파일에 문제가 있으면 용량이 400~600KB로 나오고 정상적인 경우 6KB정도의 용량을 가지더라구요. 참고하면 좋을 것 같습니다.

 

유니티 버전: 2019.4.10f1

비주얼 스튜디오 버전: Microsoft Visual Studio Community 2019 버전 16.7.3

 

비주얼 스튜디오에서 opencv_java3.so 라이브러리(버전:3.4.1)를 사용하는 wrapper so를 만들어 이를, 유니티에서 만든 안드로이드 apk에서 사용하게 하는 것이 목표입니다.

(opencv_java4.so도.. 정상동작하는 옵션이 있을 수 있음)

 

대상 API 레벨에 영향을 받습니다. 19에서 21로 올렸습니다.

opencv include 경로를 지정하면 됩니다.

C++ 예외 처리 가능을 예(-fexceptions)로 변경했습니다.

런타임 형식 정보 사용을 예(-frtti)로, C++ 언어 표준을 C++17(-std=c++1z)로 변경했습니다.

혹시나 해서.. 최종 명령줄도 자료 남깁니다.

링커>일반의 추가 라이브러리 디렉토리에 opencv 경로를 입력합니다.

링커>입력 추가 종속성에 opencv_java3.so파일 풀 경로를 입력합니다.

혹시나 해서 최종 명령줄도 자료로 남겨봅니다.

추가 옵션의 -lm -lz도 주의해서 봐야할 것 같습니다.

 

유니티에서 안드로이드 빌드 관련 Player Setting입니다.

여기서.. Scripting Backend와 Api Compatibility Level에 상당한 영향을 받습니다.

Mono와 .NET Standard 2.0을 설정했습니다.

 

참고로 IL2CPP와 .NET4.x로 설정했더니..

유니티 C#단에서 so라이브러리의 함수 호출시 데이터 통신에 문제가 생겼었습니다.

C#쪽에서 ref 키워드로 Color32[] 변수를 넘겼는데 so라이브러리 함수 호출만 하면.. 사이즈가 1이 되는 이상한 문제가 발생했었습니다.

 

비주얼 스튜디오: SharedObjectSimple.h

#pragma once

extern "C"
{
	namespace SharedObjectSimple
	{
		const char* getPlatformABI();
		struct Color32;
		void ProcessImage(Color32** rawImage1, int width1, int height1);
	}
}

 

비주얼 스튜디오: SharedObjectSimple.cpp

#include "SharedObjectSimple.h"
#include "opencv2\core.hpp"

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "SharedObjectSimple", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "SharedObjectSimple", __VA_ARGS__))

extern "C" {
	/* 이 Trivial 함수는 이 동적 네이티브 라이브러리가 컴파일되는 플랫폼 ABI를 반환합니다.*/
	const char * SharedObjectSimple::getPlatformABI()
	//void SharedObjectSimple::getPlatformABI()
	{
	#if defined(__arm__)
	#if defined(__ARM_ARCH_7A__)
	#if defined(__ARM_NEON__)
		#define ABI "armeabi-v7a/NEON"
	#else
		#define ABI "armeabi-v7a"
	#endif
	#else
		#define ABI "armeabi"
	#endif
	#elif defined(__i386__)
		#define ABI "x86"
	#else
		#define ABI "unknown"
	#endif
		//LOGI("This dynamic shared library is compiled with ABI: %s", ABI);
		return "This native library is compiled with ABI: %s" ABI ".";
	}

	struct Color32
	{
		uchar red;
		uchar green;
		uchar blue;
		uchar alpha;
	};

	void SharedObjectSimple::ProcessImage(Color32** rawImage1, int width1, int height1) {
		using namespace cv;
		Mat Image(height1, width1, CV_8UC4, *rawImage1);
		flip(Image, Image, -1);
	}
}

 

SharedObjectSimple.cpp

 

비주얼 스튜디오 빌드 성공 로그

1>------ 빌드 시작: 프로젝트: SharedObjectSimple, 구성: Debug ARM ------

1>ANDROID_HOME=C:\\Microsoft\AndroidSDK\25

1>ANT_HOME=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Apps\apache-ant-1.9.3

1>JAVA_HOME=C:\Program Files\Android\jdk\microsoft_dist_openjdk_1.8.0.25

1>NDK_ROOT=C:\\Microsoft\AndroidNDK64\android-ndk-r16b 1>pch.h 1>SharedObjectSimple.cpp

1>SharedObjectSimple.vcxproj ->

C:\Users\****\source\repos\SharedObjectSimple\ARM\Debug\libSharedObjectSimple.so

========== 빌드: 성공 1, 실패 0, 최신 0, 생략 0 ==========

 

유니티:ExScript.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
using UnityEngine.UI;
using System; //for IntPtr


public class ExScript : MonoBehaviour
{
    public Button btnFlipImage;
    public Image imageBlack;

    [DllImport("SharedObjectSimple")]
    private static extern IntPtr getPlatformABI();
    [DllImport("SharedObjectSimple")]
    private static extern void ProcessImage(ref Color32[] rawImage, int width, int height);

    // Start is called before the first frame update
    void Start()
    {
        btnFlipImage.onClick.AddListener(CallFlipImage);
        //CallFlipImage();
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void CallFlipImage()
    {
        Debug.Log("CallFlipImage called");
        IntPtr cstr = getPlatformABI();
        String str = Marshal.PtrToStringAnsi(cstr);
        Debug.Log("CallFlipImage called: " + str);
        
        var blackImage = imageBlack.sprite.texture.GetPixels32();

        ProcessImage(ref blackImage, imageBlack.sprite.texture.width, imageBlack.sprite.texture.height);

        imageBlack.sprite.texture.SetPixels32(blackImage);
        imageBlack.sprite.texture.Apply();
        
    }
}

 

관련 글

유니티에서 OpenCV 사용하기 - 1.기본 환경 설정

유니티에서 OpenCV 사용하기 - 2.Visial C++ 기본 설정

유니티에서 OpenCV 사용하기 - 3.실전(이미지 전달,통신)

[비주얼스튜디오] 동적 공유 라이브러리(so파일) 프로젝트 만드는 법

작성자

Posted by 드리머즈

관련 글

댓글 영역