1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2015
5  * Balint Cristian <cristian dot balint at gmail dot com>
6  *
7  *  Redistribution and use in source and binary forms, with or without
8  *  modification, are permitted provided that the following conditions
9  *  are met:
10  *
11  *   * Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *   * Redistributions in binary form must reproduce the above
14  *     copyright notice, this list of conditions and the following
15  *     disclaimer in the documentation and/or other materials provided
16  *     with the distribution.
17  *   * Neither the name of the copyright holders nor the names of its
18  *     contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  *  POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 #include "precomp.hpp"
36 
37 #include <hdf5.h>
38 
39 using namespace std;
40 
41 namespace cv
42 {
43 namespace hdf
44 {
45 
46 class HDF5Impl CV_FINAL : public HDF5
47 {
48 public:
49 
50     HDF5Impl( const String& HDF5Filename );
51 
~HDF5Impl()52     virtual ~HDF5Impl() CV_OVERRIDE { close(); };
53 
54     // close and release
55     virtual void close( ) CV_OVERRIDE;
56 
57     /*
58      * h5 generic
59      */
60 
61     // check if object / link exists
62     virtual bool hlexists( const String& label ) const CV_OVERRIDE;
63 
64     virtual bool atexists(const String& atlabel) const CV_OVERRIDE;
65     virtual void atdelete(const String& atlabel) CV_OVERRIDE;
66 
67     virtual void atwrite(const int value, const String& atlabel) CV_OVERRIDE;
68     virtual void atread(int* value, const String& atlabel) CV_OVERRIDE;
69 
70     virtual void atwrite(const double value, const String& atlabel) CV_OVERRIDE;
71     virtual void atread(double* value, const String& atlabel) CV_OVERRIDE;
72 
73     virtual void atwrite(const String& value, const String& atlabel) CV_OVERRIDE;
74     virtual void atread(String* value, const String& atlabel) CV_OVERRIDE;
75 
76     virtual void atwrite(InputArray value, const String& atlabel) CV_OVERRIDE;
77     virtual void atread(OutputArray value, const String& atlabel) CV_OVERRIDE;
78 
79     /*
80      * h5 group
81      */
82 
83     // create a group
84     virtual void grcreate( const String& grlabel ) CV_OVERRIDE;
85 
86     /*
87      *  cv::Mat
88      */
89 
90     // get sizes of dataset
91     virtual vector<int> dsgetsize( const String& dslabel, int dims_flag = H5_GETDIMS ) const CV_OVERRIDE;
92 
93     /* get data type of dataset */
94     virtual int dsgettype( const String& dslabel ) const CV_OVERRIDE;
95 
96     // overload dscreate() #1
97     virtual void dscreate( const int rows, const int cols, const int type, const String& dslabel ) const CV_OVERRIDE;
98 
99     // overload dscreate() #2
100     virtual void dscreate( const int rows, const int cols, const int type, const String& dslabel,
101              const int compresslevel ) const CV_OVERRIDE;
102 
103     // overload dscreate() #3
104     virtual void dscreate( const int rows, const int cols, const int type, const String& dslabel,
105              const int compresslevel, const vector<int>& dims_chunks ) const CV_OVERRIDE;
106 
107     /* create two dimensional single or mutichannel dataset */
108     virtual void dscreate( const int rows, const int cols, const int type, const String& dslabel,
109              const int compresslevel, const int* dims_chunks ) const CV_OVERRIDE;
110 
111     // overload dscreate() #1
112     virtual void dscreate( const int n_dims, const int* sizes, const int type,
113              const String& dslabel ) const CV_OVERRIDE;
114 
115     // overload dscreate() #2
116     virtual void dscreate( const int n_dims, const int* sizes, const int type,
117              const String& dslabel, const int compresslevel ) const CV_OVERRIDE;
118 
119     // overload dscreate() #3
120     virtual void dscreate( const vector<int>& sizes, const int type, const String& dslabel,
121              const int compresslevel = H5_NONE, const vector<int>& dims_chunks = vector<int>() ) const CV_OVERRIDE;
122 
123     /* create n-dimensional single or mutichannel dataset */
124     virtual void dscreate( const int n_dims, const int* sizes, const int type,
125              const String& dslabel, const int compresslevel, const int* dims_chunks ) const CV_OVERRIDE;
126 
127     // overload dswrite() #1
128     virtual void dswrite( InputArray Array, const String& dslabel ) const CV_OVERRIDE;
129 
130     // overload dswrite() #2
131     virtual void dswrite( InputArray Array, const String& dslabel, const int* dims_offset ) const CV_OVERRIDE;
132 
133     // overload dswrite() #3
134     virtual void dswrite( InputArray Array, const String& dslabel, const vector<int>& dims_offset,
135              const vector<int>& dims_counts = vector<int>() ) const CV_OVERRIDE;
136 
137     /* write into dataset */
138     virtual void dswrite( InputArray Array, const String& dslabel,
139              const int* dims_offset, const int* dims_counts ) const CV_OVERRIDE;
140 
141     // overload dsinsert() #1
142     virtual void dsinsert( InputArray Array, const String& dslabel ) const CV_OVERRIDE;
143 
144     // overload dsinsert() #2
145     virtual void dsinsert( InputArray Array, const String& dslabel, const int* dims_offset ) const CV_OVERRIDE;
146 
147     // overload dsinsert() #3
148     virtual void dsinsert( InputArray Array, const String& dslabel,
149              const vector<int>& dims_offset, const vector<int>& dims_counts = vector<int>() ) const CV_OVERRIDE;
150 
151     /* append / merge into dataset */
152     virtual void dsinsert( InputArray Array, const String& dslabel,
153              const int* dims_offset = NULL, const int* dims_counts = NULL ) const CV_OVERRIDE;
154 
155     // overload dsread() #1
156     virtual void dsread( OutputArray Array, const String& dslabel ) const CV_OVERRIDE;
157 
158     // overload dsread() #2
159     virtual void dsread( OutputArray Array, const String& dslabel, const int* dims_offset ) const CV_OVERRIDE;
160 
161     // overload dsread() #3
162     virtual void dsread( OutputArray Array, const String& dslabel,
163              const vector<int>& dims_offset, const vector<int>& dims_counts = vector<int>() ) const CV_OVERRIDE;
164 
165     // read from dataset
166     virtual void dsread( OutputArray Array, const String& dslabel,
167              const int* dims_offset, const int* dims_counts ) const CV_OVERRIDE;
168 
169     /*
170      *  std::vector<cv::KeyPoint>
171      */
172 
173     // get size of keypoints dataset
174     virtual int kpgetsize( const String& kplabel, int dims_flag = H5_GETDIMS ) const CV_OVERRIDE;
175 
176     // create KeyPoint structure
177     virtual void kpcreate( const int size, const String& kplabel,
178              const int compresslevel = H5_NONE, const int chunks = H5_NONE ) const CV_OVERRIDE;
179 
180     // write KeyPoint structures
181     virtual void kpwrite( const vector<KeyPoint> keypoints, const String& kplabel,
182              const int offset = H5_NONE, const int counts = H5_NONE ) const CV_OVERRIDE;
183 
184     // append / merge KeyPoint structures
185     virtual void kpinsert( const vector<KeyPoint> keypoints, const String& kplabel,
186              const int offset = H5_NONE, const int counts = H5_NONE ) const CV_OVERRIDE;
187 
188     // read KeyPoint structure
189     virtual void kpread( vector<KeyPoint>& keypoints, const String& kplabel,
190              const int offset = H5_NONE, const int counts = H5_NONE ) const CV_OVERRIDE;
191 
192 private:
193 
194     //! store filename
195     String m_hdf5_filename;
196 
197     //! hdf5 file handler
198     hid_t m_h5_file_id;
199 
200     //! translate cvType -> h5Type
201     inline hid_t GetH5type( int cvType ) const;
202 
203     //! translate h5Type -> cvType
204     inline int GetCVtype( hid_t h5Type ) const;
205 
206 };
207 
GetH5type(int cvType) const208 inline hid_t HDF5Impl::GetH5type( int cvType ) const
209 {
210     hid_t h5Type = -1;
211 
212     switch ( CV_MAT_DEPTH( cvType ) )
213     {
214       case CV_64F:
215         h5Type = H5T_NATIVE_DOUBLE;
216         break;
217       case CV_32F:
218         h5Type = H5T_NATIVE_FLOAT;
219         break;
220       case CV_8U:
221         h5Type = H5T_NATIVE_UCHAR;
222         break;
223       case CV_8S:
224         h5Type = H5T_NATIVE_CHAR;
225         break;
226       case CV_16U:
227         h5Type = H5T_NATIVE_USHORT;
228         break;
229       case CV_16S:
230         h5Type = H5T_NATIVE_SHORT;
231         break;
232       case CV_32S:
233         h5Type = H5T_NATIVE_INT;
234         break;
235       default:
236         CV_Error_(Error::StsInternal, ("Unknown cvType: %d.", cvType));
237     }
238     return h5Type;
239 }
240 
GetCVtype(hid_t h5Type) const241 inline int HDF5Impl::GetCVtype( hid_t h5Type ) const
242 {
243     int cvType = -1;
244 
245     if      ( H5Tequal( h5Type, H5T_NATIVE_DOUBLE ) )
246       cvType = CV_64F;
247     else if ( H5Tequal( h5Type, H5T_NATIVE_FLOAT  ) )
248       cvType = CV_32F;
249     else if ( H5Tequal( h5Type, H5T_NATIVE_UCHAR  ) )
250       cvType = CV_8U;
251     else if ( H5Tequal( h5Type, H5T_NATIVE_CHAR   ) )
252       cvType = CV_8S;
253     else if ( H5Tequal( h5Type, H5T_NATIVE_USHORT ) )
254       cvType = CV_16U;
255     else if ( H5Tequal( h5Type, H5T_NATIVE_SHORT  ) )
256       cvType = CV_16S;
257     else if ( H5Tequal( h5Type, H5T_NATIVE_INT    ) )
258       cvType = CV_32S;
259     else
260       CV_Error_(Error::StsInternal, ("Unknown H5Type: %lld.", (long long)h5Type));
261 
262     return cvType;
263 }
264 
HDF5Impl(const String & _hdf5_filename)265 HDF5Impl::HDF5Impl( const String& _hdf5_filename )
266                   : m_hdf5_filename( _hdf5_filename )
267 {
268     // save old
269     // error handler
270     void *errdata;
271     H5E_auto2_t errfunc;
272     hid_t stackid = H5E_DEFAULT;
273     H5Eget_auto( stackid, &errfunc, &errdata );
274 
275     // turn off error handling
276     H5Eset_auto( stackid, NULL, NULL );
277 
278     // check HDF5 file presence (err suppressed)
279     htri_t check = H5Fis_hdf5( m_hdf5_filename.c_str() );
280 
281     // restore previous error handler
282     H5Eset_auto( stackid, errfunc, errdata );
283 
284     if ( check == 1 || check == 0 )
285       // open the HDF5 file
286       m_h5_file_id = H5Fopen( m_hdf5_filename.c_str(),
287                             H5F_ACC_RDWR, H5P_DEFAULT );
288     else if ( check == -1 )
289       // file does not exist
290       m_h5_file_id = H5Fcreate( m_hdf5_filename.c_str(),
291                      H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT );
292     else
293       CV_Error( Error::StsInternal, "Unknown file state." );
294 }
295 
close()296 void HDF5Impl::close()
297 {
298     if ( m_h5_file_id != -1 )
299       H5Fclose( m_h5_file_id );
300     // mark closed
301     m_h5_file_id = -1;
302 }
303 
304 /*
305  * h5 generic
306  */
307 
hlexists(const String & label) const308 bool HDF5Impl::hlexists( const String& label ) const
309 {
310     bool exists = false;
311 
312     hid_t lid = H5Pcreate( H5P_LINK_ACCESS );
313     if ( H5Lexists(m_h5_file_id, label.c_str(), lid) == 1 )
314       exists = true;
315 
316     H5Pclose(lid);
317     return exists;
318 }
319 
atexists(const String & atlabel) const320 bool HDF5Impl::atexists(const String& atlabel) const
321 {
322     bool res = false;
323 
324     // save old error handler
325     void *errdata;
326     H5E_auto2_t errfunc;
327     hid_t stackid = H5E_DEFAULT;
328     H5Eget_auto(stackid, &errfunc, &errdata);
329 
330     // turn off error handling
331     H5Eset_auto(stackid, NULL, NULL);
332 
333     hid_t attr = H5Aopen_name(m_h5_file_id, atlabel.c_str());
334     if (attr >= 0)
335     {
336         res = true;
337         H5Aclose(attr);
338     }
339 
340     // restore previous error handler
341     H5Eset_auto(stackid, errfunc, errdata);
342 
343     return res;
344 }
345 
atdelete(const String & atlabel)346 void HDF5Impl::atdelete(const String& atlabel)
347 {
348     if (!atexists(atlabel))
349         CV_Error_(Error::StsInternal,("The attribute '%s' does not exist!", atlabel.c_str()));
350 
351     H5Adelete(m_h5_file_id, atlabel.c_str());
352 }
353 
atwrite(const int value,const String & atlabel)354 void HDF5Impl::atwrite(const int value, const String& atlabel)
355 {
356     if (atexists(atlabel))
357         CV_Error_(Error::StsInternal,("The attribute '%s' already exists!", atlabel.c_str()));
358 
359     hid_t aid = H5Screate(H5S_SCALAR);;
360     hid_t attr = H5Acreate2(m_h5_file_id, atlabel.c_str(), H5T_NATIVE_INT, aid,
361                             H5P_DEFAULT, H5P_DEFAULT);
362     H5Awrite(attr, H5T_NATIVE_INT, &value);
363 
364     H5Sclose(aid);
365     H5Aclose(attr);
366 }
367 
atread(int * value,const String & atlabel)368 void HDF5Impl::atread(int* value, const String& atlabel)
369 {
370     if (!value)
371         CV_Error(Error::StsBadArg, "NULL pointer");
372 
373     if (!atexists(atlabel))
374         CV_Error_(Error::StsInternal, ("Attribute '%s' does not exist!", atlabel.c_str()));
375 
376     hid_t attr = H5Aopen(m_h5_file_id, atlabel.c_str(), H5P_DEFAULT);
377     H5Aread(attr, H5T_NATIVE_INT, value);
378     H5Aclose(attr);
379 }
380 
atwrite(const double value,const String & atlabel)381 void HDF5Impl::atwrite(const double value, const String& atlabel)
382 {
383     if (atexists(atlabel))
384         CV_Error_(Error::StsInternal,("The attribute '%s' already exists!", atlabel.c_str()));
385 
386     hid_t aid = H5Screate(H5S_SCALAR);;
387     hid_t attr = H5Acreate2(m_h5_file_id, atlabel.c_str(), H5T_NATIVE_DOUBLE, aid,
388                             H5P_DEFAULT, H5P_DEFAULT);
389     H5Awrite(attr, H5T_NATIVE_DOUBLE, &value);
390 
391     H5Sclose(aid);
392     H5Aclose(attr);
393 }
394 
atread(double * value,const String & atlabel)395 void HDF5Impl::atread(double* value, const String& atlabel)
396 {
397     if (!value)
398         CV_Error(Error::StsBadArg, "NULL pointer");
399 
400     if (!atexists(atlabel))
401         CV_Error_(Error::StsInternal, ("Attribute '%s' does not exist!", atlabel.c_str()));
402 
403     hid_t attr = H5Aopen(m_h5_file_id, atlabel.c_str(), H5P_DEFAULT);
404     H5Aread(attr, H5T_NATIVE_DOUBLE, value);
405     H5Aclose(attr);
406 }
407 
atwrite(const String & value,const String & atlabel)408 void HDF5Impl::atwrite(const String& value, const String& atlabel)
409 {
410     if (atexists(atlabel))
411         CV_Error_(Error::StsInternal,("The attribute '%s' already exists!", atlabel.c_str()));
412 
413     hid_t aid = H5Screate(H5S_SCALAR);
414     hid_t atype = H5Tcopy(H5T_C_S1);
415     H5Tset_size(atype, value.size()+1);
416     H5Tset_strpad(atype, H5T_STR_NULLTERM);
417 
418     hid_t attr = H5Acreate2(m_h5_file_id, atlabel.c_str(), atype, aid, H5P_DEFAULT, H5P_DEFAULT);
419     H5Awrite(attr, atype, value.c_str());
420 
421     H5Sclose(aid);
422     H5Tclose(atype);
423     H5Aclose(attr);
424 }
425 
atread(String * value,const String & atlabel)426 void HDF5Impl::atread(String* value, const String& atlabel)
427 {
428     if (!value)
429         CV_Error(Error::StsBadArg, "NULL pointer");
430 
431     if (!atexists(atlabel))
432         CV_Error_(Error::StsInternal, ("Attribute '%s' does not exist!", atlabel.c_str()));
433 
434     hid_t attr = H5Aopen(m_h5_file_id, atlabel.c_str(), H5P_DEFAULT);
435     hid_t atype = H5Aget_type(attr);
436     H5T_class_t type_class = H5Tget_class(atype);
437     if (type_class != H5T_STRING)
438     {
439         H5Tclose(atype);
440         H5Aclose(attr);
441         CV_Error_(Error::StsInternal, ("Attribute '%s' is not of string type!", atlabel.c_str()));
442     }
443     size_t size = H5Tget_size(atype);
444     AutoBuffer<char> buf(size);
445 
446     hid_t atype_mem = H5Tget_native_type(atype, H5T_DIR_ASCEND);
447     H5Aread(attr, atype_mem, buf.data());
448     if (size > 0 && buf[size - 1] == '\0')
449         size--;
450     value->assign(buf.data(), size);
451 
452     H5Tclose(atype_mem);
453     H5Tclose(atype);
454     H5Aclose(attr);
455 }
456 
atwrite(InputArray value,const String & atlabel)457 void HDF5Impl::atwrite(InputArray value, const String& atlabel)
458 {
459     if (atexists(atlabel))
460         CV_Error_(Error::StsInternal,("The attribute '%s' already exists!", atlabel.c_str()));
461 
462     Mat value_ = value.getMat();
463 
464     if (!value_.isContinuous())
465         CV_Error(Error::StsInternal, "Only continuous array are implemented. Current array is not continuous!");
466 
467     int ndims = value_.dims;
468 
469     vector<hsize_t> dim_vec(ndims);
470     for (int i = 0; i < ndims; i++)
471         dim_vec[i] = value_.size[i];
472 
473     hid_t dtype = GetH5type(value_.type());
474     if (value_.channels() > 1)
475     {
476         hsize_t dims[1] = { (hsize_t)value_.channels()};
477         dtype = H5Tarray_create(dtype, 1, dims);
478     }
479 
480     hid_t aid = H5Screate(H5S_SIMPLE);
481     H5Sset_extent_simple(aid, ndims, dim_vec.data(), NULL);
482 
483     hid_t attr = H5Acreate2(m_h5_file_id, atlabel.c_str(), dtype,
484                             aid, H5P_DEFAULT, H5P_DEFAULT);
485 
486     H5Awrite(attr, dtype, value_.data);
487 
488     if (value_.channels() > 1)
489         H5Tclose(dtype);
490 
491     H5Sclose(aid);
492     H5Aclose(attr);
493 }
494 
atread(OutputArray value,const String & atlabel)495 void HDF5Impl::atread(OutputArray value, const String& atlabel)
496 {
497     if (!atexists(atlabel))
498         CV_Error_(Error::StsInternal, ("Attribute '%s' does not exist!", atlabel.c_str()));
499 
500     hid_t attr = H5Aopen(m_h5_file_id, atlabel.c_str(), H5P_DEFAULT);
501     hid_t atype  = H5Aget_type(attr);
502     hid_t aspace = H5Aget_space(attr);
503     int rank = H5Sget_simple_extent_ndims(aspace);
504 
505     vector<hsize_t> dim_vec_(rank);
506     H5Sget_simple_extent_dims(aspace, dim_vec_.data(), NULL);
507     vector<int> dim_vec(dim_vec_.begin(), dim_vec_.end());
508 
509     int nchannels = 1;
510     hid_t h5type;
511     if (H5Tget_class(atype) == H5T_ARRAY)
512     {
513         hsize_t dims;
514         H5Tget_array_dims(atype, &dims);
515         nchannels = (int) dims;
516 
517         hid_t super_type = H5Tget_super(atype);
518         h5type = H5Tget_native_type(super_type, H5T_DIR_ASCEND);
519         H5Tclose(super_type);
520     }
521     else
522         h5type = H5Tget_native_type(atype, H5T_DIR_ASCEND);
523 
524     int dtype = GetCVtype(h5type);
525 
526     value.create(rank, dim_vec.data(), CV_MAKETYPE(dtype, nchannels));
527     H5Aread(attr, atype, value.getMat().data);
528 
529     H5Sclose(aspace);
530     H5Tclose(atype);
531     H5Aclose(attr);
532 }
533 
534 /*
535  * h5 group
536  */
537 
grcreate(const String & grlabel)538 void HDF5Impl::grcreate( const String& grlabel )
539 {
540     if (hlexists(grlabel))
541         CV_Error_(Error::StsInternal, ("Requested group '%s' already exists.", grlabel.c_str()));
542 
543     hid_t gid = H5Gcreate(m_h5_file_id, grlabel.c_str(),
544                           H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
545     H5Gclose(gid);
546 }
547 
548 /*
549  * cv:Mat
550  */
551 
dsgetsize(const String & dslabel,int dims_flag) const552 vector<int> HDF5Impl::dsgetsize( const String& dslabel, int dims_flag ) const
553 {
554     // open dataset
555     hid_t dsdata = H5Dopen( m_h5_file_id, dslabel.c_str(), H5P_DEFAULT );
556 
557     // get file space
558     hid_t fspace = H5Dget_space( dsdata );
559 
560     // fetch rank
561     int n_dims = H5Sget_simple_extent_ndims( fspace );
562 
563     // dims storage
564     hsize_t *dims = new hsize_t[n_dims];
565 
566     // output storage
567     vector<int> SizeVect(0);
568 
569     // fetch dims
570     if ( dims_flag == H5_GETDIMS ||
571          dims_flag == H5_GETMAXDIMS )
572     {
573       if ( dims_flag == H5_GETDIMS )
574         H5Sget_simple_extent_dims( fspace, dims, NULL );
575       else
576         H5Sget_simple_extent_dims( fspace, NULL, dims );
577       SizeVect.resize( n_dims );
578     }
579     else if ( dims_flag == H5_GETCHUNKDIMS )
580     {
581       // rank size
582       int rank_chunk = -1;
583       // fetch chunk size
584       hid_t cparms = H5Dget_create_plist( dsdata );
585       if ( H5D_CHUNKED == H5Pget_layout ( cparms ) )
586       {
587          rank_chunk = H5Pget_chunk ( cparms, n_dims, dims );
588       }
589       if ( rank_chunk > 0 )
590         SizeVect.resize( n_dims );
591     }
592     else
593       CV_Error_(Error::StsInternal, ("Unknown dimension flag: %d", dims_flag));
594 
595     // fill with size data
596     for ( size_t d = 0; d < SizeVect.size(); d++ )
597       SizeVect[d] = (int) dims[d];
598 
599     H5Dclose( dsdata );
600     H5Sclose( fspace );
601 
602     delete [] dims;
603 
604     return SizeVect;
605 }
606 
dsgettype(const String & dslabel) const607 int HDF5Impl::dsgettype( const String& dslabel ) const
608 {
609     hid_t h5type;
610 
611     // open dataset
612     hid_t dsdata = H5Dopen( m_h5_file_id, dslabel.c_str(), H5P_DEFAULT );
613 
614     // get data type
615     hid_t dstype = H5Dget_type( dsdata );
616 
617     int channs = 1;
618     if ( H5Tget_class( dstype ) == H5T_ARRAY )
619     {
620       // fetch channs
621       hsize_t ardims[1];
622       H5Tget_array_dims( dstype, ardims );
623       channs = (int)ardims[0];
624       // fetch depth
625       hid_t tsuper = H5Tget_super( dstype );
626       h5type = H5Tget_native_type( tsuper, H5T_DIR_ASCEND );
627       H5Tclose( tsuper );
628     }
629     else
630       h5type = H5Tget_native_type( dstype, H5T_DIR_DESCEND );
631 
632     // convert to CVType
633     int cvtype = GetCVtype( h5type );
634 
635     H5Tclose( dstype );
636     H5Dclose( dsdata );
637 
638     return CV_MAKETYPE( cvtype, channs );
639 }
640 
641 // overload
dscreate(const int rows,const int cols,const int type,const String & dslabel) const642 void HDF5Impl::dscreate( const int rows, const int cols, const int type,
643                          const String& dslabel ) const
644 {
645     // dataset dims
646     int dsizes[2] = { rows, cols };
647 
648     // create the two dim array
649     dscreate( 2, dsizes, type, dslabel, HDF5::H5_NONE, NULL );
650 }
651 
652 // overload
dscreate(const int rows,const int cols,const int type,const String & dslabel,const int compresslevel) const653 void HDF5Impl::dscreate( const int rows, const int cols, const int type,
654                          const String& dslabel, const int compresslevel ) const
655 {
656     // dataset dims
657     int dsizes[2] = { rows, cols };
658 
659     // create the two dim array
660     dscreate( 2, dsizes, type, dslabel, compresslevel, NULL );
661 }
662 
663 // overload
dscreate(const int rows,const int cols,const int type,const String & dslabel,const int compresslevel,const vector<int> & dims_chunks) const664 void HDF5Impl::dscreate( const int rows, const int cols, const int type,
665                  const String& dslabel, const int compresslevel,
666                  const vector<int>& dims_chunks ) const
667 {
668     CV_Assert( dims_chunks.empty() || dims_chunks.size() == 2 );
669     dscreate( rows, cols, type, dslabel, compresslevel, dims_chunks.empty() ? NULL : &(dims_chunks[0]) );
670 }
671 
dscreate(const int rows,const int cols,const int type,const String & dslabel,const int compresslevel,const int * dims_chunks) const672 void HDF5Impl::dscreate( const int rows, const int cols, const int type,
673                  const String& dslabel, const int compresslevel, const int* dims_chunks ) const
674 {
675     // dataset dims
676     int dsizes[2] = { rows, cols };
677 
678     // create the two dim array
679     dscreate( 2, dsizes, type, dslabel, compresslevel, dims_chunks );
680 }
681 
682 // overload
dscreate(const int n_dims,const int * sizes,const int type,const String & dslabel) const683 void HDF5Impl::dscreate( const int n_dims, const int* sizes, const int type,
684                  const String& dslabel ) const
685 {
686     dscreate( n_dims, sizes, type, dslabel, H5_NONE, NULL );
687 }
688 
689 // overload
dscreate(const int n_dims,const int * sizes,const int type,const String & dslabel,const int compresslevel) const690 void HDF5Impl::dscreate( const int n_dims, const int* sizes, const int type,
691                  const String& dslabel, const int compresslevel ) const
692 {
693     dscreate( n_dims, sizes, type, dslabel, compresslevel, NULL );
694 }
695 
696 // overload
dscreate(const vector<int> & sizes,const int type,const String & dslabel,const int compresslevel,const vector<int> & dims_chunks) const697 void HDF5Impl::dscreate( const vector<int>& sizes, const int type,
698                  const String& dslabel, const int compresslevel,
699                  const vector<int>& dims_chunks ) const
700 {
701     CV_Assert( dims_chunks.empty() || dims_chunks.size() == sizes.size() );
702 
703     const int n_dims = (int) sizes.size();
704     dscreate( n_dims, &sizes[0], type, dslabel, compresslevel, dims_chunks.empty() ? NULL : &(dims_chunks[0]) );
705 }
706 
dscreate(const int n_dims,const int * sizes,const int type,const String & dslabel,const int compresslevel,const int * dims_chunks) const707 void HDF5Impl::dscreate( const int n_dims, const int* sizes, const int type,
708                  const String& dslabel, const int compresslevel, const int* dims_chunks ) const
709 {
710     // compress valid H5_NONE, 0-9
711     CV_Assert( compresslevel >= H5_NONE && compresslevel <= 9 );
712 
713     if ( hlexists( dslabel ) == true )
714       CV_Error_(Error::StsInternal, ("Requested dataset '%s' already exists.", dslabel.c_str()));
715 
716     int channs = CV_MAT_CN( type );
717 
718     hsize_t *chunks = new hsize_t[n_dims];
719     hsize_t *dsdims = new hsize_t[n_dims];
720     hsize_t *maxdim = new hsize_t[n_dims];
721 
722     // dimension space
723     for ( int d = 0; d < n_dims; d++ )
724     {
725       CV_Assert( sizes[d] >= H5_UNLIMITED );
726 
727       // dataset dimension
728       if ( sizes[d] == H5_UNLIMITED )
729       {
730         CV_Assert( dims_chunks != NULL );
731 
732         dsdims[d] = 0;
733         maxdim[d] = H5S_UNLIMITED;
734       }
735       else
736       {
737         dsdims[d] = sizes[d];
738         maxdim[d] = sizes[d];
739       }
740       // default chunking
741       if ( dims_chunks == NULL )
742         chunks[d] = sizes[d];
743       else
744         chunks[d] = dims_chunks[d];
745     }
746 
747     // create dataset space
748     hid_t dspace = H5Screate_simple( n_dims, dsdims, maxdim );
749 
750     // create data property
751     hid_t dsdcpl = H5Pcreate( H5P_DATASET_CREATE );
752 
753     // set properties
754     if ( compresslevel >= 0 )
755       H5Pset_deflate( dsdcpl, compresslevel );
756 
757     if ( dims_chunks != NULL || compresslevel >= 0 )
758       H5Pset_chunk( dsdcpl, n_dims, chunks );
759 
760     // convert to h5 type
761     hid_t dstype = GetH5type( type );
762 
763     // expand channs
764     if ( channs > 1 )
765     {
766       hsize_t adims[1] = { (hsize_t)channs };
767       dstype = H5Tarray_create( dstype, 1, adims );
768     }
769 
770     // create data
771     hid_t dsdata = H5Dcreate( m_h5_file_id, dslabel.c_str(), dstype,
772                dspace, H5P_DEFAULT, dsdcpl, H5P_DEFAULT );
773 
774     if ( channs > 1 )
775       H5Tclose( dstype );
776 
777     delete [] chunks;
778     delete [] dsdims;
779     delete [] maxdim;
780 
781     H5Pclose( dsdcpl );
782     H5Sclose( dspace );
783     H5Dclose( dsdata );
784 }
785 
786 // overload
dsread(OutputArray Array,const String & dslabel) const787 void HDF5Impl::dsread( OutputArray Array, const String& dslabel ) const
788 {
789     dsread( Array, dslabel, NULL, NULL );
790 }
791 
792 // overload
dsread(OutputArray Array,const String & dslabel,const int * dims_offset) const793 void HDF5Impl::dsread( OutputArray Array, const String& dslabel,
794              const int* dims_offset ) const
795 {
796     dsread( Array, dslabel, dims_offset, NULL );
797 }
798 
799 // overload
dsread(OutputArray Array,const String & dslabel,const vector<int> & dims_offset,const vector<int> & dims_counts) const800 void HDF5Impl::dsread( OutputArray Array, const String& dslabel,
801              const vector<int>& dims_offset,
802              const vector<int>& dims_counts ) const
803 {
804     dsread( Array, dslabel, &dims_offset[0], &dims_counts[0] );
805 }
806 
dsread(OutputArray Array,const String & dslabel,const int * dims_offset,const int * dims_counts) const807 void HDF5Impl::dsread( OutputArray Array, const String& dslabel,
808              const int* dims_offset, const int* dims_counts ) const
809 {
810     // only Mat support
811     CV_Assert( Array.isMat() );
812 
813     hid_t h5type;
814 
815     // open the HDF5 dataset
816     hid_t dsdata = H5Dopen( m_h5_file_id, dslabel.c_str(), H5P_DEFAULT );
817 
818     // get data type
819     hid_t dstype = H5Dget_type( dsdata );
820 
821     int channs = 1;
822     if ( H5Tget_class( dstype ) == H5T_ARRAY )
823     {
824       // fetch channs
825       hsize_t ardims[1];
826       H5Tget_array_dims( dstype, ardims );
827       channs = (int) ardims[0];
828       // fetch depth
829       hid_t tsuper = H5Tget_super( dstype );
830       h5type = H5Tget_native_type( tsuper, H5T_DIR_ASCEND );
831       H5Tclose( tsuper );
832     } else
833       h5type = H5Tget_native_type( dstype, H5T_DIR_ASCEND );
834 
835     int dType = GetCVtype( h5type );
836 
837     // get file space
838     hid_t fspace = H5Dget_space( dsdata );
839 
840     // fetch rank
841     int n_dims = H5Sget_simple_extent_ndims( fspace );
842 
843     // fetch dims
844     hsize_t *dsdims = new hsize_t[n_dims];
845     H5Sget_simple_extent_dims( fspace, dsdims, NULL );
846 
847     // set amount by custom offset
848     if ( dims_offset != NULL )
849     {
850       for ( int d = 0; d < n_dims; d++ )
851         dsdims[d] -= dims_offset[d];
852     }
853 
854     // set custom amount of data
855     if ( dims_counts != NULL )
856     {
857       for ( int d = 0; d < n_dims; d++ )
858         dsdims[d] = dims_counts[d];
859     }
860 
861     // get memory write window
862     int *mxdims = new int[n_dims];
863     hsize_t *foffset = new hsize_t[n_dims];
864     for ( int d = 0; d < n_dims; d++ )
865     {
866       foffset[d] = 0;
867       mxdims[d] = (int) dsdims[d];
868     }
869 
870     // allocate persistent Mat
871     Array.create( n_dims, mxdims, CV_MAKETYPE(dType, channs) );
872 
873     // get blank data space
874     hid_t dspace = H5Screate_simple( n_dims, dsdims, NULL );
875 
876     // get matrix write window
877     H5Sselect_hyperslab( dspace, H5S_SELECT_SET,
878                          foffset, NULL, dsdims, NULL );
879 
880     // set custom offsets
881     if ( dims_offset != NULL )
882     {
883       for ( int d = 0; d < n_dims; d++ )
884         foffset[d] = dims_offset[d];
885     }
886 
887     // get a file read window
888     H5Sselect_hyperslab( fspace, H5S_SELECT_SET,
889                          foffset, NULL, dsdims, NULL );
890 
891     // read from DS
892     Mat matrix = Array.getMat();
893     H5Dread( dsdata, dstype, dspace, fspace, H5P_DEFAULT, matrix.data );
894 
895     delete [] dsdims;
896     delete [] mxdims;
897     delete [] foffset;
898 
899     H5Tclose (h5type );
900     H5Tclose( dstype );
901     H5Sclose( dspace );
902     H5Sclose( fspace );
903     H5Dclose( dsdata );
904 }
905 
906 // overload
dswrite(InputArray Array,const String & dslabel) const907 void HDF5Impl::dswrite( InputArray Array, const String& dslabel ) const
908 {
909     dswrite( Array, dslabel, NULL, NULL );
910 }
911 // overload
dswrite(InputArray Array,const String & dslabel,const int * dims_offset) const912 void HDF5Impl::dswrite( InputArray Array, const String& dslabel,
913              const int* dims_offset ) const
914 {
915     dswrite( Array, dslabel, dims_offset, NULL );
916 }
917 // overload
dswrite(InputArray Array,const String & dslabel,const vector<int> & dims_offset,const vector<int> & dims_counts) const918 void HDF5Impl::dswrite( InputArray Array, const String& dslabel,
919              const vector<int>& dims_offset,
920              const vector<int>& dims_counts ) const
921 {
922     dswrite( Array, dslabel, &dims_offset[0], &dims_counts[0] );
923 }
924 
dswrite(InputArray Array,const String & dslabel,const int * dims_offset,const int * dims_counts) const925 void HDF5Impl::dswrite( InputArray Array, const String& dslabel,
926              const int* dims_offset, const int* dims_counts ) const
927 {
928     // only Mat support
929     CV_Assert( Array.isMat() );
930 
931     Mat matrix = Array.getMat();
932 
933     // memory array should be compact
934     CV_Assert( matrix.isContinuous() );
935 
936     int n_dims = matrix.dims;
937     int channs = matrix.channels();
938 
939     int *dsizes = new int[n_dims];
940     hsize_t *dsdims = new hsize_t[n_dims];
941     hsize_t *offset = new hsize_t[n_dims];
942     // replicate Mat dimensions
943     for ( int d = 0; d < n_dims; d++ )
944     {
945       offset[d] = 0;
946       dsizes[d] = matrix.size[d];
947       dsdims[d] = matrix.size[d];
948     }
949 
950     // FixMe: If one of the groups the dataset belongs to does not exist,
951     // FixMe: dscreate() will fail!
952     // FixMe: It should be an error if the specified dataset has not been created instead of trying to create it
953     // pre-create dataset if needed
954     if ( hlexists( dslabel ) == false )
955       dscreate( n_dims, dsizes, matrix.type(), dslabel );
956 
957     // set custom amount of data
958     if ( dims_counts != NULL )
959     {
960       for ( int d = 0; d < n_dims; d++ )
961         dsdims[d] = dims_counts[d];
962     }
963 
964     // open dataset
965     hid_t dsdata = H5Dopen( m_h5_file_id, dslabel.c_str(), H5P_DEFAULT );
966 
967     // create input data space
968     hid_t dspace = H5Screate_simple( n_dims, dsdims, NULL );
969 
970     // set custom offsets
971     if ( dims_offset != NULL )
972     {
973       for ( int d = 0; d < n_dims; d++ )
974         offset[d] = dims_offset[d];
975     }
976 
977     // create offset write window space
978     hid_t fspace = H5Dget_space( dsdata );
979     H5Sselect_hyperslab( fspace, H5S_SELECT_SET,
980                          offset, NULL, dsdims, NULL );
981 
982     // convert type
983     hid_t dstype = GetH5type( matrix.type() );
984 
985     // expand channs
986     if ( matrix.channels() > 1 )
987     {
988       hsize_t adims[1] = { (hsize_t)channs };
989       dstype = H5Tarray_create( dstype, 1, adims );
990     }
991 
992     // write into dataset
993     H5Dwrite( dsdata, dstype, dspace, fspace,
994               H5P_DEFAULT, matrix.data );
995 
996     if ( matrix.channels() > 1 )
997       H5Tclose( dstype );
998 
999     delete [] dsizes;
1000     delete [] dsdims;
1001     delete [] offset;
1002 
1003     H5Sclose( dspace );
1004     H5Sclose( fspace );
1005     H5Dclose( dsdata );
1006 }
1007 
1008 // overload
dsinsert(InputArray Array,const String & dslabel) const1009 void HDF5Impl::dsinsert( InputArray Array, const String& dslabel ) const
1010 {
1011     dsinsert( Array, dslabel, NULL, NULL );
1012 }
1013 
1014 // overload
dsinsert(InputArray Array,const String & dslabel,const int * dims_offset) const1015 void HDF5Impl::dsinsert( InputArray Array, const String& dslabel,
1016              const int* dims_offset ) const
1017 {
1018     dsinsert( Array, dslabel, dims_offset, NULL );
1019 }
1020 
1021 // overload
dsinsert(InputArray Array,const String & dslabel,const vector<int> & dims_offset,const vector<int> & dims_counts) const1022 void HDF5Impl::dsinsert( InputArray Array, const String& dslabel,
1023              const vector<int>& dims_offset,
1024              const vector<int>& dims_counts ) const
1025 {
1026     dsinsert( Array, dslabel, &dims_offset[0], &dims_counts[0] );
1027 }
1028 
dsinsert(InputArray Array,const String & dslabel,const int * dims_offset,const int * dims_counts) const1029 void HDF5Impl::dsinsert( InputArray Array, const String& dslabel,
1030              const int* dims_offset, const int* dims_counts ) const
1031 {
1032     // only Mat support
1033     CV_Assert( Array.isMat() );
1034 
1035     // check dataset exists
1036     if ( hlexists( dslabel ) == false )
1037       CV_Error_(Error::StsInternal, ("Dataset '%s' does not exist.", dslabel.c_str()));
1038 
1039     Mat matrix = Array.getMat();
1040 
1041     // memory array should be compact
1042     CV_Assert( matrix.isContinuous() );
1043 
1044     int n_dims = matrix.dims;
1045     int channs = matrix.channels();
1046 
1047     hsize_t *dsdims = new hsize_t[n_dims];
1048     hsize_t *offset = new hsize_t[n_dims];
1049     // replicate Mat dimensions
1050     for ( int d = 0; d < n_dims; d++ )
1051     {
1052       offset[d] = 0;
1053       dsdims[d] = matrix.size[d];
1054     }
1055 
1056     // set custom amount of data
1057     if ( dims_counts != NULL )
1058     {
1059       for ( int d = 0; d < n_dims; d++ )
1060       {
1061         CV_Assert( dims_counts[d] <= matrix.size[d] );
1062         dsdims[d] = dims_counts[d];
1063       }
1064     }
1065 
1066     // open dataset
1067     hid_t dsdata = H5Dopen( m_h5_file_id, dslabel.c_str(), H5P_DEFAULT );
1068 
1069     // create input data space
1070     hid_t dspace = H5Screate_simple( n_dims, dsdims, NULL );
1071 
1072     // set custom offsets
1073     if ( dims_offset != NULL )
1074     {
1075       for ( int d = 0; d < n_dims; d++ )
1076         offset[d] = dims_offset[d];
1077     }
1078 
1079     // get actual file space and dims
1080     hid_t fspace = H5Dget_space( dsdata );
1081     int f_dims = H5Sget_simple_extent_ndims( fspace );
1082     hsize_t *fsdims = new hsize_t[f_dims];
1083     H5Sget_simple_extent_dims( fspace, fsdims, NULL );
1084     H5Sclose( fspace );
1085 
1086     CV_Assert( f_dims == n_dims );
1087 
1088     // compute new extents
1089     hsize_t *nwdims = new hsize_t[n_dims];
1090     for ( int d = 0; d < n_dims; d++ )
1091     {
1092       // init
1093       nwdims[d] = 0;
1094       // add offset
1095       if ( dims_offset != NULL )
1096         nwdims[d] += dims_offset[d];
1097       // add counts or matrix size
1098       if ( dims_counts != NULL )
1099         nwdims[d] += dims_counts[d];
1100       else
1101         nwdims[d] += matrix.size[d];
1102 
1103       // clamp back if smaller
1104       if ( nwdims[d] < fsdims[d] )
1105         nwdims[d] = fsdims[d];
1106     }
1107 
1108     // extend dataset
1109     H5Dextend( dsdata, nwdims );
1110 
1111     // get the extended data space
1112     fspace = H5Dget_space( dsdata );
1113 
1114     H5Sselect_hyperslab( fspace, H5S_SELECT_SET,
1115                          offset, NULL, dsdims, NULL );
1116 
1117     // convert type
1118     hid_t dstype = GetH5type( matrix.type() );
1119 
1120     // expand channs
1121     if ( matrix.channels() > 1 )
1122     {
1123       hsize_t adims[1] = { (hsize_t)channs };
1124       dstype = H5Tarray_create( dstype, 1, adims );
1125     }
1126 
1127     // write into dataset
1128     H5Dwrite( dsdata, dstype, dspace, fspace,
1129               H5P_DEFAULT, matrix.data );
1130 
1131     if ( matrix.channels() > 1 )
1132       H5Tclose( dstype );
1133 
1134     delete [] dsdims;
1135     delete [] offset;
1136     delete [] fsdims;
1137     delete [] nwdims;
1138 
1139     H5Sclose( dspace );
1140     H5Sclose( fspace );
1141     H5Dclose( dsdata );
1142 }
1143 
1144 /*
1145  *  std::vector<cv::KeyPoint>
1146  */
1147 
kpgetsize(const String & kplabel,int dims_flag) const1148 int HDF5Impl::kpgetsize( const String& kplabel, int dims_flag ) const
1149 {
1150     vector<int> sizes = dsgetsize( kplabel, dims_flag );
1151 
1152     CV_Assert( sizes.size() == 1 );
1153 
1154     return sizes[0];
1155 }
1156 
kpcreate(const int size,const String & kplabel,const int compresslevel,const int chunks) const1157 void HDF5Impl::kpcreate( const int size, const String& kplabel,
1158              const int compresslevel, const int chunks ) const
1159 {
1160     // size valid
1161     CV_Assert( size >= H5_UNLIMITED );
1162 
1163     // valid chunks
1164     CV_Assert( chunks == H5_NONE || chunks > 0 );
1165 
1166     // compress valid -1, 0-9
1167     CV_Assert( compresslevel >= H5_NONE && compresslevel <= 9 );
1168 
1169     if ( hlexists( kplabel ) == true )
1170       CV_Error_(Error::StsInternal, ("Requested dataset '%s' already exists.", kplabel.c_str()));
1171 
1172     hsize_t dchunk[1];
1173     hsize_t dsdims[1];
1174     hsize_t maxdim[1];
1175 
1176     // dataset dimension
1177     if ( size == H5_UNLIMITED )
1178     {
1179       dsdims[0] = 0;
1180       maxdim[0] = H5S_UNLIMITED;
1181     }
1182     else
1183     {
1184       dsdims[0] = size;
1185       maxdim[0] = size;
1186     }
1187 
1188     // default chunking
1189     if ( chunks == H5_NONE )
1190       if ( size == H5_UNLIMITED )
1191         dchunk[0] = 1;
1192       else
1193         dchunk[0] = size;
1194     else
1195       dchunk[0] = chunks;
1196 
1197     // dataset compound type
1198     hid_t dstype = H5Tcreate( H5T_COMPOUND, sizeof( KeyPoint ) );
1199     H5Tinsert( dstype, "xpos",     HOFFSET( KeyPoint, pt.x     ), H5T_NATIVE_FLOAT );
1200     H5Tinsert( dstype, "ypos",     HOFFSET( KeyPoint, pt.y     ), H5T_NATIVE_FLOAT );
1201     H5Tinsert( dstype, "size",     HOFFSET( KeyPoint, size     ), H5T_NATIVE_FLOAT );
1202     H5Tinsert( dstype, "angle",    HOFFSET( KeyPoint, angle    ), H5T_NATIVE_FLOAT );
1203     H5Tinsert( dstype, "response", HOFFSET( KeyPoint, response ), H5T_NATIVE_FLOAT );
1204     H5Tinsert( dstype, "octave",   HOFFSET( KeyPoint, octave   ), H5T_NATIVE_INT32 );
1205     H5Tinsert( dstype, "class_id", HOFFSET( KeyPoint, class_id ), H5T_NATIVE_INT32 );
1206 
1207     // create dataset space
1208     hid_t dspace = H5Screate_simple( 1, dsdims, maxdim );
1209 
1210     // create data property
1211     hid_t dsdcpl = H5Pcreate( H5P_DATASET_CREATE );
1212 
1213     // set properties
1214     if ( compresslevel >= 0 )
1215       H5Pset_deflate( dsdcpl, compresslevel );
1216 
1217     // if chunking or compression
1218     if ( dchunk[0] > 0 || compresslevel >= 0 )
1219       H5Pset_chunk( dsdcpl, 1, dchunk );
1220 
1221     // create data
1222     H5Dcreate( m_h5_file_id, kplabel.c_str(), dstype,
1223                dspace, H5P_DEFAULT, dsdcpl, H5P_DEFAULT );
1224 
1225     H5Tclose( dstype );
1226     H5Pclose( dsdcpl );
1227     H5Sclose( dspace );
1228 }
1229 
kpwrite(const vector<KeyPoint> keypoints,const String & kplabel,const int offset,const int counts) const1230 void HDF5Impl::kpwrite( const vector<KeyPoint> keypoints, const String& kplabel,
1231              const int offset, const int counts ) const
1232 {
1233     CV_Assert( keypoints.size() > 0 );
1234 
1235     int dskdims[1];
1236     hsize_t dsddims[1];
1237     hsize_t doffset[1];
1238 
1239     // replicate vector dimension
1240     doffset[0] = 0;
1241     dsddims[0] = keypoints.size();
1242     dskdims[0] = (int)keypoints.size();
1243 
1244     // pre-create dataset if needed
1245     if ( hlexists( kplabel ) == false )
1246       kpcreate( dskdims[0], kplabel );
1247 
1248     // set custom amount of data
1249     if ( counts != H5_NONE )
1250       dsddims[0] = counts;
1251 
1252     // open dataset
1253     hid_t dsdata = H5Dopen( m_h5_file_id, kplabel.c_str(), H5P_DEFAULT );
1254 
1255     // create input data space
1256     hid_t dspace = H5Screate_simple( 1, dsddims, NULL );
1257 
1258     // set custom offsets
1259     if ( offset != H5_NONE )
1260       doffset[0] = offset;
1261 
1262     // create offset write window space
1263     hid_t fspace = H5Dget_space( dsdata );
1264     H5Sselect_hyperslab( fspace, H5S_SELECT_SET,
1265                          doffset, NULL, dsddims, NULL );
1266 
1267     // memory compound type
1268     hid_t mmtype = H5Tcreate( H5T_COMPOUND, sizeof( KeyPoint ) );
1269     H5Tinsert( mmtype, "xpos",     HOFFSET( KeyPoint, pt.x     ), H5T_NATIVE_FLOAT );
1270     H5Tinsert( mmtype, "ypos",     HOFFSET( KeyPoint, pt.y     ), H5T_NATIVE_FLOAT );
1271     H5Tinsert( mmtype, "size",     HOFFSET( KeyPoint, size     ), H5T_NATIVE_FLOAT );
1272     H5Tinsert( mmtype, "angle",    HOFFSET( KeyPoint, angle    ), H5T_NATIVE_FLOAT );
1273     H5Tinsert( mmtype, "response", HOFFSET( KeyPoint, response ), H5T_NATIVE_FLOAT );
1274     H5Tinsert( mmtype, "octave",   HOFFSET( KeyPoint, octave   ), H5T_NATIVE_INT32 );
1275     H5Tinsert( mmtype, "class_id", HOFFSET( KeyPoint, class_id ), H5T_NATIVE_INT32 );
1276 
1277     // write into dataset
1278     H5Dwrite( dsdata, mmtype, dspace, fspace, H5P_DEFAULT, &keypoints[0] );
1279 
1280     H5Tclose( mmtype );
1281     H5Sclose( dspace );
1282     H5Sclose( fspace );
1283     H5Dclose( dsdata );
1284 }
1285 
kpinsert(const vector<KeyPoint> keypoints,const String & kplabel,const int offset,const int counts) const1286 void HDF5Impl::kpinsert( const vector<KeyPoint> keypoints, const String& kplabel,
1287              const int offset, const int counts ) const
1288 {
1289     CV_Assert( keypoints.size() > 0 );
1290 
1291     // check dataset exists
1292     if ( hlexists( kplabel ) == false )
1293       CV_Error_(Error::StsInternal, ("Dataset '%s' does not exist.", kplabel.c_str()));
1294 
1295     hsize_t dsddims[1];
1296     hsize_t doffset[1];
1297 
1298     // replicate vector dimension
1299     doffset[0] = 0;
1300     dsddims[0] = keypoints.size();
1301 
1302     // set custom amount of data
1303     if ( counts != H5_NONE )
1304       dsddims[0] = counts;
1305 
1306     // open dataset
1307     hid_t dsdata = H5Dopen( m_h5_file_id, kplabel.c_str(), H5P_DEFAULT );
1308 
1309     // create input data space
1310     hid_t dspace = H5Screate_simple( 1, dsddims, NULL );
1311 
1312     // set custom offsets
1313     if ( offset != H5_NONE )
1314       doffset[0] = offset;
1315 
1316     // get actual file space and dims
1317     hid_t fspace = H5Dget_space( dsdata );
1318     int f_dims = H5Sget_simple_extent_ndims( fspace );
1319     hsize_t *fsdims = new hsize_t[f_dims];
1320     H5Sget_simple_extent_dims( fspace, fsdims, NULL );
1321     H5Sclose( fspace );
1322 
1323     CV_Assert( f_dims == 1 );
1324 
1325     // compute new extents
1326     hsize_t nwdims[1] = { 0 };
1327     // add offset
1328     if ( offset != H5_NONE )
1329       nwdims[0] += offset;
1330     // add counts or matrixsize
1331     if ( counts != H5_NONE )
1332       nwdims[0] += counts;
1333     else
1334       nwdims[0] += keypoints.size();
1335 
1336     // clamp back if smaller
1337     if ( nwdims[0] < fsdims[0] )
1338       nwdims[0] = fsdims[0];
1339 
1340     // extend dataset
1341     H5Dextend( dsdata, nwdims );
1342 
1343     // get the extended data space
1344     fspace = H5Dget_space( dsdata );
1345 
1346     H5Sselect_hyperslab( fspace, H5S_SELECT_SET,
1347                          doffset, NULL, dsddims, NULL );
1348 
1349     // memory compound type
1350     hid_t mmtype = H5Tcreate( H5T_COMPOUND, sizeof( KeyPoint ) );
1351     H5Tinsert( mmtype, "xpos",     HOFFSET( KeyPoint, pt.x     ), H5T_NATIVE_FLOAT );
1352     H5Tinsert( mmtype, "ypos",     HOFFSET( KeyPoint, pt.y     ), H5T_NATIVE_FLOAT );
1353     H5Tinsert( mmtype, "size",     HOFFSET( KeyPoint, size     ), H5T_NATIVE_FLOAT );
1354     H5Tinsert( mmtype, "angle",    HOFFSET( KeyPoint, angle    ), H5T_NATIVE_FLOAT );
1355     H5Tinsert( mmtype, "response", HOFFSET( KeyPoint, response ), H5T_NATIVE_FLOAT );
1356     H5Tinsert( mmtype, "octave",   HOFFSET( KeyPoint, octave   ), H5T_NATIVE_INT32 );
1357     H5Tinsert( mmtype, "class_id", HOFFSET( KeyPoint, class_id ), H5T_NATIVE_INT32 );
1358 
1359     // write into dataset
1360     H5Dwrite( dsdata, mmtype, dspace, fspace, H5P_DEFAULT, &keypoints[0] );
1361 
1362     delete [] fsdims;
1363 
1364     H5Tclose( mmtype );
1365     H5Sclose( dspace );
1366     H5Sclose( fspace );
1367     H5Dclose( dsdata );
1368 }
1369 
kpread(vector<KeyPoint> & keypoints,const String & kplabel,const int offset,const int counts) const1370 void HDF5Impl::kpread( vector<KeyPoint>& keypoints, const String& kplabel,
1371              const int offset, const int counts ) const
1372 {
1373     CV_Assert( keypoints.size() == 0 );
1374 
1375     // open the HDF5 dataset
1376     hid_t dsdata = H5Dopen( m_h5_file_id, kplabel.c_str(), H5P_DEFAULT );
1377 
1378     // get data type
1379     hid_t dstype = H5Dget_type( dsdata );
1380 
1381     // get file space
1382     hid_t fspace = H5Dget_space( dsdata );
1383 
1384     // fetch rank
1385     int n_dims = H5Sget_simple_extent_ndims( fspace );
1386 
1387     CV_Assert( n_dims == 1 );
1388 
1389     // fetch dims
1390     hsize_t dsddims[1];
1391     H5Sget_simple_extent_dims( fspace, dsddims, NULL );
1392 
1393     // set amount by custom offset
1394     if ( offset != H5_NONE )
1395       dsddims[0] -= offset;
1396 
1397     // set custom amount of data
1398     if ( counts != H5_NONE )
1399       dsddims[0] = counts;
1400 
1401     // get memory write window
1402     hsize_t foffset[1] = { 0 };
1403 
1404     // allocate keypoints vector
1405     keypoints.resize( dsddims[0] );
1406 
1407     // get blank data space
1408     hid_t dspace = H5Screate_simple( 1, dsddims, NULL );
1409 
1410     // get matrix write window
1411     H5Sselect_hyperslab( dspace, H5S_SELECT_SET,
1412                          foffset, NULL, dsddims, NULL );
1413 
1414     // set custom offsets
1415     if ( offset != H5_NONE )
1416       foffset[0] = offset;
1417 
1418     // get a file read window
1419     H5Sselect_hyperslab( fspace, H5S_SELECT_SET,
1420                          foffset, NULL, dsddims, NULL );
1421 
1422     // read from DS
1423     H5Dread( dsdata, dstype, dspace, fspace, H5P_DEFAULT, &keypoints[0] );
1424 
1425     H5Tclose( dstype );
1426     H5Sclose( dspace );
1427     H5Sclose( fspace );
1428     H5Dclose( dsdata );
1429 }
1430 
open(const String & HDF5Filename)1431 CV_EXPORTS Ptr<HDF5> open( const String& HDF5Filename )
1432 {
1433     return makePtr<HDF5Impl>( HDF5Filename );
1434 }
1435 
1436 } // end namespace hdf
1437 } // end namespace cv
1438