1 #ifndef CAIR_CML_H 2 #define CAIR_CML_H 3 4 //=========================================================================================================// 5 //CAIR Matrix Library 6 //Copyright (C) 2009 Joseph Auman (brain.recall@gmail.com) 7 8 //=========================================================================================================// 9 //This library is free software; you can redistribute it and/or 10 //modify it under the terms of the GNU Lesser General Public 11 //License as published by the Free Software Foundation; either 12 //version 2.1 of the License, or (at your option) any later version. 13 //This library is distributed in the hope that it will be useful, 14 //but WITHOUT ANY WARRANTY; without even the implied warranty of 15 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 //Lesser General Public License for more details. 17 //You should have received a copy of the GNU Lesser General Public 18 //License along with this library; if not, write to the Free Software 19 //Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 21 //=========================================================================================================// 22 //This class will be used to handle and manage all matrix types used in CAIR. 23 //For grayscale images, use the type CML_gray. 24 //For standard color images, use the type CML_color. 25 //For energy, edges, and weights, use the type CML_int. 26 //This class is used to replace and consolidate the several types I had prevously maintained separately. 27 28 //Note for developers: Unfortunately, this class means that a separate translation function will need 29 // to be written to translate from whatever internal image object to the CML_Matrix. This will keep CAIR 30 // more flexible, but adds another small step. 31 //=========================================================================================================// 32 33 #include <cstring> //for memcpy(), memmove() 34 #include <cstdlib> //for realloc() 35 36 //CML_DEBUG will print out information to the console window when CAIR tries 37 // to step out-of-bounds of the matrix. For development purposes. 38 //#define CML_DEBUG 39 #ifdef CML_DEBUG 40 #include <iostream> 41 #endif 42 43 //=========================================================================================================// 44 template <typename T> 45 class CML_Matrix 46 { 47 public: 48 //=========================================================================================================// 49 //Simple constructor. CML_Matrix(int x,int y)50 CML_Matrix( int x, int y ) 51 { 52 Allocate_Matrix( x, y ); 53 current_x = x; 54 current_y = y; 55 max_x = x; 56 max_y = y; 57 } 58 //=========================================================================================================// 59 //Simple destructor. ~CML_Matrix()60 ~CML_Matrix() 61 { 62 Deallocate_Matrix(); 63 } 64 65 //=========================================================================================================// 66 //Assignment operator; not really fast, but it works reasonably well. 67 //Does not copy Reserve()'ed memory. 68 CML_Matrix& operator= ( const CML_Matrix& input ) 69 { 70 if( this == &input ) //self-assignment check 71 { 72 return *this; 73 } 74 Deallocate_Matrix(); 75 Allocate_Matrix( input.current_x, input.current_y ); 76 current_x = input.current_x; 77 current_y = input.current_y; 78 max_x = current_x; 79 max_y = current_y; 80 81 for( int y = 0; y < current_y; y++ ) 82 { 83 //ahh, memcpy(), how I love thee 84 std::memcpy( &(matrix[y][0]), &(input.matrix[y][0]), current_x*sizeof(T) ); 85 } 86 return *this; 87 } 88 89 //=========================================================================================================// 90 //Set all values. 91 //This is important to do since the memory is not set a value after it is allocated. 92 //Make sure to do this for the weights. Fill(T value)93 void Fill( T value ) 94 { 95 for( int y = 0; y < CML_Matrix::Height(); y++ ) 96 { 97 for( int x = 0; x < CML_Matrix::Width(); x++ ) 98 { 99 matrix[y][x] = value; //remember, ROW MAJOR 100 } 101 } 102 } 103 104 //=========================================================================================================// 105 //For the access/assignment () calls. operator()106 inline T& operator()( int x, int y ) 107 { 108 #ifdef CML_DEBUG 109 if( x<0 || x>=current_x || y<0 || y>=current_y ) 110 { 111 std::cout << "CML_DEBUG: " << x << "," << y << std::endl; 112 std::cout << "current_x=" << current_x << " current_y=" << current_y << std::endl; 113 } 114 #endif 115 return matrix[y][x]; //remember, ROW MAJOR 116 } 117 118 //Returns the current image Width. Width()119 inline int Width() 120 { 121 return current_x; 122 } 123 124 //Returns the current image Height. Height()125 inline int Height() 126 { 127 return current_y; 128 } 129 130 //=========================================================================================================// 131 //Does a flip/rotate on Source and stores it into ourself. Transpose(CML_Matrix<T> * Source)132 void Transpose( CML_Matrix<T> * Source ) 133 { 134 CML_Matrix::D_Resize( (*Source).Height(), (*Source).Width() ); 135 136 for( int y = 0; y < (*Source).Height(); y++ ) 137 { 138 for( int x = 0; x < (*Source).Width(); x++ ) 139 { 140 matrix[x][y] = (*Source)(x,y); //remember, ROW MAJOR 141 } 142 } 143 } 144 145 //=========================================================================================================// 146 //Mimics the EasyBMP () operation, by constraining an out-of-bounds value back into the matrix. Get(int x,int y)147 inline T Get( int x, int y ) 148 { 149 if( x < 0 ) 150 { 151 x = 0; 152 } 153 else if( x >= current_x ) 154 { 155 x = current_x - 1; 156 } 157 if( y < 0 ) 158 { 159 y = 0; 160 } 161 else if( y >= current_y ) 162 { 163 y = current_y - 1; 164 } 165 return matrix[y][x]; //remember, ROW MAJOR 166 } 167 168 //=========================================================================================================// 169 //Destructive resize of the matrix. D_Resize(int x,int y)170 void D_Resize( int x, int y ) 171 { 172 Deallocate_Matrix(); 173 Allocate_Matrix( x, y ); 174 current_x = x; 175 current_y = y; 176 max_x = x; 177 max_y = y; 178 } 179 180 //=========================================================================================================// 181 //Non-destructive resize, but only in the x direction. 182 //Enlarging requires memory to be Reserve()'ed beforehand, for speed reasons. Resize_Width(int x)183 void Resize_Width( int x ) 184 { 185 if( x > max_x ) 186 { 187 //a graceful, slow, way to handle when someone screws up 188 for( int i = 0; i < current_y; i++ ) 189 { 190 matrix[i] = (T*)std::realloc( matrix[i], x*sizeof(T) ); 191 } 192 max_x = x; 193 } 194 current_x = x; 195 } 196 197 //=========================================================================================================// 198 //Destructive memory reservation for the internal matrix. 199 //The reported size of the image does not change. Reserve(int x,int y)200 void Reserve( int x, int y ) 201 { 202 Deallocate_Matrix(); 203 Allocate_Matrix( x, y ); 204 205 max_x = x; 206 max_y = y; 207 //current_x and y didn't change 208 } 209 210 //=========================================================================================================// 211 //Shift a row where the first element in the shift is supplied as x,y. 212 //The amount/direction of the shift is supplied in shift. 213 //Negative will shift left, positive right. Shift_Row(int x,int y,int shift)214 void Shift_Row( int x, int y, int shift ) 215 { 216 //Pretty much all of this stuff is really delicate, so don't touch it, unless you REALLY like to corrupt the heap... 217 218 //special case when we don't want any shifting to occur 219 if( (x >= current_x) && (shift<0) ) 220 return; 221 222 //bounds check the input since it's really important 223 if( x < 0 ) 224 { 225 x = 0; 226 } 227 else if( x >= current_x ) 228 { 229 x = current_x - 1; 230 } 231 if( y < 0 ) 232 { 233 y = 0; 234 } 235 else if( y >= current_y ) 236 { 237 y = current_y - 1; 238 } 239 240 //calculate and bounds check the destination x 241 int x_shift = x + shift; 242 if( x_shift < 0 ) 243 { 244 x_shift = 0; 245 } 246 else if( x_shift >= current_x ) 247 { 248 x_shift = current_x - 1; 249 } 250 251 //calculate how many elements to move 252 int shift_amount = current_x - x; 253 //keep us from shifting off the edge when shifting right 254 if( shift > 0 ) 255 { 256 shift_amount -= shift; 257 } 258 259 //memmove because this WILL overlap 260 std::memmove( &(matrix[y][x_shift]), &(matrix[y][x]), shift_amount*sizeof(T) ); 261 } 262 263 private: 264 //=========================================================================================================// 265 //Simple row-major 2D allocation algorithm. 266 //The size variables must be assigned seperately. Allocate_Matrix(int x,int y)267 void Allocate_Matrix( int x, int y ) 268 { 269 matrix = new T*[y]; 270 271 for( int i = 0; i < y; i++ ) 272 { 273 matrix[i] = new T[x]; 274 } 275 } 276 //Simple row-major 2D deallocation algorithm. 277 //Doest not maintain size variables. Deallocate_Matrix()278 void Deallocate_Matrix() 279 { 280 for( int i = 0; i < max_y; i++ ) 281 { 282 delete[] matrix[i]; 283 } 284 285 delete[] matrix; 286 } 287 288 T ** matrix; 289 int current_x; 290 int current_y; 291 int max_x; 292 int max_y; 293 }; 294 295 296 //=========================================================================================================// 297 typedef unsigned char CML_byte; 298 299 //standard 32 bit pixel 300 struct CML_RGBA 301 { 302 CML_byte red; 303 CML_byte green; 304 CML_byte blue; 305 CML_byte alpha; 306 }; 307 308 typedef CML_Matrix<CML_RGBA> CML_color; //use for images 309 typedef CML_Matrix<int> CML_int; //use for weights 310 311 #endif //CAIR_CML_H 312