主要内容

代码生成与PackNGo的面部跟踪

这个例子展示了如何生成代码基于KLT算法的人脸检测与跟踪示例与packNGo函数。的packNGo(MATLAB编码器)函数将所有相关文件打包到一个压缩zip文件中,这样您就可以在没有MATLAB的情况下在另一个开发环境中重新部署、解包和重建项目。这个示例还展示了如何为packNGo内容创建一个makefile,重新构建源文件,并最终在MATLAB环境外运行独立的可执行文件。

这个例子需要MATLAB®Coder™许可证。

这个例子是一个函数,主体位于顶部,助手例程的形式为嵌套函数在下面。

函数FaceTrackingKLTpackNGoExample ()

建立你的c++编译器

要运行这个例子,你必须有一个c++编译器的权限,并且你必须使用'mex -setup c++'命令配置它。有关更多信息,请参见选择一个c++编译器.如果您将应用程序部署在MATLAB主机上,请使用与用于构建OpenCV库的编译器兼容的c++编译器。有关更多信息,请参见使用OpenCV库的函数的可移植C代码生成

将算法的计算部分分解为一个单独的MATLAB函数

MATLAB Coder要求MATLAB代码以函数的形式生成C代码。这个示例的主要算法代码驻留在一个被调用的函数中FaceTrackingKLTpackNGo_kernel.m.该文件派生自基于KLT算法的人脸检测与跟踪.要学习如何修改MATLAB代码以使其与代码生成兼容,可以查看示例引入特征匹配和注册的代码生成

文件名=“FaceTrackingKLTpackNGo_kernel.m”;visiondemo_dir = pwd;currentDir = pwd;%存储当前目录fileName = fullfile(visiondemo_dir, fileName);

为。配置代码生成参数packNGo

在代码生成阶段调用packNGo函数,为EXE输出创建一个代码生成配置对象。

codegenArgs = createCodegenArgs (visiondemo_dir);

设置代码生成环境

更改输出目录名称。

codegenOutDir = fullfile (visiondemo_dir,“codegen”);mkdir (codegenOutDir);

向现有目录添加路径以访问必要的文件。

currentPath =目录(visiondemo_dir);pathCleanup = onCleanup(@()路径(currentPath));cd (codegenOutDir);dirChange = onCleanup (@ () cd (currentDir));

创建打包的zip文件

用packNGo函数调用调用codegen命令。

流('->生成代码(可能需要几分钟)....\n');codegen (codegenArgs{:},文件名);
->生成代码(可能需要几分钟)....代码生成成功。

请注意,您可以使用以下命令打开对话框并启动代码生成项目,而不是使用codegen命令codegen(MATLAB编码器).使用带有packNGo函数的邮政编码生成命令来创建一个zip文件。

建立独立的可执行文件

将zip文件解压缩到一个新文件夹中。请注意zip文件包含源文件、头文件、库、包含构建信息对象的mat文件、数据文件。unzipPackageContents和其他助手函数都包含在附录中。

zipFileLocation = codegenOutDir;流('->解压缩文件....\n');unzipFolderLocation = unzipPackageContents (zipFileLocation);
->解压缩文件....

从模板makefile创建平台相关的makefile。

流('->创建makefile ....\n');[~, fname, ~] = fileparts(fileName);makefileName = createMakeFile(visiondemo_dir, unzipFolderLocation, fname);
->创建makefile ....

创建生成项目和运行项目所需的命令。

流('->创建“生成命令”和“运行命令”....\n');[buildCommand, runCommand] = createBuildAndRunCommands(zipFileLocation,...unzipFolderLocation, makefileName、帧);
->创建“生成命令”和“运行命令”....

使用Build命令生成项目。

流(“- >构建可执行…\ n”);buildExecutable (unzipFolderLocation buildCommand);
- >构建可执行…

运行Executable和Deploy

运行可执行文件并验证它是否工作。

cd (unzipFolderLocation);系统(runCommand);

通过复制可执行文件和库文件,应用程序可以部署在另一台机器上。

isPublishing = ~ isempty (snapnow (“得到”));如果~ isPublishing%跳过打印目录到HTML页流('可执行文件和库文件位于以下文件夹:\n%s\n', unzipFolderLocation);流(要重新执行,请运行以下命令:\n');流(“1。cd(“% s”)\ n ', unzipFolderLocation);流(“2。系统(“% s”)\ n”runCommand);结束

附录-辅助功能

