Skip to content

Technical programming notes

Ramón Casero edited this page Jul 10, 2016 · 4 revisions

Notes about reading vectors from Matlab into different types of C++ vector-like objects

(This section was spawned from this email sent to the gerardus-user mailing list)

Our MatlabImportFilter can read vectors as input parameters directly from Matlab, and pass them to ITK without intermediate steps. For example, in the itk::VotingBinaryIterativeHoleFillingImageFilter

https://github.com/vigente/gerardus/blob/master/matlab/ItkToolbox/ItkImFilter.cpp#L529

// The variance for the discrete Gaussian kernel. Sets the
// variance independently for each dimension. The default is 0.0
// in each dimension (ITK)
typename FilterType::ArrayType defVariance;
defVariance.Fill(0.0);
filter->SetVariance(matlabImport->
                 GetRowVectorArgument<typename FilterType::ArrayType::ValueType, 
                                         typename FilterType::ArrayType,
                                         VImageDimension>(2, "VAR", defVariance));

The method GetRowVectorArgument() is declared here

https://github.com/vigente/gerardus/blob/master/matlab/MatlabImportFilter.h#L239

Because we may want to read Matlab vectors into very different classes, e.g. itk::Size<Dimension> vs. CGAL::Direction_3<CGAL::Simple_cartesian<double> >, the definition of this method relies heavily on the idea of a vector wrapper,

https://github.com/vigente/gerardus/blob/master/matlab/MatlabImportFilter.hxx#L443

VectorWrapper<VectorValueType, VectorType, mxLogical, VectorSize> paramWrap;

That is, we have a class VectorWrapper that provides a common interface from Matlab to different sorts of vectors. For the moment, by default we assume that the output vector is

https://github.com/vigente/gerardus/blob/master/matlab/VectorWrapper.h#L75

std::vector

but we have partial specialisations to deal with

https://github.com/vigente/gerardus/blob/master/matlab/VectorWrapper.h#L118

itk::Size<Dimension>
itk::FixedArray<ValueType, Dimension>

https://github.com/vigente/gerardus/blob/master/matlab/VectorWrapper.h#L250

CGAL::Point_3<CGAL::Simple_cartesian<ValueType> >
CGAL::Direction_3<CGAL::Simple_cartesian<ValueType> >

For ITK this already covers quite a bit of possibilities, because many types get reduced to the two above. For example, the itk::BoxFilterType<...,...>::RadiusType used in the Median filter is actually an itk::FixedArray<double, Dimension>.

https://github.com/vigente/gerardus/blob/master/matlab/ItkToolbox/ItkImFilter.cpp#L816

Integrating the Boost C++ libraries with Gerardus

These are notes of what we did to get the Boost libraries code into Gerardus.

  1. Go to the Boost C++ Libraries and click on the current release link (1.53.0 at the time of this writing)

  2. Download the tarball with the whole project, e.g. boost_1_53_0.tar.bz2

  3. Extract boost_1_53_0 to gerardus/cpp/src/third-party. This takes up 456M, which is too much to distribute with Gerardus

  4. Change to the boost source code directory

     cd `gerardus/cpp/src/third-party/boost_1_53_0`
    
  5. Delete documentation, tests and examples to reduce the size to 144M

     find . -name test | xargs rm -rf
     find . -name doc | xargs rm -rf
     find . -name examples | xargs rm -rf
     find . -name example | xargs rm -rf
    
  6. Add and commit the boost source code to the gerardus repository

     cd ..
     svn add boost_1_53_0
     svn ci boost_1_53_0
    

Debugging problems with MEX functions in Windows

MEX files in Windows are DLLs that can link to other DLLs. Sometimes a MEX file may not run giving the error

Invalid MEX-file <mexfilename>:
The specified module could not be found.

As explained in Mathworks support page "Invalid MEX-File Error", in Windows one can install the program Dependency Walker, and run it within Matlab to figure out whether all DLLs the MEX file depends on are visible, e.g.

>> !"C:\Program Files\depends22_x64\depends.exe" ..\ItkToolbox\itk_imfilter.mexw64

To make a DLL visible, its has to be in the same directory as the MEX file, or it's directory has to be in the system path (which is different from the Matlab toolbox path). In Gerardus, we solve this problem in the script add_gerardus_paths.m with the code

%% System paths to DLLs for Windows
if ~isempty(strfind(getenv('OS'), 'Windows'))

% full paths to directories with DLLs
pathsToDlls = {cd(cd('..\lib')), cd(cd('..\lib\bin')), cd(cd('..\cpp\src\third-party\CGAL-4.2\auxiliary\gmp\lib'))};

% get system paths
systemPath = getenv('PATH');

    % add paths to directories with DLLs unless they are already in the
    % system path
    for I = 1:length(pathsToDlls)
        if isempty(strfind(lower(systemPath), lower(pathsToDlls{I})))
            disp(['Adding ' pathsToDlls{I} ' to system path'])
            systemPath = [pathsToDlls{I} ';' systemPath];
        end
    end
    setenv('PATH', systemPath);
end

This code searches the system path, and adds any DLL directory that is missing.