GSLAM  3.0.0
GImage.h
1 // GSLAM - A general SLAM framework and benchmark
2 // Copyright 2018 PILAB Inc. All rights reserved.
3 // https://github.com/zdzhaoyong/GSLAM
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors may be
14 // used to endorse or promote products derived from this software without
15 // specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 //
29 // Author: zd5945@126.com (Yong Zhao)
30 //
31 // GImage provides seemlessly copy and basic functions of cv::Mat
32 
33 #ifndef GSLAM_GIMAGE_H
34 #define GSLAM_GIMAGE_H
35 #include <stdint.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <stddef.h>
39 #include <atomic>
40 
41 #if defined(HAS_OPENCV) || defined(HAS_OPENCV3)
42 #include <opencv2/core/core.hpp>
43 #else
44 typedef unsigned char uchar;
45 #endif
46 
47 #ifndef CV_XADD
48  #include <mutex>
49  static inline int CV_XADD(int* addr, int delta)
50  {
51  static std::mutex mutex;
52  std::unique_lock<std::mutex> lock(mutex);
53  int tmp = *addr; *addr += delta; return tmp;
54  }
55 #endif
56 
57 namespace GSLAM{
58 
59 #ifndef DOXYGEN_IGNORE_INTERNAL
60 
61 enum GElementType{
62  GElementType_8U =0,
63  GElementType_8S =1,
64  GElementType_16U=2,
65  GElementType_16S=3,
66  GElementType_32S=4,
67  GElementType_32F=5,
68  GElementType_64F=6,
69  GElementType_UserType=7
70 };
71 
72 template <typename C>
73 class GElement
74 {
75 public:
76  enum{Type=GElementType_UserType};
77 };
78 
79 template <>
80 class GElement<uint8_t>
81 {
82 public:
83  enum{Type=GElementType_8U};
84 };
85 
86 template <>
87 class GElement<char>
88 {
89 public:
90  enum{Type=GElementType_8S};
91 };
92 
93 template <>
94 class GElement<int16_t>
95 {
96 public:
97  enum{Type=GElementType_16S};
98 };
99 
100 template <>
101 class GElement<uint16_t>
102 {
103 public:
104  enum{Type=GElementType_16U};
105 };
106 
107 template <>
108 class GElement<int32_t>
109 {
110 public:
111  enum{Type=GElementType_32S};
112 };
113 
114 template <>
115 class GElement<float>
116 {
117 public:
118  enum{Type=GElementType_32F};
119 };
120 
121 template <>
122 class GElement<double>
123 {
124 public:
125  enum{Type=GElementType_64F};
126 };
127 
128 template <typename EleType=uint8_t,int channelSize=1>
129 struct GImageType
130 {
131  enum{Type=((GElement<EleType>::Type&0x7)+((channelSize-1)<<3))};
132 };
133 
134 struct UMatData// for OpenCV Version 3
135 {
136  enum { COPY_ON_MAP=1, HOST_COPY_OBSOLETE=2,
137  DEVICE_COPY_OBSOLETE=4, TEMP_UMAT=8, TEMP_COPIED_UMAT=24,
138  USER_ALLOCATED=32, DEVICE_MEM_MAPPED=64};
139  const void* prevAllocator;
140  const void* currAllocator;
141  int urefcount;
142  int refcount;
143  uchar* data;
144  uchar* origdata;
145  size_t size;
146 
147  int flags;
148  void* handle;
149  void* userdata;
150  int allocatorFlags_;
151  int mapcount;
152  UMatData* originalUMatData;
153 };
154 #endif
155 
156 /**
157  * @brief The GImage class is a tiny implementation of image for removing dependency of opencv.
158  * Most APIs are corrosponding to "cv::Mat".
159  */
160 class GImage
161 {
162 public:
163  GImage()
164  :cols(0),rows(0),flags(0),data(NULL),refCount(NULL)
165  {
166 
167  }
168 
169  GImage(int rows_,int cols_,int type=GImageType<>::Type,uchar* src=NULL,bool copy=false,int imageAlign=16)
170  :cols(cols_),rows(rows_),flags(type),data(NULL),refCount(NULL)
171  {
172  if(src&&!copy)
173  {
174  data=src;
175  return;
176  }
177 
178  int byteNum=total()*elemSize();
179  if(byteNum<=0) return;
180  int alignBytes=alignSize(byteNum, (int)sizeof(*refCount));
181  data=(uchar*)fastMalloc(alignBytes+sizeof(int*),imageAlign);
182  if(!data)
183  {
184  cols=0;rows=0;return ;
185  }
186  refCount=(int*)(data+alignBytes);
187  *refCount=1;
188  if(src)
189  memcpy(data,src,byteNum);
190  }
191 
192  GImage(const GImage& ref)
193  : cols(ref.cols),rows(ref.rows),flags(ref.flags),
194  data(ref.data),refCount(ref.refCount)
195  {
196  if(refCount)
197  CV_XADD(refCount,1);
198  }
199 
200  ~GImage()
201  {
202  if(data&&refCount)
203  {
204  if(CV_XADD(refCount,-1)==1)
205  {
206  release();
207  }
208  }
209  cols=rows=flags=0;
210  data=NULL;
211  refCount=NULL;
212  }
213 
214  // This is not thread safe when GImage not empty!
215  GImage& operator=(const GImage& rhs)
216  {
217  this->~GImage();
218  cols=rhs.cols;
219  rows=rhs.rows;
220  flags=rhs.flags;
221  data=rhs.data;
222  refCount=rhs.refCount;
223  if(refCount) CV_XADD(refCount,1);
224  return *this;
225  }
226 
227  static GImage create(int rows,int cols,int type=GImageType<>::Type,uchar* src=NULL,bool copy=false,int imageAlign=16)
228  {
229  return GImage(rows,cols,type,src,copy);
230  }
231 
232  static GImage zeros(int rows,int cols,int type=GImageType<>::Type,uchar* src=NULL,bool copy=false,int imageAlign=16)
233  {
234  GImage result(rows,cols,type,src,copy,imageAlign);
235  memset(result.data,0,result.total()*result.elemSize());
236  return result;
237  }
238 
239  bool empty()const{return !data;}
240  int elemSize()const{return channels()*elemSize1();}
241  int elemSize1()const{return (1<<((type()&0x7)>>1));}
242 
243  int channels()const{return (type()>>3)+1;}
244  int type()const{return flags;}
245  int total()const{return cols*rows;}
246 
247  GImage clone()const
248  {
249  return GImage(rows,cols,flags,data,true);
250  }
251 
252  template <typename C>
253  C& at(int idx){return ((C*)data)[idx];}
254 
255  template <typename C>
256  C& at(int ix,int iy){return ((C*)data)[iy*cols+ix];}
257 
258 
259 #if defined(HAS_OPENCV) || defined(HAS_OPENCV3)
260 #if CV_VERSION_EPOCH == 2
261  inline operator cv::Mat()const
262  {
263  if(empty()) return cv::Mat();
264  cv::Mat result(rows,cols,type(),data);
265  if(refCount)
266  {
267  result.refcount=refCount;
268  CV_XADD(refCount,1);
269  }
270  return result;
271  }
272  GImage(const cv::Mat& mat)
273  : cols(mat.cols),rows(mat.rows),flags(mat.type()),
274  data(mat.data),refCount(mat.refcount)
275  {
276  if(refCount) CV_XADD(refCount,1);
277  }
278 #elif CV_VERSION_MAJOR == 3
279  inline operator cv::Mat()const
280  {
281  if(!data) return cv::Mat();
282  cv::Mat result(rows,cols,type(),data);
283  int byteNum=total()*elemSize();
284  int alignBytes=alignSize(byteNum, (int)sizeof(*refCount));
285  if(((uchar*)refCount)==data+alignBytes)// OpenCV2 style => OpenCV3 style
286  {
287  // WARNING: MAKE SURE THERE ARE NO OTHER HOLDERS
288  // construct a UMat that ref to data
289  cv::UMatData* u=new cv::UMatData(cv::Mat::getStdAllocator());
290  u->data=data;
291 #if CV_VERSION_MINOR>=3
292  u->origdata=((uchar**)data)[-1];
293 #else
294  u->origdata=data;
295 #endif
296  u->userdata=refCount;
297  CV_XADD(refCount,1); // Now we have both refcount and both added 1
298  u->refcount=2;
299 // u->flags|=cv::UMatData::USER_ALLOCATED;
300  refCount=&u->refcount;
301  result.u=u;
302 // result.allocator=nullptr;
303  return result;
304  }
305  else // OpenCV3 style => OpenCV3 style
306  {
307  CV_XADD(refCount,1);
308  cv::UMatData* u=(cv::UMatData*)(((uchar*)refCount)-sizeof(int)-sizeof(cv::MatAllocator*)*2);
309  result.u=u;
310  return result;
311  }
312  return result;// no copy but not safe either
313  }
314 
315  GImage(const cv::Mat& mat)
316  : cols(mat.cols),rows(mat.rows),flags(mat.type()),
317  data(mat.data),refCount(NULL)
318  {
319  if(mat.u&&mat.u->currAllocator==cv::Mat::getStdAllocator())
320  // try to maintain the refcount things, but this need the mat is allocated by default StdAllocator
321  {
322  refCount=(&mat.u->refcount);
323  CV_XADD(refCount,1);
324  }
325  else if(0)// copy the data: SAFE but SLOW
326  {
327  int byteNum=total()*elemSize();
328  data=(uchar*)fastMalloc(byteNum+sizeof(int*));
329  if(!data)
330  {
331  cols=0;rows=0;return ;
332  }
333  refCount=(int*)(data+byteNum);
334  *refCount=1;
335  if(mat.data)
336  memcpy(data,mat.data,byteNum);
337  }
338  }
339 #endif
340 
341 #endif
342 
343  void release()
344  {
345  size_t totalBytes=total()*elemSize();
346  int alignBytes=alignSize(totalBytes, (int)sizeof(*refCount));
347  if(refCount==((int*)(data+alignBytes))) // OpenCV2 style
348  {
349  cols=rows=0;
350  fastFree(data);
351  refCount=NULL;
352  data=NULL;
353  }
354  else// OpenCV3 style
355  {
356  UMatData* u=(UMatData*)(((uchar*)refCount)-offsetof(UMatData,refcount));
357  if(u->userdata==data+alignBytes)
358  {
359  // this is allocated by GImage, we need minus both refcount
360  refCount=(int*)u->userdata;
361  if(CV_XADD(refCount,-1)==1)
362  {
363  return release();
364  }
365  }
366  else{
367  // allocated by OpenCV
368  assert(u->size==totalBytes);
369  //assert(u->currAllocator==NULL);// should be the default allocator
370  deallocate(u);
371  }
372  cols=rows=0;
373  refCount=NULL;
374  data=NULL;
375  }
376  }
377 
378  template<typename _Tp> _Tp* ptr(int i0=0){return (_Tp*)(data+i0*cols*elemSize());}
379 
380  template<typename _Tp> const _Tp* ptr(int i0=0) const{return (_Tp*)(data+i0*cols*elemSize());}
381 
382  const GImage row(int idx=0)const{return GImage(1,cols,type(),data+elemSize()*cols*idx);}
383 
384  int getWidth()const{return cols;}
385  int getHeight()const{return rows;}
386 
387 private:
388 
389  template<typename _Tp> static inline _Tp* alignPtr(_Tp* ptr, int n=(int)sizeof(_Tp))
390  {
391  return (_Tp*)(((size_t)ptr + n-1) & -n);
392  }
393 
394  void* fastMalloc( size_t size ,int imageAlign=16) const
395  {
396  uchar* udata = (uchar*)malloc(size + sizeof(void*) + imageAlign);
397  if(!udata)
398  return NULL;
399  uchar** adata = alignPtr((uchar**)udata + 1, imageAlign);
400  adata[-1] = udata;
401  return adata;
402  }
403 
404  void fastFree(void* ptr) const
405  {
406  if(ptr)
407  {
408  uchar* udata = ((uchar**)ptr)[-1];
409  free(udata);
410  }
411  }
412 
413  static inline size_t alignSize(size_t sz, int n)
414  {
415  assert((n & (n - 1)) == 0); // n is a power of 2
416  return (sz + n-1) & -n;
417  }
418 
419  void deallocate(UMatData* u) const// for OpenCV Version 3
420  {
421  if(!u)
422  return;
423 
424  assert(u->urefcount == 0);
425  assert(u->refcount == 0);
426  if( !(u->flags & UMatData::USER_ALLOCATED) )
427  {
428  uchar* udata = ((uchar**)u->origdata)[-1];
429  int n=u->origdata-udata;
430  if((n & (n - 1)) == 0&&n>=0&&n<=32){
431  fastFree(u->origdata);
432  }
433  else free(u->origdata);
434  u->origdata = 0;
435  }
436  delete u;
437  }
438 
439 public:
440  int cols,rows,flags;
441  uchar* data;
442  mutable int* refCount;
443 };
444 
445 }
446 #endif
447 
The GImage class is a tiny implementation of image for removing dependency of opencv.
Definition: GImage.h:160
Definition: Camera.h:45