00001 00033 #include <itpp/srccode/pnm.h> 00034 #include <itpp/base/itassert.h> 00035 #include <fstream> 00036 00037 using std::istream; 00038 using std::ostream; 00039 using std::endl; 00040 using std::string; 00041 using std::ifstream; 00042 using std::ofstream; 00043 using std::istringstream; 00044 using std::ios; 00045 using std::ios_base; 00046 using std::streampos; 00047 00048 00049 namespace itpp { 00050 00051 00052 // Suppress the additional white characters and return the comments 00053 static void pnm_read_comments( istream & i, string & comments ); 00054 00055 // Write comment in the image file 00056 static void pnm_write_comments( ostream & o, const string & comments ); 00057 00058 // Read/Write the header for the pnm file format 00059 static bool pnm_read_header(ifstream & file, char & pnm_type, 00060 int & width, int & height, int & max_val, 00061 string & comments, char pnm_type_required = '0' ); 00062 00063 static bool pnm_write_header(ofstream & file, char type, 00064 int width, int height, int max_val, 00065 const string & comments ); 00066 00067 00068 //-------------------------------------------------------------- 00069 // General PNM functions 00070 //-------------------------------------------------------------- 00071 char pnm_type( const string & filename ) 00072 { 00073 ifstream file; 00074 char pnm_type; 00075 00076 file.open( filename.c_str() ); 00077 00078 string comments; 00079 int width, height, max_val; 00080 pnm_read_header( file, pnm_type, width, height, max_val, comments ); 00081 00082 return pnm_type; 00083 } 00084 00085 00086 //-------------------------------------------------------------- 00087 bool pnm_info( const string & filename, char & pnm_type, 00088 int & width, int & height, int & max_val, 00089 string & comments ) 00090 { 00091 ifstream file; 00092 00093 file.open( filename.c_str() ); 00094 00095 pnm_read_header( file, pnm_type, width, height, max_val, comments ); 00096 00097 return true; 00098 } 00099 00100 00101 //-------------------------------------------------------------- 00102 // PGM related functions (gray images) 00103 //-------------------------------------------------------------- 00104 00105 bool pgm_read(const string & filename, 00106 imat & m, string & comments ) 00107 { 00108 ifstream file; 00109 int width, height, max_val, i, j; 00110 comments = ""; 00111 00112 file.open( filename.c_str() ); 00113 00114 // The format code is 'P5' for pgm files 00115 char pnm_type; 00116 if ( !pnm_read_header(file, pnm_type, width, height, max_val, comments, '5' ) ) 00117 return false; 00118 00119 // Format the returned matrix 00120 m.set_size( height, width, false ); 00121 00122 // Retrieve the integer value from the file 00123 for( i = 0 ; i<height; i++) 00124 for( j = 0; j<width; j++) 00125 m(i,j) = file.get(); 00126 00127 return true; 00128 } 00129 00130 00131 //-------------------------------------------------------------- 00132 // Simplified version of read_pgm 00133 imat pgm_read( const string & filename ) 00134 { 00135 imat I; 00136 string comments; 00137 if( !pgm_read( filename, I, comments) ) 00138 it_warning( "pgm_read (PGM file->imat) failed " ); 00139 00140 return I; 00141 } 00142 00143 00144 //-------------------------------------------------------------- 00145 bool pgm_read(const string & filename, imat &m, 00146 int r1, int r2, int c1, int c2) 00147 { 00148 ifstream file; 00149 int width, height, max_val, i, j; 00150 00151 // This is a dummy variable. 00152 // Its purpose is the call of function pnm_read_header. 00153 string comments; 00154 00155 file.open( filename.c_str() ); 00156 00157 char pnm_type; 00158 if (!pnm_read_header(file, pnm_type, width, height, max_val, comments, '5' ) ) 00159 return false; 00160 00161 // Inversion of the column/row numbers may be required 00162 if( r1 > r2 ) 00163 { 00164 int rtmp = r2; 00165 r2 = r1; 00166 r1 = rtmp; 00167 } 00168 00169 if( c1 > c2 ) 00170 { 00171 int ctmp = c2; 00172 c2 = c1; 00173 c1 = ctmp; 00174 } 00175 00176 if( r1 < 0 ) 00177 it_error( "Bad parameter value : row number must be >=0" ); 00178 00179 if( c1 < 0 ) 00180 it_error( "Bad parameter value : column number must be >=0" ); 00181 00182 if (r2 >= height ) 00183 it_error( "Bad parameter value : row number exceeds the image heigth" ); 00184 00185 if( c1 >= width ) 00186 it_error( "Bad parameter value : column number exceeds the image width" ); 00187 00188 m.set_size( r2-r1+1, c2-c1+1, false ); 00189 file.seekg( r1 * width + c1, ios::cur ); 00190 00191 for( i = 0 ; i < m.rows() ; i++ ) 00192 { 00193 for( j = 0 ; j < m.cols() ; j++ ) 00194 m( i, j ) = file.get(); 00195 file.seekg( width - ( c2-c1+1 ), ios::cur ); 00196 } 00197 00198 return true; 00199 } 00200 00201 00202 //-------------------------------------------------------------- 00203 bool pgm_write( const string & filename, 00204 const imat &m, const string & comments ) 00205 { 00206 00207 ofstream file; 00208 int i, j; 00209 00210 file.open( filename.c_str(), ofstream::out | ofstream::binary ); 00211 00212 if (!pnm_write_header(file, '5', m.cols(), m.rows(), 255, comments )) 00213 return false; 00214 00215 for (i=0; i<m.rows(); i++) 00216 for (j=0; j<m.cols(); j++) 00217 file.put( m(i,j) ); 00218 00219 if (!file) 00220 return false; 00221 00222 return true; 00223 } 00224 00225 00226 //-------------------------------------------------------------- 00227 // PPM related functions (color images) 00228 //-------------------------------------------------------------- 00229 00230 bool ppm_read( const string & filename, 00231 imat &r, imat &g, imat &b, 00232 string & comments ) 00233 { 00234 ifstream file; 00235 int width, height, max_val, i, j; 00236 00237 file.open( filename.c_str() ); 00238 00239 char pnm_type; 00240 if(!pnm_read_header(file, pnm_type, width, height, max_val, comments, '6' ) ) 00241 return false; 00242 00243 r.set_size(height, width, false); 00244 g.set_size(height, width, false); 00245 b.set_size(height, width, false); 00246 for (i=0; i<height; i++) 00247 for (j=0; j<width; j++) { 00248 r(i,j) = file.get(); 00249 g(i,j) = file.get(); 00250 b(i,j) = file.get(); 00251 } 00252 00253 return true; 00254 } 00255 00256 00257 //-------------------------------------------------------------- 00258 // Same function but suppress the comments 00259 bool ppm_read( const string & filename, 00260 imat &r, imat &g, imat &b ) 00261 { 00262 string comments; // This is a dummy variable 00263 00264 return ppm_read( filename, r, g, b, comments ); 00265 } 00266 00267 //-------------------------------------------------------------- 00268 bool ppm_read( const string & filename, 00269 imat &r, imat &g, imat &b, 00270 int r1, int r2, int c1, int c2) 00271 { 00272 ifstream file; 00273 int width, height, max_val, i, j; 00274 00275 // This is a dummy variable. Its purpose is the call of function pnm_read_header. 00276 string comments; 00277 00278 file.open( filename.c_str() ); 00279 00280 char pnm_type; 00281 if (!pnm_read_header(file, pnm_type, width, height, max_val, comments, '6' ) ) 00282 return false; 00283 00284 // Inversion of the column/row numbers may be required 00285 if( r1 > r2 ) 00286 { 00287 // Funny way to do it... (without using any temporary variable) 00288 r1 += r2; 00289 r2 = r1 - r2; 00290 r1 -= r2; 00291 } 00292 00293 if( c1 > c2 ) 00294 { 00295 // Conventionnal way to do it 00296 int ctmp = c2; 00297 c2 = c1; 00298 c1 = ctmp; 00299 } 00300 00301 if( r1 < 0 ) 00302 it_error( "Bad parameter value : row number must be >=0" ); 00303 00304 if( c1 < 0 ) 00305 it_error( "Bad parameter value : column number must be >=0" ); 00306 00307 if (r2 >= height ) 00308 it_error( "Bad parameter value : row number exceeds the image heigth" ); 00309 00310 if( c1 >= width) 00311 it_error( "Bad parameter value : column number exceeds the image width" ); 00312 00313 r.set_size( r2-r1+1, c2-c1+1, false); 00314 g.set_size( r2-r1+1, c2-c1+1, false); 00315 b.set_size( r2-r1+1, c2-c1+1, false); 00316 file.seekg( 3 *( r1 * width + c1 ), ios::cur); 00317 00318 for (i=0; i<r.rows(); i++) { 00319 for (j=0; j<r.cols(); j++) { 00320 r(i,j) = file.get(); 00321 g(i,j) = file.get(); 00322 b(i,j) = file.get(); 00323 } 00324 file.seekg( 3 * ( width - (c2-c1+1) ), ios::cur); 00325 } 00326 00327 return true; 00328 } 00329 00330 00331 //-------------------------------------------------------------- 00332 bool ppm_write( const string & filename, 00333 const imat &r, const imat &g, const imat &b, 00334 const string & comments, 00335 int max_val ) 00336 { 00337 ofstream file; 00338 int i, j; 00339 00340 it_assert1(r.cols() == g.cols() && g.cols() == b.cols() && 00341 r.rows() == g.rows() && g.rows() == b.rows(), 00342 "Matrices r, g and b must have the same size in ppm_write()"); 00343 00344 file.open( filename.c_str(), ofstream::out | ofstream::binary ); 00345 00346 if( max_val < 0 || max_val > 65535 ) 00347 { 00348 it_warning( "Proposed maximal value is incorrect" ); 00349 return false; 00350 } 00351 00352 if (!pnm_write_header(file, '6', r.cols(), r.rows(), max_val, comments )) 00353 return false; 00354 00355 for (i=0; i<r.rows(); i++) 00356 for (j=0; j<r.cols(); j++) { 00357 file.put( r(i,j) ); 00358 file.put( g(i,j) ); 00359 file.put( b(i,j) ); 00360 } 00361 00362 if (!file) 00363 return false; 00364 00365 return true; 00366 } 00367 00368 00369 //-------------------------------------------------------------- 00370 imat img_double2int( const mat & m, 00371 int max_val, 00372 double double_min, 00373 double double_max ) 00374 { 00375 int i, j; 00376 imat M( m.rows(), m.cols() ); 00377 00378 for( i = 0 ; i < m.rows() ; i++ ) 00379 for( j = 0 ; j < m.cols() ; j++ ) 00380 if( m( i, j ) <= double_min ) 00381 M( i, j ) = 0; 00382 00383 else if( m( i, j ) >= double_max ) 00384 M( i, j ) = max_val; 00385 00386 else 00387 M( i, j ) = (int) ( max_val * ( m( i, j ) - double_min ) 00388 / ( double_max - double_min ) + 0.5 ); 00389 00390 return M; 00391 } 00392 00393 //-------------------------------------------------------------- 00394 mat img_int2double( const imat & m, 00395 int max_val, 00396 double double_min, 00397 double double_max ) 00398 { 00399 int i, j; 00400 mat M( m.rows(), m.cols() ); 00401 00402 for( i = 0 ; i < m.rows() ; i++ ) 00403 for( j = 0 ; j < m.cols() ; j++ ) 00404 if( m( i, j ) <= 0 ) 00405 M( i, j ) = double_min; 00406 00407 else if( m( i, j ) >= max_val ) 00408 M( i, j ) = double_max; 00409 00410 else 00411 // This rounding works well when m(i,j) is positive 00412 M( i, j ) = double_min + ( double_max - double_min ) 00413 * m( i, j ) / (double) max_val; 00414 00415 return M; 00416 } 00417 00418 00419 //-------------------------------------------------------------- 00420 // Static functions: Used in this file only 00421 //-------------------------------------------------------------- 00422 00423 //-------------------------------------------------------------- 00424 static void pnm_read_comments( istream & i, string & comments ) 00425 { 00426 while (isspace(i.peek())) 00427 { 00428 while (isspace(i.peek())) 00429 i.get(); 00430 00431 if (i.peek() == '#') 00432 while (i.peek()!='\r' && i.peek()!='\n') 00433 comments += i.get(); 00434 } 00435 } 00436 00437 00438 //-------------------------------------------------------------- 00439 static void pnm_write_comments( ostream & o, const string & comments ) 00440 { 00441 istringstream comments_stream( comments ); 00442 char comment_line[ 256 ]; 00443 00444 // Put header and comment 00445 while( !comments_stream.eof() ) 00446 { 00447 o << "#"; 00448 comments_stream.get( comment_line, 256 ); 00449 o << comment_line << endl; 00450 } 00451 } 00452 00453 00454 //-------------------------------------------------------------- 00455 // Read the header of a pnm file 00456 static bool pnm_read_header( ifstream & file, char & pnm_type, 00457 int & width, int & height, int & max_val, 00458 string & comments, char pnm_type_required ) 00459 { 00460 bool return_code = true; 00461 00462 if (file.get() != 'P') 00463 return_code = false; 00464 00465 if( !return_code ) 00466 it_error("Invalid format file: code of file format has not been found"); 00467 00468 // Read the type of the pnm file 00469 pnm_type = file.get(); 00470 00471 if( pnm_type < '1' || pnm_type > '6' ) 00472 { 00473 string err_msg("Bad file code P"); 00474 err_msg += pnm_type; 00475 it_error(err_msg); 00476 } 00477 00478 // If a type has been specified 00479 if( pnm_type_required != '0' ) 00480 if( pnm_type_required != pnm_type ) 00481 { 00482 string err_msg( "Found file code P" ); 00483 err_msg += pnm_type + " instead of P" + pnm_type_required; 00484 it_error( err_msg ); 00485 } 00486 00487 // Retrieve the image format and the comments 00488 pnm_read_comments(file, comments ); 00489 file >> width; 00490 pnm_read_comments(file, comments ); 00491 file >> height; 00492 pnm_read_comments(file, comments ); 00493 00494 if( height < 0 || width < 0 ) 00495 it_error( "Bad image size" ); 00496 00497 // Maximal values is not present in PBM files 00498 if( pnm_type == '2' || pnm_type == '3' || pnm_type == '5' || pnm_type == '6' ) 00499 file >> max_val; 00500 00501 file.get(); // Eat the last whitespace 00502 00503 // According to the pnm specification, the maximal value should not 00504 // be greater than 65536 and lower than 0 00505 if( max_val >= 65536 || max_val < 0 ) 00506 it_error( "Invalid maximum number in pnm header" ); 00507 00508 // For type P5 and P6, the value have to be lower than 255 00509 if( ( pnm_type == '5' || pnm_type == '6' ) && max_val > 255 ) 00510 it_error( "Invalid maximum number in pnm header" ); 00511 00512 return file.good(); 00513 } 00514 00515 00516 //-------------------------------------------------------------- 00517 static bool pnm_write_header( ofstream &file, char pnm_type, 00518 int width, int height, int max_val, 00519 const string & comments ) 00520 { 00521 file << 'P' << pnm_type << endl; 00522 pnm_write_comments( file, comments ); 00523 file << width << ' ' << height << endl; 00524 00525 // Maximal values is not present in PBM files 00526 if( pnm_type == '2' || pnm_type == '3' || pnm_type == '5' || pnm_type == '6' ) 00527 file << max_val << endl; 00528 00529 return file.good(); 00530 } 00531 00532 } // namespace itpp
Generated on Thu Apr 19 14:20:38 2007 for IT++ by Doxygen 1.4.6