contrib/mul/vil3d/file_formats/vil3d_meta_image_format.cxx
Go to the documentation of this file.
00001 // This is mul/vil3d/file_formats/vil3d_meta_image_format.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \brief Reader/Writer for meta image format images.
00008 // \author Chris Wolstenholme - Imorphics Ltd
00009 // This file contains classes for reading and writing meta image format images
00010 // Three key components are
00011 // * vil3d_meta_image_header: Structure to contain header information
00012 // * vil3d_meta_image: Resource object which interfaces to the file,
00013 //                        allowing reading and writing via the get_copy_image()
00014 //                        and put_image() functions
00015 // * vil3d_meta_image_format: Object to create an appropriate vil3d_meta_image
00016 //
00017 // The main work of loading and saving happens in vil3d_meta_image
00018 
00019 #include "vil3d_meta_image_format.h"
00020 #include <vul/vul_file.h>
00021 #include <vil/vil_stream_fstream.h>
00022 #include <vil3d/vil3d_image_view.h>
00023 #include <vil3d/vil3d_property.h>
00024 #include <vil3d/vil3d_image_resource.h>
00025 #include <vil3d/vil3d_new.h>
00026 #include <vil3d/vil3d_copy.h>
00027 #include <vcl_algorithm.h>
00028 #include <vcl_cstring.h>
00029 #include <vcl_cstdlib.h> // for std::atoi() and atof()
00030 #include <vcl_cstddef.h> // for std::size_t
00031 #include <vcl_iostream.h>
00032 
00033 //
00034 // Helper functions
00035 //
00036 inline void vil3d_meta_image_swap16(char *a, unsigned n)
00037 {
00038   for (unsigned i = 0; i < n * 2; i += 2)
00039   {
00040     char c = a[i]; a[i] = a[i+1]; a[i+1] = c;
00041   }
00042 }
00043 
00044 inline void vil3d_meta_image_swap32(char *a, unsigned n)
00045 {
00046   for (unsigned i = 0; i < n * 4; i += 4)
00047   {
00048     char c= a[i]; a[i] = a[i+3]; a[i+3] = c;
00049     c = a[i+1]; a[i+1] = a[i+2]; a[i+2] = c;
00050   }
00051 }
00052 
00053 inline void vil3d_meta_image_swap64(char *a, unsigned n)
00054 {
00055   for (unsigned i = 0; i < n * 2; i += 2)
00056   {
00057     char c = a[i]; a[i] = a[i+7]; a[i+7] = c;
00058     c = a[i+1]; a[i+1] = a[i+6]; a[i+6] = c;
00059     c = a[i+2]; a[i+2] = a[i+5]; a[i+5] = c;
00060     c = a[i+3]; a[i+3] = a[i+4]; a[i+4] = c;
00061   }
00062 }
00063 
00064 //
00065 // Header stuff
00066 //
00067 
00068 //===================================================================
00069 // Header constructor
00070 //===================================================================
00071 vil3d_meta_image_header::vil3d_meta_image_header(void) :
00072 header_valid_(false),
00073 byte_order_msb_(false),
00074 offset_i_(0.0), offset_j_(0.0), offset_k_(0.0),
00075 vox_size_i_(1.0), vox_size_j_(1.0), vox_size_k_(1.0),
00076 dim_size_i_(0), dim_size_j_(0), dim_size_k_(0), nplanes_(1),
00077 need_swap_(false)
00078 {
00079   // No construction code
00080 }
00081 
00082 //===================================================================
00083 // Header destructor
00084 //===================================================================
00085 vil3d_meta_image_header::~vil3d_meta_image_header(void)
00086 {
00087   // No destructor code
00088 }
00089 
00090 //===================================================================
00091 // Set/get byte order
00092 //===================================================================
00093 void vil3d_meta_image_header::set_byte_order_msb(const bool is_msb)
00094 {
00095   byte_order_msb_ = is_msb;
00096 }
00097 
00098 bool vil3d_meta_image_header::byte_order_is_msb(void) const
00099 {
00100   return byte_order_msb_;
00101 }
00102 
00103 //===================================================================
00104 // Set/get offset
00105 //===================================================================
00106 void vil3d_meta_image_header::set_offset(const double off_i,
00107                                          const double off_j,
00108                                          const double off_k)
00109 {
00110   offset_i_ = off_i;
00111   offset_j_ = off_j;
00112   offset_k_ = off_k;
00113 }
00114 
00115 double vil3d_meta_image_header::offset_i(void) const
00116 {
00117   return offset_i_;
00118 }
00119 
00120 double vil3d_meta_image_header::offset_j(void) const
00121 {
00122   return offset_j_;
00123 }
00124 
00125 double vil3d_meta_image_header::offset_k(void) const
00126 {
00127   return offset_k_;
00128 }
00129 
00130 //===================================================================
00131 // Set/get voxel sizes
00132 //===================================================================
00133 void vil3d_meta_image_header::set_vox_size(const double vox_i,
00134                                            const double vox_j,
00135                                            const double vox_k)
00136 {
00137   vox_size_i_ = vox_i;
00138   vox_size_j_ = vox_j;
00139   vox_size_k_ = vox_k;
00140 }
00141 
00142 double vil3d_meta_image_header::vox_size_i(void) const
00143 {
00144   return vox_size_i_;
00145 }
00146 
00147 double vil3d_meta_image_header::vox_size_j(void) const
00148 {
00149   return vox_size_j_;
00150 }
00151 
00152 double vil3d_meta_image_header::vox_size_k(void) const
00153 {
00154   return vox_size_k_;
00155 }
00156 
00157 //===================================================================
00158 // Set/get image dimensions
00159 //===================================================================
00160 void vil3d_meta_image_header::set_dim_size(const unsigned int ni,
00161                                            const unsigned int nj,
00162                                            const unsigned int nk,
00163                                            const unsigned int np)
00164 {
00165   dim_size_i_ = ni;
00166   dim_size_j_ = nj;
00167   dim_size_k_ = nk;
00168   nplanes_ = np;
00169 }
00170 
00171 unsigned int vil3d_meta_image_header::ni(void) const
00172 {
00173   return dim_size_i_;
00174 }
00175 
00176 unsigned int vil3d_meta_image_header::nj(void) const
00177 {
00178   return dim_size_j_;
00179 }
00180 
00181 unsigned int vil3d_meta_image_header::nk(void) const
00182 {
00183   return dim_size_k_;
00184 }
00185 
00186 unsigned int vil3d_meta_image_header::nplanes(void) const
00187 {
00188   return nplanes_;
00189 }
00190 
00191 //===================================================================
00192 // Set/get element type
00193 //===================================================================
00194 void vil3d_meta_image_header::set_element_type(const vcl_string &elem_type)
00195 {
00196   elem_type_ = elem_type;
00197 }
00198 
00199 const vcl_string &vil3d_meta_image_header::element_type(void) const
00200 {
00201   return elem_type_;
00202 }
00203 
00204 //===================================================================
00205 // Set/get image file name
00206 //===================================================================
00207 void vil3d_meta_image_header::set_image_fname(const vcl_string &image_fname)
00208 {
00209   im_file_ = image_fname;
00210 }
00211 
00212 const vcl_string &vil3d_meta_image_header::image_fname(void) const
00213 {
00214   return im_file_;
00215 }
00216 
00217 //===================================================================
00218 // Set/get the pixel format
00219 //===================================================================
00220 void vil3d_meta_image_header::set_pixel_format(const vil_pixel_format format)
00221 {
00222   pformat_ = format;
00223 }
00224 
00225 vil_pixel_format vil3d_meta_image_header::pixel_format(void) const
00226 {
00227   return pformat_;
00228 }
00229 
00230 //===================================================================
00231 // Set the header back to defaults
00232 //===================================================================
00233 void vil3d_meta_image_header::clear(void)
00234 {
00235   header_valid_ = false;
00236   byte_order_msb_ = false;
00237   offset_i_ = offset_j_ = offset_k_ = 0.0;
00238   vox_size_i_ = vox_size_j_ = vox_size_k_ = 1.0;
00239   dim_size_i_ = dim_size_j_ = dim_size_k_ = 0;
00240   elem_type_ = im_file_ = "";
00241   need_swap_ = false;
00242 }
00243 
00244 //===================================================================
00245 // Read the header
00246 //===================================================================
00247 bool vil3d_meta_image_header::read_header(const vcl_string &header_fname)
00248 {
00249   vcl_ifstream hfs(header_fname.c_str());
00250 
00251   if (!hfs)
00252     return false;
00253 
00254   vcl_string nxt_line;
00255   vcl_getline(hfs,nxt_line);
00256   while (hfs.good() && !hfs.eof())
00257   {
00258     if (!check_next_header_line(nxt_line))
00259     {
00260       hfs.close();
00261       return false;
00262     }
00263     vcl_getline(hfs,nxt_line);
00264   }
00265   hfs.close();
00266   if (header_valid_)
00267   {
00268     vcl_string pth = vul_file::dirname(header_fname);
00269     pth += "/" + im_file_;
00270     im_file_ = pth;
00271     return true;
00272   }
00273   else
00274     return false;
00275 }
00276 
00277 //===================================================================
00278 // Write the header
00279 //===================================================================
00280 bool vil3d_meta_image_header::write_header(const vcl_string &header_fname) const
00281 {
00282   vcl_ofstream ofs(header_fname.c_str());
00283   if (!ofs)
00284     return false;
00285 
00286   ofs << "ObjectType = Image\n"
00287       << "NDims = 3\n"
00288       << "BinaryData = True\n"
00289       << "BinaryDataByteOrderMSB = " << ((byte_order_msb_) ? "True" : "False") << '\n'
00290       << "CompressedData = False\n"
00291       << "TransformMatrix = 1 0 0 0 1 0 0 0 1\n"
00292       << "Offset = " << offset_i_ << ' ' << offset_j_ << ' ' << offset_k_ << '\n'
00293       << "CenterOfRotation = 0 0 0\n"
00294       << "AnatomicalOrientation = RAI\n"
00295       << "ElementSpacing = " << vox_size_i_ << ' ' << vox_size_j_ << ' ' << vox_size_k_ << '\n'
00296       << "DimSize = " << dim_size_i_ << ' ' << dim_size_j_ << ' ' << dim_size_k_ << '\n'
00297       << "ElementType = " << elem_type_ << '\n'
00298       << "ElementDataFile = " << vul_file::strip_directory(im_file_) << vcl_endl;
00299 
00300   ofs.close();
00301   return true;
00302 }
00303 
00304 //===================================================================
00305 // Display header elements
00306 //===================================================================
00307 void vil3d_meta_image_header::print_header(vcl_ostream &os) const
00308 {
00309   os << "\n============= Meta Image Header Summary Begin =============\n"
00310      << "vil3d_meta_image_header - byte order is msb: " << ((byte_order_msb_) ? "true" : "false") << '\n'
00311      << "vil3d_meta_image_header - offset " << offset_i_ << ", " << offset_j_ << ", " << offset_k_ << '\n'
00312      << "vil3d_meta_image_header - voxel size: " << vox_size_i_ << ", " << vox_size_j_ << ", " << vox_size_k_ << '\n'
00313      << "vil3d_meta_image_header - dimension size: " << dim_size_i_ << ", " << dim_size_j_ << ", " << dim_size_k_ << '\n'
00314      << "vil3d_meta_image_header - nplanes: " << nplanes_ << '\n'
00315      << "vil3d_meta_image_header - element type: " << elem_type_ << '\n'
00316      << "vil3d_meta_image_header - image file: " << im_file_ << '\n'
00317      << "============= Meta Image Header Summary End =============\n" << vcl_endl;
00318 }
00319 
00320 //===================================================================
00321 // Check if swapping is needed
00322 //===================================================================
00323 void vil3d_meta_image_header::check_need_swap(void)
00324 {
00325   union short_char
00326   {
00327     short short_val;
00328     char char_val[2];
00329   } test_swap;
00330 
00331   test_swap.short_val = 1;
00332 
00333   if (test_swap.char_val[0]==1 && byte_order_msb_) // System little endian, file big endian
00334     need_swap_ = true;
00335   else if (test_swap.char_val[1]==1 && (!byte_order_msb_)) // System big endian, file little endian
00336     need_swap_ = true;
00337   else
00338     need_swap_ = false;
00339 }
00340 
00341 //===================================================================
00342 // Return whether swap is needed
00343 //===================================================================
00344 bool vil3d_meta_image_header::need_swap(void) const
00345 {
00346   return need_swap_;
00347 }
00348 
00349 //===================================================================
00350 // Check the next line in the header
00351 //===================================================================
00352 bool vil3d_meta_image_header::check_next_header_line(const vcl_string &nxt_line)
00353 {
00354   // Look for each element we're interested in
00355   vcl_string val = get_header_value(nxt_line);
00356   if (val=="")
00357     return false;
00358 
00359   if (nxt_line.find("ObjectType")!= vcl_string::npos)
00360   {
00361     if (val != "Image")
00362     {
00363       vcl_cerr << "Loader only handles Image Types.\n";
00364       return false;
00365     }
00366   }
00367   else if (nxt_line.find("NDims")!= vcl_string::npos)
00368   {
00369     unsigned int nd = vcl_atoi(val.c_str());
00370     if (nd != 3)
00371     {
00372       vcl_cerr << "Loader only handles 3D Images.\n";
00373       return false;
00374     }
00375   }
00376   else if (nxt_line.find("BinaryDataByteOrderMSB")!= vcl_string::npos)
00377   {
00378     byte_order_msb_ = (val=="True") ? true : false;
00379     header_valid_ = true;
00380     check_need_swap();
00381   }
00382   else if (nxt_line.find("CompressedData")!= vcl_string::npos)
00383   {
00384     if (val=="True")
00385     {
00386       vcl_cerr << "Loader does not handle compressed data\n";
00387       return false;
00388     }
00389   }
00390   else if (nxt_line.find("TransformMatrix")!= vcl_string::npos)
00391   {
00392     if (val != "1 0 0 0 1 0 0 0 1")
00393     {
00394       vcl_cout << "Loader only handles identity in TransformMatrix.\n"
00395                << "Transformation ignored." << vcl_endl;
00396     }
00397   }
00398   else if (nxt_line.find("Offset")!= vcl_string::npos) // If there is another field at some point with Offset in the name check them before this one!
00399   {
00400     return set_header_offset(val);
00401   }
00402   else if (nxt_line.find("DimSize")!= vcl_string::npos)
00403   {
00404     return set_header_dim_size(val);
00405   }
00406   else if (nxt_line.find("ElementSpacing")!= vcl_string::npos)
00407   {
00408     return set_header_voxel_size(val);
00409   }
00410   else if (nxt_line.find("ElementSize")!= vcl_string::npos)
00411   {
00412     return set_header_voxel_size(val);
00413   }
00414   else if (nxt_line.find("ElementType")!= vcl_string::npos)
00415   {
00416     elem_type_ = val;
00417     if (elem_type_ == "MET_SHORT")
00418       pformat_ = VIL_PIXEL_FORMAT_INT_16;
00419     else if (elem_type_ == "MET_UCHAR")
00420       pformat_ = VIL_PIXEL_FORMAT_BYTE;
00421     else if (elem_type_ == "MET_CHAR")
00422       pformat_ = VIL_PIXEL_FORMAT_SBYTE;
00423     else if (elem_type_ == "MET_DOUBLE")
00424       pformat_ = VIL_PIXEL_FORMAT_DOUBLE;
00425     else if (elem_type_ == "MET_FLOAT")
00426       pformat_ = VIL_PIXEL_FORMAT_FLOAT;
00427     else
00428     {
00429       vcl_cerr << "Unsupported element type specified: " << val << "\n";
00430       return false;
00431     }
00432     header_valid_ = true;
00433   }
00434   else if (nxt_line.find("ElementDataFile")!= vcl_string::npos)
00435   {
00436     im_file_ = val;
00437     header_valid_ = true;
00438   }
00439   return true;
00440 }
00441 
00442 //===================================================================
00443 // Get the value associated with a header element
00444 //===================================================================
00445 vcl_string vil3d_meta_image_header::get_header_value(const vcl_string &nxt_line)
00446 {
00447   vcl_string::size_type pos, epos;
00448   pos = nxt_line.find("=");
00449   if (pos == vcl_string::npos || pos == nxt_line.size()-1)
00450   {
00451     return "";
00452   }
00453 
00454   pos = nxt_line.find_first_not_of(" ", pos+1);
00455   epos = nxt_line.find_last_not_of(" ");
00456   if (pos == vcl_string::npos || epos == vcl_string::npos)
00457   {
00458     return "";
00459   }
00460 
00461   return nxt_line.substr(pos, (epos-pos)+1);
00462 }
00463 
00464 //===================================================================
00465 // Set the header offset
00466 //===================================================================
00467 bool vil3d_meta_image_header::set_header_offset(const vcl_string &offs)
00468 {
00469   vcl_string::size_type pos,epos;
00470   epos=offs.find_first_of(" ");
00471   if (epos==vcl_string::npos)
00472   {
00473     vcl_cerr << "Offset does not contain three values.\n";
00474     return false;
00475   }
00476 
00477   offset_i_=vcl_atof(offs.substr(0,epos).c_str());
00478   pos=offs.find_first_not_of(" ",epos);
00479   epos=offs.find_first_of(" ",pos);
00480   if (pos==vcl_string::npos || epos==vcl_string::npos)
00481   {
00482     vcl_cerr << "Offset does not contain three values.\n";
00483     return false;
00484   }
00485 
00486   offset_j_=vcl_atof(offs.substr(pos,epos).c_str());
00487   pos=offs.find_first_not_of(" ",epos);
00488   if (pos==vcl_string::npos)
00489   {
00490     vcl_cerr << "Offset does not contain three values.\n";
00491     return false;
00492   }
00493   offset_k_=vcl_atof(offs.substr(pos).c_str());
00494   epos = offs.find_first_of(" ",pos);
00495   pos=offs.find_first_not_of(" ",epos);
00496   if (pos != vcl_string::npos)
00497   {
00498      vcl_cerr << "Offset contains more than three values.\n";
00499      return false;
00500   }
00501   header_valid_ = true;
00502   return true;
00503 }
00504 
00505 //===================================================================
00506 // Set the dimensions from the header
00507 //===================================================================
00508 bool vil3d_meta_image_header::set_header_dim_size(const vcl_string &dims)
00509 {
00510   vcl_string::size_type pos,epos;
00511   epos=dims.find_first_of(" ");
00512   if (epos==vcl_string::npos)
00513   {
00514     vcl_cerr << "Dim Size does not contain three values.\n";
00515     return false;
00516   }
00517   dim_size_i_=vcl_atoi(dims.substr(0,epos).c_str());
00518   pos=dims.find_first_not_of(" ",epos);
00519   epos=dims.find_first_of(" ",pos);
00520   if (pos==vcl_string::npos || epos==vcl_string::npos)
00521   {
00522     vcl_cerr << "Dim Size does not contain three values.\n";
00523     return false;
00524   }
00525   dim_size_j_=vcl_atoi(dims.substr(pos,epos).c_str());
00526   pos=dims.find_first_not_of(" ",epos);
00527   if (pos==vcl_string::npos)
00528   {
00529     vcl_cerr << "Dim Size does not contain three values.\n";
00530     return false;
00531   }
00532   dim_size_k_=vcl_atoi(dims.substr(pos).c_str());
00533   epos = dims.find_first_of(" ",pos);
00534   pos=dims.find_first_not_of(" ",epos);
00535   if (pos != vcl_string::npos)
00536   {
00537      vcl_cerr << "Dim Size contains more than three values.\n";
00538      return false;
00539   }
00540   // For now only deal with 1 plane
00541   nplanes_=1;
00542   header_valid_=true;
00543   return true;
00544 }
00545 
00546 //===================================================================
00547 // Set the header voxel size
00548 //===================================================================
00549 bool vil3d_meta_image_header::set_header_voxel_size(const vcl_string &vsize)
00550 {
00551   vcl_string::size_type pos,epos;
00552   epos=vsize.find_first_of(" ");
00553   if (epos==vcl_string::npos)
00554   {
00555     vcl_cerr << "Element Spacing/Size does not contain three values.\n";
00556     return false;
00557   }
00558   vox_size_i_=vcl_atof(vsize.substr(0,epos).c_str());
00559   pos=vsize.find_first_not_of(" ",epos);
00560   epos=vsize.find_first_of(" ",pos);
00561   if (pos==vcl_string::npos || epos==vcl_string::npos)
00562   {
00563     vcl_cerr << "Element Spacing/Size does not contain three values.\n";
00564     return false;
00565   }
00566   vox_size_j_=vcl_atof(vsize.substr(pos,epos).c_str());
00567   pos=vsize.find_first_not_of(" ",epos);
00568   if (pos==vcl_string::npos)
00569   {
00570     vcl_cerr << "Element Spacing/Size does not contain three values.\n";
00571     return false;
00572   }
00573   vox_size_k_=vcl_atof(vsize.substr(pos).c_str());
00574   epos = vsize.find_first_of(" ",pos);
00575   pos=vsize.find_first_not_of(" ",epos);
00576   if (pos != vcl_string::npos)
00577   {
00578      vcl_cerr << "Element Spacing/Size contains more than three values.\n";
00579      return false;
00580   }
00581   header_valid_ = true;
00582   return true;
00583 }
00584 
00585 //===================================================================
00586 // Display the header
00587 //===================================================================
00588 vcl_ostream& operator<<(vcl_ostream& os, const vil3d_meta_image_header& header)
00589 {
00590   header.print_header(os);
00591   return os;
00592 }
00593 
00594 /*
00595  * Format stuff
00596  */
00597 
00598 //===================================================================
00599 // Construct image format
00600 //===================================================================
00601 vil3d_meta_image_format::vil3d_meta_image_format()
00602 {
00603   // Nothing to be done on construction
00604 }
00605 
00606 //===================================================================
00607 // Destruct image format
00608 //===================================================================
00609 vil3d_meta_image_format::~vil3d_meta_image_format()
00610 {
00611   // Nothing to be done on destruction
00612 }
00613 
00614 //===================================================================
00615 // Create an input image
00616 //===================================================================
00617 vil3d_image_resource_sptr vil3d_meta_image_format::make_input_image(const char *fname) const
00618 {
00619   vil3d_meta_image_header header;
00620   vcl_string filename(fname);
00621 
00622   if (!header.read_header(fname)) return 0;
00623   //vcl_cout<<"vil3d_meta_image_format::make_input_image() Header: "<<header<<vcl_endl;
00624 
00625   return new vil3d_meta_image(header,filename);
00626 }
00627 
00628 //===================================================================
00629 // Create an output image
00630 //===================================================================
00631 vil3d_image_resource_sptr vil3d_meta_image_format::make_output_image(const char *filename,
00632                                                                      unsigned int ni,
00633                                                                      unsigned int nj,
00634                                                                      unsigned int nk,
00635                                                                      unsigned int nplanes,
00636                                                                      vil_pixel_format format) const
00637 {
00638   if (format != VIL_PIXEL_FORMAT_BYTE   &&
00639       format != VIL_PIXEL_FORMAT_SBYTE &&
00640       format != VIL_PIXEL_FORMAT_INT_16 &&
00641       format != VIL_PIXEL_FORMAT_DOUBLE &&
00642       format != VIL_PIXEL_FORMAT_FLOAT)
00643   {
00644     vcl_cerr << "vil3d_meta_image_format::make_output_image() WARNING\n"
00645              << "  Unable to deal with pixel format : " << format << vcl_endl;
00646     return 0;
00647   }
00648 
00649   vil3d_meta_image_header header;
00650   header.clear();
00651   header.set_dim_size(ni,nj,nk,nplanes);
00652   header.set_pixel_format(format);
00653 
00654   switch (format)
00655   {
00656   case VIL_PIXEL_FORMAT_BYTE: header.set_element_type("MET_UCHAR");
00657                               break;
00658   case VIL_PIXEL_FORMAT_SBYTE: header.set_element_type("MET_CHAR");
00659                               break;
00660   case VIL_PIXEL_FORMAT_INT_16: header.set_element_type("MET_SHORT");
00661                               break;
00662   case VIL_PIXEL_FORMAT_DOUBLE: header.set_element_type("MET_DOUBLE");
00663                               break;
00664   case VIL_PIXEL_FORMAT_FLOAT: header.set_element_type("MET_FLOAT");
00665                               break;
00666   default:
00667       vcl_cerr << "vil3d_meta_image_format::make_output_image() WARNING\n"
00668                << "  Unable to deal with pixel format : " << format << vcl_endl;
00669       return 0;
00670   }
00671 
00672   vcl_string str_fname(filename);
00673   vcl_string base_filename;
00674   vcl_size_t n=str_fname.size();
00675   if (n>=4 && (str_fname.substr(n-4,4)==".mhd" || str_fname.substr(n-4,4)==".raw"))
00676     base_filename = str_fname.substr(0,n-4);
00677   else
00678     base_filename = str_fname;
00679   vcl_string im_file = vul_file::strip_directory(base_filename);
00680   header.set_image_fname(im_file + ".raw");
00681   if (!header.write_header(base_filename+".mhd")) return 0;
00682   return new vil3d_meta_image(header,base_filename);
00683 }
00684 
00685 /*
00686  * Image stuff
00687  */
00688 
00689 //===================================================================
00690 // Construct an image
00691 //===================================================================
00692 vil3d_meta_image::vil3d_meta_image(const vil3d_meta_image_header &header,
00693                                    const vcl_string &fname) :
00694 header_(header),
00695 fpath_(fname)
00696 {
00697   // No code necessary
00698 }
00699 
00700 //===================================================================
00701 // Destruct
00702 //===================================================================
00703 vil3d_meta_image::~vil3d_meta_image(void)
00704 {
00705   // No code necessary
00706 }
00707 
00708 //===================================================================
00709 // Get the image dimension details
00710 //===================================================================
00711 unsigned int vil3d_meta_image::nplanes(void) const
00712 {
00713   return header_.nplanes();
00714 }
00715 
00716 unsigned int vil3d_meta_image::ni(void) const
00717 {
00718   return header_.ni();
00719 }
00720 
00721 unsigned int vil3d_meta_image::nj(void) const
00722 {
00723   return header_.nj();
00724 }
00725 
00726 unsigned int vil3d_meta_image::nk(void) const
00727 {
00728   return header_.nk();
00729 }
00730 
00731 //===================================================================
00732 // Get the current header
00733 //===================================================================
00734 const vil3d_meta_image_header &vil3d_meta_image::header(void) const
00735 {
00736   return header_;
00737 }
00738 
00739 //===================================================================
00740 // Get the pixel format
00741 //===================================================================
00742 vil_pixel_format vil3d_meta_image::pixel_format(void) const
00743 {
00744   return header_.pixel_format();
00745 }
00746 
00747 //===================================================================
00748 // Set the voxel size
00749 //===================================================================
00750 bool vil3d_meta_image::set_voxel_size(float vi, float vj, float vk)
00751 {
00752   header_.set_vox_size(vi,vj,vk);
00753   if (!header_.write_header(fpath_+".mhd")) return false;
00754   return true;
00755 }
00756 
00757 //===================================================================
00758 // Set the offet
00759 //===================================================================
00760 void vil3d_meta_image::set_offset(const double i, const double j, const double k,
00761                                   const double vx_i, const double vx_j, const double vx_k)
00762 {
00763   double os_i, os_j, os_k;
00764   os_i = (-(i*vx_i));
00765   os_j = (-(j*vx_j));
00766   os_k = (-(k*vx_k));
00767   header_.set_offset(os_i,os_j,os_k);
00768   header_.set_vox_size(vx_i,vx_j,vx_k);
00769   header_.write_header(fpath_+".mhd");
00770 }
00771 
00772 //===================================================================
00773 // Create a read/write view of a copy of this data
00774 //===================================================================
00775 vil3d_image_view_base_sptr vil3d_meta_image::get_copy_view(unsigned int i0, unsigned int ni,
00776                                                            unsigned int j0, unsigned int nj,
00777                                                            unsigned int k0, unsigned int nk) const
00778 {
00779   // Can only cope with loading whole image at present.
00780   if (i0!=0 || ni!=header_.ni() ||
00781       j0!=0 || nj!=header_.nj() ||
00782       k0!=0 || nk!=header_.nk()   )
00783     return 0;
00784 
00785   vcl_string image_data_path=header_.image_fname();
00786   vil_smart_ptr<vil_stream> is = new vil_stream_fstream(image_data_path.c_str(),"r");
00787   if (!is->ok()) return 0;
00788 
00789 // NOTE: See GIPL loader for more general data reading
00790 #define read_data_of_type(type) \
00791   vil3d_image_view< type > im = \
00792          vil3d_new_image_view_plane_k_j_i(ni, nj, nk, nplanes(), type()); \
00793   is->read(&im(0,0,0,0), ni * nj * nk * nplanes() * sizeof(type));
00794 
00795   switch (pixel_format())
00796   {
00797    case VIL_PIXEL_FORMAT_BYTE:
00798    {
00799     read_data_of_type(vxl_byte);
00800     return new vil3d_image_view<vxl_byte>(im);
00801    }
00802    case VIL_PIXEL_FORMAT_SBYTE:
00803    {
00804      read_data_of_type(vxl_sbyte);
00805      return new vil3d_image_view<vxl_sbyte>(im);
00806    }
00807    case VIL_PIXEL_FORMAT_INT_16:
00808    {
00809     read_data_of_type(vxl_int_16);
00810     if (header_.need_swap())
00811       vil3d_meta_image_swap16((char *)(im.origin_ptr()), ni*nj*nk);
00812     return new vil3d_image_view<vxl_int_16>(im);
00813    }
00814    case VIL_PIXEL_FORMAT_DOUBLE:
00815    {
00816     read_data_of_type(double);
00817     if (header_.need_swap())
00818       vil3d_meta_image_swap64((char *)(im.origin_ptr()), ni*nj*nk);
00819     return new vil3d_image_view<double>(im);
00820    }
00821    case VIL_PIXEL_FORMAT_FLOAT:
00822    {
00823     read_data_of_type(float);
00824     if (header_.need_swap())
00825       vil3d_meta_image_swap32((char *)(im.origin_ptr()), ni*nj*nk);
00826     return new vil3d_image_view<float>(im);
00827    }
00828    default:
00829     vcl_cout<<"ERROR: vil3d_meta_image_format::get_copy_view()\n"
00830             <<"Can't deal with pixel type " << pixel_format() << vcl_endl;
00831     return 0;
00832   }
00833 }
00834 
00835 //===================================================================
00836 // Put view
00837 //===================================================================
00838 bool vil3d_meta_image::put_view(const vil3d_image_view_base &im,
00839                                 unsigned int i0,
00840                                 unsigned int j0,
00841                                 unsigned int k0)
00842 {
00843   if (!view_fits(im, i0, j0, k0))
00844   {
00845     vcl_cerr << "ERROR: " << __FILE__ << ":\n view does not fit\n";
00846     return false;
00847   }
00848   if (im.ni()!=ni() || im.nj()!=nj() || im.nk()!=nk())
00849   {
00850     vcl_cerr<<"Can only write whole image at once.\n";
00851     return false;
00852   }
00853 
00854   vcl_string image_data_path=fpath_+".raw";
00855   vil_smart_ptr<vil_stream> os = new vil_stream_fstream(image_data_path.c_str(),"w");
00856   if (!os->ok()) return 0;
00857 
00858   switch (pixel_format())
00859   {
00860    case VIL_PIXEL_FORMAT_BYTE:
00861    {
00862     vil3d_image_view<vxl_byte> view_copy(ni(),nj(),nk(),nplanes());
00863     vil3d_copy_reformat(static_cast<const vil3d_image_view<vxl_byte>&>(im),view_copy);
00864     os->write(view_copy.origin_ptr(),ni()*nj()*nk()*nplanes());
00865     // Should check that write was successful
00866     return true;
00867    }
00868    case VIL_PIXEL_FORMAT_SBYTE:
00869    {
00870     vil3d_image_view<vxl_sbyte> view_copy(ni(),nj(),nk(),nplanes());
00871     vil3d_copy_reformat(static_cast<const vil3d_image_view<vxl_sbyte>&>(im),view_copy);
00872     os->write(view_copy.origin_ptr(),ni()*nj()*nk()*nplanes());
00873     // Should check that write was successful
00874     return true;
00875    }
00876    case VIL_PIXEL_FORMAT_INT_16:
00877    {
00878      header_.check_need_swap();
00879     vil3d_image_view<vxl_int_16> view_copy(ni(),nj(),nk(),nplanes());
00880     vil3d_copy_reformat(static_cast<const vil3d_image_view<vxl_int_16>&>(im),view_copy);
00881     if (header_.need_swap())
00882       vil3d_meta_image_swap16((char *)(view_copy.origin_ptr()), ni()*nj()*nk()*nplanes());
00883     os->write(view_copy.origin_ptr(),ni()*nj()*nk()*nplanes()*sizeof(vxl_int_16));
00884     // Should check that write was successful
00885     return true;
00886    }
00887    case VIL_PIXEL_FORMAT_DOUBLE:
00888    {
00889      header_.check_need_swap();
00890     vil3d_image_view<double> view_copy(ni(),nj(),nk(),nplanes());
00891     vil3d_copy_reformat(static_cast<const vil3d_image_view<double>&>(im),view_copy);
00892     if (header_.need_swap())
00893       vil3d_meta_image_swap64((char *)(view_copy.origin_ptr()), ni()*nj()*nk()*nplanes());
00894     os->write(view_copy.origin_ptr(),ni()*nj()*nk()*nplanes()*sizeof(double));
00895     // Should check that write was successful
00896     return true;
00897    }
00898    case VIL_PIXEL_FORMAT_FLOAT:
00899    {
00900      header_.check_need_swap();
00901     vil3d_image_view<float> view_copy(ni(),nj(),nk(),nplanes());
00902     vil3d_copy_reformat(static_cast<const vil3d_image_view<float>&>(im),view_copy);
00903     if (header_.need_swap())
00904       vil3d_meta_image_swap32((char *)(view_copy.origin_ptr()), ni()*nj()*nk()*nplanes());
00905     os->write(view_copy.origin_ptr(),ni()*nj()*nk()*nplanes()*sizeof(float));
00906     // Should check that write was successful
00907     return true;
00908    }
00909    default:
00910     vcl_cout<<"ERROR: vil3d_analyze_format::put_view()\n"
00911             <<"Can't deal with pixel type " << pixel_format() << vcl_endl;
00912   }
00913 
00914   return false;
00915 }
00916 
00917 //===================================================================
00918 // Get an image property
00919 //===================================================================
00920 bool vil3d_meta_image::get_property(const char *label, void *property_value) const
00921 {
00922   if (vcl_strcmp(vil3d_property_voxel_size, label)==0)
00923   {
00924     float* array = static_cast<float*>(property_value);
00925     // meta image stores data in mm
00926     array[0] = static_cast<float>(header_.vox_size_i() / 1000.0);
00927     array[1] = static_cast<float>(header_.vox_size_j() / 1000.0);
00928     array[2] = static_cast<float>(header_.vox_size_k() / 1000.0);
00929     return true;
00930   }
00931 
00932   if (vcl_strcmp(vil3d_property_origin_offset, label)==0)
00933   {
00934     float* array = static_cast<float*>(property_value);
00935     array[0] = static_cast<float>((-header_.offset_i())/header_.vox_size_i());
00936     array[1] = static_cast<float>((-header_.offset_j())/header_.vox_size_j());
00937     array[2] = static_cast<float>((-header_.offset_k())/header_.vox_size_k());
00938     return true;
00939   }
00940 
00941   return false;
00942 }
00943