%配置编码器以创建可执行文件。邮政编码使用packNGo%生成阶段。函数codegenArgs = createCodegenArgs (folderForMainC)%创建代码生成所需的参数。%对于独立的可执行文件,需要一个主C函数。c的为本例创建的%与文件内容兼容% visionFaceTrackingKLTpackNGo_kernel.mmainCFile = fullfile (folderForMainC,“c”);%用空格处理路径如果包含(mainCFile' ') mainCFile = [“””mainCFile“””];结束cfg = coder.config (exe”);cfg。PostCodeGenCommand =“packNGo (buildInfo,“packType”,“分层”);“;cfg。CustomSource = mainCFile;cfg。CustomInclude = folderForMainC;cfg。EnableOpenMP = false;codegenArgs = {“配置”cfg};结束%创建一个文件夹并将packNGo内容解压到其中。函数unzipFolderLocation = unzipPackageContents (zipFileLocation)%解压打包的zip文件。unzipFolderLocationName =“unzipPackNGo”;mkdir (unzipFolderLocationName);%获取packNGo生成的zip文件的名称。zipFile = dir (‘* . zip”);断言(元素个数(zipFile) = = 1);解压缩(zipFile.name unzipFolderLocationName);解压分层packNGo中创建的内部zip文件。zipFileInternal = dir (fullfile (unzipFolderLocationName‘* . zip”));断言(元素个数(zipFileInternal) = = 3);i = 1:元素个数(zipFileInternal)解压缩(fullfile (unzipFolderLocationName, zipFileInternal (i) . name),...unzipFolderLocationName);结束unzipFolderLocation = fullfile (zipFileLocation unzipFolderLocationName);结束从模板makefile中创建平台相关的makefile。使用% buildInfo获取关于工具链的信息。函数makefileName = createMakeFile(visiondemo_dir, unzipFolderLocation, fname)从buildInfo创建Makefile。binfo =负载(fullfile (pwd,“codegen”exe”、帧,“buildInfo.mat”));lastDir = cd (unzipFolderLocation);dirCleanup = onCleanup (@ () cd (lastDir));%获取包含toolbox/vision子目录的根目录matlabDirName = getRootDirName (unzipFolderLocation);%得到定义horzcat_with_space = @ (cellval) sprintf (' % s ', cellval {:});def = horzcat_with_space (getDefines (binfo.buildInfo));%获取源文件列表如果ispc [~, cFiles] = system([“dir / s / b”‘* . c”]);[~, cppFiles] = system([“dir / s / b”‘* . cpp‘]);其他的[~, cFiles] = system([“。/”“- name”“* . c”]);[~, cppFiles] = system([“。/”“- name”“* . cpp”]);结束cIndx = strfind(用,“c”);cppIndx = strfind (cppFiles,. cpp的);srcFilesC = [];srcFilesCPP = [];i = 1:长度(cIndx)如果i == 1 startIdx = 1;endIdx = cIndx(我);其他的startIdx = cIndx(张)+ 1;endIdx = cIndx(我);结束[~, b, ~] = fileparts(cFiles(startIdx:endIdx));srcFilesC = [srcFilesC' 'b“c”];% #好< AGROW >结束i = 1:长度(cppIndx)如果i == 1 startIdx = 1;endIdx = cppIndx(我);其他的startIdx = cppIndx(张)+ 1;endIdx = cppIndx(我);结束[~, b, ~] = fileparts(cppFiles(startIdx:endIdx));srcFilesCPP = [srcFilesCPP' 'b. cpp的];% #好< AGROW >结束srcFiles = [srcFilesC' 'srcFilesCPP];获取平台相关名称如果isunix% MAC和Linuxtmf =“TemplateMakefilePackNGo_unix”如果ismac archDir =“maci64”;dllExt =“dylib”其他的archDir =“glnxa64”;dllExt =“所以”结束其他的tmf =“TemplateMakefilePackNGo_win”;archDir =“win64”;dllExt =“dll”结束现在我们已经有了定义,让我们创建一个依赖于平台的makefile%的模板。fid = fopen (fullfile (visiondemo_dir tmf));filecontent = char(从文件中读(fid) ');文件关闭(fid);newfilecontent = regexprep (filecontent,...“PASTE_ARCH”“PASTE_EXT”“PASTE_DEFINES”“PASTE_SRCFILES”“PASTE_MATLAB”},...{archDir, dllExt, defs, srcFiles, matlabDirName});makefileName =“Makefile”;mk_name = fullfile (unzipFolderLocation makefileName);如果isunix如果(ismac) [status, syshederpath] = system(“xcode-select -print-path”);断言(状态= = 0,(“无法获得进入系统的路径”...'头文件使用'xcode-select -print-path''']);[status,sdkPaths] = system([“发现”deblank (sysHeaderPath)...“- name“MacOSX * .sdk””]);断言(状态= = 0,'Could not find MacOSX sdk');%可能有多个SDKsdkPathCell = strsplit (sdkPaths,' \ n ');idx = 1:元素个数(sdkPathCell)如果~ isempty (sdkPathCell {idx})%选择第一个非空的。sdkPath = sdkPathCell {idx};流(在%s\n中选择SDK, sdkPath);打破结束结束断言(~ isempty (sdkPath),...sprintf ('在%s中没有可用的sdk。请检查系统环境。\n'sysHeaderPath));ccCMD = ['xcrun clang -isysroot 'deblank(sdkPath);cppCMD = ['xcrun clang++ -isysroot 'deblank(sdkPath);其他的ccCMD =“海合会”;cppCMD =“g++”结束newfilecontent = regexprep (newfilecontent,“PASTE_CC”, ccCMD);newfilecontent = regexprep (newfilecontent,“PASTE_CPP”, cppCMD);结束fid = fopen (mk_name,“w +”);流(fid检测器,' % s ', newfilecontent);文件关闭(fid);结束%创建构建可执行文件所需的平台特定命令%来运行它。函数[buildCommand, runCommand] = createBuildAndRunCommands(...packageLocation、unzipFolderLocation makefileName文件名)%创建生成并运行命令。如果ismac buildCommand = [' xcron make -f 'makefileName];runCommand = [“。/”文件名“””文件名“””];elseifisunix buildCommand = [' make -f 'makefileName];runCommand = [“。/”文件名“””文件名“””];其他的%在PC上,我们使用生成的BAT文件(应该有2个)来帮助%生成生成的代码。这些文件被复制到% unzipFolderLocation,我们可以使用它们来构建。batFilename =[文件名“_rtw.bat”];batFilelocation = fullfile (packageLocation,“codegen”...filesep,exe”filesep,文件名);batFileDestination = unzipFolderLocation;% For MSVC,也复制'setup_msvc.bat'fid = fopen(fullfile(batFilelocation, batFilename));batFileContent =从文件中读(fid,“*字符”);文件关闭(fid);如果~ isempty(正则表达式(convertCharsToStrings (batFileContent),“setup_msvc.bat”“一次”) setup_msvc_batFile = fullfile(batFilelocation,“setup_msvc.bat”);拷贝文件(setup_msvc_batFile batFileDestination);结束%复制到packNGo输出目录。拷贝文件(fullfile (batFilelocation batFilename) batFileDestination);我们创建的Makefile命名为“Makefile”,而批处理文件命名为“Makefile”% file指的是_rtw.mk。因此,我们重命名该文件。newMakefileName =[文件名“_rtw.mk”];oldMakefilename = makefileName;拷贝文件(fullfile (batFileDestination oldMakefilename),...fullfile (batFileDestination newMakefileName));buildCommand = batFilename;runCommand =[文件名. exe”“””文件名“””];结束结束%使用Build命令生成可执行文件。函数buildExecutable (unzipFolderLocation buildCommand)%调用系统命令来构建可执行文件。lastDir = cd (unzipFolderLocation);dirCleanup = onCleanup (@ () cd (lastDir));[hadError, sysResults] = system(buildCommand);如果hadError错误(sysResults);结束结束%获取包含toolbox/vision子目录的根目录函数matlabDirName = getRootDirName(unzipFolderName) dirLists = dir(unzipFolderName);目录=目录(~ ismember ({dirLists.name}, {“。”“. .”}));matlabDirName =''ij=1:length(dirLists) thisDirName = dirLists(ij).name;如果(isfolder (thisDirName))%子目录将具有toolbox/vision[subDir1, hasSubDir1] = hasSubdirectory(thisDirName,“工具箱”);如果hasSubDir1 [~, hasSubDir2] = hasSubdirectory(subDir1,“愿景”);如果hasSubDir2 matlabDirName = thisDirName;打破结束结束结束结束结束%查找包含指定子目录的目录函数[subDir, hasSubDir] = hasSubdirectory(dirName, subDirName) dirLists = dir(dirName);目录=目录(~ ismember ({dirLists.name}, {“。”“. .”}));子目录='';hasSubDir = false;ij=1:length(dirLists) thisDirName = dirLists(ij).name;thisDirName thisDir = fullfile(目录名);如果(isfolder(thisDir) && strcmp(thisDirName, subDirName)) hasSubDir = true;子目录= thisDir;打破结束结束结束
结束