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