难点主要在与Android端,PC端SDK打包好后基本就可以使用,Android端遇到了各种兼容之类的bug
参考
https://my.oschina.net/jjyuangu/blog/2243591
https://blog.csdn.net/u012234115/article/details/90642844
Dlib官网下载地址 工程里(源码在上一篇文章里)使用的是19.7版本,只针对UE4的Android版本
修改后的UE4版本
if (DLIB_ISO_CPP_ONLY)
option(DLIB_JPEG_SUPPORT ${DLIB_JPEG_SUPPORT_STR} OFF)
option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} OFF)
option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} OFF)
option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} OFF)
option(DLIB_USE_CUDA ${DLIB_USE_CUDA_STR} OFF)
option(DLIB_PNG_SUPPORT ${DLIB_PNG_SUPPORT_STR} OFF)
option(DLIB_GIF_SUPPORT ${DLIB_GIF_SUPPORT_STR} OFF)
#option(DLIB_USE_FFTW ${DLIB_USE_FFTW_STR} OFF)
option(DLIB_USE_MKL_FFT ${DLIB_USE_MKL_FFT_STR} OFF)
else()
option(DLIB_JPEG_SUPPORT ${DLIB_JPEG_SUPPORT_STR} ON)
option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} ON)
option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} ON)
option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} ON)
option(DLIB_USE_CUDA ${DLIB_USE_CUDA_STR} ON)
option(DLIB_PNG_SUPPORT ${DLIB_PNG_SUPPORT_STR} ON)
option(DLIB_GIF_SUPPORT ${DLIB_GIF_SUPPORT_STR} ON)
#option(DLIB_USE_FFTW ${DLIB_USE_FFTW_STR} ON)
option(DLIB_USE_MKL_FFT ${DLIB_USE_MKL_FFT_STR} ON)
endif()
将DLIB_USE_CUDA_和DLIB_PNG_SUPPORT_STR 的ON改成OFF, 否则与UE4冲突
2. dlib目录下的Config.h 添加一下代码
// If you are compiling dlib as a shared library and installing it somewhere on your system
// then it is important that any programs that use dlib agree on the state of the
// DLIB_ASSERT statements (i.e. they are either always on or always off). Therefore,
// uncomment one of the following lines to force all DLIB_ASSERTs to either always on or
// always off. If you don't define one of these two macros then DLIB_ASSERT will toggle
// automatically depending on the state of certain other macros, which is not what you want
// when creating a shared library.
//#define ENABLE_ASSERTS // asserts always enabled
//#define DLIB_DISABLE_ASSERTS // asserts always disabled
//#define DLIB_ISO_CPP_ONLY
//#define DLIB_NO_GUI_SUPPORT
//#define DLIB_ENABLE_STACK_TRACE
// You should also consider telling dlib to link against libjpeg, libpng, libgif, fftw, CUDA,
// and a BLAS and LAPACK library. To do this you need to uncomment the following #defines.
// #define DLIB_JPEG_SUPPORT
// #define DLIB_PNG_SUPPORT
// #define DLIB_GIF_SUPPORT
// #define DLIB_USE_FFTW
// #define DLIB_USE_BLAS
// #define DLIB_USE_LAPACK
// #define DLIB_USE_CUDA
#ifndef STDTOSTRING_H
#define STDTOSTRING_H
#if defined(ANDROID)
#ifdef ATOMIC_INT_LOCK_FREE
#undef ATOMIC_INT_LOCK_FREE
#endif
#define ATOMIC_INT_LOCK_FREE 2
#include
#include
#include
#include
using namespace std;
namespace std {
template std::string to_string(const T& n) {
std::ostringstream stm;
stm << n;
return stm.str();
}
template T round(T v) {
return (v > 0) ? (v + 0.5) : (v - 0.5);
}
}
#endif
#endif
#-*-coding:utf-8-*-
import os
import shutil
import zipfile
import hashlib
import sys
import platform
import requests
import urllib
import subprocess
#工具类
class Utils():
#如果目录不存,则创建。
@staticmethod
def mkDir(dirPath):
if os.path.exists(dirPath) and os.path.isdir(dirPath):
return
parent = os.path.dirname(dirPath)
if not (os.path.exists(parent) and os.path.isdir(parent)):
Utils.mkDir(parent)
os.mkdir(dirPath)
#获取某个目录是否含有某个文件, extList获取指定的文件后缀
@staticmethod
def getAllDirFiles(dirPath, extList = None):
ret = []
for file in os.listdir( dirPath):
if os.path.isfile(os.path.join(dirPath, file)):
ret.append(os.path.join(dirPath, file))
else:
ret += Utils.getAllDirFiles(os.path.join(dirPath, file))
#需要过滤某些文件
if extList != None:
extList = [tmp.lower() for tmp in extList]
ret = [path for path in ret if os.path.splitext(path)[1].lower() in extList]
return ret
#清理掉某个数据
@staticmethod
def cleanFile(path):
if not os.path.exists(path):
return
if os.path.isdir(path):
shutil.rmtree(path)
elif os.path.isfile(path):
os.remove(path)
#将一个文件夹压缩成zip文件
@staticmethod
def makeZipFile(fileName, fromDir):
fileList = Utils.getAllDirFiles(fromDir)
with zipfile.ZipFile(fileName , 'w') as zip:
for file in fileList:
zip.write(file, os.path.relpath(file, fromDir))
@staticmethod
def extractZipFile(fileName, toDir = "."):
file_zip = zipfile.ZipFile(fileName, 'r')
for file in file_zip.namelist():
file_zip.extract(file, toDir)
file_zip.close()
@staticmethod
def sha256_checksum(filename, block_size=65536):
sha256 = hashlib.sha256()
with open(filename, 'rb') as f:
for block in iter(lambda: f.read(block_size), b''):
sha256.update(block)
return sha256.hexdigest()
#获取python文件所在的路径
def p():
frozen = "not"
if getattr(sys, 'frozen',False):
frozen = "ever so"
return os.path.dirname(sys.executable)
return os.path.split(os.path.realpath(__file__))[0]
#下载进度条回调
def callbackfunc(blocknum, blocksize, totalsize):
'''回调函数
@blocknum: 已经下载的数据块
@blocksize: 数据块的大小
@totalsize: 远程文件的大小
'''
percent = 100.0 * blocknum * blocksize / totalsize
if percent > 100:
percent = 100
max_arrow = 50 #进度条的长度
num_arrow = int(percent * max_arrow/100.0)
process_bar = '\r[' + '>' * num_arrow + '#' * (max_arrow - num_arrow) + ']'\
+ '%.2f%%' % percent #带输出的字符串,'\r'表示不换行回到最左边
sys.stdout.write(process_bar) #这两句打印字符到终端
sys.stdout.flush()
#andoird sdk 的操作sdk路径
class AndroidSDK():
def __init__(self):
self.ANDROID_SDK = self.getAndroidSDKPath()
if self.ANDROID_SDK == None:
self.ANDROID_SDK = self.installAndroidSDK()
#更新android sdk
self.updateSDK(['platforms;android-16'])
self.cmakeDir = self.getCmakeDir()
if self.cmakeDir == None:
self.updateSDK(['cmake;3.6.4111459'])
self.cmakeDir = self.getCmakeDir()
self.NDKPath = self.getNDKPath()
if self.NDKPath == None:
self.updateSDK(['ndk-bundle'])
self.NDKPath = self.getNDKPath()
def installAndroidSDK(self):
sysstr = platform.system().lower()
SHA_256 = {
"windows":'7e81d69c303e47a4f0e748a6352d85cd0c8fd90a5a95ae4e076b5e5f960d3c7a',
'darwin':'ecb29358bc0f13d7c2fa0f9290135a5b608e38434aad9bf7067d0252c160853e',
'linux':'92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9',
}
#是否需要下载包
needDownload = True
android_sdk_zip = "android_sdk.zip"
if os.path.isfile(android_sdk_zip):
sha256 = Utils.sha256_checksum(android_sdk_zip)
if sha256.lower() == SHA_256[sysstr]:
needDownload = False
print u"下载Android_sdk"
#下载包
if needDownload:
sdk_download_url = 'https://dl.google.com/android/repository/sdk-tools-%s-4333796.zip'%(sysstr, )
urllib.urlretrieve(sdk_download_url, android_sdk_zip, callbackfunc)
#解压文件
Utils.extractZipFile(android_sdk_zip, "./android_sdk")
os.environ['ANDROID_HOME'] = os.path.realpath("android_sdk")
return os.environ['ANDROID_HOME']
def updateSDK(self, package = [ 'platforms;android-16', 'cmake;3.6.4111459', 'ndk-bundle' ]):
sdkmanager = os.path.join(self.ANDROID_SDK, 'tools/bin/sdkmanager')
if "windows" == platform.system().lower():
sdkmanager = sdkmanager + '.bat'
else:
cmd = 'chmod +x %s' %(sdkmanager,)
os.system(cmd)
args = ['"%s"' %(key) for key in package]
args.insert(0, sdkmanager)
cmd = 'echo y|' + " ".join(args)
os.system(cmd)
#获取sdk里的 cmake 信息
def getCmakeDir(self):
ndk_cmake_dir = os.path.join(self.ANDROID_SDK, "cmake")
if not os.path.isdir(ndk_cmake_dir):
return None
cmake_dir_list = os.listdir(ndk_cmake_dir)
list_len = len(cmake_dir_list)
if list_len <= 0:
return None
return os.path.join(ndk_cmake_dir, cmake_dir_list[list_len - 1] )
def getNDKPath(self):
#通过系统变量来寻找
environ_names = [
'NDK_ROOT',
]
for name in environ_names:
#环境变量里不存在
if name not in os.environ.keys():
continue
android_ndk_path = os.environ[name]
#验证如果不存在此目录
if not os.path.isdir(android_ndk_path):
continue
return android_ndk_path
ndk_bundle_dir = os.path.join(self.ANDROID_SDK, "ndk-bundle")
ndk_bundle_list = os.listdir( ndk_bundle_dir)
ndk_bundle_list_len = len(ndk_bundle_list)
if ndk_bundle_list_len <= 0 :
return None
#取最后一个高版本的使用
return os.path.join(self.ANDROID_SDK, "ndk-bundle/" + ndk_bundle_dir[ndk_bundle_list_len - 1] )
# 根据系统变量android sdk的路径
def getAndroidSDKPath(self):
environ_names = [
'ANDROID_HOME',
'ANDROID_SDK_ROOT'
]
for name in environ_names:
#环境变量里不存在
if name not in os.environ.keys():
continue
android_sdk_path = os.environ[name]
#验证如果不存在此目录
if not os.path.isdir(android_sdk_path):
continue
return android_sdk_path
#没有找到相应的sdk路径
return None
if '__main__' == __name__:
android_sdk = AndroidSDK()
ANDROID_SDK = android_sdk.getAndroidSDKPath()
ANDROID_NDK =android_sdk.getNDKPath()
ANDROID_CMAKE = os.path.join(android_sdk.getCmakeDir(), 'bin/cmake')
ANDROID_NINJA=os.path.join(android_sdk.getCmakeDir(),'bin/ninja')
if "windows" == platform.system().lower():
ANDROID_CMAKE = ANDROID_CMAKE + '.exe'
ANDROID_NINJA = ANDROID_NINJA + '.exe'
pyPath = p()
buildDir = os.path.join(pyPath, "build")
outDir = os.path.join(pyPath, "out")
Utils().cleanFile(outDir)
Utils().mkDir(outDir)
#需要打包的abi
abiList = [
'armeabi',
'armeabi-v7a',
"arm64-v8a",
"x86",
'x86_64',
'mips',
'mips64',
]
for abi in abiList:
os.chdir(pyPath)
Utils().cleanFile(buildDir)
Utils().mkDir(buildDir)
os.chdir(buildDir)
#导出目录
outSoPath = os.path.join(outDir, "" + abi)
Utils().cleanFile(outSoPath)
Utils().mkDir(outSoPath)
cmd = '''%s -DANDROID_ABI=%s \
-DANDROID_PLATFORM=android-16 \
-DCMAKE_BUILD_TYPE=Release \
-DANDROID_NDK=%s \
-DCMAKE_CXX_FLAGS=-std=c++11 -frtti -fexceptions \
-DCMAKE_TOOLCHAIN_FILE=%s/build/cmake/android.toolchain.cmake \
-DCMAKE_MAKE_PROGRAM=%s -G "Ninja" \
-DDLIB_NO_GUI_SUPPORT=1 \
-DCMAKE_INSTALL_PREFIX=%s \
..'''%(ANDROID_CMAKE,abi,ANDROID_NDK,ANDROID_NDK,ANDROID_NINJA, outSoPath )
print cmd
os.system(cmd)
os.system("%s --build ."%(ANDROID_CMAKE, ))
os.system("%s -P cmake_install.cmake"%(ANDROID_CMAKE, ))
执行 Python ./ndk_build.py,成功的话 会在sdk更目录创建出Out
里面有对应的Include文件和.a库文件,将Config.h覆盖这里,然后拷到插件对应的目录中
Windows:
安装CMake GUI,生成vs工程后就是传统的打包lib了,将lib拷贝到插件目录中
4. Dlib插件编写
5.Dlib测试使用
UE_LOG(LogTemp, Warning, TEXT("Begin Serialize file TempPath = %s"), *TempPath );
std::string strTemp(TCHAR_TO_UTF8(*TempPath));
std::ofstream StreamOut(strTemp.c_str(), std::ios::binary);
UE_LOG(LogTemp, Warning, TEXT("custom serialize begin, TempPath = %s"), *TempPath );
serialize(learned_pfunct, StreamOut);
StreamOut.clear();
StreamOut.close();
UE_LOG(LogTemp, Warning, TEXT("custom serialize end, TempPath = %s"), *TempPath );
std::ifstream StreamIn(strTemp.c_str(), std::ios::binary);
UE_LOG(LogTemp, Warning, TEXT("custom deserialize begin, begin deserialize TempPath = %s"), *TempPath );
deserialize(learned_pfunct, StreamIn);
UE_LOG(LogTemp, Warning, TEXT("custom deserialize end, begin deserialize TempPath = %s"), *TempPath );