[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
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) |
html generated using doxygen and Python
|