UsTK : Ultrasound ToolKit  version 2.0.1 under development (2023-12-07)
usImageIo.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ustk software.
4  * Copyright (C) 2016 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ustk with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * This software was developed at:
17  * Inria Rennes - Bretagne Atlantique
18  * Campus Universitaire de Beaulieu
19  * 35042 Rennes Cedex
20  * France
21  *
22  * If you have questions regarding the use of this file, please contact
23  * Inria at ustk@inria.fr
24  *
25  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27  *
28  * Authors:
29  * Marc Pouliquen
30  *
31  *****************************************************************************/
32 
37 #include <fstream>
38 #include <iostream>
39 
40 #include <visp3/core/vpXmlParser.h>
41 #include <visp3/io/vpImageIo.h>
42 
43 #include <visp3/ustk_core/usImageIo.h>
44 #include <visp3/ustk_core/usImagePreScanSettings.h>
45 #include <visp3/ustk_core/usMotorSettings.h>
46 #include <visp3/ustk_core/usRawFileParser.h>
47 #include <visp3/ustk_core/usRfReader.h>
48 #include <visp3/ustk_core/usSequenceReader.h>
49 
51 {
52  std::string ext = usImageIo::getExtension(headerFileName);
53  if (ext.compare(".xml") == 0)
54  return FORMAT_XML;
55  else if (ext.compare(".XML") == 0)
56  return FORMAT_XML;
57  else if (ext.compare(".mhd") == 0)
58  return FORMAT_MHD;
59  else if (ext.compare(".MHD") == 0)
60  return FORMAT_MHD;
61  else if (ext.compare(".vol") == 0)
62  return FORMAT_VOL;
63  else if (ext.compare(".VOL") == 0)
64  return FORMAT_VOL;
65  else if (ext.compare(".rf") == 0)
66  return FORMAT_RF;
67  else if (ext.compare(".RF") == 0)
68  return FORMAT_RF;
69  else
70  return HEADER_FORMAT_UNKNOWN;
71 }
72 
73 std::string usImageIo::getExtension(const std::string &filename)
74 {
75  // extract the extension
76  size_t dot = filename.find_last_of(".");
77  std::string filenameCopy = filename;
78  std::string ext = filenameCopy.substr(dot, filenameCopy.size() - 1);
79  return ext;
80 }
81 
87 void usImageIo::write(const usImageRF2D<short> &imageRf2D, const std::string &headerFileName)
88 {
89  // checking header type
90  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
91  if (headerFormat == FORMAT_XML) {
92  write(imageRf2D, headerFileName, std::string(".png"));
93  } else if (headerFormat == FORMAT_MHD) {
94  write(imageRf2D, headerFileName, std::string(".raw"));
95  }
96 }
97 
104 void usImageIo::write(const usImageRF2D<short> &imageRf2D, const std::string &headerFileName,
105  const std::string &imageExtension2D)
106 {
107  // checking header type
108  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
109  if (headerFormat == FORMAT_MHD) {
110  if (imageExtension2D != ".raw") {
111  throw(vpException(vpException::fatalError, "mhd files goes with .raw image extension"));
112  }
113 
114  std::string imageFileName = vpIoTools::splitChain(headerFileName, ".")[0].append(".raw");
115  // filling header
116  usMetaHeaderParser::MHDHeader header;
117  header.numberOfDimensions = 2;
118  header.elementType = usMetaHeaderParser::MET_SHORT;
119  header.imageType = us::RF_2D;
120  header.elementSpacing[0] = 1;
121  header.elementSpacing[1] = 1;
122  header.dim[0] = imageRf2D.getScanLineNumber();
123  header.dim[1] = imageRf2D.getRFSampleNumber();
124  header.msb = false;
125  header.MHDFileName = headerFileName;
126  // remove full path for image file name (located in the same directory as the mhd
127  header.rawFileName = vpIoTools::getName(imageFileName);
128  header.isTransducerConvex = imageRf2D.isTransducerConvex();
129  header.transducerRadius = imageRf2D.getTransducerRadius();
130  header.scanLinePitch = imageRf2D.getScanLinePitch();
131  header.samplingFrequency = imageRf2D.getSamplingFrequency();
132  header.transmitFrequency = imageRf2D.getTransmitFrequency();
133  // writing in file
134  usMetaHeaderParser mhdParser;
135  mhdParser.setMHDHeader(header);
136  mhdParser.setAxialResolution(imageRf2D.getAxialResolution());
137  mhdParser.parse();
138 
139  // filling raw
140  usRawFileParser rawParser;
141  rawParser.write(imageRf2D, imageFileName);
142  } else {
143  throw(vpException(vpException::fatalError, "Only mdh/raw files types are allowed to write 3D RF images."));
144  }
145 }
146 
153 void usImageIo::read(usImageRF2D<short int> &imageRf2D, const std::string &headerFileName)
154 {
155  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
156  if (headerFormat == FORMAT_RF) {
157  usRfReader reader;
158  reader.setFileName(headerFileName);
159  reader.open(imageRf2D);
160  } else if (headerFormat == FORMAT_MHD) {
161  // header parsing
162  usMetaHeaderParser mhdParser;
163  mhdParser.read(headerFileName);
164  if (mhdParser.getImageType() != us::RF_2D && mhdParser.getImageType() != us::NOT_SET) {
165  throw(vpException(vpException::badValue, "Reading a non rf 2D image!"));
166  }
167  if (mhdParser.getElementType() != usMetaHeaderParser::MET_SHORT) {
168  throw(vpException(vpException::badValue, "Reading a non short image!"));
169  }
170 
171  usMetaHeaderParser::MHDHeader mhdHeader = mhdParser.getMHDHeader();
172 
173  usImagePreScanSettings settings;
174  settings.setTransducerRadius(mhdHeader.transducerRadius);
175  settings.setScanLinePitch(mhdHeader.scanLinePitch);
176  settings.setTransducerConvexity(mhdHeader.isTransducerConvex);
177  settings.setAxialResolution(mhdParser.getAxialResolution());
178  settings.setDepth(settings.getAxialResolution() * mhdHeader.dim[1]);
179  settings.setSamplingFrequency(mhdHeader.samplingFrequency);
180  settings.setTransmitFrequency(mhdHeader.transmitFrequency);
181  imageRf2D.setImagePreScanSettings(settings);
182 
183  // resizing image in memory
184  imageRf2D.resize(mhdHeader.dim[1], mhdHeader.dim[0]);
185 
186  // data parsing
187  usRawFileParser rawParser;
188  std::string fullImageFileName =
189  vpIoTools::getParent(headerFileName) + vpIoTools::path("/") + mhdParser.getRawFileName();
190  rawParser.read(imageRf2D, fullImageFileName);
191  } else
192  throw(vpException(vpException::fatalError, "Unknown header format."));
193 }
194 
200 void usImageIo::write(const usImageRF3D<short> &imageRf3D, const std::string &headerFileName)
201 {
202  // checking header type
203  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
204  if (headerFormat == FORMAT_XML) {
205  write(imageRf3D, headerFileName, std::string(".png"));
206  } else if (headerFormat == FORMAT_MHD) {
207  write(imageRf3D, headerFileName, std::string(".raw"));
208  }
209 }
210 
217 void usImageIo::write(const usImageRF3D<short> &imageRf3D, const std::string &headerFileName,
218  const std::string &imageExtension3D)
219 {
220  // checking header type
221  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
222  if (headerFormat == FORMAT_MHD) {
223  if (imageExtension3D != ".raw") {
224  throw(vpException(vpException::fatalError, "mhd files goes with .raw image extension"));
225  }
226  std::string imageFileName = vpIoTools::splitChain(headerFileName, ".")[0].append(".raw");
227  // filling header
228  usMetaHeaderParser::MHDHeader header;
229  header.numberOfDimensions = 3;
230  header.elementType = usMetaHeaderParser::MET_SHORT;
231  header.imageType = us::RF_3D;
232  header.elementSpacing[0] = 1;
233  header.elementSpacing[1] = 1;
234  header.elementSpacing[2] = 1;
235  header.dim[0] = imageRf3D.getWidth();
236  header.dim[1] = imageRf3D.getHeight();
237  header.dim[2] = imageRf3D.getNumberOfFrames();
238  header.msb = false;
239  header.MHDFileName = headerFileName;
240  // remove full path for image file name (located in the same directory as the mhd
241  header.rawFileName = vpIoTools::getName(imageFileName);
242  header.isTransducerConvex = imageRf3D.isTransducerConvex();
243  header.transducerRadius = imageRf3D.getTransducerRadius();
244  header.scanLinePitch = imageRf3D.getScanLinePitch();
245  header.motorType = imageRf3D.getMotorType();
246  header.motorRadius = imageRf3D.getMotorRadius();
247  header.framePitch = imageRf3D.getFramePitch();
248  header.samplingFrequency = imageRf3D.getSamplingFrequency();
249  header.transmitFrequency = imageRf3D.getTransmitFrequency();
250  // writing in file
251  usMetaHeaderParser mhdParser;
252  mhdParser.setMHDHeader(header);
253  mhdParser.setAxialResolution(imageRf3D.getAxialResolution());
254  mhdParser.parse();
255 
256  // filling raw
257  usRawFileParser rawParser;
258  rawParser.write(imageRf3D, imageFileName);
259  } else {
260  throw(vpException(vpException::fatalError, "Unknown extension, only mdh allowed for 3D RF images."));
261  }
262 }
263 
269 void usImageIo::read(usImageRF3D<short> &imageRf3, const std::string &headerFileName)
270 {
271  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
272  if (headerFormat == FORMAT_MHD) {
273  // header parsing
274  usMetaHeaderParser mhdParser;
275  mhdParser.read(headerFileName);
276  if (mhdParser.getImageType() != us::RF_3D && mhdParser.getImageType() != us::NOT_SET) {
277  throw(vpException(vpException::badValue, "Reading a non rf 3D image!"));
278  }
279  if (mhdParser.getElementType() != usMetaHeaderParser::MET_SHORT) {
280  throw(vpException(vpException::badValue, "Reading a non short image!"));
281  }
282 
283  usMetaHeaderParser::MHDHeader mhdHeader = mhdParser.getMHDHeader();
284 
285  // resizing image in memory
286  imageRf3.resize(mhdHeader.dim[1], mhdHeader.dim[0], mhdHeader.dim[2]);
287 
288  usImagePreScanSettings settings;
289  settings.setTransducerRadius(mhdHeader.transducerRadius);
290  settings.setScanLinePitch(mhdHeader.scanLinePitch);
291  settings.setTransducerConvexity(mhdHeader.isTransducerConvex);
292  settings.setScanLineNumber(mhdHeader.dim[0]);
293  settings.setAxialResolution(mhdParser.getAxialResolution());
294  settings.setDepth(mhdParser.getAxialResolution() * mhdHeader.dim[1]);
295  settings.setSamplingFrequency(mhdHeader.samplingFrequency);
296  settings.setTransmitFrequency(mhdHeader.transmitFrequency);
297  imageRf3.setImagePreScanSettings(settings);
298 
299  usMotorSettings motorSettings;
300  motorSettings.setMotorRadius(mhdHeader.motorRadius);
301  motorSettings.setFramePitch(mhdHeader.framePitch);
302  motorSettings.setMotorType(mhdHeader.motorType);
303  motorSettings.setFrameNumber(mhdHeader.dim[2]);
304  imageRf3.setMotorSettings(motorSettings);
305 
306  // data parsing
307  usRawFileParser rawParser;
308  std::string fullImageFileName =
309  vpIoTools::getParent(headerFileName) + vpIoTools::path("/") + mhdParser.getRawFileName();
310  rawParser.read(imageRf3, fullImageFileName);
311  } else
312  throw(vpException(vpException::fatalError, "Only mdh type is allowed for RF 3D."));
313 }
314 
320 void usImageIo::write(const usImagePreScan2D<unsigned char> &preScanImage, const std::string &headerFileName)
321 {
322  // checking header type
323  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
324  if (headerFormat == FORMAT_XML) {
325  write(preScanImage, headerFileName, std::string(".png"));
326  } else if (headerFormat == FORMAT_MHD) {
327  write(preScanImage, headerFileName, std::string(".raw"));
328  } else {
329  throw(vpException(vpException::fatalError, "Unknown extension."));
330  }
331 }
332 
339 void usImageIo::write(const usImagePreScan2D<unsigned char> &preScanImage, const std::string &headerFileName,
340  const std::string &imageExtension2D)
341 {
342  // checking header type
343  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
344  if (headerFormat == FORMAT_XML) {
345  std::string imageFileName = vpIoTools::splitChain(headerFileName, ".")[0].append(imageExtension2D);
346 #ifdef VISP_HAVE_XML2
347  try {
348  // writing image
349  vpImageIo::write(preScanImage, imageFileName);
350  // writing xml
351  usImageSettingsXmlParser xmlSettings;
352  xmlSettings.setImageType(us::PRESCAN_2D);
353  xmlSettings.setImageSettings(preScanImage.getTransducerRadius(), preScanImage.getScanLinePitch(),
354  preScanImage.isTransducerConvex(), preScanImage.getAxialResolution(), us::PRESCAN_2D,
355  preScanImage.getSamplingFrequency(), preScanImage.getTransmitFrequency());
356  // just writing the image file name without parents directories (header and image are in the same directory).
357  imageFileName = vpIoTools::getName(imageFileName);
358  xmlSettings.setImageFileName(imageFileName);
359  // write xml
360  xmlSettings.save(headerFileName);
361  } catch (std::exception &e) {
362  std::cout << "Error writing postScan image : " << std::endl;
363  std::cout << e.what() << std::endl;
364  }
365 #else
366  throw(vpException(vpException::fatalError, "Requires xml2"));
367 #endif
368  } else if (headerFormat == FORMAT_MHD) {
369  if (imageExtension2D != ".raw") {
370  throw(vpException(vpException::fatalError, "mhd files goes with .raw image extension"));
371  }
372  std::string imageFileName = vpIoTools::splitChain(headerFileName, ".")[0].append(".raw");
373  // filling header
374  usMetaHeaderParser::MHDHeader header;
375  header.numberOfDimensions = 2;
376  header.elementType = usMetaHeaderParser::MET_UCHAR;
377  header.imageType = us::PRESCAN_2D;
378  header.elementSpacing[0] = 1;
379  header.elementSpacing[1] = 1;
380  header.dim[0] = preScanImage.getScanLineNumber();
381  header.dim[1] = preScanImage.getBModeSampleNumber();
382  header.msb = false;
383  header.MHDFileName = headerFileName;
384  // remove full path for image file name (located in the same directory as the mhd
385  header.rawFileName = vpIoTools::getName(imageFileName);
386  header.isTransducerConvex = preScanImage.isTransducerConvex();
387  header.transducerRadius = preScanImage.getTransducerRadius();
388  header.scanLinePitch = preScanImage.getScanLinePitch();
389  header.samplingFrequency = preScanImage.getSamplingFrequency();
390  header.transmitFrequency = preScanImage.getTransmitFrequency();
391  // writing in file
392  usMetaHeaderParser mhdParser;
393  mhdParser.setMHDHeader(header);
394  mhdParser.setAxialResolution(preScanImage.getAxialResolution());
395  mhdParser.parse();
396 
397  // filling raw
398  usRawFileParser rawParser;
399  rawParser.write(preScanImage, imageFileName);
400  } else {
401  throw(vpException(vpException::fatalError, "Unknown extension."));
402  }
403 }
404 
410 void usImageIo::read(usImagePreScan2D<unsigned char> &preScanImage, const std::string &headerFileName)
411 {
412  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
413  if (headerFormat == FORMAT_XML) {
414 #ifdef VISP_HAVE_XML2
415  // parsing xml file
416  usImageSettingsXmlParser xmlSettings;
417  xmlSettings.parse(headerFileName);
418 
419  std::string fullImageFileName =
420  vpIoTools::getParent(headerFileName) + vpIoTools::path("/") + xmlSettings.getImageFileName();
421  vpImageIo::read(preScanImage, fullImageFileName);
422 
423  preScanImage.setTransducerRadius(xmlSettings.getTransducerSettings().getTransducerRadius());
424  preScanImage.setScanLinePitch(xmlSettings.getTransducerSettings().getScanLinePitch());
426  preScanImage.setAxialResolution(xmlSettings.getAxialResolution());
427  preScanImage.setScanLineNumber(preScanImage.getWidth());
428  preScanImage.setDepth(xmlSettings.getAxialResolution() * preScanImage.getHeight());
431 #else
432  throw(vpException(vpException::fatalError, "Requires xml2 library"));
433 #endif // VISP_HAVE_XML2
434  } else if (headerFormat == FORMAT_MHD) {
435  // header parsing
436  usMetaHeaderParser mhdParser;
437  mhdParser.read(headerFileName);
438  if (mhdParser.getImageType() != us::PRESCAN_2D && mhdParser.getImageType() != us::NOT_SET) {
439  throw(vpException(vpException::badValue, "Reading a non pre-scan 2D image!"));
440  }
441  if (mhdParser.getElementType() != usMetaHeaderParser::MET_UCHAR) {
442  throw(vpException(vpException::badValue, "Reading a non unsigned char image!"));
443  }
444 
445  usMetaHeaderParser::MHDHeader mhdHeader = mhdParser.getMHDHeader();
446 
447  // resizing image in memory
448  preScanImage.resize(mhdHeader.dim[1], mhdHeader.dim[0], 0);
449 
450  usImagePreScanSettings settings;
451  settings.setTransducerRadius(mhdHeader.transducerRadius);
452  settings.setScanLinePitch(mhdHeader.scanLinePitch);
453  settings.setTransducerConvexity(mhdHeader.isTransducerConvex);
454  settings.setAxialResolution(mhdParser.getAxialResolution());
455  settings.setSamplingFrequency(mhdHeader.samplingFrequency);
456  settings.setTransmitFrequency(mhdHeader.transmitFrequency);
457  preScanImage.setImagePreScanSettings(settings);
458  preScanImage.setDepth(settings.getAxialResolution() * preScanImage.getHeight());
459  preScanImage.setScanLineNumber(preScanImage.getWidth());
460 
461  // data parsing
462  usRawFileParser rawParser;
463  std::string fullImageFileName =
464  vpIoTools::getParent(headerFileName) + vpIoTools::path("/") + mhdParser.getRawFileName();
465  rawParser.read(preScanImage, fullImageFileName);
466  } else
467  throw(vpException(vpException::fatalError, "Unknown header format."));
468 }
469 
475 void usImageIo::write(const usImagePreScan3D<unsigned char> &preScanImage, const std::string &headerFileName)
476 {
477  // checking header type
478  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
479  if (headerFormat == FORMAT_XML) {
480  write(preScanImage, headerFileName, std::string(".png"));
481  } else if (headerFormat == FORMAT_MHD) {
482  write(preScanImage, headerFileName, std::string(".raw"));
483  }
484 }
485 
492 void usImageIo::write(const usImagePreScan3D<unsigned char> &preScanImage, const std::string &headerFileName,
493  const std::string &imageExtension2D)
494 {
495  // checking header type
496  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
497  if (headerFormat == FORMAT_XML) {
498 // std::string imageFileName = vpIoTools::splitChain(headerFileName, ".")[0].append(imageExtension2D);
499 #ifdef VISP_HAVE_XML2
500  // case of a set of successive 2D frames, not implemented
501  throw(vpException(vpException::notImplementedError, "Reading a 3D image as a set of 2D frames is not implemented"));
502 #else
503  throw(vpException(vpException::fatalError, "Requires xml2"));
504 #endif
505  } else if (headerFormat == FORMAT_MHD) {
506  if (imageExtension2D != ".raw") {
507  throw(vpException(vpException::fatalError, "mhd files goes with .raw image extension"));
508  }
509  std::string imageFileName = vpIoTools::splitChain(headerFileName, ".")[0].append(".raw");
510  // filling header
511  usMetaHeaderParser::MHDHeader header;
512  header.numberOfDimensions = 3;
513  header.elementType = usMetaHeaderParser::MET_UCHAR;
514  header.imageType = us::PRESCAN_3D;
515  header.elementSpacing[0] = 1;
516  header.elementSpacing[1] = 1;
517  header.elementSpacing[2] = 1;
518  header.dim[0] = preScanImage.getWidth();
519  header.dim[1] = preScanImage.getHeight();
520  header.dim[2] = preScanImage.getNumberOfFrames();
521  header.msb = false;
522  header.MHDFileName = headerFileName;
523  // remove full path for image file name (located in the same directory as the mhd)
524  header.rawFileName = vpIoTools::getName(imageFileName);
525  header.isTransducerConvex = preScanImage.isTransducerConvex();
526  header.transducerRadius = preScanImage.getTransducerRadius();
527  header.scanLinePitch = preScanImage.getScanLinePitch();
528  header.samplingFrequency = preScanImage.getSamplingFrequency();
529  header.transmitFrequency = preScanImage.getTransmitFrequency();
530  header.motorType = preScanImage.getMotorType();
531  header.motorRadius = preScanImage.getMotorRadius();
532  header.framePitch = preScanImage.getFramePitch();
533  // writing in file
534  usMetaHeaderParser mhdParser;
535  mhdParser.setMHDHeader(header);
536  mhdParser.setAxialResolution(preScanImage.getAxialResolution());
537  mhdParser.parse();
538 
539  // filling raw
540  usRawFileParser rawParser;
541  rawParser.write(preScanImage, imageFileName);
542  } else {
543  throw(vpException(vpException::fatalError, "Unknown extension."));
544  }
545 }
546 
552 void usImageIo::read(usImagePreScan3D<unsigned char> &preScanImage, const std::string &headerFileName)
553 {
554  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
555  if (headerFormat == FORMAT_XML) {
556 // case of a set of sucessive 2D frames
557 #ifdef VISP_HAVE_XML2
558  usImagePreScan2D<unsigned char> preScanFrame;
560  sequenceReader.setSequenceFileName(headerFileName);
561 
562  // read the first frame outside the loop to get the image settings contained in xml sequence file to resize 3D image
563  sequenceReader.open(preScanFrame);
564  if (sequenceReader.getFrameCount() == 0)
565  throw(vpException(vpException::fatalError, "Trying to open a 2D image, check your xml settings (frameNumber) !"));
566 
567  preScanImage.resize(preScanFrame.getBModeSampleNumber(), preScanFrame.getScanLineNumber(),
568  sequenceReader.getFrameCount());
569 
570  int frameIndex = 0;
571  preScanImage.insertFrame(preScanFrame, frameIndex);
572 
573  while (!sequenceReader.end()) {
574  sequenceReader.acquire(preScanFrame);
575  preScanImage.insertFrame(preScanFrame, frameIndex);
576  frameIndex++;
577  }
578  // here we have filled all the volume
579 
580  // we set the image settings
581  preScanImage.setImagePreScanSettings(preScanFrame);
582  usMotorSettings motorSettings = sequenceReader.getXmlParser().getMotorSettings();
583  motorSettings.setFrameNumber(sequenceReader.getFrameCount());
584  preScanImage.setMotorSettings(motorSettings);
585 
586 #else
587  throw(vpException(vpException::fatalError, "Requires xml2 library"));
588 #endif // VISP_HAVE_XML2
589  } else if (headerFormat == FORMAT_MHD) {
590  // header parsing
591  usMetaHeaderParser mhdParser;
592  mhdParser.read(headerFileName);
593  if (mhdParser.getImageType() != us::PRESCAN_3D && mhdParser.getImageType() != us::NOT_SET) {
594  throw(vpException(vpException::badValue, "Reading a non pre-scan 3D image!"));
595  }
596  if (mhdParser.getElementType() != usMetaHeaderParser::MET_UCHAR) {
597  throw(vpException(vpException::badValue, "Reading a non unsigned char image!"));
598  }
599 
600  usMetaHeaderParser::MHDHeader mhdHeader = mhdParser.getMHDHeader();
601 
602  // resizing image in memory
603  preScanImage.resize(mhdHeader.dim[1], mhdHeader.dim[0], mhdHeader.dim[2]);
604 
605  usImagePreScanSettings settings;
606  settings.setTransducerRadius(mhdHeader.transducerRadius);
607  settings.setScanLinePitch(mhdHeader.scanLinePitch);
608  settings.setTransducerConvexity(mhdHeader.isTransducerConvex);
609  settings.setScanLineNumber(mhdHeader.dim[0]);
610  settings.setAxialResolution(mhdParser.getAxialResolution());
611  settings.setDepth(mhdParser.getAxialResolution() * mhdHeader.dim[1]);
612  settings.setSamplingFrequency(mhdHeader.samplingFrequency);
613  settings.setTransmitFrequency(mhdHeader.transmitFrequency);
614  preScanImage.setImagePreScanSettings(settings);
615 
616  usMotorSettings motorSettings;
617  motorSettings.setMotorRadius(mhdHeader.motorRadius);
618  motorSettings.setFramePitch(mhdHeader.framePitch);
619  motorSettings.setMotorType(mhdHeader.motorType);
620  motorSettings.setFrameNumber(mhdHeader.dim[2]);
621  preScanImage.setMotorSettings(motorSettings);
622 
623  // data parsing
624  usRawFileParser rawParser;
625  std::string fullImageFileName =
626  vpIoTools::getParent(headerFileName) + vpIoTools::path("/") + mhdParser.getRawFileName();
627  rawParser.read(preScanImage, fullImageFileName);
628  } else if (headerFormat == FORMAT_VOL) {
629  // INIT
630  int szHeader = sizeof(VolHeader);
631  int n = 0;
632  char byte;
633  VolHeader header;
634  header.type = 0;
635  header.volumes = 0;
636  header.fpv = 0;
637  header.w = 0;
638  header.h = 0;
639  header.ss = 0;
640  header.degPerFr = 0;
641 
642  // FILE OPENING
643  std::ifstream volFile;
644  volFile.open(headerFileName.c_str(), std::ios::in | std::ios::binary);
645 
646  // READING HEADER
647  while (n < szHeader) {
648  volFile.read(&byte, 1);
649  ((char *)&header)[n] = byte;
650  n++;
651  }
652  // Print header info
653  std::cout << std::endl
654  << "Data header information: " << std::endl
655  << " type = " << header.type << std::endl
656  << " volumes = " << header.volumes << std::endl
657  << " fpv = " << header.fpv << std::endl
658  << " w = " << header.w << std::endl
659  << " h = " << header.h << std::endl
660  << " ss = " << header.ss << std::endl;
661 
662  // CHECK IMAGE TYPE
663  if (header.type != 0)
664  throw(vpException(vpException::badValue, "trying to read non-prescan in .vol file"));
665 
666  // CHECK DATA TYPE
667  if (header.ss != 8)
668  throw(vpException(vpException::badValue, ".vol file doesn't contain unsigned char data"));
669 
670  // OFFSET : TODO
671  // to select volume to read (in .vol files multiple volumes can be stacked after the header part)
672 
673  // READING DATA
674  preScanImage.resize(header.h, header.w, header.fpv);
675  n = 0;
676  unsigned char voxel;
677  for (int k = 0; k < header.fpv; k++) {
678  for (int j = 0; j < header.w; j++) {
679  for (int i = 0; i < header.h; i++) {
680  volFile.read((char *)&voxel, 1);
681  preScanImage(j, i, k, voxel);
682  }
683  }
684  }
685 
686  } else
687  throw(vpException(vpException::fatalError, "Unknown header format."));
688 }
689 
696 void usImageIo::write(const usImagePreScan2D<double> &preScan2DImage, const std::string &headerFileName,
697  const std::string &imageExtension2D)
698 {
699  // TODO: to implement
700  (void)preScan2DImage;
701  (void)headerFileName;
702  (void)imageExtension2D;
703 }
704 
710 void usImageIo::read(usImagePreScan2D<double> &preScan2D, const std::string &headerFileName)
711 {
712  // TODO: to implement
713  (void)preScan2D;
714  (void)headerFileName;
715 }
716 
723 void usImageIo::write(const usImagePreScan3D<double> &preScan3DImage, const std::string &headerFileName,
724  const std::string &imageExtension2D)
725 {
726  // TODO: to implement
727  (void)preScan3DImage;
728  (void)headerFileName;
729  (void)imageExtension2D;
730 }
731 
737 void usImageIo::read(usImagePreScan3D<double> &preScan3DImage, const std::string &headerFileName)
738 {
739  // TODO: to implement
740  (void)preScan3DImage;
741  (void)headerFileName;
742 }
743 
749 void usImageIo::write(const usImagePostScan2D<unsigned char> &postScanImage, const std::string &headerFileName)
750 {
751  // checking header type
752  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
753  if (headerFormat == FORMAT_XML) {
754  write(postScanImage, headerFileName, std::string(".png"));
755  } else if (headerFormat == FORMAT_MHD) {
756  write(postScanImage, headerFileName, std::string(".raw"));
757  }
758 }
759 
766 void usImageIo::write(const usImagePostScan2D<unsigned char> &postScanImage, const std::string &headerFileName,
767  const std::string &imageExtension2D)
768 {
769  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
770  if (headerFormat == FORMAT_XML) {
771 #ifdef VISP_HAVE_XML2
772  std::string imageFileName = vpIoTools::splitChain(headerFileName, ".")[0].append(imageExtension2D);
773  try {
774  // writing image
775  vpImageIo::writePNG(postScanImage, imageFileName);
776  // writing xml file using xml parser
777  usImageSettingsXmlParser xmlSettings;
778  xmlSettings.setImageSettings(postScanImage.getTransducerRadius(), postScanImage.getScanLinePitch(),
779  postScanImage.isTransducerConvex(), postScanImage.getScanLineNumber(),
780  postScanImage.getWidthResolution(), postScanImage.getHeightResolution(),
781  postScanImage.getSamplingFrequency(), postScanImage.getTransmitFrequency());
782 
783  xmlSettings.setImageType(us::POSTSCAN_2D);
784  // just writing the image file name without parents directories (header and image are in the same directory).
785  imageFileName = vpIoTools::getName(imageFileName);
786  xmlSettings.setImageFileName(imageFileName);
787  xmlSettings.save(headerFileName);
788  } catch (std::exception &e) {
789  std::cout << "Error writing postScan image : " << std::endl;
790  std::cout << e.what() << std::endl;
791  }
792 #else
793  throw(vpException(vpException::fatalError, "Requires xml2 library"));
794 #endif
795  } else if (headerFormat == FORMAT_MHD) {
796  if (imageExtension2D != ".raw" && imageExtension2D != ".RAW") {
797  throw(vpException(vpException::fatalError, "mhd files goes with .raw image extension"));
798  }
799  // mhd writing
800  std::string imageFileName = vpIoTools::splitChain(headerFileName, ".")[0].append(".raw");
801  // filling header
802  usMetaHeaderParser::MHDHeader header;
803  header.numberOfDimensions = 2;
804  header.elementType = usMetaHeaderParser::MET_UCHAR;
805  header.imageType = us::POSTSCAN_2D;
806  header.elementSpacing[0] = 1;
807  header.elementSpacing[1] = 1;
808  header.dim[0] = postScanImage.getWidth();
809  header.dim[1] = postScanImage.getHeight();
810  header.msb = false;
811  header.MHDFileName = headerFileName;
812  // remove full path for image file name (located in the same directory as the mhd
813  header.rawFileName = vpIoTools::getName(imageFileName);
814  header.isTransducerConvex = postScanImage.isTransducerConvex();
815  header.transducerRadius = postScanImage.getTransducerRadius();
816  header.scanLinePitch = postScanImage.getScanLinePitch();
817  header.scanLineNumber = postScanImage.getScanLineNumber();
818  header.samplingFrequency = postScanImage.getSamplingFrequency();
819  header.transmitFrequency = postScanImage.getTransmitFrequency();
820  // writing in file
821  usMetaHeaderParser mhdParser;
822  mhdParser.setMHDHeader(header);
823  mhdParser.setHeightResolution(postScanImage.getHeightResolution());
824  mhdParser.setWidthResolution(postScanImage.getWidthResolution());
825  mhdParser.parse();
826 
827  // filling raw
828  usRawFileParser rawParser;
829  rawParser.write(postScanImage, imageFileName);
830  } else
831  throw(vpException(vpException::fatalError, "Unknown header format."));
832 }
833 
839 void usImageIo::read(usImagePostScan2D<unsigned char> &postScanImage, const std::string &headerFileName)
840 {
841  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
842  if (headerFormat == FORMAT_XML) {
843 #ifdef VISP_HAVE_XML2
844  usImageSettingsXmlParser xmlSettings;
845  xmlSettings.parse(headerFileName);
846 
847  std::string fullImageFileName =
848  vpIoTools::getParent(headerFileName) + vpIoTools::path("/") + xmlSettings.getImageFileName();
849  vpImageIo::read(postScanImage, fullImageFileName);
850 
851  postScanImage.setTransducerRadius(xmlSettings.getTransducerSettings().getTransducerRadius());
852  postScanImage.setScanLinePitch(xmlSettings.getTransducerSettings().getScanLinePitch());
853  postScanImage.setScanLineNumber(xmlSettings.getTransducerSettings().getScanLineNumber());
854  postScanImage.setTransducerConvexity(xmlSettings.getTransducerSettings().isTransducerConvex());
855  postScanImage.setWidthResolution(xmlSettings.getWidthResolution());
856  postScanImage.setHeightResolution(xmlSettings.getHeightResolution());
857  postScanImage.setSamplingFrequency(xmlSettings.getTransducerSettings().getSamplingFrequency());
858  postScanImage.setTransmitFrequency(xmlSettings.getTransducerSettings().getTransmitFrequency());
859 #else
860  throw(vpException(vpException::fatalError, "Requires xml2 library"));
861 #endif
862  } else if (headerFormat == FORMAT_MHD) {
863  // mhd reading
864  // header parsing
865  usMetaHeaderParser mhdParser;
866  mhdParser.read(headerFileName);
867  if (mhdParser.getImageType() != us::POSTSCAN_2D && mhdParser.getImageType() != us::NOT_SET) {
868  throw(vpException(vpException::badValue, "Reading a non post-scan 2D image!"));
869  }
870  if (mhdParser.getElementType() != usMetaHeaderParser::MET_UCHAR) {
871  throw(vpException(vpException::badValue, "Reading a non unsigned char image!"));
872  }
873 
874  usMetaHeaderParser::MHDHeader mhdHeader = mhdParser.getMHDHeader();
875 
876  // resizing image in memory
877  postScanImage.resize(mhdHeader.dim[1], mhdHeader.dim[0]);
878 
879  postScanImage.setTransducerRadius(mhdHeader.transducerRadius);
880  postScanImage.setScanLinePitch(mhdHeader.scanLinePitch);
881  postScanImage.setScanLineNumber(mhdHeader.scanLineNumber);
882  postScanImage.setSamplingFrequency(mhdHeader.samplingFrequency);
883  postScanImage.setTransmitFrequency(mhdHeader.transmitFrequency);
884  postScanImage.setTransducerConvexity(mhdHeader.isTransducerConvex);
885  postScanImage.setHeightResolution(mhdParser.getHeightResolution());
886  postScanImage.setWidthResolution(mhdParser.getWidthResolution());
887  postScanImage.resize(mhdHeader.dim[1], mhdHeader.dim[0]);
888  // data parsing
889  usRawFileParser rawParser;
890  std::string fullImageFileName =
891  vpIoTools::getParent(headerFileName) + vpIoTools::path("/") + mhdParser.getRawFileName();
892  rawParser.read(postScanImage, fullImageFileName);
893  } else
894  throw(vpException(vpException::fatalError, "Unknown header format."));
895 }
896 
902 void usImageIo::write(const usImagePostScan3D<unsigned char> &postScanImage, const std::string &headerFileName)
903 {
904  // checking header type
905  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
906  if (headerFormat == FORMAT_XML) {
907  write(postScanImage, headerFileName, std::string(".png"));
908  } else if (headerFormat == FORMAT_MHD) {
909  write(postScanImage, headerFileName, std::string(".raw"));
910  }
911 }
912 
919 void usImageIo::write(const usImagePostScan3D<unsigned char> &postScanImage, const std::string &headerFileName,
920  const std::string &imageExtension2D)
921 {
922  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
923  if (headerFormat == FORMAT_XML) {
924 #ifdef VISP_HAVE_XML2
925 // case of a set of sucessive 2D frames
926 #else
927  throw(vpException(vpException::fatalError, "Requires xml2 library"));
928 #endif
929  } else if (headerFormat == FORMAT_MHD) {
930  if (imageExtension2D != ".raw") {
931  throw(vpException(vpException::fatalError, "mhd files goes with .raw image extension"));
932  }
933  std::string imageFileName = vpIoTools::splitChain(headerFileName, ".")[0].append(".raw");
934  // filling header
935  usMetaHeaderParser::MHDHeader header;
936  header.numberOfDimensions = 3;
937  header.elementType = usMetaHeaderParser::MET_UCHAR;
938  header.imageType = us::POSTSCAN_3D;
939  header.elementSpacing[0] = postScanImage.getElementSpacingX();
940  header.elementSpacing[1] = postScanImage.getElementSpacingY();
941  header.elementSpacing[2] = postScanImage.getElementSpacingZ();
942  header.dim[0] = postScanImage.getWidth();
943  header.dim[1] = postScanImage.getHeight();
944  header.dim[2] = postScanImage.getNumberOfFrames();
945  header.msb = false;
946  header.MHDFileName = headerFileName;
947  // remove full path for image file name (located in the same directory as the mhd
948  header.rawFileName = vpIoTools::getName(imageFileName);
949  header.isTransducerConvex = postScanImage.isTransducerConvex();
950  header.motorType = postScanImage.getMotorType();
951  header.transducerRadius = postScanImage.getTransducerRadius();
952  header.scanLinePitch = postScanImage.getScanLinePitch();
953  header.motorRadius = postScanImage.getMotorRadius();
954  header.framePitch = postScanImage.getFramePitch();
955  header.frameNumber = postScanImage.getFrameNumber();
956  header.scanLineNumber = postScanImage.getScanLineNumber();
957  header.samplingFrequency = postScanImage.getSamplingFrequency();
958  header.transmitFrequency = postScanImage.getTransmitFrequency();
959  // writing in file
960  usMetaHeaderParser mhdParser;
961  mhdParser.setMHDHeader(header);
962  mhdParser.setHeightResolution(postScanImage.getElementSpacingX());
963  mhdParser.setWidthResolution(postScanImage.getElementSpacingY());
964  mhdParser.parse();
965 
966  // filling raw
967  usRawFileParser rawParser;
968  rawParser.write(postScanImage, imageFileName);
969  } else
970  throw(vpException(vpException::fatalError, "Unknown header format."));
971 }
972 
978 void usImageIo::read(usImagePostScan3D<unsigned char> &postScanImage, const std::string &headerFileName)
979 {
980  usImageIo::usHeaderFormatType headerFormat = getHeaderFormat(headerFileName);
981  if (headerFormat == FORMAT_XML) {
982 #ifdef VISP_HAVE_XML2
983 // case of a set of successive 2D frames
984 #else
985  throw(vpException(vpException::fatalError, "Requires xml2 library"));
986 #endif
987  } else if (headerFormat == FORMAT_MHD) {
988  // header parsing
989  usMetaHeaderParser mhdParser;
990  mhdParser.read(headerFileName);
991  if (mhdParser.getImageType() != us::POSTSCAN_3D && mhdParser.getImageType() != us::NOT_SET) {
992  throw(vpException(vpException::badValue, "Reading a non post-scan 3D image!"));
993  }
994  if (mhdParser.getElementType() != usMetaHeaderParser::MET_UCHAR) {
995  throw(vpException(vpException::badValue, "Reading a non unsigned char image!"));
996  }
997 
998  usMetaHeaderParser::MHDHeader mhdHeader = mhdParser.getMHDHeader();
999 
1000  // resizing image in memory
1001  postScanImage.resize(mhdHeader.dim[1], mhdHeader.dim[0], mhdHeader.dim[2]);
1002 
1003  postScanImage.setTransducerRadius(mhdHeader.transducerRadius);
1004  postScanImage.setScanLinePitch(mhdHeader.scanLinePitch);
1005  postScanImage.setTransducerConvexity(mhdHeader.isTransducerConvex);
1006  postScanImage.setScanLineNumber(mhdHeader.scanLineNumber);
1007  postScanImage.setElementSpacingX(mhdHeader.elementSpacing[0]);
1008  postScanImage.setElementSpacingY(mhdHeader.elementSpacing[1]);
1009  postScanImage.setElementSpacingZ(mhdHeader.elementSpacing[2]);
1010  postScanImage.setMotorRadius(mhdHeader.motorRadius);
1011  postScanImage.setFramePitch(mhdHeader.framePitch);
1012  postScanImage.setFrameNumber(mhdHeader.frameNumber);
1013  postScanImage.setMotorType(mhdHeader.motorType);
1014  postScanImage.setSamplingFrequency(mhdHeader.samplingFrequency);
1015  postScanImage.setTransmitFrequency(mhdHeader.transmitFrequency);
1016 
1017  // data parsing
1018  usRawFileParser rawParser;
1019  std::string fullImageFileName =
1020  vpIoTools::getParent(headerFileName) + vpIoTools::path("/") + mhdParser.getRawFileName();
1021  rawParser.read(postScanImage, fullImageFileName);
1022  } else
1023  throw(vpException(vpException::fatalError, "Unknown header format."));
1024 }
unsigned int getNumberOfFrames() const
Definition: usImage3D.h:137
void resize(unsigned int height, unsigned int width, unsigned int numberOfFrames)
Definition: usImage3D.h:376
unsigned int getHeight() const
Definition: usImage3D.h:131
unsigned int getWidth() const
Definition: usImage3D.h:125
static usHeaderFormatType getHeaderFormat(const std::string &headerfilename)
Definition: usImageIo.cpp:50
static void read(usImageRF2D< short int > &imageRf2D, const std::string &headerFileName)
Definition: usImageIo.cpp:153
usHeaderFormatType
Definition: usImageIo.h:152
@ FORMAT_MHD
Definition: usImageIo.h:152
@ FORMAT_XML
Definition: usImageIo.h:152
@ HEADER_FORMAT_UNKNOWN
Definition: usImageIo.h:152
@ FORMAT_VOL
Definition: usImageIo.h:152
static void write(const usImageRF2D< short > &rfImage, const std::string &headerFileName, const std::string &imageExtension2D)
Definition: usImageIo.cpp:104
void setHeightResolution(double heightResolution)
double getHeightResolution() const
void setWidthResolution(double widthResolution)
double getWidthResolution() const
double getElementSpacingX() const
void setElementSpacingZ(double elementSpacingZ)
void setElementSpacingX(double elementSpacingX)
double getElementSpacingY() const
double getElementSpacingZ() const
void setElementSpacingY(double elementSpacingY)
void resize(const unsigned int h, const unsigned int w)
unsigned int getBModeSampleNumber() const
void setScanLineNumber(unsigned int scanLineNumber)
void resize(unsigned int height, unsigned int width, unsigned int numberOfFrames)
void insertFrame(const usImagePreScan2D< Type > &frame, unsigned int index)
Settings associated to ultrasound pre-scan images implemented in usImageRF2D, usImageRF3D,...
void setImagePreScanSettings(const usImagePreScanSettings &preScanSettings)
void setAxialResolution(const double axialResolution)
2D Radio Frequence (RF) ultrasound image.
Definition: usImageRF2D.h:112
void resize(const unsigned int height, const unsigned int width)
Definition: usImageRF2D.h:328
unsigned int getRFSampleNumber() const
Definition: usImageRF2D.h:305
3D Radio Frequence (RF) ultrasound image.
Definition: usImageRF3D.h:136
unsigned int getWidth() const
Definition: usImageRF3D.h:471
void resize(unsigned int height, unsigned int width, unsigned int numberOfFrames)
Definition: usImageRF3D.h:357
unsigned int getHeight() const
Definition: usImageRF3D.h:477
unsigned int getNumberOfFrames() const
Definition: usImageRF3D.h:483
Input/output operations between ultrasound image settings and the assiciated xml files.
usMotorSettings getMotorSettings() const
void setImageFileName(const std::string &imageFileName)
void setImageType(us::ImageType image_type)
usTransducerSettings getTransducerSettings() const
void setImageSettings(double transducerRadius, double scanLinePitch, bool isTransducerConvex, double axialResolution, us::ImageType image_type, int samplingFrequency, int transmitFrequency)
std::string getImageFileName() const
Generic class for 3D ultrasound motor settings associated to the 3D probe used during acquisition.
void setMotorSettings(const usMotorSettings &other)
unsigned int getFrameNumber() const
double getMotorRadius() const
void setMotorType(const usMotorType &motorType)
void setMotorRadius(double motorRadius)
double getFramePitch() const
void setFrameNumber(unsigned int frameNumber)
usMotorType getMotorType() const
void setFramePitch(double framePitch)
Reading of sequences of ultrasound images.
void open(ImageType &image, uint64_t &timestamp)
void acquire(ImageType &image)
void setSequenceFileName(const std::string &sequenceFileName)
usImageSettingsXmlParser getXmlParser()
void setTransducerConvexity(const bool isTransducerConvex)
void setDepth(double depth)
void setScanLinePitch(const double scanLinePitch)
void setTransmitFrequency(const int transmitFrequency)
void setSamplingFrequency(const int samplingFrequency)
void setTransducerRadius(const double transducerRadius)
double getTransducerRadius() const
unsigned int getScanLineNumber() const
void setScanLineNumber(unsigned int scanLineNumber)
@ PRESCAN_2D
Definition: us.h:70
@ POSTSCAN_2D
Definition: us.h:72
@ RF_2D
Definition: us.h:68
@ PRESCAN_3D
Definition: us.h:71
@ NOT_SET
Definition: us.h:67
@ POSTSCAN_3D
Definition: us.h:73
@ RF_3D
Definition: us.h:69