exponenta event banner

Создание кода для отслеживания лица с помощью PackNGo

В этом примере показано, как генерировать код из команды Face Detection and Tracking Using the KLT Algorithm с помощью функции packNGo. packNGo Функция (MATLAB Coder) упаковывает все соответствующие файлы в сжатый zip-файл, чтобы можно было переместить, распаковать и перестроить проект в другой среде разработки без использования MATLAB. В этом примере также показано, как создать makefile для содержимого packNGo, перестроить исходные файлы и, наконец, запустить автономный исполняемый файл вне среды MATLAB.

В этом примере требуется лицензия MATLAB ® Coder™.

Этот пример является функцией с основным корпусом в верхней части и вспомогательными подпрограммами в виде вложенных функций ниже.

function FaceTrackingKLTpackNGoExample()

Настройка компилятора C++

Для выполнения этого примера необходимо иметь доступ к компилятору C++ и настроить его с помощью команды «mex -setup c++». Дополнительные сведения см. в разделе Выбор компилятора C++. При развертывании приложения на сервере MATLAB используйте компилятор C++, совместимый с компилятором, используемым для построения библиотек OpenCV. Дополнительные сведения см. в разделе Создание кода Portable C для функций, использующих библиотеку OpenCV.

Разбейте вычислительную часть алгоритма на отдельную функцию MATLAB

Кодер MATLAB требует, чтобы код MATLAB имел форму функции для генерации кода C. Код основного алгоритма этого примера находится в функции, называемой 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));

Создание упакованного ZIP-файла

Вызовите команду 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). Команда post code generation с функцией 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