contrib/mul/vil3d/file_formats/vil3d_slice_list.cxx
Go to the documentation of this file.
00001 #include "vil3d_slice_list.h"
00002 //:
00003 // \file
00004 // \brief Reader/Writer for a volume made up of a list of slices.
00005 // \author Ian Scott - Manchester
00006 
00007 #include <vcl_cstring.h>
00008 #include <vcl_cstdlib.h>
00009 #include <vcl_algorithm.h>
00010 #include <vul/vul_file.h>
00011 #include <vul/vul_file_iterator.h>
00012 #include <vil/vil_load.h>
00013 #include <vil/vil_copy.h>
00014 #include <vil3d/vil3d_image_view.h>
00015 #include <vil3d/vil3d_slice.h>
00016 #include <vil3d/file_formats/vil3d_dicom.h>
00017 
00018 vil3d_slice_list_format::vil3d_slice_list_format() {}
00019 
00020 vil3d_slice_list_format::~vil3d_slice_list_format()
00021 {
00022 }
00023 
00024 // Look for a set of filenames that match the glob spec in filename
00025 // The globbing format expects only '#' to represent numbers.
00026 // Do not use "*" or "?"
00027 // All "#" should be in one contiguous group.
00028 void parse_globbed_filenames(const vcl_string & input,
00029                              vcl_vector<vcl_string> &filenames)
00030 {
00031   filenames.clear();
00032   vcl_string filename = input;
00033 
00034   // Avoid confusing globbing functions
00035   if (filename.find("*") != filename.npos) return;
00036   if (filename.find("?") != filename.npos) return;
00037 
00038   // Check that all the #s are in a single group.
00039   vcl_size_t start = filename.find_first_of("#");
00040   if (start == filename.npos) return;
00041   vcl_size_t end = filename.find_first_not_of("#", start);
00042   if (filename.find_first_of("#",end) != filename.npos) return;
00043   if (end == filename.npos) end = filename.length();
00044   for (vcl_size_t i=start, j=start; i!=end; ++i, j+=12)
00045     filename.replace(j,1,"[0123456789]");
00046 
00047 
00048   // Search for the files
00049   for (vul_file_iterator fit(filename); fit; ++fit)
00050     filenames.push_back(fit());
00051 
00052 
00053   if (filenames.empty()) return;
00054 
00055   start = (start + filenames.front().size()) - input.size();
00056   end = (end + filenames.front().size()) - input.size();
00057 
00058   // Put them all in numeric order.
00059   vcl_sort(filenames.begin(), filenames.end());
00060 
00061   // Now discard non-contiguously numbered files.
00062   long count = vcl_atol(filenames.front().substr(start, end-start).c_str());
00063   vcl_vector<vcl_string>::iterator it=filenames.begin()+1;
00064   while (it != filenames.end())
00065   {
00066     if (vcl_atol(it->substr(start, end-start).c_str()) != ++count)
00067       break;
00068     ++it;
00069   }
00070   filenames.erase(it, filenames.end());
00071 }
00072 
00073 
00074 void parse_multiple_filenames(const vcl_string & input,
00075                               vcl_vector<vcl_string> &filenames)
00076 {
00077   filenames.clear();
00078   unsigned start=0;
00079   for (unsigned i=0; i != input.size(); ++i)
00080   {
00081     if (input[i]==';')
00082     {
00083       filenames.push_back(input.substr(start, i-start));
00084       start=i+1;
00085     }
00086   }
00087   filenames.push_back(input.substr(start, input.size() - start));
00088 }
00089 
00090 vil3d_image_resource_sptr
00091 vil3d_slice_list_format::make_input_image(const char * filename) const
00092 {
00093   vcl_vector<vcl_string> filenames;
00094   parse_multiple_filenames(filename, filenames);
00095 
00096   for (unsigned i=0; i<filenames.size(); ++i)
00097     if (!vul_file::exists(filenames[i]))
00098     {
00099       filenames.clear();
00100       break;
00101     }
00102 
00103 
00104   if (filenames.empty() || filenames.size()==1)
00105     parse_globbed_filenames(filename, filenames);
00106 
00107   if (filenames.empty()) return 0;
00108 
00109   // load all the slices
00110   vcl_vector<vil_image_resource_sptr> images(filenames.size());
00111 
00112   bool same = true;
00113 
00114   for (unsigned i=0; i<filenames.size(); ++i)
00115   {
00116     vil_image_resource_sptr im  =
00117       vil_load_image_resource(filenames[i].c_str());
00118 
00119     images[i]=im;
00120     // make sure all slices are consistent,
00121     if (!im ||
00122         im->nplanes() != images.front()->nplanes() ||
00123         im->ni() != images.front()->ni() ||
00124         im->nj() != images.front()->nj() ||
00125         im->pixel_format() != images.front()->pixel_format())
00126       return 0;
00127     // decide if all slices are of the same type.
00128     if (vcl_strcmp(im->file_format(), images.front()->file_format())!=0)
00129       same=true;
00130   }
00131 
00132   // everything seems fine so create the volume
00133 
00134   // If they are all dicom images, create an explicit dicom volume.
00135   if (same && vcl_strcmp("dicom", images.front()->file_format())==0)
00136     return new vil3d_dicom_image(images);
00137 
00138   return new vil3d_slice_list_image(images);
00139 }
00140 
00141 
00142 vil3d_image_resource_sptr
00143 vil3d_slice_list_to_volume(const vcl_vector<vil_image_resource_sptr> & images)
00144 {
00145   if (!images.empty() && !images.front()) return 0;
00146   for (unsigned i=1; i<images.size(); ++i)
00147   {
00148     // make sure all slices are consistent,
00149     if (!images[i] ||
00150         images[i]->nplanes() != images.front()->nplanes() ||
00151         images[i]->ni() != images.front()->ni() ||
00152         images[i]->nj() != images.front()->nj() ||
00153         images[i]->pixel_format() != images.front()->pixel_format())
00154       return 0;
00155   }
00156   // everything seems fine so create the volume
00157   return new vil3d_slice_list_image(images);
00158 }
00159 
00160 
00161 //: Not implemented - Make a "generic_image" on which put_section may be applied.
00162 // The file may be opened immediately for writing so that a header can be written.
00163 // The width/height etc are explicitly specified, so that file_format implementors
00164 // know what they need to do...
00165 vil3d_image_resource_sptr
00166 vil3d_slice_list_format::make_output_image(const char* /*filename*/,
00167                                            unsigned /*ni*/, unsigned /*nj*/,
00168                                            unsigned /*nk*/, unsigned /*nplanes*/,
00169                                            enum vil_pixel_format) const
00170 {
00171   // This should follow the pattern of make_input_image.
00172   // Construct a load of image resources using vil_new_image_resource
00173   // If you are able to construct them all, then create the slice_image.
00174   vcl_cerr <<"vil3d_slice_list_format::make_output_image() NYI\n";
00175   vcl_abort();
00176   return 0;
00177 }
00178 
00179 
00180 vil3d_slice_list_image::vil3d_slice_list_image(const vcl_vector<vil_image_resource_sptr>& images):
00181 slices_(images)
00182 {
00183 }
00184 
00185 vil3d_slice_list_image::~vil3d_slice_list_image()
00186 {
00187 }
00188 
00189 //: Dimensions:  nplanes x ni x nj x nk.
00190 // This concept is treated as a synonym to components.
00191 unsigned vil3d_slice_list_image::nplanes() const
00192 {
00193   return slices_.empty()?0:slices_.front()->nplanes();
00194 }
00195 //: Dimensions:  nplanes x ni x nj x nk.
00196 // The number of pixels in each row.
00197 unsigned vil3d_slice_list_image::ni() const
00198 {
00199   return slices_.empty()?0:slices_.front()->ni();
00200 }
00201 //: Dimensions:  nplanes x ni x nj x nk.
00202 // The number of pixels in each column.
00203 unsigned vil3d_slice_list_image::nj() const
00204 {
00205   return slices_.empty()?0:slices_.front()->nj();
00206 }
00207 //: Dimensions:  nplanes x ni x nj x nk.
00208 // The number of slices per image.
00209 unsigned vil3d_slice_list_image::nk() const
00210 {
00211   return (unsigned)(slices_.size());
00212 }
00213 
00214 //: Pixel Format.
00215 enum vil_pixel_format vil3d_slice_list_image::pixel_format() const
00216 {
00217   return slices_.empty() ? VIL_PIXEL_FORMAT_UNKNOWN :
00218     slices_.front()->pixel_format();
00219 }
00220 
00221 //: Get the properties (of the first slice)
00222 bool vil3d_slice_list_image::get_property(char const *key, void * value) const
00223 {
00224   return slices_.empty()?false:slices_.front()->get_property(key, value);
00225 }
00226 
00227 //: Get some or all of the volume.
00228 vil3d_image_view_base_sptr
00229 vil3d_slice_list_image::get_copy_view(unsigned i0, unsigned ni,
00230                                       unsigned j0, unsigned nj,
00231                                       unsigned k0, unsigned nk) const
00232 {
00233   if (i0+ni > this->ni() || j0+nj > this->nj() || k0+nk > this->nk()) return 0;
00234 
00235 #define macro( type ) { \
00236   vil3d_image_view< type > vv(ni, nj, nk, nplanes()); \
00237   for (unsigned k=0; k<nk; ++k)  { \
00238     vil_image_view< type > src(slices_[k+k0]->get_view(i0, ni, j0, nj)); \
00239     vil_image_view< type > dest(vil3d_slice_ij(vv, k)); \
00240     vil_copy_reformat(src, dest); } \
00241   return new vil3d_image_view< type >(vv); \
00242 }
00243 
00244   switch (pixel_format())
00245   {
00246   case VIL_PIXEL_FORMAT_BYTE:
00247     macro( vxl_byte );
00248   case VIL_PIXEL_FORMAT_SBYTE:
00249     macro( vxl_sbyte );
00250   case VIL_PIXEL_FORMAT_UINT_16:
00251     macro( vxl_uint_16 );
00252   case VIL_PIXEL_FORMAT_INT_16:
00253     macro( vxl_int_16 );
00254   case VIL_PIXEL_FORMAT_UINT_32:
00255     macro( vxl_uint_32 );
00256   case VIL_PIXEL_FORMAT_INT_32:
00257     macro( vxl_int_32 );
00258   case VIL_PIXEL_FORMAT_FLOAT:
00259     macro( float );
00260   case VIL_PIXEL_FORMAT_DOUBLE:
00261     macro( double );
00262 #if 0 // Several missing templates needed before these can be used
00263   case VIL_PIXEL_FORMAT_COMPLEX_FLOAT:
00264     macro( vcl_complex<float> );
00265   case VIL_PIXEL_FORMAT_COMPLEX_DOUBLE:
00266     macro( vcl_complex<double> );
00267 #endif
00268   default:
00269     vcl_cerr<< "ERROR: vil3d_slice_list_image::get_copy_view\n"
00270             << "       Can't deal with pixel_format " << pixel_format() << '\n';
00271     return 0;
00272   }
00273 }
00274 
00275 //: Set the contents of the volume.
00276 bool vil3d_slice_list_image::put_view(const vil3d_image_view_base& /*vv*/,
00277                                       unsigned /*i0*/, unsigned /*j0*/, unsigned /*k0*/)
00278 {
00279   vcl_cerr << "ERROR: vil3d_slice_list_image::put_view NYI\n\n";
00280   return false;
00281 }