DFace SDK  1.8.5
mat.h
1 
2 
3 #ifndef DFACE_MAT_H
4 #define DFACE_MAT_H
5 
6 #include "dface/def.h"
7 #include "dface/config.h"
8 #include <stdlib.h>
9 #include <string.h>
10 #if __ARM_NEON
11 #include <arm_neon.h>
12 #endif
13 #include "cpu.h"
14 
15 
16 namespace dface {
17 
23 class DFACE_EXPORTS Mat
24 {
25 public:
26  // empty
27  Mat();
28  // vec
29  Mat(int w, size_t elemsize = 4);
30  // image
31  Mat(int w, int h, size_t elemsize = 4);
32  // dim
33  Mat(int w, int h, int c, size_t elemsize = 4);
34  // copy
35  Mat(const Mat& m);
36  // external vec
37  Mat(int w, void* data, size_t elemsize = 4);
38  // external image
39  Mat(int w, int h, void* data, size_t elemsize = 4);
40  // external dim
41  Mat(int w, int h, int c, void* data, size_t elemsize = 4);
42  // release
43  ~Mat();
44  // assign
45  Mat& operator=(const Mat& m);
46  // set all
47  void fill(float v);
48  template <typename T> void fill(T v);
49  // deep copy
50  Mat clone() const;
51  // reshape vec
52  Mat reshape(int w) const;
53  // reshape image
54  Mat reshape(int w, int h) const;
55  // reshape dim
56  Mat reshape(int w, int h, int c) const;
57  // allocate vec
58  void create(int w, size_t elemsize = 4);
59  // allocate image
60  void create(int w, int h, size_t elemsize = 4);
61  // allocate dim
62  void create(int w, int h, int c, size_t elemsize = 4);
63  // refcount++
64  void addref();
65  // refcount--
66  void release();
67 
68  bool empty() const;
69  size_t total() const;
70 
71  // data reference
72  Mat channel(int c);
73  const Mat channel(int c) const;
74  float* row(int y);
75  const float* row(int y) const;
76  template<typename T> T* row(int y);
77  template<typename T> const T* row(int y) const;
78 
79  // access raw data
80  template<typename T> operator T*();
81  template<typename T> operator const T*() const;
82 
83  // convenient access float vec element
84  float& operator[](int i);
85  const float& operator[](int i) const;
86 
87  enum
88  {
89  PIXEL_CONVERT_SHIFT = 16,
90  PIXEL_FORMAT_MASK = 0x0000ffff,
91  PIXEL_CONVERT_MASK = 0xffff0000,
92 
93  PIXEL_RGB = 1,
94  PIXEL_BGR = (1 << 1),
95  PIXEL_GRAY = (1 << 2),
96  PIXEL_RGBA = (1 << 3),
97 
98  PIXEL_RGB2BGR = PIXEL_RGB | (PIXEL_BGR << PIXEL_CONVERT_SHIFT),
99  PIXEL_RGB2GRAY = PIXEL_RGB | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT),
100 
101  PIXEL_BGR2RGB = PIXEL_BGR | (PIXEL_RGB << PIXEL_CONVERT_SHIFT),
102  PIXEL_BGR2GRAY = PIXEL_BGR | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT),
103 
104  PIXEL_GRAY2RGB = PIXEL_GRAY | (PIXEL_RGB << PIXEL_CONVERT_SHIFT),
105  PIXEL_GRAY2BGR = PIXEL_GRAY | (PIXEL_BGR << PIXEL_CONVERT_SHIFT),
106 
107  PIXEL_RGBA2RGB = PIXEL_RGBA | (PIXEL_RGB << PIXEL_CONVERT_SHIFT),
108  PIXEL_RGBA2BGR = PIXEL_RGBA | (PIXEL_BGR << PIXEL_CONVERT_SHIFT),
109  PIXEL_RGBA2GRAY = PIXEL_RGBA | (PIXEL_GRAY << PIXEL_CONVERT_SHIFT),
110  };
127  static Mat from_pixels(const unsigned char* pixels, int type, int w, int h);
128  // convenient construct from pixel data and resize to specific size
129  static Mat from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height);
130 
147  void to_pixels(unsigned char* pixels, int type) const;
148 
149  // convenient export to pixel data and resize to specific size
150  void to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const;
151 
152  // substract channel-wise mean values, then multiply by normalize values, pass 0 to skip
153  void substract_mean_normalize(const float* mean_vals, const float* norm_vals);
154 
155  // convenient construct from half precisoin floating point data
156  static Mat from_float16(const unsigned short* data, int size);
157 
158  // pointer to the data
159  void* data;
160 
161  // pointer to the reference counter
162  // when points to user-allocated data, the pointer is NULL
163  int* refcount;
164 
165  // element size in bytes
166  // 4 = float32/int32
167  // 2 = float16
168  // 1 = int8/uint8
169  // 0 = empty
170  size_t elemsize;
171 
172  // the dimensionality
173  int dims;
174 
175  int w;
176  int h;
177  int c;
178 
179  size_t cstep;
180 };
181 
182 // misc function
183 // image pixel bilinear resize
184 //void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h);
185 //void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h);
186 //void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h);
187 
188 // mat process
189 enum
190 {
191  BORDER_CONSTANT = 0,
192  BORDER_REPLICATE = 1,
193 };
194 void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v);
195 void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right);
196 
205 void resize_bilinear(const Mat& src, Mat& dst, int w, int h);
206 
207 // the alignment of all the allocated buffers
208 #define MALLOC_ALIGN 16
209 
210 // Aligns a pointer to the specified number of bytes
211 // ptr Aligned pointer
212 // n Alignment size that must be a power of two
213 template<typename _Tp> static inline _Tp* alignPtr(_Tp* ptr, int n=(int)sizeof(_Tp))
214 {
215  return (_Tp*)(((size_t)ptr + n-1) & -n);
216 }
217 
218 // Aligns a buffer size to the specified number of bytes
219 // The function returns the minimum number that is greater or equal to sz and is divisible by n
220 // sz Buffer size to align
221 // n Alignment size that must be a power of two
222 static inline size_t alignSize(size_t sz, int n)
223 {
224  return (sz + n-1) & -n;
225 }
226 
227 static inline void* fastMalloc(size_t size)
228 {
229  unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + MALLOC_ALIGN);
230  if (!udata)
231  return 0;
232  unsigned char** adata = alignPtr((unsigned char**)udata + 1, MALLOC_ALIGN);
233  adata[-1] = udata;
234  return adata;
235 }
236 
237 static inline void fastFree(void* ptr)
238 {
239  if (ptr)
240  {
241  unsigned char* udata = ((unsigned char**)ptr)[-1];
242  free(udata);
243  }
244 }
245 
246 // exchange-add operation for atomic operations on reference counters
247 #if defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32)
248 // atomic increment on the linux version of the Intel(tm) compiler
249 # define DFACE_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast<void*>(reinterpret_cast<volatile void*>(addr)), delta)
250 #elif defined __GNUC__
251 # if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__)
252 # ifdef __ATOMIC_ACQ_REL
253 # define DFACE_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL)
254 # else
255 # define DFACE_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4)
256 # endif
257 # else
258 # if defined __ATOMIC_ACQ_REL && !defined __clang__
259 // version for gcc >= 4.7
260 # define DFACE_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL)
261 # else
262 # define DFACE_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta))
263 # endif
264 # endif
265 #elif defined _MSC_VER && !defined RC_INVOKED
266 # include <intrin.h>
267 # define DFACE_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta)
268 #else
269 static inline void DFACE_XADD(int* addr, int delta) { int tmp = *addr; *addr += delta; return tmp; }
270 #endif
271 
272 inline Mat::Mat()
273  : data(0), refcount(0), elemsize(0), dims(0), w(0), h(0), c(0), cstep(0)
274 {
275 }
276 
277 inline Mat::Mat(int _w, size_t _elemsize)
278  : data(0), refcount(0), dims(0)
279 {
280  create(_w, _elemsize);
281 }
282 
283 inline Mat::Mat(int _w, int _h, size_t _elemsize)
284  : data(0), refcount(0), dims(0)
285 {
286  create(_w, _h, _elemsize);
287 }
288 
289 inline Mat::Mat(int _w, int _h, int _c, size_t _elemsize)
290  : data(0), refcount(0), dims(0)
291 {
292  create(_w, _h, _c, _elemsize);
293 }
294 
295 inline Mat::Mat(const Mat& m)
296  : data(m.data), refcount(m.refcount), elemsize(m.elemsize), dims(m.dims)
297 {
298  if (refcount)
299  DFACE_XADD(refcount, 1);
300 
301  w = m.w;
302  h = m.h;
303  c = m.c;
304 
305  cstep = m.cstep;
306 }
307 
308 inline Mat::Mat(int _w, void* _data, size_t _elemsize)
309  : data(_data), refcount(0), elemsize(_elemsize), dims(1)
310 {
311  w = _w;
312  h = 1;
313  c = 1;
314 
315  cstep = w;
316 }
317 
318 inline Mat::Mat(int _w, int _h, void* _data, size_t _elemsize)
319  : data(_data), refcount(0), elemsize(_elemsize), dims(2)
320 {
321  w = _w;
322  h = _h;
323  c = 1;
324 
325  cstep = w * h;
326 }
327 
328 inline Mat::Mat(int _w, int _h, int _c, void* _data, size_t _elemsize)
329  : data(_data), refcount(0), elemsize(_elemsize), dims(3)
330 {
331  w = _w;
332  h = _h;
333  c = _c;
334 
335  cstep = alignSize(w * h * elemsize, 16) / elemsize;
336 }
337 
338 inline Mat::~Mat()
339 {
340  release();
341 }
342 
343 inline Mat& Mat::operator=(const Mat& m)
344 {
345  if (this == &m)
346  return *this;
347 
348  if (m.refcount)
349  DFACE_XADD(m.refcount, 1);
350 
351  release();
352 
353  data = m.data;
354  refcount = m.refcount;
355  elemsize = m.elemsize;
356 
357  dims = m.dims;
358  w = m.w;
359  h = m.h;
360  c = m.c;
361 
362  cstep = m.cstep;
363 
364  return *this;
365 }
366 
367 inline void Mat::fill(float _v)
368 {
369  int size = total();
370  float* ptr = (float*)data;
371 
372 #if __ARM_NEON
373  int nn = size >> 2;
374  int remain = size - (nn << 2);
375 #else
376  int remain = size;
377 #endif // __ARM_NEON
378 
379 #if __ARM_NEON
380  float32x4_t _c = vdupq_n_f32(_v);
381 #if __aarch64__
382  if (nn > 0)
383  {
384  asm volatile (
385  "0: \n"
386  "subs %w0, %w0, #1 \n"
387  "st1 {%4.4s}, [%1], #16 \n"
388  "bne 0b \n"
389  : "=r"(nn), // %0
390  "=r"(ptr) // %1
391  : "0"(nn),
392  "1"(ptr),
393  "w"(_c) // %4
394  : "cc", "memory"
395  );
396  }
397 #else
398  if (nn > 0)
399  {
400  asm volatile(
401  "0: \n"
402  "subs %0, #1 \n"
403  "vst1.f32 {%e4-%f4}, [%1 :128]!\n"
404  "bne 0b \n"
405  : "=r"(nn), // %0
406  "=r"(ptr) // %1
407  : "0"(nn),
408  "1"(ptr),
409  "w"(_c) // %4
410  : "cc", "memory"
411  );
412  }
413 #endif // __aarch64__
414 #endif // __ARM_NEON
415  for (; remain>0; remain--)
416  {
417  *ptr++ = _v;
418  }
419 }
420 
421 template <typename T>
422 inline void Mat::fill(T _v)
423 {
424  int size = total();
425  T* ptr = (T*)data;
426  for (int i=0; i<size; i++)
427  {
428  ptr[i] = _v;
429  }
430 }
431 
432 inline Mat Mat::clone() const
433 {
434  if (empty())
435  return Mat();
436 
437  Mat m;
438  if (dims == 1)
439  m.create(w, elemsize);
440  else if (dims == 2)
441  m.create(w, h, elemsize);
442  else if (dims == 3)
443  m.create(w, h, c, elemsize);
444 
445  if (total() > 0)
446  {
447  memcpy(m.data, data, total() * elemsize);
448  }
449 
450  return m;
451 }
452 
453 inline Mat Mat::reshape(int _w) const
454 {
455  if (w * h * c != _w)
456  return Mat();
457 
458  if (dims == 3 && cstep != (size_t)w * h)
459  {
460  Mat m;
461  m.create(_w, elemsize);
462 
463  // flatten
464  for (int i=0; i<c; i++)
465  {
466  const void* ptr = (unsigned char*)data + i * cstep * elemsize;
467  void* mptr = (unsigned char*)m.data + i * w * h * elemsize;
468  memcpy(mptr, ptr, w * h * elemsize);
469  }
470 
471  return m;
472  }
473 
474  Mat m = *this;
475 
476  m.dims = 1;
477  m.w = _w;
478  m.h = 1;
479  m.c = 1;
480 
481  m.cstep = _w;
482 
483  return m;
484 }
485 
486 inline Mat Mat::reshape(int _w, int _h) const
487 {
488  if (w * h * c != _w * _h)
489  return Mat();
490 
491  if (dims == 3 && cstep != (size_t)w * h)
492  {
493  Mat m;
494  m.create(_w, _h, elemsize);
495 
496  // flatten
497  for (int i=0; i<c; i++)
498  {
499  const void* ptr = (unsigned char*)data + i * cstep * elemsize;
500  void* mptr = (unsigned char*)m.data + i * w * h * elemsize;
501  memcpy(mptr, ptr, w * h * elemsize);
502  }
503 
504  return m;
505  }
506 
507  Mat m = *this;
508 
509  m.dims = 2;
510  m.w = _w;
511  m.h = _h;
512  m.c = 1;
513 
514  m.cstep = _w * _h;
515 
516  return m;
517 }
518 
519 inline Mat Mat::reshape(int _w, int _h, int _c) const
520 {
521  if (w * h * c != _w * _h * _c)
522  return Mat();
523 
524  if (dims < 3)
525  {
526  if ((size_t)_w * _h != alignSize(_w * _h * elemsize, 16) / elemsize)
527  {
528  Mat m;
529  m.create(_w, _h, _c, elemsize);
530 
531  // align channel
532  for (int i=0; i<_c; i++)
533  {
534  const void* ptr = (unsigned char*)data + i * _w * _h * elemsize;
535  void* mptr = (unsigned char*)m.data + i * m.cstep * m.elemsize;
536  memcpy(mptr, ptr, _w * _h * elemsize);
537  }
538 
539  return m;
540  }
541  }
542  else if (c != _c)
543  {
544  // flatten and then align
545  Mat tmp = reshape(_w * _h * _c);
546  return tmp.reshape(_w, _h, _c);
547  }
548 
549  Mat m = *this;
550 
551  m.dims = 3;
552  m.w = _w;
553  m.h = _h;
554  m.c = _c;
555 
556  m.cstep = alignSize(_w * _h * elemsize, 16) / elemsize;
557 
558  return m;
559 }
560 
561 inline void Mat::create(int _w, size_t _elemsize)
562 {
563  if (dims == 1 && w == _w && elemsize == _elemsize)
564  return;
565 
566  release();
567 
568  elemsize = _elemsize;
569 
570  dims = 1;
571  w = _w;
572  h = 1;
573  c = 1;
574 
575  cstep = w;
576 
577  if (total() > 0)
578  {
579  size_t totalsize = total() * elemsize;
580  data = fastMalloc(totalsize + (int)sizeof(*refcount));
581  refcount = (int*)(((unsigned char*)data) + totalsize);
582  *refcount = 1;
583  }
584 }
585 
586 inline void Mat::create(int _w, int _h, size_t _elemsize)
587 {
588  if (dims == 2 && w == _w && h == _h && elemsize == _elemsize)
589  return;
590 
591  release();
592 
593  elemsize = _elemsize;
594 
595  dims = 2;
596  w = _w;
597  h = _h;
598  c = 1;
599 
600  cstep = w * h;
601 
602  if (total() > 0)
603  {
604  size_t totalsize = total() * elemsize;
605  data = fastMalloc(totalsize + (int)sizeof(*refcount));
606  refcount = (int*)(((unsigned char*)data) + totalsize);
607  *refcount = 1;
608  }
609 }
610 
611 inline void Mat::create(int _w, int _h, int _c, size_t _elemsize)
612 {
613  if (dims == 3 && w == _w && h == _h && c == _c && elemsize == _elemsize)
614  return;
615 
616  release();
617 
618  elemsize = _elemsize;
619 
620  dims = 3;
621  w = _w;
622  h = _h;
623  c = _c;
624 
625  cstep = alignSize(w * h * elemsize, 16) / elemsize;
626 
627  if (total() > 0)
628  {
629  size_t totalsize = total() * elemsize;
630  data = fastMalloc(totalsize + (int)sizeof(*refcount));
631  refcount = (int*)(((unsigned char*)data) + totalsize);
632  *refcount = 1;
633  }
634 }
635 
636 inline void Mat::addref()
637 {
638  if (refcount)
639  DFACE_XADD(refcount, 1);
640 }
641 
642 inline void Mat::release()
643 {
644  if (refcount && DFACE_XADD(refcount, -1) == 1)
645  fastFree(data);
646 
647  data = 0;
648 
649  elemsize = 0;
650 
651  dims = 0;
652  w = 0;
653  h = 0;
654  c = 0;
655 
656  cstep = 0;
657 
658  refcount = 0;
659 }
660 
661 inline bool Mat::empty() const
662 {
663  return data == 0 || total() == 0;
664 }
665 
666 inline size_t Mat::total() const
667 {
668  return cstep * c;
669 }
670 
671 inline Mat Mat::channel(int c)
672 {
673  return Mat(w, h, (unsigned char*)data + cstep * c * elemsize, elemsize);
674 }
675 
676 inline const Mat Mat::channel(int c) const
677 {
678  return Mat(w, h, (unsigned char*)data + cstep * c * elemsize, elemsize);
679 }
680 
681 inline float* Mat::row(int y)
682 {
683  return (float*)data + w * y;
684 }
685 
686 inline const float* Mat::row(int y) const
687 {
688  return (const float*)data + w * y;
689 }
690 
691 template <typename T>
692 inline T* Mat::row(int y)
693 {
694  return (T*)data + w * y;
695 }
696 
697 template <typename T>
698 inline const T* Mat::row(int y) const
699 {
700  return (const T*)data + w * y;
701 }
702 
703 template <typename T>
704 inline Mat::operator T*()
705 {
706  return (T*)data;
707 }
708 
709 template <typename T>
710 inline Mat::operator const T*() const
711 {
712  return (const T*)data;
713 }
714 
715 inline float& Mat::operator[](int i)
716 {
717  return ((float*)data)[i];
718 }
719 
720 inline const float& Mat::operator[](int i) const
721 {
722  return ((const float*)data)[i];
723 }
724 
725 
726 
727 inline void Mat::substract_mean_normalize(const float* mean_vals, const float* norm_vals)
728 {
729  int size = w * h;
730 
731  if (mean_vals && !norm_vals)
732  {
733  // substract mean only
734 #pragma omp parallel for
735  for (int q=0; q<c; q++)
736  {
737  float* ptr = channel(q);//data + cstep * q;
738  const float mean = mean_vals[q];
739 
740 #if __ARM_NEON
741  int nn = size >> 2;
742  int remain = size - (nn << 2);
743 #else
744  int remain = size;
745 #endif // __ARM_NEON
746 
747 #if __ARM_NEON
748  #if __aarch64__
749  if (nn > 0)
750  {
751  asm volatile(
752  "dup v1.4s, %w4 \n"
753  "0: \n"
754  "prfm pldl1keep, [%1, #128] \n"
755  "ld1 {v0.4s}, [%1] \n"
756  "fsub v0.4s, v0.4s, v1.4s \n"
757  "subs %w0, %w0, #1 \n"
758  "st1 {v0.4s}, [%1], #16 \n"
759  "bne 0b \n"
760  : "=r"(nn), // %0
761  "=r"(ptr) // %1
762  : "0"(nn),
763  "1"(ptr),
764  "r"(mean) // %4
765  : "cc", "memory", "v0", "v1"
766  );
767  }
768 #else
769  if (nn > 0)
770  {
771  asm volatile(
772  "vdup.f32 q1, %4 \n"
773  "0: \n"
774  "pld [%1, #128] \n"
775  "vld1.f32 {d0-d1}, [%1 :128] \n"
776  "vsub.f32 q0, q0, q1 \n"
777  "subs %0, #1 \n"
778  "vst1.f32 {d0-d1}, [%1 :128]! \n"
779  "bne 0b \n"
780  : "=r"(nn), // %0
781  "=r"(ptr) // %1
782  : "0"(nn),
783  "1"(ptr),
784  "r"(mean) // %4
785  : "cc", "memory", "q0", "q1"
786  );
787  }
788 #endif // __aarch64__
789 #endif // __ARM_NEON
790  for (; remain>0; remain--)
791  {
792  *ptr -= mean;
793  ptr++;
794  }
795  }
796  }
797  else if (!mean_vals && norm_vals)
798  {
799  // normalize only
800 #pragma omp parallel for
801  for (int q=0; q<c; q++)
802  {
803  float* ptr = channel(q);//data + cstep * q;
804  const float norm = norm_vals[q];
805 
806 #if __ARM_NEON
807  int nn = size >> 2;
808  int remain = size - (nn << 2);
809 #else
810  int remain = size;
811 #endif // __ARM_NEON
812 
813 #if __ARM_NEON
814  #if __aarch64__
815  if (nn > 0)
816  {
817  asm volatile(
818  "dup v1.4s, %w4 \n"
819  "0: \n"
820  "prfm pldl1keep, [%1, #128] \n"
821  "ld1 {v0.4s}, [%1] \n"
822  "fmul v0.4s, v0.4s, v1.4s \n"
823  "subs %w0, %w0, #1 \n"
824  "st1 {v0.4s}, [%1], #16 \n"
825  "bne 0b \n"
826  : "=r"(nn), // %0
827  "=r"(ptr) // %1
828  : "0"(nn),
829  "1"(ptr),
830  "r"(norm) // %4
831  : "cc", "memory", "v0", "v1"
832  );
833  }
834 #else
835  if (nn > 0)
836  {
837  asm volatile(
838  "vdup.f32 q1, %4 \n"
839  "0: \n"
840  "pld [%1, #128] \n"
841  "vld1.f32 {d0-d1}, [%1 :128] \n"
842  "vmul.f32 q0, q0, q1 \n"
843  "subs %0, #1 \n"
844  "vst1.f32 {d0-d1}, [%1 :128]! \n"
845  "bne 0b \n"
846  : "=r"(nn), // %0
847  "=r"(ptr) // %1
848  : "0"(nn),
849  "1"(ptr),
850  "r"(norm) // %4
851  : "cc", "memory", "q0", "q1"
852  );
853  }
854 #endif // __aarch64__
855 #endif // __ARM_NEON
856  for (; remain>0; remain--)
857  {
858  *ptr *= norm;
859  ptr++;
860  }
861  }
862  }
863  else if (mean_vals && norm_vals)
864  {
865  // substract mean and normalize
866 #pragma omp parallel for
867  for (int q=0; q<c; q++)
868  {
869  float* ptr = channel(q);//data + cstep * q;
870  const float mean = mean_vals[q];
871  const float norm = norm_vals[q];
872 
873 #if __ARM_NEON
874  int nn = size >> 2;
875  int remain = size - (nn << 2);
876 #else
877  int remain = size;
878 #endif // __ARM_NEON
879 
880 #if __ARM_NEON
881  #if __aarch64__
882  if (nn > 0)
883  {
884  asm volatile(
885  "dup v1.4s, %w4 \n"
886  "dup v2.4s, %w5 \n"
887  "0: \n"
888  "prfm pldl1keep, [%1, #128] \n"
889  "ld1 {v0.4s}, [%1] \n"
890  "fsub v0.4s, v0.4s, v1.4s \n"
891  "fmul v0.4s, v0.4s, v2.4s \n"
892  "subs %w0, %w0, #1 \n"
893  "st1 {v0.4s}, [%1], #16 \n"
894  "bne 0b \n"
895  : "=r"(nn), // %0
896  "=r"(ptr) // %1
897  : "0"(nn),
898  "1"(ptr),
899  "r"(mean), // %4
900  "r"(norm) // %5
901  : "cc", "memory", "v0", "v1", "v2"
902  );
903  }
904 #else
905  if (nn > 0)
906  {
907  asm volatile(
908  "vdup.f32 q1, %4 \n"
909  "vdup.f32 q2, %5 \n"
910  "0: \n"
911  "pld [%1, #128] \n"
912  "vld1.f32 {d0-d1}, [%1 :128] \n"
913  "vsub.f32 q0, q0, q1 \n"
914  "vmul.f32 q0, q0, q2 \n"
915  "subs %0, #1 \n"
916  "vst1.f32 {d0-d1}, [%1 :128]! \n"
917  "bne 0b \n"
918  : "=r"(nn), // %0
919  "=r"(ptr) // %1
920  : "0"(nn),
921  "1"(ptr),
922  "r"(mean), // %4
923  "r"(norm) // %5
924  : "cc", "memory", "q0", "q1", "q2"
925  );
926  }
927 #endif // __aarch64__
928 #endif // __ARM_NEON
929  for (; remain>0; remain--)
930  {
931  *ptr = (*ptr - mean) * norm;
932  ptr++;
933  }
934  }
935  }
936 }
937 
938 // convert half precision floating point to float
939 static float half2float(unsigned short value)
940 {
941  // 1 : 5 : 10
942  unsigned short sign = (value & 0x8000) >> 15;
943  unsigned short exponent = (value & 0x7c00) >> 10;
944  unsigned short significand = value & 0x03FF;
945 
946 // fprintf(stderr, "%d %d %d\n", sign, exponent, significand);
947 
948  // 1 : 8 : 23
949  union
950  {
951  unsigned int u;
952  float f;
953  } tmp;
954  if (exponent == 0)
955  {
956  if (significand == 0)
957  {
958  // zero
959  tmp.u = (sign << 31);
960  }
961  else
962  {
963  // denormal
964  exponent = 0;
965  // find non-zero bit
966  while ((significand & 0x200) == 0)
967  {
968  significand <<= 1;
969  exponent++;
970  }
971  significand <<= 1;
972  significand &= 0x3FF;
973  tmp.u = (sign << 31) | ((-exponent + (-15 + 127)) << 23) | (significand << 13);
974  }
975  }
976  else if (exponent == 0x1F)
977  {
978  // infinity or NaN
979  tmp.u = (sign << 31) | (0xFF << 23) | (significand << 13);
980  }
981  else
982  {
983  // normalized
984  tmp.u = (sign << 31) | ((exponent + (-15 + 127)) << 23) | (significand << 13);
985  }
986 
987  return tmp.f;
988 }
989 
990 inline Mat Mat::from_float16(const unsigned short* data, int size)
991 {
992  Mat m(size);
993  if (m.empty())
994  return m;
995 
996  float* ptr = m;//.data;
997 
998 #if __ARM_NEON && (__ARM_FP & 2)
999  int nn = cpu_support_arm_vfpv4() ? size >> 2 : 0;
1000 int remain = size - (nn << 2);
1001 #else
1002  int remain = size;
1003 #endif // __ARM_NEON
1004 
1005 #if __ARM_NEON && (__ARM_FP & 2)
1006  #if __aarch64__
1007 if (nn > 0)
1008 {
1009 asm volatile(
1010  "0: \n"
1011  "ld1 {v0.4h}, [%1], #8 \n"
1012  "fcvtl v1.4s, v0.4h \n"
1013  "subs %w0, %w0, #1 \n"
1014  "st1 {v1.4s}, [%2], #16 \n"
1015  "bne 0b \n"
1016  : "=r"(nn), // %0
1017  "=r"(data), // %1
1018  "=r"(ptr) // %2
1019  : "0"(nn),
1020  "1"(data),
1021  "2"(ptr)
1022  : "cc", "memory", "v0", "v1"
1023 );
1024 }
1025 #else
1026 if (nn > 0)
1027 {
1028 asm volatile(
1029  "0: \n"
1030  "pld [%1, #64] \n"
1031  "vld1.s16 {d0}, [%1 :64]! \n"
1032  "vcvt.f32.f16 q1, d0 \n"
1033  "subs %0, #1 \n"
1034  "vst1.f32 {d2-d3}, [%2 :128]! \n"
1035  "bne 0b \n"
1036  : "=r"(nn), // %0
1037  "=r"(data), // %1
1038  "=r"(ptr) // %2
1039  : "0"(nn),
1040  "1"(data),
1041  "2"(ptr)
1042  : "cc", "memory", "q0", "q1"
1043 );
1044 }
1045 #endif // __aarch64__
1046 #endif // __ARM_NEON
1047  for (; remain>0; remain--)
1048  {
1049  *ptr = half2float(*data);
1050 
1051  data++;
1052  ptr++;
1053  }
1054 
1055  return m;
1056 }
1057 
1058 static void copy_make_border_image(const Mat& src, Mat& dst, int top, int left, int type, float v)
1059 {
1060  int w = dst.w;
1061  int h = dst.h;
1062 
1063  const float* ptr = src;//.data;
1064  float* outptr = dst;//.data;
1065 
1066  if (type == BORDER_CONSTANT)
1067  {
1068  int y = 0;
1069  // fill top
1070  for (; y < top; y++)
1071  {
1072  int x = 0;
1073  for (; x < w; x++)
1074  {
1075  outptr[x] = v;
1076  }
1077  outptr += w;
1078  }
1079  // fill center
1080  for (; y < (top + src.h); y++)
1081  {
1082  int x = 0;
1083  for (; x < left; x++)
1084  {
1085  outptr[x] = v;
1086  }
1087  if (src.w < 12)
1088  {
1089  for (; x < (left + src.w); x++)
1090  {
1091  outptr[x] = ptr[x - left];
1092  }
1093  }
1094  else
1095  {
1096  memcpy(outptr + left, ptr, src.w * sizeof(float));
1097  x += src.w;
1098  }
1099  for (; x < w; x++)
1100  {
1101  outptr[x] = v;
1102  }
1103  ptr += src.w;
1104  outptr += w;
1105  }
1106  // fill bottom
1107  for (; y < h; y++)
1108  {
1109  int x = 0;
1110  for (; x < w; x++)
1111  {
1112  outptr[x] = v;
1113  }
1114  outptr += w;
1115  }
1116  }
1117  else if (type == BORDER_REPLICATE)
1118  {
1119  int y = 0;
1120  // fill top
1121  for (; y < top; y++)
1122  {
1123  int x = 0;
1124  for (; x < left; x++)
1125  {
1126  outptr[x] = ptr[0];
1127  }
1128  if(src.w < 12)
1129  {
1130  for (; x < (left + src.w); x++)
1131  {
1132  outptr[x] = ptr[x - left];
1133  }
1134  }
1135  else
1136  {
1137  memcpy(outptr + left, ptr, src.w * sizeof(float));
1138  x += src.w;
1139  }
1140  for (; x < w; x++)
1141  {
1142  outptr[x] = ptr[src.w - 1];
1143  }
1144  outptr += w;
1145  }
1146  // fill center
1147  for (; y < (top + src.h); y++)
1148  {
1149  int x = 0;
1150  for (; x < left; x++)
1151  {
1152  outptr[x] = ptr[0];
1153  }
1154  if(src.w < 12)
1155  {
1156  for (; x < (left + src.w); x++)
1157  {
1158  outptr[x] = ptr[x - left];
1159  }
1160  }
1161  else
1162  {
1163  memcpy(outptr + left, ptr, src.w * sizeof(float));
1164  x += src.w;
1165  }
1166  for (; x < w; x++)
1167  {
1168  outptr[x] = ptr[src.w - 1];
1169  }
1170  ptr += src.w;
1171  outptr += w;
1172  }
1173  // fill bottom
1174  ptr -= src.w;
1175  for (; y < h; y++)
1176  {
1177  int x = 0;
1178  for (; x < left; x++)
1179  {
1180  outptr[x] = ptr[0];
1181  }
1182  if(src.w < 12)
1183  {
1184  for (; x < (left + src.w); x++)
1185  {
1186  outptr[x] = ptr[x - left];
1187  }
1188  }
1189  else
1190  {
1191  memcpy(outptr + left, ptr, src.w * sizeof(float));
1192  x += src.w;
1193  }
1194  for (; x < w; x++)
1195  {
1196  outptr[x] = ptr[src.w - 1];
1197  }
1198  outptr += w;
1199  }
1200  }
1201 }
1202 
1203 inline void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v)
1204 {
1205  int w = src.w + left + right;
1206  int h = src.h + top + bottom;
1207 
1208  if (w == src.w && h == src.h)
1209  {
1210  dst = src;
1211  return;
1212  }
1213 
1214  if (src.dims == 2)
1215  {
1216  dst.create(w, h);
1217  if (dst.empty())
1218  return;
1219 
1220  copy_make_border_image(src, dst, top, left, type, v);
1221  }
1222  else if (src.dims == 3)
1223  {
1224  int channels = src.c;
1225 
1226  dst.create(w, h, channels);
1227  if (dst.empty())
1228  return;
1229 
1230  // unroll image channel
1231 #pragma omp parallel for
1232  for (int q=0; q<channels; q++)
1233  {
1234  const Mat m = src.channel(q);
1235  Mat borderm = dst.channel(q);
1236 
1237  copy_make_border_image(m, borderm, top, left, type, v);
1238  }
1239  }
1240 }
1241 
1242 static void copy_cut_border_image(const Mat& src, Mat& dst, int top, int left)
1243 {
1244  int w = dst.w;
1245  int h = dst.h;
1246 
1247  const float* ptr = src.row(top) + left;//.data + src.w * top + left;
1248  float* outptr = dst;//.data;
1249 
1250  for (int y = 0; y < h; y++)
1251  {
1252  if(w < 12)
1253  {
1254  for (int x = 0; x < w; x++)
1255  {
1256  outptr[x] = ptr[x];
1257  }
1258  }
1259  else
1260  {
1261  memcpy(outptr, ptr, w*sizeof(float));
1262  }
1263  outptr += w;
1264  ptr += src.w;
1265  }
1266 }
1267 
1268 inline void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right)
1269 {
1270  int w = src.w - left - right;
1271  int h = src.h - top - bottom;
1272 
1273  if (w == src.w && h == src.h)
1274  {
1275  dst = src;
1276  return;
1277  }
1278 
1279  if (src.dims == 2)
1280  {
1281  dst.create(w, h);
1282  if (dst.empty())
1283  return;
1284 
1285  copy_cut_border_image(src, dst, top, left);
1286  }
1287  else if (src.dims == 3)
1288  {
1289  int channels = src.c;
1290 
1291  dst.create(w, h, channels);
1292  if (dst.empty())
1293  return;
1294 
1295  // unroll image channel
1296 #pragma omp parallel for
1297  for (int q=0; q<channels; q++)
1298  {
1299  const Mat m = src.channel(q);
1300  Mat cutm = dst.channel(q);
1301 
1302  copy_cut_border_image(m, cutm, top, left);
1303  }
1304  }
1305 }
1306 
1307 static void resize_bilinear_image(const Mat& src, Mat& dst, int w, int h)
1308 {
1309  double scale_x = (double)src.w / w;
1310  double scale_y = (double)src.h / h;
1311 
1312  int* buf = new int[w + h + w*2 + h*2];
1313 
1314  int* xofs = buf;//new int[w];
1315  int* yofs = buf + w;//new int[h];
1316 
1317  float* alpha = (float*)(buf + w + h);//new float[w * 2];
1318  float* beta = (float*)(buf + w + h + w*2);//new float[h * 2];
1319 
1320  float fx;
1321  float fy;
1322  int sx;
1323  int sy;
1324 
1325  for (int dx = 0; dx < w; dx++)
1326  {
1327  fx = (float)((dx + 0.5) * scale_x - 0.5);
1328  sx = fx;//cvFloor(fx);
1329  fx -= sx;
1330 
1331  if( sx >= src.w-1 )
1332  {
1333  sx = src.w - 2;
1334  fx = 1.f;
1335  }
1336 
1337  xofs[dx] = sx;
1338 
1339  alpha[dx*2 ] = 1.f - fx;
1340  alpha[dx*2 + 1] = fx;
1341  }
1342 
1343  for (int dy = 0; dy < h; dy++)
1344  {
1345  fy = (float)((dy + 0.5) * scale_y - 0.5);
1346  sy = fy;//cvFloor(fy);
1347  fy -= sy;
1348 
1349  if (sy >= src.h - 1)
1350  {
1351  sy = src.h - 2;
1352  fy = 1.f;
1353  }
1354 
1355  yofs[dy] = sy;
1356 
1357  beta[dy*2 ] = 1.f - fy;
1358  beta[dy*2 + 1] = fy;
1359  }
1360 
1361  // loop body
1362  Mat rowsbuf0(w + 1);
1363  Mat rowsbuf1(w + 1);
1364  float* rows0 = rowsbuf0;
1365  float* rows1 = rowsbuf1;
1366 
1367  int prev_sy1 = -1;
1368 
1369  for (int dy = 0; dy < h; dy++ )
1370  {
1371  int sy = yofs[dy];
1372 
1373  if (sy == prev_sy1)
1374  {
1375  // hresize one row
1376  float* rows0_old = rows0;
1377  rows0 = rows1;
1378  rows1 = rows0_old;
1379  const float* S1 = src.row(sy+1);
1380 
1381  const float* alphap = alpha;
1382  float* rows1p = rows1;
1383  int dx = 0;
1384 #if __ARM_NEON
1385  for ( ; dx+1 < w; dx += 2 )
1386  {
1387  int sx = xofs[dx];
1388  int sxn = xofs[dx+1];
1389  const float* S1p = S1 + sx;
1390  const float* S1np = S1 + sxn;
1391 
1392  float32x4_t _a = vld1q_f32(alphap);
1393  float32x2_t _S1 = vld1_f32(S1p);
1394  float32x2_t _S1n = vld1_f32(S1np);
1395 
1396  float32x4_t _S1S1n = vcombine_f32(_S1, _S1n);
1397  float32x4_t _ms1 = vmulq_f32(_S1S1n, _a);
1398  float32x2_t _rows1 = vpadd_f32(vget_low_f32(_ms1), vget_high_f32(_ms1));
1399 
1400  vst1_f32(rows1p + dx, _rows1);
1401 
1402  alphap += 4;
1403  }
1404 #endif // __ARM_NEON
1405  for ( ; dx < w; dx++ )
1406  {
1407  int sx = xofs[dx];
1408  const float* S1p = S1 + sx;
1409 
1410  float a0 = alphap[0];
1411  float a1 = alphap[1];
1412  rows1p[dx] = S1p[0]*a0 + S1p[1]*a1;
1413 
1414  alphap += 2;
1415  }
1416  }
1417  else
1418  {
1419  // hresize two rows
1420  const float* S0 = src.row(sy);
1421  const float* S1 = src.row(sy+1);
1422 
1423  const float* alphap = alpha;
1424  float* rows0p = rows0;
1425  float* rows1p = rows1;
1426  int dx = 0;
1427 #if __ARM_NEON
1428  for ( ; dx+1 < w; dx += 2 )
1429  {
1430  int sx = xofs[dx];
1431  int sxn = xofs[dx+1];
1432  const float* S0p = S0 + sx;
1433  const float* S1p = S1 + sx;
1434  const float* S0np = S0 + sxn;
1435  const float* S1np = S1 + sxn;
1436 
1437  float32x4_t _a = vld1q_f32(alphap);
1438  float32x2_t _S0 = vld1_f32(S0p);
1439  float32x2_t _S1 = vld1_f32(S1p);
1440  float32x2_t _S0n = vld1_f32(S0np);
1441  float32x2_t _S1n = vld1_f32(S1np);
1442 
1443  float32x4_t _S0S0n = vcombine_f32(_S0, _S0n);
1444  float32x4_t _S1S1n = vcombine_f32(_S1, _S1n);
1445  float32x4_t _ms0 = vmulq_f32(_S0S0n, _a);
1446  float32x4_t _ms1 = vmulq_f32(_S1S1n, _a);
1447  float32x2_t _rows0 = vpadd_f32(vget_low_f32(_ms0), vget_high_f32(_ms0));
1448  float32x2_t _rows1 = vpadd_f32(vget_low_f32(_ms1), vget_high_f32(_ms1));
1449 
1450  vst1_f32(rows0p + dx, _rows0);
1451  vst1_f32(rows1p + dx, _rows1);
1452 
1453  alphap += 4;
1454  }
1455 #endif // __ARM_NEON
1456  for ( ; dx < w; dx++ )
1457  {
1458  int sx = xofs[dx];
1459  const float* S0p = S0 + sx;
1460  const float* S1p = S1 + sx;
1461 
1462  float a0 = alphap[0];
1463  float a1 = alphap[1];
1464  rows0p[dx] = S0p[0]*a0 + S0p[1]*a1;
1465  rows1p[dx] = S1p[0]*a0 + S1p[1]*a1;
1466 
1467  alphap += 2;
1468  }
1469  }
1470 
1471  prev_sy1 = sy + 1;
1472 
1473  // vresize
1474  float b0 = beta[0];
1475  float b1 = beta[1];
1476 
1477  float* rows0p = rows0;
1478  float* rows1p = rows1;
1479  float* Dp = dst.row(dy);
1480 
1481 #if __ARM_NEON
1482  int nn = w >> 3;
1483 #else
1484  int nn = 0;
1485 #endif
1486  int remain = w - (nn << 3);
1487 
1488 #if __ARM_NEON
1489  float32x4_t _b0 = vdupq_n_f32(b0);
1490  float32x4_t _b1 = vdupq_n_f32(b1);
1491  for (; nn>0; nn--)
1492  {
1493  float32x4_t _rows0 = vld1q_f32(rows0p);
1494  float32x4_t _rows1 = vld1q_f32(rows1p);
1495 
1496  float32x4_t _D = vmulq_f32(_rows0, _b0);
1497  _D = vmlaq_f32(_D, _rows1, _b1);
1498 
1499  vst1q_f32(Dp, _D);
1500 
1501  float32x4_t _rows0n = vld1q_f32(rows0p+4);
1502  float32x4_t _rows1n = vld1q_f32(rows1p+4);
1503 
1504  float32x4_t _Dn = vmulq_f32(_rows0n, _b0);
1505  _Dn = vmlaq_f32(_Dn, _rows1n, _b1);
1506 
1507  vst1q_f32(Dp+4, _Dn);
1508 
1509  Dp += 8;
1510  rows0p += 8;
1511  rows1p += 8;
1512  }
1513 #endif // __ARM_NEON
1514  for ( ; remain; --remain )
1515  {
1516 // D[x] = rows0[x]*b0 + rows1[x]*b1;
1517  *Dp++ = *rows0p++ * b0 + *rows1p++ * b1;
1518  }
1519 
1520  beta += 2;
1521  }
1522 
1523  delete[] buf;
1524 }
1525 
1526 inline void resize_bilinear(const Mat& src, Mat& dst, int w, int h)
1527 {
1528  if (w == src.w && h == src.h)
1529  {
1530  dst = src;
1531  return;
1532  }
1533 
1534  if (src.dims == 2)
1535  {
1536  dst.create(w, h);
1537  if (dst.empty())
1538  return;
1539 
1540  resize_bilinear_image(src, dst, w, h);
1541  }
1542  else if (src.dims == 3)
1543  {
1544  int channels = src.c;
1545 
1546  dst.create(w, h, channels);
1547  if (dst.empty())
1548  return;
1549 
1550  // unroll image channel
1551 #pragma omp parallel for
1552  for (int q=0; q<channels; q++)
1553  {
1554  const Mat m = src.channel(q);
1555  Mat resizem = dst.channel(q);
1556 
1557  resize_bilinear_image(m, resizem, w, h);
1558  }
1559  }
1560 }
1561 
1562 
1563 
1564 
1565 
1566 
1567 
1568 } // namespace dface
1569 
1570 #endif // DFACE_MAT_H
Definition: common.h:37
Mat dface内置的图像数据 dface的所有接口只支持dface::Mat(RGB格式)
Definition: mat.h:23