[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

vigra/multi_impex.hxx

00001 /************************************************************************/
00002 /*                                                                      */
00003 /*               Copyright 2003 by Gunnar Kedenburg                     */
00004 /*       Cognitive Systems Group, University of Hamburg, Germany        */
00005 /*                                                                      */
00006 /*    This file is part of the VIGRA computer vision library.           */
00007 /*    The VIGRA Website is                                              */
00008 /*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
00009 /*    Please direct questions, bug reports, and contributions to        */
00010 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
00011 /*        vigra@informatik.uni-hamburg.de                               */
00012 /*                                                                      */
00013 /*    Permission is hereby granted, free of charge, to any person       */
00014 /*    obtaining a copy of this software and associated documentation    */
00015 /*    files (the "Software"), to deal in the Software without           */
00016 /*    restriction, including without limitation the rights to use,      */
00017 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
00018 /*    sell copies of the Software, and to permit persons to whom the    */
00019 /*    Software is furnished to do so, subject to the following          */
00020 /*    conditions:                                                       */
00021 /*                                                                      */
00022 /*    The above copyright notice and this permission notice shall be    */
00023 /*    included in all copies or substantial portions of the             */
00024 /*    Software.                                                         */
00025 /*                                                                      */
00026 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
00027 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
00028 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
00029 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
00030 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
00031 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
00032 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
00033 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
00034 /*                                                                      */
00035 /************************************************************************/
00036 
00037 
00038 #ifndef VIGRA_MULTI_IMPEX_HXX
00039 #define VIGRA_MULTI_IMPEX_HXX
00040 
00041 #include <memory>
00042 #include <iomanip>
00043 #include <sstream>
00044 #include <iostream>
00045 #include <string>
00046 #include <fstream>
00047 
00048 #include "config.hxx"
00049 #include "basicimageview.hxx"
00050 #include "impex.hxx"
00051 #include "multi_array.hxx"
00052 #include "multi_pointoperators.hxx"
00053 
00054 #ifdef _MSC_VER
00055 # include <direct.h>
00056 #else
00057 # include <unistd.h>
00058 #endif
00059 
00060 namespace vigra {
00061 
00062 class VolumeImportInfo
00063 {
00064   public:
00065     typedef ImageImportInfo::PixelType PixelType;
00066 
00067         /// type of volume size returned by shape()
00068     typedef MultiArrayShape<3>::type   ShapeType;
00069 
00070         /// provided for backwards-compatibility (deprecated)
00071     typedef ShapeType                  size_type;
00072 
00073         /// 3D resolution type returned by resolution()
00074     typedef TinyVector<float, 3>       Resolution;
00075 
00076     VIGRA_EXPORT VolumeImportInfo(const std::string &filename);
00077     VIGRA_EXPORT VolumeImportInfo(const std::string &baseName, const std::string &extension);
00078 
00079     VIGRA_EXPORT ShapeType shape() const { return shape_; }
00080 
00081         /**
00082          * resolution() contains the alignment and resolution of the
00083          * volume.  resolution()[0] is the x increment in a left-handed
00084          * world coordinate system of one unstrided step in the volume
00085          * memory.  The [1] and [2] elements contain the y resp. z
00086          * increments of the strided row resp. slice steps in the
00087          * volume.
00088          *
00089          * EXAMPLES: (1.f, 1.f, 4.f) means that the slices are four
00090          * times thicker than the x/y resolution.
00091          * (1.f, -1.f, 1.f) means that the volume coordinate system is
00092          * right-handed.
00093          */
00094     VIGRA_EXPORT Resolution resolution() const { return resolution_; }
00095 
00096     VIGRA_EXPORT PixelType pixelType() const { return pixelType_; }
00097 
00098     VIGRA_EXPORT int numBands() const { return numBands_; }
00099     VIGRA_EXPORT bool isGrayscale() const { return numBands_ == 1; }
00100     VIGRA_EXPORT bool isColor() const { return numBands_ > 1; }
00101 
00102     // get base file name without path, image index, and extension
00103     VIGRA_EXPORT const std::string &name() const { return name_; }
00104 
00105     VIGRA_EXPORT const std::string &description() const { return description_; }
00106 
00107     template <class T, class Allocator>
00108     void importImpl(MultiArray <3, T, Allocator> &volume) const;
00109 
00110   protected:
00111     void getVolumeInfoFromFirstSlice(const std::string &filename);
00112 
00113     size_type shape_;
00114     Resolution resolution_;
00115     PixelType pixelType_;
00116     int numBands_;
00117 
00118     std::string path_, name_, description_;
00119 
00120     std::string rawFilename_;
00121     std::string baseName_, extension_;
00122     std::vector<std::string> numbers_;
00123 };
00124 
00125 template <class T, class Allocator>
00126 void VolumeImportInfo::importImpl(MultiArray <3, T, Allocator> &volume) const
00127 {
00128     volume.reshape(this->shape());
00129 
00130     if(rawFilename_.size())
00131     {
00132         std::string dirName, baseName;
00133         char oldCWD[2048];
00134 
00135 #ifdef _MSC_VER
00136         _getcwd(oldCWD, 2048);
00137         if(_chdir(path_.c_str()))
00138             perror("chdir");
00139 #else
00140         getcwd(oldCWD, 2048);
00141         if(chdir(path_.c_str()))
00142             perror("chdir");
00143 #endif
00144 
00145         std::ifstream s(rawFilename_.c_str(), std::ios::binary);
00146         vigra_precondition(s.good(), "RAW file could not be opened");
00147         s.read((char*)volume.begin(), shape_[0]*shape_[1]*shape_[2]*sizeof(T));
00148 
00149 #ifdef _MSC_VER
00150         _chdir(oldCWD);
00151 #else
00152         chdir(oldCWD);
00153 #endif
00154 
00155         vigra_postcondition(
00156             volume.shape() == shape(), "imported volume has wrong size");
00157     }
00158     else
00159     {
00160         for (unsigned int i = 0; i < numbers_.size(); ++i)
00161         {
00162             // build the filename
00163             std::string name = baseName_ + numbers_[i] + extension_;
00164 
00165             // import the image
00166             ImageImportInfo info (name.c_str ());
00167 
00168             // generate a basic image view to the current layer
00169             MultiArrayView <2, T> array_view (volume.bindOuter (i));
00170             BasicImageView <T> view = makeBasicImageView (array_view);
00171             vigra_precondition(view.size() == info.size(),
00172                 "importVolume(): image size mismatch.");
00173 
00174             importImage (info, destImage(view));
00175         }
00176     }
00177 }
00178 
00179 
00180 VIGRA_EXPORT void findImageSequence(const std::string &name_base,
00181                        const std::string &name_ext,
00182                        std::vector<std::string> & numbers);
00183 
00184 /** \addtogroup VolumeImpex Import/export of volume data.
00185 */
00186 
00187 //@{
00188 
00189 /********************************************************/
00190 /*                                                      */
00191 /*                    importVolume                      */
00192 /*                                                      */
00193 /********************************************************/
00194 
00195 /** \brief Function for importing a 3D volume.
00196 
00197     The data are expected to be stored in a by-slice manner,
00198     where the slices are enumerated from <tt>name_base+"[0-9]+"+name_ext</tt>.
00199     <tt>name_base</tt> may contain a path. All slice files with the same name base and
00200     extension are considered part of the same volume. Slice numbers must be non-negative,
00201     but can otherwise start anywhere and need not be successive. Slices will be read
00202     in ascending numerical (not lexicographic) order. All slices must have the
00203     same size. The <tt>volume</tt> will be reshaped to match the count and
00204     size of the slices found.
00205 
00206     <b>\#include</b>
00207     <<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>>
00208 
00209     Namespace: vigra
00210 */
00211 template <class T, class Allocator>
00212 void importVolume (MultiArray <3, T, Allocator> & volume,
00213                    const std::string &name_base,
00214                    const std::string &name_ext)
00215 {
00216     VolumeImportInfo info(name_base, name_ext);
00217 
00218     info.importImpl(volume);
00219 }
00220 
00221 
00222 /** \brief Function for importing a 3D volume.
00223 
00224     The data can be given in two ways:
00225 
00226     <UL>
00227     <LI> If the volume is stored in a by-slice manner (e.g. one image per slice),
00228          the <tt>filename</tt> can refer to an arbitrary image from the set. <tt>importVolume()</tt>
00229          then assumes that the slices are enumerated like <tt>name_base+"[0-9]+"+name_ext</tt>,
00230          where <tt>name_base</tt>, the index, and <tt>name_ext</tt> are determined automatically.
00231          All slice files with the same name base and extension are considered part of the same
00232          volume. Slice numbers must be non-negative, but can otherwise start anywhere and need
00233          not be successive. Slices will be read in ascending numerical (not lexicographic) order.
00234          All slices must have the same size.
00235     <li> Otherwise, <tt>importVolume()</tt> will try to read <tt>filename</tt> as an
00236          info text file with the following key-value pairs:
00237          <UL>
00238          <LI> name = [short descriptive name of the volume] (optional)
00239          <LI> filename = [absolute or relative path to raw voxel data file] (required)
00240          <li> gradfile =  [absolute or relative path to gradient data file] (currently ignored)
00241          <li> description =  [arbitrary description of the data set] (optional)
00242          <li> width = [positive integer] (required)
00243          <li> height = [positive integer] (required)
00244          <li> depth = [positive integer] (required)
00245          <li> datatype = [UNSIGNED_CHAR | UNSIGNED_BYTE] (default: UNSIGNED_CHAR)
00246          </UL>
00247          The voxel type is currently assumed to be binary compatible to the <tt>value_type T</TT>
00248          of the <tt>MuliArray</tt>. Lines starting with "#" are ignored.
00249     </UL>
00250 
00251     In either case, the <tt>volume</tt> will be reshaped to match the count and
00252     size of the slices found.
00253 
00254     <b>\#include</b>
00255     <<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>>
00256 
00257     Namespace: vigra
00258 */
00259 template <class T, class Allocator>
00260 void importVolume(MultiArray <3, T, Allocator> &volume,
00261                   const std::string &filename)
00262 {
00263     VolumeImportInfo info(filename);
00264 
00265     info.importImpl(volume);
00266 }
00267 
00268 /** \brief Function for importing a 3D volume.
00269 
00270     Read the volume data set <tt>info</tt> refers to. Explicit construction
00271     of the info object allows to allocate a <tt>volume</tt> object type whose
00272     <tt>value_type</tt> matches the voxel type of the stored data.
00273     The <tt>volume</tt> will be reshaped to match the count and
00274     size of the slices found.
00275 
00276     <b>\#include</b>
00277     <<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>>
00278 
00279     Namespace: vigra
00280 */
00281 template <class T, class Allocator>
00282 void importVolume(VolumeImportInfo const & info, MultiArray <3, T, Allocator> &volume)
00283 {
00284     info.importImpl(volume);
00285 }
00286 
00287 namespace detail {
00288 
00289 template <class T>
00290 void setRangeMapping(std::string const & pixeltype,
00291                      FindMinMax<T> const & minmax, ImageExportInfo & info)
00292 {
00293     if(pixeltype == "UINT8")
00294         info.setForcedRangeMapping(minmax.min, minmax.max,
00295                                    (double)NumericTraits<Int8>::min(),
00296                                    (double)NumericTraits<Int8>::max());
00297     else if(pixeltype == "INT16")
00298         info.setForcedRangeMapping(minmax.min, minmax.max,
00299                                    (double)NumericTraits<Int16>::min(),
00300                                    (double)NumericTraits<Int16>::max());
00301     else if(pixeltype == "UINT16")
00302         info.setForcedRangeMapping(minmax.min, minmax.max,
00303                                    (double)NumericTraits<UInt16>::min(),
00304                                    (double)NumericTraits<UInt16>::max());
00305     else if(pixeltype == "INT32")
00306         info.setForcedRangeMapping(minmax.min, minmax.max,
00307                                    (double)NumericTraits<Int32>::min(),
00308                                    (double)NumericTraits<Int32>::max());
00309     else if(pixeltype == "UINT32")
00310         info.setForcedRangeMapping(minmax.min, minmax.max,
00311                                    (double)NumericTraits<UInt32>::min(),
00312                                    (double)NumericTraits<UInt32>::max());
00313     else if(pixeltype == "FLOAT")
00314         info.setForcedRangeMapping(minmax.min, minmax.max, 0.0, 1.0);
00315     else if(pixeltype == "DOUBLE")
00316         info.setForcedRangeMapping(minmax.min, minmax.max, 0.0, 1.0);
00317 }
00318 
00319 template <class T, class Tag>
00320 void setRangeMapping(MultiArrayView <3, T, Tag> const & volume,
00321                      ImageExportInfo & info, VigraTrueType /* isScalar */)
00322 {
00323     std::string pixeltype = info.getPixelType();
00324     bool downcast = negotiatePixelType(getEncoderType(info.getFileName(), info.getFileType()),
00325                                        TypeAsString<T>::result(), pixeltype);
00326 
00327     if(downcast)
00328     {
00329         FindMinMax<T> minmax;
00330         inspectMultiArray(srcMultiArrayRange(volume), minmax);
00331         setRangeMapping(pixeltype, minmax, info);
00332     }
00333 }
00334 
00335 template <class T, class Tag>
00336 void setRangeMapping(MultiArrayView <3, T, Tag> const & volume,
00337                      ImageExportInfo & info, VigraFalseType /* isScalar */)
00338 {
00339     typedef typename T::value_type SrcComponent;
00340     std::string pixeltype = info.getPixelType();
00341     bool downcast = negotiatePixelType(getEncoderType(info.getFileName(), info.getFileType()),
00342                                        TypeAsString<SrcComponent>::result(), pixeltype);
00343 
00344     if(downcast)
00345     {
00346         unsigned int bands = volume(0,0,0).size();
00347         FindMinMax<SrcComponent> minmax;
00348         for(unsigned int i=0; i<bands; ++i)
00349         {
00350             VectorComponentValueAccessor<T> band(i);
00351             inspectMultiArray(srcMultiArrayRange(volume, band), minmax );
00352         }
00353         setRangeMapping(pixeltype, minmax, info);
00354     }
00355 }
00356 
00357 } // namespace detail
00358 
00359 /********************************************************/
00360 /*                                                      */
00361 /*                    exportVolume                      */
00362 /*                                                      */
00363 /********************************************************/
00364 
00365 /** \brief Function for exporting a 3D volume.
00366 
00367     The volume is exported in a by-slice manner, where the number of slices equals
00368     the depth of the volume. The file names will be enumerated like
00369     <tt>name_base+"000"+name_ext</tt>, <tt>name_base+"001"+name_ext</tt> etc.
00370     (the actual number of zeros depends on the depth). If the target image type
00371     does not support the source voxel type, all slices will be mapped simultaneously
00372     to the appropriate target range.
00373 
00374     <b>\#include</b>
00375     <<a href="multi__impex_8hxx-source.html">vigra/multi_impex.hxx</a>>
00376 
00377     Namespace: vigra
00378 */
00379 template <class T, class Tag>
00380 void exportVolume (MultiArrayView <3, T, Tag> const & volume,
00381                    const std::string &name_base,
00382                    const std::string &name_ext)
00383 {
00384     std::string name = name_base + name_ext;
00385     ImageExportInfo info(name.c_str());
00386     detail::setRangeMapping(volume, info, typename NumericTraits<T>::isScalar());
00387 
00388     const unsigned int depth = volume.shape (2);
00389     int numlen = static_cast <int> (std::ceil (std::log10 ((double)depth)));
00390     for (unsigned int i = 0; i < depth; ++i)
00391     {
00392 
00393         // build the filename
00394         std::stringstream stream;
00395         stream << std::setfill ('0') << std::setw (numlen) << i;
00396         std::string name_num;
00397         stream >> name_num;
00398         std::string name = name_base + name_num + name_ext;
00399 
00400         if(i == 0)
00401         {
00402         }
00403 
00404         // generate a basic image view to the current layer
00405         MultiArrayView <2, T, Tag> array_view (volume.bindOuter (i));
00406         BasicImageView <T> view = makeBasicImageView (array_view);
00407 
00408         // export the image
00409         info.setFileName(name.c_str ());
00410         exportImage(srcImageRange(view), info);
00411     }
00412 }
00413 
00414 //@}
00415 
00416 } // namespace vigra
00417 
00418 #endif // VIGRA_MULTI_IMPEX_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
VIGRA 1.6.0 (5 Nov 2009)