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

vigra/hdf5impex.hxx
00001 /************************************************************************/
00002 /*                                                                      */
00003 /*       Copyright 2009 by Michael Hanselmann and Ullrich Koethe        */
00004 /*                                                                      */
00005 /*    This file is part of the VIGRA computer vision library.           */
00006 /*    The VIGRA Website is                                              */
00007 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
00008 /*    Please direct questions, bug reports, and contributions to        */
00009 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
00010 /*        vigra@informatik.uni-hamburg.de                               */
00011 /*                                                                      */
00012 /*    Permission is hereby granted, free of charge, to any person       */
00013 /*    obtaining a copy of this software and associated documentation    */
00014 /*    files (the "Software"), to deal in the Software without           */
00015 /*    restriction, including without limitation the rights to use,      */
00016 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
00017 /*    sell copies of the Software, and to permit persons to whom the    */
00018 /*    Software is furnished to do so, subject to the following          */
00019 /*    conditions:                                                       */
00020 /*                                                                      */
00021 /*    The above copyright notice and this permission notice shall be    */
00022 /*    included in all copies or substantial portions of the             */
00023 /*    Software.                                                         */
00024 /*                                                                      */
00025 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
00026 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
00027 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
00028 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
00029 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
00030 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
00031 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
00032 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
00033 /*                                                                      */
00034 /************************************************************************/
00035 
00036 #ifndef VIGRA_HDF5IMPEX_HXX
00037 #define VIGRA_HDF5IMPEX_HXX
00038 
00039 #include <string>
00040 #include <H5version.h>
00041 
00042 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR >= 8 && defined(H5_USE_16_API_DEFAULT))
00043 # define H5Gcreate_vers 2
00044 # define H5Gopen_vers 2
00045 # define H5Dopen_vers 2
00046 # define H5Dcreate_vers 2
00047 # define H5Acreate_vers 2
00048 #endif
00049 
00050 #include <hdf5.h>
00051 
00052 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
00053 # ifndef H5Gopen
00054 #   define H5Gopen(a, b, c) H5Gopen(a, b)
00055 # endif
00056 # ifndef H5Gcreate
00057 #  define H5Gcreate(a, b, c, d, e) H5Gcreate(a, b, 1)
00058 # endif
00059 # ifndef H5Dopen
00060 #  define H5Dopen(a, b, c) H5Dopen(a, b)
00061 # endif
00062 # ifndef H5Dcreate
00063 #  define H5Dcreate(a, b, c, d, e, f, g) H5Dcreate(a, b, c, d, f)
00064 # endif
00065 # ifndef H5Acreate
00066 #  define H5Acreate(a, b, c, d, e, f) H5Acreate(a, b, c, d, e)
00067 # endif
00068 # include <H5LT.h>
00069 #else
00070 # include <hdf5_hl.h>
00071 #endif
00072 
00073 #include "impex.hxx"
00074 #include "multi_array.hxx"
00075 #include "multi_impex.hxx"
00076 
00077 namespace vigra {
00078 
00079 /** \addtogroup VigraHDF5Impex Import/Export of Images and Arrays in HDF5 Format
00080 
00081     Supports arrays with arbitrary element types and arbitrary many dimensions.
00082     See the <a href="http://www.hdfgroup.org/HDF5/">HDF5 Website</a> for more
00083     information on the HDF5 file format.
00084 **/
00085 //@{
00086 
00087     /** \brief Wrapper for hid_t objects.
00088 
00089     Newly created or opened HDF5 handles are usually stored as objects of type 'hid_t'. When the handle
00090     is no longer needed, the appropriate close function must be called. However, if a function is 
00091     aborted by an exception, this is difficult to ensure. Class HDF5Handle is a smart pointer that 
00092     solves this problem by calling the close function in the destructor (This is analogous to how 
00093     std::auto_ptr calls 'delete' on the contained pointer). A pointer to the close function must be 
00094     passed to the constructor, along with an error message that is raised when creation/opening fails. 
00095     
00096     Since HDF5Handle objects are convertible to hid_t, they can be used in the code in place 
00097     of the latter.
00098 
00099     <b>Usage:</b>
00100 
00101     \code
00102     HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT), 
00103                        &H5Fclose, 
00104                        "Error message.");
00105                        
00106     ... // use file_id in the same way as a plain hid_t object
00107     \endcode
00108 
00109     <b>\#include</b> <<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex.hxx</a>><br>
00110     Namespace: vigra
00111     **/
00112 class HDF5Handle
00113 {
00114 public:
00115     typedef herr_t (*Destructor)(hid_t);
00116     
00117 private:
00118     hid_t handle_;
00119     Destructor destructor_;
00120     
00121 public:
00122 
00123         /** \brief Default constuctor.
00124             Creates a NULL handle.
00125         **/
00126     HDF5Handle()
00127     : handle_( 0 ),
00128       destructor_(0)
00129     {}
00130 
00131         /** \brief Create a wrapper for a hid_t object.
00132 
00133         The hid_t object \a h is assumed to be the return value of an open or create function.
00134         It will be closed with the given close function \a destructor as soon as this 
00135         HDF5Handle is destructed, except when \a destructor is a NULL pointer (in which
00136         case nothing happens at destruction time). If \a h has a value that indicates
00137         failed opening or creation (by HDF5 convention, this means if it is a negative number),
00138         an exception is raised by calling <tt>vigra_fail(error_message)</tt>.
00139 
00140         <b>Usage:</b>
00141 
00142         \code
00143         HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT), 
00144                            &H5Fclose, 
00145                            "Error message.");
00146                            
00147         ... // use file_id in the same way
00148         \endcode
00149         **/
00150     HDF5Handle(hid_t h, Destructor destructor, const char * error_message)
00151     : handle_( h ),
00152       destructor_(destructor)
00153     {
00154         if(handle_ < 0)
00155             vigra_fail(error_message);
00156     }
00157 
00158         /** \brief Copy constructor.
00159             Hands over ownership of the RHS handle (analogous to std::auto_ptr).
00160         **/
00161     HDF5Handle(HDF5Handle const & h)
00162     : handle_( h.handle_ ),
00163       destructor_(h.destructor_)
00164     {
00165         const_cast<HDF5Handle &>(h).handle_ = 0;
00166     }
00167     
00168         /** \brief Assignment.
00169             Calls close() for the LHS handle and hands over ownership of the 
00170             RHS handle (analogous to std::auto_ptr).
00171         **/
00172     HDF5Handle & operator=(HDF5Handle const & h)
00173     {
00174         if(h.handle_ != handle_)
00175         {
00176             close();
00177             handle_ = h.handle_;
00178             destructor_ = h.destructor_;
00179             const_cast<HDF5Handle &>(h).handle_ = 0;
00180         }
00181         return *this;
00182     }
00183 
00184         /** \brief Destreuctor.
00185             Calls close() for the contained handle.
00186         **/
00187     ~HDF5Handle()
00188     {
00189         close();
00190     }
00191     
00192         /** \brief Explicitly call the stored function (if one has been stored within
00193              this object) for the contained handle and set the handle to NULL.
00194         **/
00195     herr_t close()
00196     {
00197         herr_t res = 1;
00198         if(handle_ && destructor_)
00199             res = (*destructor_)(handle_);
00200         handle_ = 0;
00201         return res;
00202     }
00203 
00204         /** \brief Get a temporary hid_t object for the contained handle.
00205             Do not call a close function on the return value - a crash will be likely
00206             otherwise.
00207         **/
00208     hid_t get() const
00209     {
00210         return handle_;
00211     }
00212 
00213         /** \brief Convert to a plain hid_t object.
00214 
00215         This function ensures that hid_t objects can be transparently replaced with 
00216         HDF5Handle objects in user code. Do not call a close function on the return 
00217         value - a crash will be likely otherwise.
00218         **/
00219     operator hid_t() const
00220     {
00221         return handle_;
00222     }
00223 
00224         /** \brief Equality comparison of the contained handle.
00225         **/
00226     bool operator==(HDF5Handle const & h) const
00227     {
00228         return handle_ == h.handle_;
00229     }
00230 
00231         /** \brief Equality comparison of the contained handle.
00232         **/
00233     bool operator==(hid_t h) const
00234     {
00235         return handle_ == h;
00236     }
00237 
00238         /** \brief Unequality comparison of the contained handle.
00239         **/
00240     bool operator!=(HDF5Handle const & h) const
00241     {
00242         return handle_ != h.handle_;
00243     }
00244 
00245         /** \brief Unequality comparison of the contained handle.
00246         **/
00247     bool operator!=(hid_t h) const
00248     {
00249         return handle_ != h;
00250     }
00251 };
00252 
00253 
00254 /********************************************************/
00255 /*                                                      */
00256 /*                   HDF5ImportInfo                     */
00257 /*                                                      */
00258 /********************************************************/
00259 
00260 /** \brief Argument object for the function readHDF5().
00261 
00262 See \ref readHDF5() for a usage example. This object must be
00263 used to read an image or array from a HDF5 file 
00264 and enquire about its properties.
00265 
00266 <b>\#include</b> <<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex.hxx</a>><br>
00267 Namespace: vigra
00268 **/
00269 class HDF5ImportInfo
00270 {
00271   public:
00272     enum PixelType { UINT8, UINT16, UINT32, UINT64, 
00273                      INT8, INT16, INT32, INT64,
00274                      FLOAT, DOUBLE };
00275 
00276         /** Construct HDF5ImportInfo object.
00277 
00278             The dataset \a pathInFile in the HDF5 file \a filename is accessed to 
00279             read its properties. \a pathInFile may contain '/'-separated group
00280             names, but must end with the name of the desired dataset:
00281             
00282             \code
00283             HDF5ImportInfo info(filename, "/group1/group2/my_dataset");
00284             \endcode
00285          **/
00286     VIGRA_EXPORT HDF5ImportInfo( const char* filePath, const char* pathInFile );
00287 
00288     VIGRA_EXPORT ~HDF5ImportInfo();
00289 
00290         /** Get the filename of this HDF5 object.
00291          **/
00292     VIGRA_EXPORT const std::string& getFilePath() const;
00293 
00294         /** Get the dataset's full name in the HDF5 file.
00295          **/
00296     VIGRA_EXPORT const std::string& getPathInFile() const;
00297 
00298         /** Get a handle to the file represented by this info object.
00299          **/
00300     VIGRA_EXPORT hid_t getH5FileHandle() const;
00301 
00302         /** Get a handle to the dataset represented by this info object.
00303          **/
00304     VIGRA_EXPORT hid_t getDatasetHandle() const;
00305 
00306         /** Get the number of dimensions of the dataset represented by this info object.
00307          **/
00308     VIGRA_EXPORT MultiArrayIndex numDimensions() const;
00309 
00310         /** Get the shape of the dataset represented by this info object.
00311          **/
00312     VIGRA_EXPORT ArrayVector<hsize_t> const & shape() const
00313     {
00314         return m_dims;
00315     }
00316 
00317         /** Get the shape (length) of the dataset along dimension \a dim.
00318          **/
00319     VIGRA_EXPORT MultiArrayIndex shapeOfDimension(const int dim) const;
00320 
00321         /** Query the pixel type of the dataset.
00322 
00323             Possible values are:
00324             <DL>
00325             <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char)
00326             <DT>"INT16"<DD> 16-bit signed integer (short)
00327             <DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short)
00328             <DT>"INT32"<DD> 32-bit signed integer (long)
00329             <DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long)
00330             <DT>"FLOAT"<DD> 32-bit floating point (float)
00331             <DT>"DOUBLE"<DD> 64-bit floating point (double)
00332             </DL>
00333          **/
00334     VIGRA_EXPORT const char * getPixelType() const;
00335 
00336         /** Query the pixel type of the dataset.
00337 
00338             Same as getPixelType(), but the result is returned as a 
00339             ImageImportInfo::PixelType enum. This is useful to implement
00340             a switch() on the pixel type.
00341 
00342             Possible values are:
00343             <DL>
00344             <DT>UINT8<DD> 8-bit unsigned integer (unsigned char)
00345             <DT>INT16<DD> 16-bit signed integer (short)
00346             <DT>UINT16<DD> 16-bit unsigned integer (unsigned short)
00347             <DT>INT32<DD> 32-bit signed integer (long)
00348             <DT>UINT32<DD> 32-bit unsigned integer (unsigned long)
00349             <DT>FLOAT<DD> 32-bit floating point (float)
00350             <DT>DOUBLE<DD> 64-bit floating point (double)
00351             </DL>
00352          **/
00353     VIGRA_EXPORT PixelType pixelType() const;
00354 
00355   private:
00356     HDF5Handle m_file_handle, m_dataset_handle;
00357     std::string m_filename, m_path, m_pixeltype;
00358     hssize_t m_dimensions;
00359     ArrayVector<hsize_t> m_dims;
00360 };
00361 
00362 namespace detail {
00363 
00364 template<class type>
00365 inline hid_t getH5DataType()
00366 {
00367     std::runtime_error("getH5DataType(): invalid type");
00368     return 0;
00369 }
00370 
00371 #define VIGRA_H5_DATATYPE(type, h5type) \
00372 template<> \
00373 inline hid_t getH5DataType<type>() \
00374 { return h5type;}
00375 VIGRA_H5_DATATYPE(char, H5T_NATIVE_CHAR)
00376 VIGRA_H5_DATATYPE(Int8, H5T_NATIVE_INT8)
00377 VIGRA_H5_DATATYPE(Int16, H5T_NATIVE_INT16)
00378 VIGRA_H5_DATATYPE(Int32, H5T_NATIVE_INT32)
00379 VIGRA_H5_DATATYPE(Int64, H5T_NATIVE_INT64)
00380 VIGRA_H5_DATATYPE(UInt8, H5T_NATIVE_UINT8)
00381 VIGRA_H5_DATATYPE(UInt16, H5T_NATIVE_UINT16)
00382 VIGRA_H5_DATATYPE(UInt32, H5T_NATIVE_UINT32)
00383 VIGRA_H5_DATATYPE(UInt64, H5T_NATIVE_UINT64)
00384 VIGRA_H5_DATATYPE(float, H5T_NATIVE_FLOAT)
00385 VIGRA_H5_DATATYPE(double, H5T_NATIVE_DOUBLE)
00386 VIGRA_H5_DATATYPE(long double, H5T_NATIVE_LDOUBLE)
00387 
00388 #undef VIGRA_H5_DATATYPE
00389 
00390 } // namespace detail
00391 
00392 namespace detail {
00393 
00394 template <class Shape>
00395 inline void
00396 selectHyperslabs(HDF5Handle & mid1, HDF5Handle & mid2, Shape const & shape, int & counter, const int elements, const int numBandsOfType)
00397 {
00398     // select hyperslab in HDF5 file
00399     hsize_t shapeHDF5[2];
00400     shapeHDF5[0] = 1;
00401     shapeHDF5[1] = elements;
00402     hsize_t startHDF5[2];
00403     startHDF5[0] = 0;
00404     startHDF5[1] = counter * numBandsOfType * shape[0]; // we have to reserve space for the pixel type channel(s)
00405     hsize_t strideHDF5[2];
00406     strideHDF5[0] = 1;
00407     strideHDF5[1] = 1;                        
00408     hsize_t countHDF5[2];
00409     countHDF5[0] = 1;
00410     countHDF5[1] = numBandsOfType * shape[0];
00411     hsize_t blockHDF5[2];
00412     blockHDF5[0] = 1;
00413     blockHDF5[1] = 1;
00414     mid1 = HDF5Handle(H5Screate_simple(2, shapeHDF5, NULL),
00415                       &H5Sclose, "unable to create hyperslabs."); 
00416     H5Sselect_hyperslab(mid1, H5S_SELECT_SET, startHDF5, strideHDF5, countHDF5, blockHDF5);
00417     // select hyperslab in input data object
00418     hsize_t shapeData[2];
00419     shapeData[0] = 1;
00420     shapeData[1] = numBandsOfType * shape[0];
00421     hsize_t startData[2];
00422     startData[0] = 0;
00423     startData[1] = 0;
00424     hsize_t strideData[2];
00425     strideData[0] = 1;
00426     strideData[1] = 1;
00427     hsize_t countData[2];
00428     countData[0] = 1;
00429     countData[1] = numBandsOfType * shape[0];
00430     hsize_t blockData[2];
00431     blockData[0] = 1;
00432     blockData[1] = 1;
00433     mid2 = HDF5Handle(H5Screate_simple(2, shapeData, NULL),
00434                       &H5Sclose, "unable to create hyperslabs."); 
00435     H5Sselect_hyperslab(mid2, H5S_SELECT_SET, startData, strideData, countData, blockData);
00436 }
00437 
00438 template <class DestIterator, class Shape, class T>
00439 inline void
00440 readHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elements, const int numBandsOfType, MetaInt<0>)
00441 {
00442     HDF5Handle mid1, mid2;
00443 
00444     // select hyperslabs
00445     selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType);
00446 
00447     // read from hdf5
00448     H5Dread(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data());
00449 
00450     // increase counter
00451     counter++;
00452 
00453 
00454     //std::cout << "numBandsOfType: " << numBandsOfType << std::endl;
00455     DestIterator dend = d + shape[0];
00456     int k = 0;
00457     for(; d < dend; ++d, k++)
00458     {
00459         *d = buffer[k];
00460         //std::cout << buffer[k] << "| ";
00461     }
00462 
00463 }
00464 
00465 template <class DestIterator, class Shape, class T, int N>
00466 void
00467 readHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elements, const int numBandsOfType, MetaInt<N>)
00468 {
00469     DestIterator dend = d + shape[N];
00470     for(; d < dend; ++d)
00471     {
00472         readHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, counter, elements, numBandsOfType, MetaInt<N-1>());
00473     }
00474 }
00475 
00476 } // namespace detail
00477 
00478     /** \brief Read the data specified by the given \ref vigra::HDF5ImportInfo object
00479                 and write the into the given 'array'.
00480                 
00481     The array must have the correct number of dimensions and shape for the dataset 
00482     represented by 'info'. When the element type of 'array' differs from the stored element
00483     type, HDF5 will convert the type on the fly (except when the HDF5 version is 1.6 or below,
00484     in which case an error will result). Multi-channel element types (i.e. \ref vigra::RGBValue
00485     and \ref vigra::TinyVector) are recognized and handled correctly.
00486     
00487     <b> Declaration:</b>
00488     
00489     \code
00490     namespace vigra {
00491         template<unsigned int N, class T, class StrideTag>
00492         void 
00493         readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> array);
00494     }
00495     \endcode
00496     
00497     <b> Usage:</b>
00498     
00499     <b>\#include</b> <<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex.hxx</a>><br>
00500     Namespace: vigra
00501     
00502     \code
00503     
00504     HDF5ImportInfo info(filename, dataset_name);
00505     vigra_precondition(info.numDimensions() == 3, "Dataset must be 3-dimensional.");
00506     
00507     MultiArrayShape<3>::type shape(info.shape().begin());
00508     MultiArray<3, int> array(shape);
00509     
00510     readHDF5(info, array);
00511     \endcode
00512 */
00513 doxygen_overloaded_function(template <...> void readHDF5)
00514 
00515 // scalar and unstrided target multi array
00516 template<unsigned int N, class T>
00517 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, UnstridedArrayTag> array) // scalar
00518 {
00519     readHDF5(info, array, detail::getH5DataType<T>(), 1);
00520 }
00521 
00522 // non-scalar (TinyVector) and unstrided target multi array
00523 template<unsigned int N, class T, int SIZE>
00524 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> array)
00525 {
00526     readHDF5(info, array, detail::getH5DataType<T>(), SIZE);
00527 }
00528 
00529 // non-scalar (RGBValue) and unstrided target multi array
00530 template<unsigned int N, class T>
00531 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> array)
00532 {
00533     readHDF5(info, array, detail::getH5DataType<T>(), 3);
00534 }
00535 
00536 // unstrided target multi array
00537 template<unsigned int N, class T>
00538 void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, UnstridedArrayTag> array, const hid_t datatype, const int numBandsOfType) 
00539 {
00540     int offset = (numBandsOfType > 1);
00541 
00542     //std::cout << "offset: " << offset << ", N: " << N << ", dims: " << info.numDimensions() << std::endl;
00543     vigra_precondition(( (N + offset ) == info.numDimensions()), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
00544         "readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimensions().");
00545 
00546     typename MultiArrayShape<N>::type shape;
00547     for(int k=offset; k<info.numDimensions(); ++k) {
00548         shape[k-offset] = info.shapeOfDimension(k); 
00549     }
00550 
00551     vigra_precondition(shape == array.shape(), 
00552          "readHDF5(): Array shape disagrees with HDF5ImportInfo.");
00553 
00554     // simply read in the data as is
00555     H5Dread( info.getDatasetHandle(), datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data() ); // .data() possible since void pointer!
00556 }
00557 
00558 // scalar and strided target multi array
00559 template<unsigned int N, class T>
00560 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StridedArrayTag> array) // scalar
00561 {
00562     readHDF5(info, array, detail::getH5DataType<T>(), 1);
00563 }
00564 
00565 // non-scalar (TinyVector) and strided target multi array
00566 template<unsigned int N, class T, int SIZE>
00567 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVector<T, SIZE>, StridedArrayTag> array) 
00568 {
00569     readHDF5(info, array, detail::getH5DataType<T>(), SIZE);
00570 }
00571 
00572 // non-scalar (RGBValue) and strided target multi array
00573 template<unsigned int N, class T>
00574 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue<T>, StridedArrayTag> array) 
00575 {
00576     readHDF5(info, array, detail::getH5DataType<T>(), 3);
00577 }
00578 
00579 // strided target multi array
00580 template<unsigned int N, class T>
00581 void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StridedArrayTag> array, const hid_t datatype, const int numBandsOfType)
00582 {
00583     int offset = (numBandsOfType > 1);
00584 
00585     //std::cout << "offset: " << offset << ", N: " << N << ", dims: " << info.numDimensions() << std::endl;
00586     vigra_precondition(( (N + offset ) == info.numDimensions()), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
00587         "readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimensions().");
00588 
00589     typename MultiArrayShape<N>::type shape;
00590     for(int k=offset; k<info.numDimensions(); ++k) {
00591         shape[k-offset] = info.shapeOfDimension(k); 
00592     }
00593 
00594     vigra_precondition(shape == array.shape(), 
00595          "readHDF5(): Array shape disagrees with HDF5ImportInfo.");
00596 
00597     //Get the data
00598     int counter = 0;
00599     int elements = numBandsOfType;
00600     for(unsigned int i=0;i<N;++i)
00601         elements *= shape[i];
00602     ArrayVector<T> buffer(shape[0]);
00603     detail::readHDF5Impl(array.traverser_begin(), shape, info.getDatasetHandle(), datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<N-1>());
00604 }
00605 
00606 inline hid_t openGroup(hid_t parent, std::string group_name)
00607 {
00608     //std::cout << group_name << std::endl;
00609     size_t last_slash = group_name.find_last_of('/'); 
00610     if (last_slash == std::string::npos || last_slash != group_name.size() - 1)
00611         group_name = group_name + '/';
00612     std::string::size_type begin = 0, end = group_name.find('/');
00613     int ii =  0;
00614     while (end != std::string::npos)
00615     {
00616         std::string group(group_name.begin()+begin, group_name.begin()+end);
00617         hid_t prev_parent = parent; 
00618         parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
00619 
00620         if(ii != 0)     H5Gclose(prev_parent);
00621         if(parent < 0)  return parent;
00622         ++ii; 
00623         begin = end + 1;
00624         end = group_name.find('/', begin);
00625     }
00626     return parent; 
00627 }
00628 
00629 inline hid_t createGroup(hid_t parent, std::string group_name)
00630 {
00631     if(group_name.size() == 0 ||*group_name.rbegin() != '/')
00632         group_name = group_name + '/';
00633     if(group_name == "/")
00634         return H5Gopen(parent, group_name.c_str(), H5P_DEFAULT);
00635     
00636     std::string::size_type begin = 0, end = group_name.find('/');
00637     int ii =  0;
00638     while (end != std::string::npos)
00639     {
00640         std::string group(group_name.begin()+begin, group_name.begin()+end);
00641         hid_t prev_parent = parent; 
00642         
00643         if(H5LTfind_dataset(parent, group.c_str()) == 0)
00644         {
00645             parent = H5Gcreate(prev_parent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00646         } else {
00647             parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
00648         }
00649 
00650         if(ii != 0)     H5Gclose(prev_parent);
00651         if(parent < 0)  return parent;
00652         ++ii; 
00653         begin = end + 1;
00654         end = group_name.find('/', begin);
00655     }
00656     return parent; 
00657 }
00658 
00659 inline void deleteDataset(hid_t parent, std::string dataset_name)
00660 {
00661     // delete existing data and create new dataset
00662     if(H5LTfind_dataset(parent, dataset_name.c_str()))
00663     {
00664         //std::cout << "dataset already exists" << std::endl;
00665 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
00666         if(H5Gunlink(parent, dataset_name.c_str()) < 0)
00667         {
00668             vigra_postcondition(false, "writeToHDF5File(): Unable to delete existing data.");
00669         }
00670 #else
00671         if(H5Ldelete(parent, dataset_name.c_str(), H5P_DEFAULT ) < 0)
00672         {
00673             vigra_postcondition(false, "createDataset(): Unable to delete existing data.");
00674         }
00675 #endif
00676     } 
00677 }
00678 
00679 inline hid_t createFile(std::string filePath, bool append_ = true)
00680 {
00681     FILE * pFile;
00682     pFile = fopen ( filePath.c_str(), "r" );
00683     hid_t file_id; 
00684     if ( pFile == NULL )
00685     {
00686         file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
00687     } 
00688     else if(append_)
00689     {
00690         fclose( pFile );
00691         file_id = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
00692     }
00693     else
00694     {
00695         fclose(pFile);
00696         std::remove(filePath.c_str());
00697         file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
00698     }
00699     return file_id; 
00700 }
00701 
00702 template<unsigned int N, class T, class Tag>
00703 void createDataset(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, Tag> & array, const hid_t datatype, const int numBandsOfType, HDF5Handle & file_handle, HDF5Handle & dataset_handle)
00704 {
00705     std::string path_name(pathInFile), group_name, data_set_name, message;
00706     std::string::size_type delimiter = path_name.rfind('/');
00707     
00708     //create or open file
00709     file_handle = HDF5Handle(createFile(filePath), &H5Fclose, 
00710                        "createDataset(): unable to open output file.");
00711 
00712     // get the groupname and the filename
00713     if(delimiter == std::string::npos)
00714     {
00715         group_name    = "/";
00716         data_set_name = path_name;
00717     }
00718     else
00719     {
00720         group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
00721         data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
00722     }
00723 
00724     // create all groups
00725     HDF5Handle group(createGroup(file_handle, group_name), &H5Gclose, 
00726                      "createDataset(): Unable to create and open group. generic v");
00727 
00728     // delete the dataset if it already exists
00729     deleteDataset(group, data_set_name);
00730 
00731     // create dataspace
00732     // add an extra dimension in case that the data is non-scalar
00733     HDF5Handle dataspace_handle;
00734     if(numBandsOfType > 1) {
00735         // invert dimensions to guarantee c-order
00736         hsize_t shape_inv[N+1]; // one additional dimension for pixel type channel(s)
00737         for(unsigned int k=0; k<N; ++k) {
00738             shape_inv[N-1-k] = array.shape(k);  // the channels (eg of an RGB image) are represented by the first dimension (before inversion)
00739             //std::cout << shape_inv[N-k] << " (" << N << ")";
00740         }
00741         shape_inv[N] = numBandsOfType;
00742 
00743         // create dataspace
00744         dataspace_handle = HDF5Handle(H5Screate_simple(N+1, shape_inv, NULL),
00745                                     &H5Sclose, "createDataset(): unable to create dataspace for non-scalar data.");
00746     } else {
00747         // invert dimensions to guarantee c-order
00748         hsize_t shape_inv[N];
00749         for(unsigned int k=0; k<N; ++k)
00750             shape_inv[N-1-k] = array.shape(k);
00751 
00752         // create dataspace
00753         dataspace_handle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
00754                                     &H5Sclose, "createDataset(): unable to create dataspace for scalar data.");
00755     }
00756 
00757     //alloc memory for dataset. 
00758     dataset_handle = HDF5Handle(H5Dcreate(group, 
00759                                         data_set_name.c_str(), 
00760                                         datatype, 
00761                                         dataspace_handle, 
00762                                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT),
00763                               &H5Dclose, "createDataset(): unable to create dataset.");
00764 }
00765 
00766 
00767 
00768 namespace detail {
00769 
00770 template <class DestIterator, class Shape, class T>
00771 inline void
00772 writeHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elements, const int numBandsOfType, MetaInt<0>)
00773 {
00774     DestIterator dend = d + (typename DestIterator::difference_type)shape[0];
00775     int k = 0;
00776     //std::cout << "new:" << std::endl;
00777     for(; d < dend; ++d, k++)
00778     {
00779         buffer[k] = *d; 
00780         //std::cout << buffer[k] << " ";
00781     }
00782     //std::cout << std::endl;
00783     HDF5Handle mid1, mid2;
00784 
00785     // select hyperslabs
00786     selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType);
00787 
00788     // write to hdf5
00789     H5Dwrite(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data());
00790     // increase counter
00791     counter++;
00792 }
00793 
00794 template <class DestIterator, class Shape, class T, int N>
00795 void
00796 writeHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elements, const int numBandsOfType, MetaInt<N>)
00797 {
00798         DestIterator dend = d + (typename DestIterator::difference_type)shape[N];
00799         for(; d < dend; ++d)
00800         {
00801             writeHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, counter, elements, numBandsOfType, MetaInt<N-1>());
00802         }
00803 }
00804 
00805 } // namespace detail
00806 
00807     /** \brief Store array data in an HDF5 file.
00808                 
00809     The number of dimensions, shape and element type of the stored dataset is automatically 
00810     determined from the properties of the given \a array. Strided arrays are stored in an
00811     unstrided way, i.e. in contiguous scan-order. Multi-channel element types 
00812     (i.e. \ref vigra::RGBValue and \ref vigra::TinyVector) are recognized and handled correctly
00813     (in particular, the will form the innermost dimension of the stored dataset).
00814     \a pathInFile may contain '/'-separated group names, but must end with the name 
00815     of the dataset to be created.
00816     
00817     <b> Declaration:</b>
00818     
00819     \code
00820     namespace vigra {
00821         template<unsigned int N, class T, class StrideTag>
00822         void 
00823         writeHDF5(const char* filePath, const char* pathInFile, 
00824                   MultiArrayView<N, T, StrideTag>const  & array);
00825     }
00826     \endcode
00827     
00828     <b> Usage:</b>
00829     
00830     <b>\#include</b> <<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex.hxx</a>><br>
00831     Namespace: vigra
00832     
00833     \code
00834     MultiArrayShape<3>::type shape(100, 200, 20);
00835     MultiArray<3, int> array(shape);
00836     ... // fill array with data
00837     
00838     writeHDF5("mydata.h5", "/group1/my_dataset", array);
00839     \endcode
00840 */
00841 doxygen_overloaded_function(template <...> void writeHDF5)
00842 
00843 // scalar and unstrided multi arrays
00844 template<unsigned int N, class T>
00845 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, UnstridedArrayTag> & array) // scalar
00846 {
00847     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1);
00848 }
00849 
00850 // non-scalar (TinyVector) and unstrided multi arrays
00851 template<unsigned int N, class T, int SIZE>
00852 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
00853 {
00854     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), SIZE);
00855 }
00856 
00857 // non-scalar (RGBValue) and unstrided multi arrays
00858 template<unsigned int N, class T>
00859 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
00860 {
00861     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 3);
00862 }
00863 
00864 // unstrided multi arrays
00865 template<unsigned int N, class T>
00866 void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, UnstridedArrayTag> & array, const hid_t datatype, const int numBandsOfType)
00867 {
00868     HDF5Handle file_handle;
00869     HDF5Handle dataset_handle;
00870     createDataset(filePath, pathInFile, array, datatype, numBandsOfType, file_handle, dataset_handle);
00871     
00872     // Write the data to the HDF5 dataset as is
00873     H5Dwrite( dataset_handle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data()); // .data() possible since void pointer!
00874 
00875     H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
00876 }
00877 
00878 
00879 // scalar and strided multi arrays
00880 template<unsigned int N, class T>
00881 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StridedArrayTag> & array) // scalar
00882 {
00883     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1);
00884 }
00885 
00886 // non-scalar (TinyVector) and strided multi arrays
00887 template<unsigned int N, class T, int SIZE>
00888 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, TinyVector<T, SIZE>, StridedArrayTag> & array) 
00889 {
00890     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), SIZE);
00891 }
00892 
00893 // non-scalar (RGBValue) and strided multi arrays
00894 template<unsigned int N, class T>
00895 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, RGBValue<T>, StridedArrayTag> & array) 
00896 {
00897     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 3);
00898 }
00899 
00900 // strided multi arrays
00901 template<unsigned int N, class T>
00902 void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StridedArrayTag> & array, const hid_t datatype, const int numBandsOfType)
00903 {
00904     HDF5Handle file_handle;
00905     HDF5Handle dataset_handle;
00906     createDataset(filePath, pathInFile, array, datatype, numBandsOfType, file_handle, dataset_handle);
00907     
00908     vigra::TinyVector<int,N> shape;
00909     vigra::TinyVector<int,N> stride;
00910     int elements = numBandsOfType;
00911     for(unsigned int k=0; k<N; ++k)
00912     {
00913         shape[k] = array.shape(k);
00914         stride[k] = array.stride(k);
00915         elements *= (int)shape[k];
00916     }
00917     int counter = 0;
00918 
00919     ArrayVector<T> buffer((int)array.shape(0));
00920     detail::writeHDF5Impl(array.traverser_begin(), shape, dataset_handle, datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<N-1>());
00921 
00922     H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
00923 
00924 }
00925 
00926 namespace detail
00927 {
00928 struct MaxSizeFnc
00929 {
00930     size_t size;
00931 
00932     MaxSizeFnc()
00933     : size(0)
00934     {}
00935 
00936     void operator()(std::string const & in)
00937     {
00938         size = in.size() > size ? 
00939                     in.size() :
00940                     size;
00941     }
00942 };
00943 }
00944 
00945 
00946 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8) || DOXYGEN
00947 /** Write a numeric MultiArray as an attribute with name \a name 
00948     of the dataset specified by the handle \a loc. 
00949 
00950     <b>\#include</b> <<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex.hxx</a>><br>
00951     Namespace: vigra
00952 */
00953 template<size_t N, class T, class C>
00954 void writeHDF5Attr(hid_t loc, 
00955                    const char* name, 
00956                    MultiArrayView<N, T, C> const & array)
00957 {
00958     if(H5Aexists(loc, name) > 0)
00959         H5Adelete(loc, name);
00960     
00961     ArrayVector<hsize_t> shape(array.shape().begin(), 
00962                                array.shape().end());
00963     HDF5Handle 
00964         dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
00965                          &H5Sclose, 
00966                          "writeToHDF5File(): unable to create dataspace.");
00967     
00968     HDF5Handle attr(H5Acreate(loc, 
00969                               name, 
00970                               detail::getH5DataType<T>(), 
00971                               dataspace_handle,
00972                               H5P_DEFAULT ,H5P_DEFAULT ),
00973                     &H5Aclose,
00974                     "writeHDF5Attr: unable to create Attribute");
00975 
00976     //copy data - since attributes are small - who cares!
00977     ArrayVector<T> buffer;
00978     for(int ii = 0; ii < array.size(); ++ii)
00979         buffer.push_back(array[ii]);
00980     H5Awrite(attr, detail::getH5DataType<T>(), buffer.data());
00981 }
00982 
00983 /** Write a string MultiArray as an attribute with name \a name 
00984     of the dataset specified by the handle \a loc. 
00985 
00986     <b>\#include</b> <<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex.hxx</a>><br>
00987     Namespace: vigra
00988 */
00989 template<size_t N, class C>
00990 void writeHDF5Attr(hid_t loc, 
00991                    const char* name, 
00992                    MultiArrayView<N, std::string, C> const & array)
00993 {
00994     if(H5Aexists(loc, name) > 0)
00995         H5Adelete(loc, name);
00996     
00997     ArrayVector<hsize_t> shape(array.shape().begin(), 
00998                                array.shape().end());
00999     HDF5Handle 
01000         dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
01001                          &H5Sclose, 
01002                          "writeToHDF5File(): unable to create dataspace.");
01003     
01004     HDF5Handle atype(H5Tcopy (H5T_C_S1), 
01005                      &H5Tclose, 
01006                      "writeToHDF5File(): unable to create type.");
01007 
01008     detail::MaxSizeFnc max_size;
01009     max_size = std::for_each(array.data(),array.data()+ array.size(), max_size);
01010     H5Tset_size (atype, max_size.size);
01011     
01012     HDF5Handle attr(H5Acreate(loc, 
01013                               name, 
01014                               atype, 
01015                               dataspace_handle,
01016                               H5P_DEFAULT ,H5P_DEFAULT ),
01017                     &H5Aclose,
01018                     "writeHDF5Attr: unable to create Attribute");
01019     
01020     std::string buf ="";
01021     for(int ii = 0; ii < array.size(); ++ii)
01022     {
01023         buf = buf + array[ii]
01024                   + std::string(max_size.size - array[ii].size(), ' ');
01025     }
01026     H5Awrite(attr, atype, buf.c_str());
01027 }
01028 
01029 /** Write a numeric ArrayVectorView as an attribute with name \a name 
01030     of the dataset specified by the handle \a loc. 
01031 
01032     <b>\#include</b> <<a href="hdf5impex_8hxx-source.html">vigra/hdf5impex.hxx</a>><br>
01033     Namespace: vigra
01034 */
01035 template<class T>
01036 inline void writeHDF5Attr(  hid_t loc,
01037                             const char* name,
01038                             ArrayVectorView<T>  & array)
01039 {
01040     writeHDF5Attr(loc, name, 
01041                   MultiArrayView<1, T>(MultiArrayShape<1>::type(array.size()),
01042                                        array.data()));
01043 }
01044 
01045 /** write an Attribute given a file and a path in the file.
01046  *  the path in the file should have the format 
01047  *  [attribute] or /[subgroups/]dataset.attribute or
01048  *  /[subgroups/]group.attribute.
01049  *  The attribute is written to the root group, a dataset or a subgroup
01050  *  respectively
01051  */
01052 template<class Arr>
01053 inline void writeHDF5Attr(  std::string filePath,
01054                             std::string pathInFile,
01055                             Arr  & ar)
01056 {
01057     std::string path_name(pathInFile), group_name, data_set_name, message, attr_name;
01058     std::string::size_type delimiter = path_name.rfind('/');
01059     
01060     //create or open file
01061     HDF5Handle file_id(createFile(filePath), &H5Fclose, 
01062                        "writeToHDF5File(): unable to open output file.");
01063 
01064     // get the groupname and the filename
01065     if(delimiter == std::string::npos)
01066     {
01067         group_name    = "/";
01068         data_set_name = path_name;
01069     }
01070 
01071     else
01072     {
01073         group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
01074         data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
01075     }
01076     delimiter = data_set_name.rfind('.');
01077     if(delimiter == std::string::npos)
01078     {
01079         attr_name = path_name;
01080         data_set_name = "/";
01081     }
01082     else
01083     {
01084         attr_name = std::string(data_set_name.begin()+delimiter+1, data_set_name.end());
01085         data_set_name = std::string(data_set_name.begin(), data_set_name.begin()+delimiter);
01086     }
01087     
01088     HDF5Handle group(openGroup(file_id, group_name), &H5Gclose, 
01089                      "writeToHDF5File(): Unable to create and open group. attr ver");
01090 
01091     if(data_set_name != "/")
01092     {
01093         HDF5Handle dset(H5Dopen(group, data_set_name.c_str(), H5P_DEFAULT), &H5Dclose,
01094                         "writeHDF5Attr():unable to open dataset");
01095         writeHDF5Attr(hid_t(dset), attr_name.c_str(), ar);
01096     }
01097     else
01098     {
01099         writeHDF5Attr(hid_t(group), attr_name.c_str(), ar);
01100     }
01101 
01102 }
01103 #endif
01104 
01105 //@}
01106 
01107 } // namespace vigra
01108 
01109 #endif // VIGRA_HDF5IMPEX_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.7.0 (Thu Aug 25 2011)