В этом примере показано, как сгенерировать код от Обнаружения Поверхности и Отслеживающий Используя пример Алгоритма KLT с функцией packNGo. packNGo
(MATLAB Coder) пакеты функции все соответствующие файлы в сжатом zip-файле, таким образом, можно переместить, распакуйте и восстановите проект в другой среде разработки без существующего MATLAB. Этот пример также показывает, как создать make-файл для packNGo содержимого, восстановить исходные файлы и наконец запустить независимый исполняемый файл вне среды MATLAB.
Этот пример требует лицензии MATLAB® Coder™.
Этим примером является функция с основной частью наверху и стандартными программами помощника в форме Вложенных функций ниже.
function FaceTrackingKLTpackNGoExample()
Чтобы запустить этот пример, у вас должен быть доступ к компилятору C++, и необходимо сконфигурировать его с помощью 'mex - устанавливают C++' команда. Для получения дополнительной информации смотрите, Выбирают C ++ Compiler. Если вы развертываете приложение на хосте MATLAB, используйте компилятор C++, который совместим с компилятором, используемым, чтобы создать библиотеки OpenCV. Для получения дополнительной информации смотрите Портативную генерацию кода C для Функций, Которые Пользуются Библиотекой 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). Используйте команду генерации кода сообщения с функцией 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' ....
Разработайте проект с помощью команды сборки.
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