IT++ Logo
pnm.cpp
Go to the documentation of this file.
1 
29 #include <itpp/srccode/pnm.h>
30 #include <itpp/base/itassert.h>
31 #include <fstream>
32 
34 
35 using std::istream;
36 using std::ostream;
37 using std::endl;
38 using std::string;
39 using std::ifstream;
40 using std::ofstream;
41 using std::istringstream;
42 using std::ios;
43 using std::ios_base;
44 using std::streampos;
45 
46 
47 namespace itpp
48 {
49 
50 
51 // Suppress the additional white characters and return the comments
52 static void pnm_read_comments(istream & i, string & comments);
53 
54 // Write comment in the image file
55 static void pnm_write_comments(ostream & o, const string & comments);
56 
57 // Read/Write the header for the pnm file format
58 static bool pnm_read_header(ifstream & file, char & pnm_type,
59  int & width, int & height, int & max_val,
60  string & comments, char pnm_type_required = '0');
61 
62 static bool pnm_write_header(ofstream & file, char type,
63  int width, int height, int max_val,
64  const string & comments);
65 
66 
67 //--------------------------------------------------------------
68 // General PNM functions
69 //--------------------------------------------------------------
70 char pnm_type(const string & filename)
71 {
72  ifstream file;
73  char pnm_type;
74 
75  file.open(filename.c_str(), ifstream::in | ifstream::binary);
76 
77  string comments;
78  int width, height, max_val;
79  pnm_read_header(file, pnm_type, width, height, max_val, comments);
80 
81  return pnm_type;
82 }
83 
84 
85 //--------------------------------------------------------------
86 bool pnm_info(const string & filename, char & pnm_type,
87  int & width, int & height, int & max_val,
88  string & comments)
89 {
90  ifstream file;
91 
92  file.open(filename.c_str(), ifstream::in | ifstream::binary);
93 
94  pnm_read_header(file, pnm_type, width, height, max_val, comments);
95 
96  return true;
97 }
98 
99 
100 //--------------------------------------------------------------
101 // PGM related functions (gray images)
102 //--------------------------------------------------------------
103 
104 bool pgm_read(const string & filename,
105  imat & m, string & comments)
106 {
107  ifstream file;
108  int width, height, max_val, i, j;
109  comments = "";
110 
111  file.open(filename.c_str(), ifstream::in | ifstream::binary);
112 
113  // The format code is 'P5' for pgm files
114  char pnm_type;
115  if (!pnm_read_header(file, pnm_type, width, height, max_val, comments, '5'))
116  return false;
117 
118  // Format the returned matrix
119  m.set_size(height, width, false);
120 
121  // Retrieve the integer value from the file
122  for (i = 0 ; i < height; i++)
123  for (j = 0; j < width; j++)
124  m(i, j) = file.get();
125 
126  return true;
127 }
128 
129 
130 //--------------------------------------------------------------
131 // Simplified version of read_pgm
132 imat pgm_read(const string & filename)
133 {
134  imat I;
135  string comments;
136  if (!pgm_read(filename, I, comments)) {
137  it_warning("pgm_read (PGM file->imat) failed ");
138  }
139  return I;
140 }
141 
142 
143 //--------------------------------------------------------------
144 bool pgm_read(const string & filename, imat &m,
145  int r1, int r2, int c1, int c2)
146 {
147  ifstream file;
148  int width, height, max_val, i, j;
149 
150  // This is a dummy variable.
151  // Its purpose is the call of function pnm_read_header.
152  string comments;
153 
154  file.open(filename.c_str(), ifstream::in | ifstream::binary);
155 
156  char pnm_type;
157  if (!pnm_read_header(file, pnm_type, width, height, max_val, comments, '5'))
158  return false;
159 
160  // Inversion of the column/row numbers may be required
161  if (r1 > r2) {
162  int rtmp = r2;
163  r2 = r1;
164  r1 = rtmp;
165  }
166 
167  if (c1 > c2) {
168  int ctmp = c2;
169  c2 = c1;
170  c1 = ctmp;
171  }
172 
173  it_error_if((r1 < 0) || (c1 < 0),
174  "Bad parameter value: row and column number must be >=0");
175  it_error_if((r2 >= height) || (c1 >= width), "Bad parameter value: "
176  "row or column number exceeds the image heigth");
177 
178  m.set_size(r2 - r1 + 1, c2 - c1 + 1, false);
179  file.seekg(r1 * width + c1, ios::cur);
180 
181  for (i = 0 ; i < m.rows() ; i++) {
182  for (j = 0 ; j < m.cols() ; j++)
183  m(i, j) = file.get();
184  file.seekg(width - (c2 - c1 + 1), ios::cur);
185  }
186 
187  return true;
188 }
189 
190 
191 //--------------------------------------------------------------
192 bool pgm_write(const string & filename,
193  const imat &m, const string & comments)
194 {
195 
196  ofstream file;
197  int i, j;
198 
199  file.open(filename.c_str(), ofstream::out | ofstream::binary);
200 
201  if (!pnm_write_header(file, '5', m.cols(), m.rows(), 255, comments))
202  return false;
203 
204  for (i = 0; i < m.rows(); i++)
205  for (j = 0; j < m.cols(); j++)
206  file.put(static_cast<char>(m(i, j)));
207 
208  if (!file)
209  return false;
210 
211  return true;
212 }
213 
214 
215 //--------------------------------------------------------------
216 // PPM related functions (color images)
217 //--------------------------------------------------------------
218 
219 bool ppm_read(const string & filename,
220  imat &r, imat &g, imat &b,
221  string & comments)
222 {
223  ifstream file;
224  int width, height, max_val, i, j;
225 
226  file.open(filename.c_str(), ifstream::in | ifstream::binary);
227 
228  char pnm_type;
229  if (!pnm_read_header(file, pnm_type, width, height, max_val, comments, '6'))
230  return false;
231 
232  r.set_size(height, width, false);
233  g.set_size(height, width, false);
234  b.set_size(height, width, false);
235  for (i = 0; i < height; i++)
236  for (j = 0; j < width; j++) {
237  r(i, j) = file.get();
238  g(i, j) = file.get();
239  b(i, j) = file.get();
240  }
241 
242  return true;
243 }
244 
245 
246 //--------------------------------------------------------------
247 // Same function but suppress the comments
248 bool ppm_read(const string & filename,
249  imat &r, imat &g, imat &b)
250 {
251  string comments; // This is a dummy variable
252 
253  return ppm_read(filename, r, g, b, comments);
254 }
255 
256 //--------------------------------------------------------------
257 bool ppm_read(const string & filename,
258  imat &r, imat &g, imat &b,
259  int r1, int r2, int c1, int c2)
260 {
261  ifstream file;
262  int width, height, max_val, i, j;
263 
264  // This is a dummy variable. Its purpose is the call of function pnm_read_header.
265  string comments;
266 
267  file.open(filename.c_str(), ifstream::in | ifstream::binary);
268 
269  char pnm_type;
270  if (!pnm_read_header(file, pnm_type, width, height, max_val, comments, '6'))
271  return false;
272 
273  // Inversion of the column/row numbers may be required
274  if (r1 > r2) {
275  // Funny way to do it... (without using any temporary variable)
276  r1 += r2;
277  r2 = r1 - r2;
278  r1 -= r2;
279  }
280 
281  if (c1 > c2) {
282  // Conventionnal way to do it
283  int ctmp = c2;
284  c2 = c1;
285  c1 = ctmp;
286  }
287 
288  it_error_if((r1 < 0) || (c1 < 0),
289  "Bad parameter value: row and column number must be >=0");
290  it_error_if((r2 >= height) || (c1 >= width), "Bad parameter value: "
291  "row or column number exceeds the image heigth");
292 
293  r.set_size(r2 - r1 + 1, c2 - c1 + 1, false);
294  g.set_size(r2 - r1 + 1, c2 - c1 + 1, false);
295  b.set_size(r2 - r1 + 1, c2 - c1 + 1, false);
296  file.seekg(3 *(r1 * width + c1), ios::cur);
297 
298  for (i = 0; i < r.rows(); i++) {
299  for (j = 0; j < r.cols(); j++) {
300  r(i, j) = file.get();
301  g(i, j) = file.get();
302  b(i, j) = file.get();
303  }
304  file.seekg(3 * (width - (c2 - c1 + 1)), ios::cur);
305  }
306 
307  return true;
308 }
309 
310 
311 //--------------------------------------------------------------
312 bool ppm_write(const string & filename,
313  const imat &r, const imat &g, const imat &b,
314  const string & comments,
315  int max_val)
316 {
317  ofstream file;
318  int i, j;
319 
320  it_assert_debug(r.cols() == g.cols() && g.cols() == b.cols() &&
321  r.rows() == g.rows() && g.rows() == b.rows(),
322  "Matrices r, g and b must have the same size in ppm_write()");
323 
324  file.open(filename.c_str(), ofstream::out | ofstream::binary);
325 
326  if (max_val < 0 || max_val > 65535) {
327  it_warning("Proposed maximal value is incorrect");
328  return false;
329  }
330 
331  if (!pnm_write_header(file, '6', r.cols(), r.rows(), max_val, comments))
332  return false;
333 
334  for (i = 0; i < r.rows(); i++)
335  for (j = 0; j < r.cols(); j++) {
336  file.put(static_cast<char>(r(i, j)));
337  file.put(static_cast<char>(g(i, j)));
338  file.put(static_cast<char>(b(i, j)));
339  }
340 
341  if (!file)
342  return false;
343 
344  return true;
345 }
346 
347 
348 //--------------------------------------------------------------
349 imat img_double2int(const mat & m,
350  int max_val,
351  double double_min,
352  double double_max)
353 {
354  int i, j;
355  imat M(m.rows(), m.cols());
356 
357  for (i = 0 ; i < m.rows() ; i++)
358  for (j = 0 ; j < m.cols() ; j++)
359  if (m(i, j) <= double_min)
360  M(i, j) = 0;
361 
362  else if (m(i, j) >= double_max)
363  M(i, j) = max_val;
364 
365  else
366  M(i, j) = (int)(max_val * (m(i, j) - double_min)
367  / (double_max - double_min) + 0.5);
368 
369  return M;
370 }
371 
372 //--------------------------------------------------------------
373 mat img_int2double(const imat & m,
374  int max_val,
375  double double_min,
376  double double_max)
377 {
378  int i, j;
379  mat M(m.rows(), m.cols());
380 
381  for (i = 0 ; i < m.rows() ; i++)
382  for (j = 0 ; j < m.cols() ; j++)
383  if (m(i, j) <= 0)
384  M(i, j) = double_min;
385 
386  else if (m(i, j) >= max_val)
387  M(i, j) = double_max;
388 
389  else
390  // This rounding works well when m(i,j) is positive
391  M(i, j) = double_min + (double_max - double_min)
392  * m(i, j) / (double) max_val;
393 
394  return M;
395 }
396 
397 
398 //--------------------------------------------------------------
399 // Static functions: Used in this file only
400 //--------------------------------------------------------------
401 
402 //--------------------------------------------------------------
403 static void pnm_read_comments(istream & i, string & comments)
404 {
405  while (isspace(i.peek())) {
406  while (isspace(i.peek()))
407  i.get();
408 
409  if (i.peek() == '#')
410  while (i.peek() != '\r' && i.peek() != '\n')
411  comments += static_cast<char>(i.get());
412  }
413 }
414 
415 
416 //--------------------------------------------------------------
417 static void pnm_write_comments(ostream & o, const string & comments)
418 {
419  istringstream comments_stream(comments);
420  char comment_line[ 256 ];
421 
422  // Put header and comment
423  while (!comments_stream.eof()) {
424  o << "#";
425  comments_stream.get(comment_line, 256);
426  o << comment_line << endl;
427  }
428 }
429 
430 
431 //--------------------------------------------------------------
432 // Read the header of a pnm file
433 static bool pnm_read_header(ifstream & file, char & pnm_type,
434  int & width, int & height, int & max_val,
435  string & comments, char pnm_type_required)
436 {
437  bool return_code = true;
438 
439  if (file.get() != 'P')
440  return_code = false;
441  it_error_if(!return_code, "Invalid format file: code of file format has "
442  "not been found");
443 
444  // Read the type of the pnm file
445  file.get(pnm_type);
446  it_error_if((pnm_type < '1') || (pnm_type > '6'),
447  "Bad file code P" << pnm_type);
448 
449  // If a type has been specified
450  if (pnm_type_required != '0')
451  if (pnm_type_required != pnm_type) {
452  string err_msg("Found file code P");
453  err_msg += pnm_type + " instead of P" + pnm_type_required;
454  it_error(err_msg);
455  }
456 
457  // Retrieve the image format and the comments
458  pnm_read_comments(file, comments);
459  file >> width;
460  pnm_read_comments(file, comments);
461  file >> height;
462  pnm_read_comments(file, comments);
463 
464  it_error_if((height < 0) || (width < 0), "Bad image size");
465 
466  // Maximal values is not present in PBM files
467  if (pnm_type == '2' || pnm_type == '3' || pnm_type == '5' || pnm_type == '6')
468  file >> max_val;
469 
470  file.get(); // Eat the last whitespace
471 
472  // According to the pnm specification, the maximal value should not
473  // be greater than 65536 and lower than 0
474  it_error_if((max_val >= 65536) || (max_val < 0),
475  "Invalid maximum number in pnm header");
476 
477  // For type P5 and P6, the value have to be lower than 255
478  it_error_if((pnm_type == '5' || pnm_type == '6') && (max_val > 255),
479  "Invalid maximum number in pnm header");
480 
481  return file.good();
482 }
483 
484 
485 //--------------------------------------------------------------
486 static bool pnm_write_header(ofstream &file, char pnm_type,
487  int width, int height, int max_val,
488  const string & comments)
489 {
490  file << 'P' << pnm_type << endl;
491  pnm_write_comments(file, comments);
492  file << width << ' ' << height << endl;
493 
494  // Maximal values is not present in PBM files
495  if (pnm_type == '2' || pnm_type == '3' || pnm_type == '5' || pnm_type == '6')
496  file << max_val << endl;
497 
498  return file.good();
499 }
500 
501 } // namespace itpp
502 
SourceForge Logo

Generated on Sat Jul 6 2013 10:54:25 for IT++ by Doxygen 1.8.2