https://github.com/Brandon-Wilson/OpenCV-Plugin
https://github.com/TianxingWu/OpenVHead
https://unreal.gg-labs.com/wiki-archives/ar-vr/integrating-opencv-into-unreal-engine-4
https://github.com/Batname/UE4OpenCV
OpenCV.cpp
//Request Android Permission
TArray AndroidTotalPermissions = {
TEXT("android.permission.CAMERA"),
TEXT("android.permission.READ_EXTERNAL_STORAGE"),
TEXT("android.permission.WRITE_EXTERNAL_STORAGE"),
TEXT("android.permission.MOUNT_UNMOUNT_FILESYSTEMS"),
};
TArray AndroidNeedReqPermissions;
for(int i = 0; i < AndroidTotalPermissions.Num(); i++)
{
if(!UAndroidPermissionFunctionLibrary::CheckPermission(AndroidTotalPermissions[i]))
{
AndroidNeedReqPermissions.Add(AndroidTotalPermissions[i]);
}
}
UAndroidPermissionFunctionLibrary::AcquirePermissions(AndroidNeedReqPermissions);
源码
有可能会有遗漏,以下所有内容最终以源码中的结果为准
UE4新建Blank插件或者ThirdPartyLibrary插件,我这里是直接Blank
下载OpenCV SDK,放置Include library到指定目录中
// cofolict with UE4
// #if defined(check)
// # warning Detected Apple 'check' macro definition, it can cause build conflicts. Please, include this header before any Apple headers.
// #endif
// cofolict with UE4
// bool check() const;
这里插件需要创建对应的Library Include目录
if (Target.Platform == UnrealTargetPlatform.Android)
{
//for jni call
PrivateDependencyModuleNames.Add("Launch");
}
string OpenCVIncludePath = Path.Combine(ModuleDirectory, "../../Include");
string OpenCVLibraryPath = Path.Combine(ModuleDirectory, "../../Library");
System.Console.WriteLine("----Architecture -----" + Target.Architecture);
//Load OpenCV Include
if (Target.Platform == UnrealTargetPlatform.Win64)
{
OpenCVIncludePath = Path.Combine(OpenCVIncludePath, "Win64");
}
else if (Target.Platform == UnrealTargetPlatform.Android)
{
OpenCVIncludePath = Path.Combine(OpenCVIncludePath, "Android");
}
else if (Target.Platform == UnrealTargetPlatform.IOS)
{
OpenCVIncludePath = Path.Combine(OpenCVIncludePath, "IOS");
}
System.Console.WriteLine("----Include -----" + OpenCVIncludePath);
PublicIncludePaths.AddRange(new string[] { OpenCVIncludePath });
//Load OpenCV Library
string OpenCVFinalLibraryPath = "";
if(Target.Platform == UnrealTargetPlatform.Win64)
{
OpenCVFinalLibraryPath = Path.Combine(OpenCVLibraryPath, "Win64");
// Add Library Path
PublicLibraryPaths.Add(OpenCVFinalLibraryPath);
PublicAdditionalLibraries.Add(Path.Combine(OpenCVFinalLibraryPath, "opencv_world340.lib"));
//add dynamic library
PublicDelayLoadDLLs.Add("opencv_ffmpeg340_64.dll");
PublicDelayLoadDLLs.Add("opencv_world340.dll");
RuntimeDependencies.Add(new RuntimeDependency(Path.Combine(OpenCVFinalLibraryPath, "opencv_ffmpeg340_64.dll"))); //for package
RuntimeDependencies.Add(new RuntimeDependency(Path.Combine(OpenCVFinalLibraryPath, "opencv_world340.dll"))); //for package
System.Console.WriteLine("----Library -----" + OpenCVFinalLibraryPath);
}
else if(Target.Platform == UnrealTargetPlatform.Android)
{
string[] AndroidTarget = { "arm64-v8a", "armeabi", "armeabi-v7a", "mips", "mips64", "x86", "x86_64" };
string[] ThirdLibName = { "libcpufeatures.a", "libIlmImf.a", "liblibjasper.a", "liblibjpeg.a",
"liblibprotobuf.a", "liblibtiff.a", "liblibwebp.a", "libtbb.a", "libtegra_hal.a"
};
string[] ThirdLibName_x86 = { "libcpufeatures.a", "libIlmImf.a", "libippicv.a", "libippiw.a", "libittnotify.a",
"liblibjasper.a", "liblibjpeg.a", "liblibprotobuf.a", "liblibtiff.a", "liblibwebp.a", "libtbb.a"
};
string[] OpenCVLibName = { "libopencv_calib3d.a", "libopencv_core.a", "libopencv_flann.a", "libopencv_highgui.a",
"libopencv_imgcodecs.a", "libopencv_imgproc.a", "libopencv_ml.a", "libopencv_objdetect.a",
"libopencv_photo.a", "libopencv_shape.a", "libopencv_stitching.a", "libopencv_superres.a", "libopencv_video.a",
"libopencv_videoio.a", "libopencv_videostab.a", "libopencv_dnn.a", "libopencv_features2d.a"
};
OpenCVFinalLibraryPath = Path.Combine(OpenCVLibraryPath, "Android");
//add Third lib
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < ThirdLibName.Length; j++)
{
PublicAdditionalLibraries.Add(Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", AndroidTarget[i], ThirdLibName[j]));
System.Console.WriteLine("----Android -----" + Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", AndroidTarget[i], ThirdLibName[j]));
}
}
for (int j = 0; j < ThirdLibName.Length - 1; j++)
{
PublicAdditionalLibraries.Add(Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", "mips", ThirdLibName[j]));
System.Console.WriteLine("----Android -----" + Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", "mips", ThirdLibName[j]));
}
for (int j = 0; j < ThirdLibName.Length - 1; j++)
{
PublicAdditionalLibraries.Add(Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", "mips64", ThirdLibName[j]));
System.Console.WriteLine("----Android -----" + Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", "mips64", ThirdLibName[j]));
}
for (int j = 0; j < ThirdLibName_x86.Length ; j++)
{
PublicAdditionalLibraries.Add(Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", "x86", ThirdLibName_x86[j]));
System.Console.WriteLine("----Android -----" + Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", "x86", ThirdLibName_x86[j]));
}
for (int j = 0; j < ThirdLibName_x86.Length; j++)
{
PublicAdditionalLibraries.Add(Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", "x86_64", ThirdLibName_x86[j]));
System.Console.WriteLine("----Android -----" + Path.Combine(OpenCVFinalLibraryPath, "3rdparty\\libs", "x86_64", ThirdLibName_x86[j]));
}
//add core lib
for (int i = 0; i < AndroidTarget.Length; i++)
{
for (int k = 0; k < OpenCVLibName.Length; k++)
{
PublicAdditionalLibraries.Add(Path.Combine(OpenCVFinalLibraryPath, "libs", AndroidTarget[i], OpenCVLibName[k]));
System.Console.WriteLine("----Android -----" + Path.Combine(OpenCVFinalLibraryPath, "libs", AndroidTarget[i], OpenCVLibName[k]));
}
}
//load APL.xml
string APLXmlPath = Utils.MakePathRelativeTo(ModuleDirectory, Target.RelativeEnginePath);
AdditionalPropertiesForReceipt.Add("AndroidPlugin", Path.Combine(APLXmlPath, "OpenCV_APL.xml"));
System.Console.WriteLine("----APLXmlPath -----" + Path.Combine(APLXmlPath, "OpenCV_APL.xml"));
}
else if(Target.Platform == UnrealTargetPlatform.IOS)
{
}
Android平台 遍历加载所有的.a库,最后一步需要设置OpenCV_APL.xml 用来指定将so库拷贝到android中,以及Android编译的一些相关配置
OpenCV_APL.xml
prebuildCopies用来配置将我们自定义的so还有java文件添加到Android工程中
androidManifestUpdates 用来添加相机权限到Android中,没有需求可以不加
soLoadLibrary 添加so库
进入Library\Android\jni 创建Android.mk
LOCAL_PATH := $(call my-dir)
PATH_TO_LIBS = libs
include $(CLEAR_VARS)
LOCAL_MODULE := opencv_java3
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libopencv_java3.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := UE4
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libUE4.so
include $(PREBUILT_SHARED_LIBRARY)
void FOpenCVModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
const FString PluginDir = IPluginManager::Get().FindPlugin(TEXT("OpenCV"))->GetBaseDir();
FString LibraryPath;
#if PLATFORM_WINDOWS
LibraryPath = FPaths::Combine(*PluginDir, TEXT("Library/Win64/"));
UE_LOG(LogTemp, Warning, TEXT("opencv world LibraryPath == %s"), *(LibraryPath + TEXT("opencv_world340.dll")));
OpenCV_World_Handler = FPlatformProcess::GetDllHandle(*(LibraryPath + TEXT("opencv_world340.dll")));
OpenCV_FFmpeg_Handler = FPlatformProcess::GetDllHandle(*(LibraryPath + TEXT("opencv_ffmpeg340_64.dll")));
if (!OpenCV_World_Handler || !OpenCV_FFmpeg_Handler)
{
UE_LOG(LogTemp, Error, TEXT("Load OpenCV dll failed!"));
}
#elif PLATFORM_ANDROID
#elif PLATFORM_IOS
#endif
}
void FOpenCVModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
// we call this function before unloading the module.
#if PLATFORM_WINDOWS
FPlatformProcess::FreeDllHandle(OpenCV_World_Handler);
OpenCV_World_Handler = nullptr;
FPlatformProcess::FreeDllHandle(OpenCV_FFmpeg_Handler);
OpenCV_FFmpeg_Handler = nullptr;
#elif PLATFORM_ANDROID
#elif PLATFORM_IOS
#endif
}
下面是具体的使用例子,其中对摄像机的使用需要用到JNI与Java交互比较麻烦
使用OpenCV 加载图片
主要知识点:
extern const FString &GetFileBasePath();
FString ProjectPath = GetFileBasePath();
FString TestImgPath = FPaths::Combine(ProjectPath, FApp::GetProjectName(), TEXT("Content/TestRes/test.jpg"));
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
if(!PlatformFile.FileExists(*TestImgPath))
{
GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Red, FString::Printf(TEXT("TestImgPath == %s not exist "), *TestImgPath));
}
else
{
GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Green, FString::Printf(TEXT("TestImgPath == %s exist "), *TestImgPath));
}
std::string temp(TCHAR_TO_UTF8(*TestImgPath));
Mat img = imread(temp, IMREAD_UNCHANGED);
if(img.empty())
{
GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, TEXT("Opencv open img failed!"));
return;
}
else
{
GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Green, TEXT("Opencv open img Success!"));
}
这里大致说明一下Android的流程
主要函数在CameraFrame中
captureCamera() == 》Java startPreview() 配置Camera相关
Java onPreviewFrame()更新Data数据 ==> FrameProcessing() 将数据从Java端传递到C++中
GetFrame*( 将经过转换过格式还有翻转方向后的图像数据返回给WebcamReader,用来更新Texture2D内容