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
35using std::istream;
36using std::ostream;
37using std::endl;
38using std::string;
39using std::ifstream;
40using std::ofstream;
41using std::istringstream;
42using std::ios;
43using std::ios_base;
44using std::streampos;
45
46
47namespace itpp
48{
49
50
51// Suppress the additional white characters and return the comments
52static void pnm_read_comments(istream & i, string & comments);
53
54// Write comment in the image file
55static void pnm_write_comments(ostream & o, const string & comments);
56
57// Read/Write the header for the pnm file format
58static 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
62static 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//--------------------------------------------------------------
70char 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//--------------------------------------------------------------
86bool 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
104bool 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
132imat 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//--------------------------------------------------------------
144bool 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//--------------------------------------------------------------
192bool 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
219bool 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
248bool 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//--------------------------------------------------------------
257bool 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//--------------------------------------------------------------
312bool 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//--------------------------------------------------------------
349imat 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//--------------------------------------------------------------
373mat 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//--------------------------------------------------------------
403static 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//--------------------------------------------------------------
417static 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
433static 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//--------------------------------------------------------------
486static 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
#define it_error_if(t, s)
Abort if t is true.
Definition: itassert.h:117
#define it_error(s)
Abort unconditionally.
Definition: itassert.h:126
#define it_warning(s)
Display a warning message.
Definition: itassert.h:173
#define it_assert_debug(t, s)
Abort if t is not true and NDEBUG is not defined.
Definition: itassert.h:107
ITPP_EXPORT bool pgm_write(const std::string &filename, const imat &m, const std::string &comments="Generated by IT++ (http://itpp.sourceforge.net)")
Create an image file from the matrix of integer.
ITPP_EXPORT char pnm_type(const std::string &filename)
Determines the type of a PNM file, based on magic numbers. The returned value is a character between ...
ITPP_EXPORT bool pgm_read(const std::string &filename, imat &m, std::string &comments)
Read the entire graymap into the matrix m or return false if the function failed.
ITPP_EXPORT mat img_int2double(const imat &m, int max_val=255, double double_min=0, double double_max=1)
Return a matrix of double which is a scaled version of the input matrix m of integers.
ITPP_EXPORT imat img_double2int(const mat &m, int max_val=255, double double_min=0, double double_max=1)
Prepare a matrix of double to be writted as an image.
ITPP_EXPORT bool pnm_info(const std::string &filename, char &pnm_type, int &width, int &height, int &max_val, std::string &comments)
Retrieve some information about an pnm file.
ITPP_EXPORT bool ppm_write(const std::string &filename, const imat &r, const imat &g, const imat &b, const std::string &comments="Generated by IT++ (http://itpp.sourceforge.net)", int max_val=255)
Write the matrix m as a pixmap.
ITPP_EXPORT bool ppm_read(const std::string &filename, imat &r, imat &g, imat &b, std::string &comments)
Read the color image file in the format ppm. The image is retrieved as a set of three matrices,...
Error handling functions - header file.
itpp namespace
Definition: itmex.h:37
Definitions of PNM graphics format I/O function.
SourceForge Logo

Generated on Tue Jan 24 2023 00:00:00 for IT++ by Doxygen 1.9.6