00001 /*! 00002 @file Matlab/MatAPI.C 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.C $ 00037 // $Id: MatAPI.C 10794 2009-02-08 06:21:09Z itti $ 00038 // 00039 00040 //------------------------------ HEADERS -------------------------------- 00041 00042 // Matlab API header 00043 #include "Matlab/MatAPI.H" 00044 00045 // INVT headers 00046 00047 // Standard C++ headers 00048 #include <sstream> 00049 #include <algorithm> 00050 #include <iterator> 00051 00052 //----------------------- NAMESPACE DEFINITION -------------------------- 00053 00054 // Encapsulate this API within its own namespace 00055 namespace Matlab { 00056 00057 //--------------------------- MATLAB ARRAYS ----------------------------- 00058 00059 // Matlab stores matrices internally in flat 1-dimensional arrays using 00060 // column major ordering. Thus, to copy an entire row into an mxArray, we 00061 // start off at the appropriate offset from the start of the internal 00062 // data array and increment by the number of rows. 00063 // 00064 // Here is an illustrative example: let us say we want to append rows to 00065 // a 4x3 matrix. The first row will be in array indices 0, 4, 8; the 00066 // next row will occupy indices 1, 5, 9; and so on. 00067 // 00068 // The Matrix::mx_data_ptr inner class implements an iterator (for use 00069 // with STL algorithms) that starts off pointing at the first array 00070 // element of the "current" row in the mxArray, i.e., the row number the 00071 // push_back() function will fill, and then increments this pointer by 00072 // the number of rows in the matrix to get at the array element that will 00073 // store the next value of the matrix's row. 00074 Matrix::mx_data_ptr::mx_data_ptr(const Matrix& M) 00075 : p(mxGetPr(M.mat_array) + M.current_row), n(M.num_rows) 00076 {} 00077 00078 // Create an mxn matrix of real numbers with all elements initialized to 00079 // zero. 00080 Matrix::Matrix(int m, int n) 00081 : num_rows(m), num_cols(n), 00082 mat_array(mxCreateDoubleMatrix(m, n, mxREAL)), 00083 current_row(0), 00084 ref_count(1) 00085 { 00086 if (! mat_array) 00087 throw std::runtime_error("unable to create matrix") ; 00088 } 00089 00090 // Wrap a preexisting mxArray pointer into a Matrix object. This 00091 // pointer must actually reference an already initialized mxArray (i.e., 00092 // not an empty matrix). 00093 // 00094 // WARNING: Once the pointer is handed over to an instance of this class, 00095 // it should not be used directly thereafter (and especially not deleted 00096 // or destroyed with the mxDestroyArray() function). 00097 Matrix::Matrix(mxArray* A) 00098 : num_rows(mxGetM(A)), num_cols(mxGetN(A)), 00099 mat_array(A), 00100 current_row(num_rows), // cannot modify matrix! 00101 ref_count(1) 00102 {} 00103 00104 // Object copy 00105 // 00106 // WARNING: Only meant for use with temporaries (i.e., function 00107 // parameters and return values). Any use more sophisticated than this 00108 // will mess up the ref-counting. See ref-counting notes in comment 00109 // preceding class definition. 00110 Matrix::Matrix(const Matrix& M) 00111 : num_rows(M.num_rows), num_cols(M.num_cols), 00112 mat_array(M.mat_array), 00113 current_row(M.current_row), 00114 ref_count(M.ref_count + 1) 00115 {} 00116 00117 // Clean-up 00118 Matrix::~Matrix() 00119 { 00120 if (--ref_count == 0) 00121 mxDestroyArray(mat_array) ; 00122 } 00123 00124 // Append a given row of numbers to the matrix 00125 void Matrix::push_back(const std::vector<double>& row) 00126 { 00127 if (row.size() != num_cols) 00128 throw std::runtime_error("cannot append row of different size") ; 00129 if (current_row >= num_rows) 00130 throw std::runtime_error("cannot append any more rows") ; 00131 00132 std::copy(row.begin(), row.end(), mx_data_ptr(*this)) ; 00133 ++current_row ; 00134 } 00135 00136 //--------------------------- MATLAB ENGINE ----------------------------- 00137 00138 // Matlab engine initialization and setup for Netlab toolbox 00139 Engine::Engine(const std::string& netlab_path) 00140 : mat_engine(engOpen("matlab -nosplash -nojvm")) 00141 { 00142 if (! mat_engine) 00143 throw std::runtime_error("unable to start Matlab engine") ; 00144 00145 exec("addpath '" + netlab_path + "'") ; 00146 } 00147 00148 // Getting and sending matrices from/to Matlab engine 00149 Matrix Engine::get(const std::string& var_name) 00150 { 00151 mxArray* M = engGetVariable(mat_engine, var_name.c_str()) ; 00152 if (! M) 00153 throw std::runtime_error("unable to retrieve variable " 00154 + var_name + " from Matlab engine") ; 00155 return M ; 00156 } 00157 00158 void Engine::put(const std::string& var_name, const Matrix& M) 00159 { 00160 if (engPutVariable(mat_engine, var_name.c_str(), M)) 00161 throw std::runtime_error("unable to send variable " + var_name + 00162 " to Matlab engine") ; 00163 } 00164 00165 // Getting the Matlab engine to do our bidding 00166 void Engine::exec(const std::string& cmd) 00167 { 00168 if (engEvalString(mat_engine, cmd.c_str())) 00169 throw std::runtime_error("Matlab engine could not eval: " + cmd) ; 00170 } 00171 00172 // Shutting down the Matlab engine 00173 Engine::~Engine() 00174 { 00175 engClose(mat_engine) ; 00176 } 00177 00178 //---------------------------- MATLAB FILE ------------------------------ 00179 00180 // Initialization 00181 File::File(const std::string& file_name, const std::string& mode) 00182 : mat_file(matOpen(file_name.c_str(), mode.c_str())) 00183 { 00184 if (! mat_file) 00185 throw std::runtime_error("unable to open " + file_name) ; 00186 } 00187 00188 // Reading data from the .mat file 00189 Matrix File::get(const std::string& var_name) 00190 { 00191 mxArray* M = matGetVariable(mat_file, var_name.c_str()) ; 00192 if (! M) 00193 throw std::runtime_error("no variable named " + var_name) ; 00194 return M ; 00195 } 00196 00197 // Writing data to the .mat file 00198 void File::put(const std::string& var_name, const Matrix& matrix) 00199 { 00200 matPutVariable(mat_file, var_name.c_str(), matrix) ; 00201 } 00202 00203 // Clean-up 00204 File::~File() 00205 { 00206 matClose(mat_file) ; 00207 } 00208 00209 // Output operator for writing textons to a File instance 00210 File& operator<<(File& f, const FileData& d) 00211 { 00212 f.put(d.first, d.second) ; 00213 return f ; 00214 } 00215 00216 //----------------------------------------------------------------------- 00217 00218 } // end of namespace encapsulating this file 00219 00220 /* So things look consistent in everyone's emacs... */ 00221 /* Local Variables: */ 00222 /* indent-tabs-mode: nil */ 00223 /* End: */