В этом примере показано, как сгенерировать код из Face Detection and Tracking Используя пример алгоритма KLT с функцией packNGo. The packNGo
Функция (MATLAB Coder) упаковывает все релевантные файлы в сжатый zip-файл, чтобы можно было перемещать, распаковывать и перестраивать проект в другой среде разработки без присутствия MATLAB. В этом примере также показано, как создать make-файл для содержимого packNGo, перестроить исходные файлы и, наконец, запустить независимый исполняемый файл вне окружения MATLAB.
Для этого примера требуется лицензия Coder™ MATLAB ®.
Этот пример является функцией с основным телом в верхней части и стандартными программами в форме Вложенных функций ниже.
function FaceTrackingKLTpackNGoExample()
Чтобы запустить этот пример, вы должны иметь доступ к компилятору C++, и вы должны сконфигурировать его с помощью команды 'mex -setup c++'. Для получения дополнительной информации смотрите Выбор компилятора C++. Если вы развертываете приложение на узле MATLAB, используйте компилятор C++, совместимый с компилятором, используемым для создания библиотек OpenCV. Для получения дополнительной информации смотрите Portable C Code Generation для функций, которые используют библиотеку OpenCV.
MATLAB Coder требует, чтобы код MATLAB был в форме функции, порядка для генерации Кода С. Код для основного алгоритма этого примера находится в функции, называемой FaceTrackingKLTpackNGo_kernel.m. Этот файл получен из обнаружения и отслеживания лиц с использованием алгоритма KLT. Чтобы узнать, как изменить код MATLAB, чтобы сделать его совместимым для генерации кода, можно посмотреть пример Введение в генерацию кода с сопоставлением функций и регистрацией.
fileName = 'FaceTrackingKLTpackNGo_kernel.m'; visiondemo_dir = pwd; currentDir = pwd; % Store the current directory fileName = fullfile(visiondemo_dir, fileName);
packNGo
Создайте объект строения генерации кода для выхода EXE с вызовом функции packNGo на этапе генерации посткода.
codegenArgs = createCodegenArgs(visiondemo_dir);
Измените имя выходной директории.
codegenOutDir = fullfile(visiondemo_dir, 'codegen');
mkdir(codegenOutDir);
Добавьте путь к существующей директории, чтобы иметь доступ к необходимым файлам.
currentPath = addpath(visiondemo_dir); pathCleanup = onCleanup(@()path(currentPath)); cd(codegenOutDir); dirChange = onCleanup(@()cd(currentDir));
Активируйте команду codegen с вызовом функции packNGo.
fprintf('-> Generating Code (it may take a few minutes) ....\n');
codegen(codegenArgs{:}, fileName);
-> Generating Code (it may take a few minutes) .... Code generation successful.
Обратите внимание, что вместо использования команды codegen можно открыть диалоговое окно и запустить проект генерации кода с помощью codegen
(MATLAB Coder). Используйте команду post генерации кода с функцией packNGo, чтобы создать zip- файла.
Разархивируйте zip- файла в новую папку. Обратите внимание, что zip-файл содержит исходные файлы, заголовочные файлы, библиотеки, MAT-файл, содержащий информационный объект сборки, файлы данных. unzipPackageContents
и другие вспомогательные функции включены в приложение.
zipFileLocation = codegenOutDir;
fprintf('-> Unzipping files ....\n');
unzipFolderLocation = unzipPackageContents(zipFileLocation);
-> Unzipping files ....
Создайте зависящий от платформы make-файл из шаблона make-файла.
fprintf('-> Creating makefile ....\n');
[~, fname, ~] = fileparts(fileName);
makefileName = createMakeFile(visiondemo_dir, unzipFolderLocation, fname);
-> Creating makefile ....
Создайте команды, необходимые для создания проекта и его запуска.
fprintf('-> Creating ''Build Command'' and ''Run command'' ....\n'); [buildCommand, runCommand] = createBuildAndRunCommands(zipFileLocation,... unzipFolderLocation,makefileName,fname);
-> Creating 'Build Command' and 'Run command' ....
Создайте проект с помощью команды build.
fprintf('-> Building executable....\n');
buildExecutable(unzipFolderLocation, buildCommand);
-> Building executable....
Запустите исполняемый файл и проверьте, что он работает.
cd(unzipFolderLocation); system(runCommand);
Приложение можно развернуть на другой машине, скопировав исполняемый файл и файлы библиотеки.
isPublishing = ~isempty(snapnow('get')); if ~isPublishing % skip printing out directory to html page fprintf('Executable and library files are located in the following folder:\n%s\n', unzipFolderLocation); fprintf('To re-execute run the following commands:\n'); fprintf('1. cd(''%s'')\n', unzipFolderLocation); fprintf('2. system(''%s'')\n', runCommand); end
% Configure coder to create executable. Use packNGo at post code % generation stage. function codegenArgs = createCodegenArgs(folderForMainC) % Create arguments required for code generation. % For standalone executable a main C function is required. The main.c % created for this example is compatible with the content of the file % visionFaceTrackingKLTpackNGo_kernel.m mainCFile = fullfile(folderForMainC,'main.c'); % Handle path with space if contains(mainCFile, ' ') mainCFile = ['"' mainCFile '"']; end cfg = coder.config('exe'); cfg.PostCodeGenCommand = 'packNGo(buildInfo,''packType'',''hierarchical'');'; cfg.CustomSource = mainCFile; cfg.CustomInclude = folderForMainC; cfg.EnableOpenMP = false; codegenArgs = {'-config', cfg}; end % Create a folder and unzip the packNGo content into it. function unzipFolderLocation = unzipPackageContents(zipFileLocation) % Unzip the packaged zip file. unzipFolderLocationName = 'unzipPackNGo'; mkdir(unzipFolderLocationName); % Get the name of the zip file generated by packNGo. zipFile = dir('*.zip'); assert(numel(zipFile)==1); unzip(zipFile.name,unzipFolderLocationName); % Unzip internal zip files created in hierarchical packNGo. zipFileInternal = dir(fullfile(unzipFolderLocationName,'*.zip')); assert(numel(zipFileInternal)==3); for i=1:numel(zipFileInternal) unzip(fullfile(unzipFolderLocationName,zipFileInternal(i).name), ... unzipFolderLocationName); end unzipFolderLocation = fullfile(zipFileLocation,unzipFolderLocationName); end % Create platform dependent makefile from template makefile. Use % buildInfo to get info about toolchain. function makefileName = createMakeFile(visiondemo_dir, unzipFolderLocation, fname) % Create Makefile from buildInfo. binfo = load(fullfile(pwd, 'codegen', 'exe', fname, 'buildInfo.mat')); lastDir = cd(unzipFolderLocation); dirCleanup = onCleanup(@()cd(lastDir)); % Get the root directory that contains toolbox/vision sub-directories matlabDirName = getRootDirName(unzipFolderLocation); % Get defines horzcat_with_space = @(cellval)sprintf('%s ',cellval{:}); defs = horzcat_with_space(getDefines(binfo.buildInfo)); % Get source file list if ispc [~, cFiles] = system(['dir /s/b ' '*.c']); [~, cppFiles] = system(['dir /s/b ' '*.cpp']); else [~, cFiles] = system(['find ./ ' '-name ' '''*.c''']); [~, cppFiles] = system(['find ./ ' '-name ' '''*.cpp''']); end cIndx = strfind(cFiles, '.c'); cppIndx = strfind(cppFiles, '.cpp'); srcFilesC = []; srcFilesCPP = []; for i = 1:length(cIndx) if i == 1 startIdx = 1; endIdx = cIndx(i); else startIdx = cIndx(i-1)+1; endIdx = cIndx(i); end [~, b, ~] = fileparts(cFiles(startIdx:endIdx)); srcFilesC = [srcFilesC ' ' b '.c']; %#ok<AGROW> end for i = 1:length(cppIndx) if i == 1 startIdx = 1; endIdx = cppIndx(i); else startIdx = cppIndx(i-1)+1; endIdx = cppIndx(i); end [~, b, ~] = fileparts(cppFiles(startIdx:endIdx)); srcFilesCPP = [srcFilesCPP ' ' b '.cpp']; %#ok<AGROW> end srcFiles = [srcFilesC ' ' srcFilesCPP]; % Get platform dependent names if isunix % both mac and linux tmf = 'TemplateMakefilePackNGo_unix'; if ismac archDir = 'maci64'; dllExt = 'dylib'; else archDir = 'glnxa64'; dllExt = 'so'; end else tmf = 'TemplateMakefilePackNGo_win'; archDir = 'win64'; dllExt = 'dll'; end % Now that we have defines, lets create a platform dependent makefile % from template. fid = fopen(fullfile(visiondemo_dir,tmf)); filecontent = char(fread(fid)'); fclose(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); if isunix if( ismac ) [status,sysHeaderPath] = system( 'xcode-select -print-path' ); assert(status==0, ['Could not obtain a path to the system ' ... 'header files using ''xcode-select -print-path''' '']); [status,sdkPaths] = system( [ 'find ' deblank( sysHeaderPath ) ... ' -name ''MacOSX*.sdk''' ] ); assert(status==0, 'Could not find MacOSX sdk' ); % There might be multiple SDK's sdkPathCell = strsplit(sdkPaths,'\n'); for idx = 1:numel(sdkPathCell) if ~isempty(sdkPathCell{idx}) % Pick the first one that's not empty. sdkPath = sdkPathCell{idx}; fprintf('Choosing SDK in %s\n',sdkPath); break; end end assert(~isempty(sdkPath), ... sprintf('There is no sdk available in %s. Please check system environment.\n',sysHeaderPath)); ccCMD = [ 'xcrun clang -isysroot ' deblank( sdkPath ) ]; cppCMD = [ 'xcrun clang++ -isysroot ' deblank( sdkPath ) ]; else ccCMD = 'gcc'; cppCMD = 'g++'; end newfilecontent = regexprep(newfilecontent,'PASTE_CC',ccCMD); newfilecontent = regexprep(newfilecontent,'PASTE_CPP',cppCMD); end fid = fopen(mk_name,'w+'); fprintf(fid,'%s',newfilecontent); fclose(fid); end % Create platform specific commands needed to build the executable and % to run it. function [buildCommand, runCommand] = createBuildAndRunCommands( ... packageLocation,unzipFolderLocation,makefileName,fileName) % Create the build and run command. if ismac buildCommand = [' xcrun make -f ' makefileName]; runCommand = ['./' fileName ' "' fileName '"']; elseif isunix buildCommand = [' make -f ' makefileName]; runCommand = ['./' fileName ' "' fileName '"']; else % On PC we use the generated BAT files (there should be 2) to help % build the generated code. These files are copied to the % unzipFolderLocation where we can use them to build. batFilename = [fileName '_rtw.bat']; batFilelocation = fullfile(packageLocation,'codegen', ... filesep,'exe',filesep,fileName); batFileDestination = unzipFolderLocation; % For MSVC, also copy 'setup_msvc.bat' fid = fopen(fullfile(batFilelocation, batFilename)); batFileContent = fread(fid, '*char'); fclose(fid); if ~isempty(regexp(convertCharsToStrings(batFileContent), 'setup_msvc.bat', 'once')) setup_msvc_batFile = fullfile(batFilelocation, 'setup_msvc.bat'); copyfile(setup_msvc_batFile, batFileDestination); end % Copy it to packNGo output directory. copyfile(fullfile(batFilelocation,batFilename),batFileDestination); % The Makefile we created is named 'Makefile', whereas the Batch % file refers to <filename>_rtw.mk. Hence we rename the file. newMakefileName = [fileName '_rtw.mk']; oldMakefilename = makefileName; copyfile(fullfile(batFileDestination,oldMakefilename),... fullfile(batFileDestination,newMakefileName)); buildCommand = batFilename; runCommand = [fileName '.exe' ' "' fileName '"']; end end % Build the executable with the build command. function buildExecutable(unzipFolderLocation, buildCommand) % Call system command to build the executable. lastDir = cd(unzipFolderLocation); dirCleanup = onCleanup(@()cd(lastDir)); [hadError, sysResults] = system(buildCommand); if hadError error (sysResults); end end % Get the root directory that contains toolbox/vision sub-directories function matlabDirName = getRootDirName(unzipFolderName) dirLists = dir(unzipFolderName); dirLists = dirLists(~ismember({dirLists.name},{'.','..'})); matlabDirName=''; for ij=1:length(dirLists) thisDirName = dirLists(ij).name; if (isfolder(thisDirName)) % subdirectory will have toolbox/vision [subDir1, hasSubDir1] = hasSubdirectory(thisDirName, 'toolbox'); if hasSubDir1 [~, hasSubDir2] = hasSubdirectory(subDir1, 'vision'); if hasSubDir2 matlabDirName = thisDirName; break; end end end end end % Find the directory that contains the specified sub-directory function [subDir, hasSubDir] = hasSubdirectory(dirName, subDirName) dirLists = dir(dirName); dirLists = dirLists(~ismember({dirLists.name},{'.','..'})); subDir = ''; hasSubDir = false; for ij=1:length(dirLists) thisDirName = dirLists(ij).name; thisDir = fullfile(dirName,thisDirName); if (isfolder(thisDir) && strcmp(thisDirName, subDirName)) hasSubDir = true; subDir = thisDir; break; end end end
end