00001 /*! 00002 @file Matlab/MatAPI.H some basic wrappers for the Matlab API 00003 */ 00004 00005 // //////////////////////////////////////////////////////////////////// // 00006 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00007 // University of Southern California (USC) and the iLab at USC. // 00008 // See http://iLab.usc.edu for information about this project. // 00009 // //////////////////////////////////////////////////////////////////// // 00010 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00011 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00012 // in Visual Environments, and Applications'' by Christof Koch and // 00013 // Laurent Itti, California Institute of Technology, 2001 (patent // 00014 // pending; application number 09/912,225 filed July 23, 2001; see // 00015 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00016 // //////////////////////////////////////////////////////////////////// // 00017 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00018 // // 00019 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00020 // redistribute it and/or modify it under the terms of the GNU General // 00021 // Public License as published by the Free Software Foundation; either // 00022 // version 2 of the License, or (at your option) any later version. // 00023 // // 00024 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00025 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00026 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00027 // PURPOSE. See the GNU General Public License for more details. // 00028 // // 00029 // You should have received a copy of the GNU General Public License // 00030 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00031 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00032 // Boston, MA 02111-1307 USA. // 00033 // //////////////////////////////////////////////////////////////////// // 00034 // 00035 // Primary maintainer for this file: Manu Viswanathan <mviswana at usc dot edu> 00036 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Matlab/MatAPI.H $ 00037 // $Id: MatAPI.H 10794 2009-02-08 06:21:09Z itti $ 00038 // 00039 00040 #ifndef MATLAB_MATAPI_H_DEFINED 00041 #define MATLAB_MATAPI_H_DEFINED 00042 00043 //------------------------------ HEADERS -------------------------------- 00044 00045 // INVT headers 00046 #include "Image/Image.H" 00047 00048 // Matlab headers 00049 #ifdef MATLAB_LIBS_AVAILABLE // should be made available by configure system 00050 00051 #include <engine.h> 00052 #include <mat.h> 00053 00054 #else // use dummies to NOP out Matlab types and functions 00055 00056 // Use dummies for various Matlab types and functions. Otherwise, builds 00057 // will break! 00058 // 00059 // DEVNOTE: Although this module and others dependent on it will build 00060 // okay with these dummies, runtime errors will prevent any dependent 00061 // programs from executing smoothly. thus, it may be a good idea to check 00062 // the MATLAB_LIBS_AVAILABLE preprocessor symbol in those modules as well 00063 // and do something appropriate in case the Matlab headers and libraries 00064 // are not available (e.g., have main() print a message stating that it 00065 // needs this API rather than allow it to blithely proceed and then 00066 // crash shortly thereafter with some inscrutable complaint about null 00067 // pointers or some such thing). 00068 #define mxREAL 0 00069 00070 typedef double mxArray ; 00071 typedef double Engine ; 00072 typedef double MATFile ; 00073 00074 inline mxArray* mxCreateDoubleMatrix(int, int, int) {return 0 ;} 00075 inline void mxDestroyArray(mxArray*) {} 00076 inline double* mxGetPr(mxArray*) {return 0;} 00077 inline unsigned mxGetM(mxArray*) {return 0;} 00078 inline unsigned mxGetN(mxArray*) {return 0;} 00079 00080 inline Engine* engOpen(const char*) {return 0 ;} 00081 inline mxArray* engGetVariable(Engine*, const char*) {return 0 ;} 00082 inline int engPutVariable(Engine*, const char*, const mxArray*) {return 1 ;} 00083 inline int engEvalString(Engine*, const char*) {return 1 ;} 00084 inline void engClose(Engine*) {} 00085 00086 inline MATFile* matOpen(const char*, const char*) {return 0 ;} 00087 inline mxArray* matGetVariable(MATFile*, const char*) {return 0 ;} 00088 inline void matPutVariable(MATFile*, const char*, const mxArray*) {} 00089 inline void matClose(MATFile*) {} 00090 00091 #endif // MATLAB_LIBS_AVAILABLE 00092 00093 // Standard C++ headers 00094 #include <stdexcept> 00095 #include <vector> 00096 #include <iterator> 00097 #include <utility> 00098 00099 //----------------------- NAMESPACE DEFINITION -------------------------- 00100 00101 // Encapsulate this API within its own namespace 00102 namespace Matlab { 00103 00104 //--------------------------- MATLAB ARRAYS ----------------------------- 00105 00106 // Quick helper to encapsulate the necessary portions of the Matlab 00107 // mxArray API. 00108 // 00109 // DEVNOTE: REFERENCE COUNTING HACK 00110 // 00111 // This class implements a VERY BAD reference counting mechanism. It is 00112 // only meant to be used for taking care of copying of temporaries, e.g., 00113 // when passing parameters to functions or getting back return values. 00114 // Taking advantage of this mechanism for anything more sophisticated can 00115 // only lead to trouble... To help prevent some of the pathologies 00116 // associated with this hacked up ref-counting, assignment and creation 00117 // of MatArrays on the heap are disabled. 00118 // 00119 // We could (and probably should) have used nub::ref_counted over here. 00120 // But it seemed a bit heavy-duty. But more importantly, the author was 00121 // unable to quickly locate documentation with a tutorial nature that 00122 // could have helped figure out how to use it in less than ten minutes. 00123 // Thus this monstrosity. When time permits, this class should be 00124 // revamped and made more generally useful (to ease interfacing with 00125 // Matlab from inside of C++). 00126 class Matrix { 00127 unsigned int num_rows, num_cols ; 00128 mxArray* mat_array; 00129 unsigned int current_row ; 00130 int ref_count ; // WARNING: MAJOR HACK! SEE COMMENT ABOVE. 00131 00132 // Disable assignment and creation on the heap as they can be 00133 // hazardous to the hackish reference counting mechanism implemented 00134 // herein. 00135 Matrix& operator=(const Matrix&) ; 00136 void* operator new(size_t) ; 00137 00138 // Quick-and-dirty output iterator for accessing mxArray in 00139 // column-major order (that's how Matlab arrays are stored). 00140 class mx_data_ptr { 00141 mutable double* p ; // current element being pointed to 00142 int n ; // increment value for p (equals num_rows in matrix) 00143 public : 00144 mx_data_ptr(const Matrix&) ; 00145 mx_data_ptr& operator++() throw() { 00146 p += n ; return *this ; 00147 } 00148 const mx_data_ptr& operator++() const throw() { 00149 p += n ; return *this ; 00150 } 00151 mx_data_ptr operator++(int) throw() { // post-increment 00152 mx_data_ptr prev(*this) ; ++*this ; return prev ; 00153 } 00154 const mx_data_ptr operator++(int) const throw() { 00155 mx_data_ptr prev(*this) ; ++*this ; return prev ; 00156 } 00157 double& operator*() throw() {return *p ;} 00158 const double& operator*() const throw() {return *p ;} 00159 00160 // Need to define these types for STL compatibility 00161 typedef std::output_iterator_tag iterator_category ; 00162 typedef double value_type ; 00163 typedef int difference_type ; 00164 typedef double* pointer ; 00165 typedef double& reference ; 00166 } ; // end of inner class mx_data_ptr 00167 00168 public : 00169 Matrix(int m, int n) ; 00170 Matrix(mxArray* M) ; 00171 template<typename T> Matrix(const Image<T>&) ; 00172 Matrix(const Matrix& M) ; // copy okay, but see ref counting notes above 00173 ~Matrix() ; 00174 00175 void push_back(const std::vector<double>& row) ; 00176 00177 operator const mxArray*() const {return mat_array ;} // conversion operator 00178 template<typename T> Image<T> to_image() const ; // explicit "conv.op" 00179 } ; 00180 00181 // Initialize an mxArray using an Image<T> 00182 template<typename T> 00183 Matrix::Matrix(const Image<T>& I) 00184 : num_rows(I.getHeight()), num_cols(I.getWidth()), 00185 mat_array(mxCreateDoubleMatrix(num_rows, num_cols, mxREAL)), 00186 current_row(num_rows), // cannot modify this particular matrix! 00187 ref_count(1) 00188 { 00189 if (! mat_array) 00190 throw std::runtime_error("unable to create matrix") ; 00191 00192 double* p = mxGetPr(mat_array) ; 00193 for (uint x = 0; x < num_cols; ++x) 00194 for (uint y = 0; y < num_rows; ++y, ++p) 00195 *p = I.getVal(x, y) ; // column major order 00196 } 00197 00198 // Convert an mxArray to an Image<T> 00199 template<typename T> 00200 Image<T> Matrix::to_image() const 00201 { 00202 Image<T> I(num_cols, num_rows, NO_INIT) ; 00203 00204 const double* p = mxGetPr(mat_array) ; 00205 for (uint x = 0; x < num_cols; ++x) 00206 for (uint y = 0; y < num_rows; ++y, ++p) 00207 I.setVal(x, y, static_cast<T>(*p)) ; // column major order 00208 00209 return I ; 00210 } 00211 00212 //--------------------------- MATLAB ENGINE ----------------------------- 00213 00214 // Renninger-Malik used the Netlab toolbox's K-means implementation to 00215 // compute the universal textons of the training set. We do the same 00216 // thing. But rather than fire up Matlab separately and hand it the 00217 // training textons via a .mat file, we simply start the Matlab engine 00218 // from inside of C++ and pass it the training textons matrix directly. 00219 // Once the K-means is done, we obtain the universal textons matrix from 00220 // the engine before shutting it down. 00221 // 00222 // The following class provides a quick wrapper around the Matlab engine 00223 // API. 00224 typedef Engine MatEngine ; 00225 class Engine { 00226 MatEngine* mat_engine ; 00227 public : 00228 Engine(const std::string& netlab_path) ; 00229 Matrix get(const std::string& variable_name) ; 00230 void put(const std::string& variable_name, const Matrix&) ; 00231 void exec(const std::string& command) ; 00232 ~Engine() ; 00233 } ; 00234 00235 //---------------------------- MATLAB FILE ------------------------------ 00236 00237 // The following class encapsulates a small portion of the Matlab file 00238 // API to help with the task of writing the training set's universal 00239 // textons to a .mat file. 00240 class File { 00241 MATFile* mat_file ; 00242 public : 00243 File(const std::string& file_name, const std::string& open_mode) ; 00244 Matrix get(const std::string& variable_name) ; 00245 void put(const std::string& variable_name, const Matrix& matrix) ; 00246 ~File() ; 00247 } ; 00248 00249 // To put some data into a Matlab file, we need a variable name and an 00250 // mxArray containing the data. 00251 typedef std::pair<std::string, Matrix> FileData ; 00252 00253 // Output operator for writing matrices to a Matlab file 00254 File& operator<<(File& f, const FileData& d) ; 00255 00256 //----------------------------------------------------------------------- 00257 00258 } // end of namespace encapsulating this file 00259 00260 /* So things look consistent in everyone's emacs... */ 00261 /* Local Variables: */ 00262 /* indent-tabs-mode: nil */ 00263 /* End: */ 00264 00265 #endif