VAT  3.0
Video Analysis Tool
DistanceUtils.h
1 #pragma once
2 
3 #include <opencv2/core/types_c.h>
4 #include <type_traits>
5 
7 template<typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type L1dist(T a, T b) {
8  return (size_t)abs((int)a-b);
9 }
10 
12 template<typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type L1dist(T a, T b) {
13  return fabs((float)a-(float)b);
14 }
15 
17 template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b) -> decltype(L1dist(*a,*b)) {
18  decltype(L1dist(*a,*b)) oResult = 0;
19  for(size_t c=0; c<nChannels; ++c)
20  oResult += L1dist(a[c],b[c]);
21  return oResult;
22 }
23 
25 template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L1dist<nChannels>(a,b)) {
26  decltype(L1dist<nChannels>(a,b)) oResult = 0;
27  size_t nTotElements = nElements*nChannels;
28  if(m) {
29  for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
30  if(m[i])
31  oResult += L1dist<nChannels>(a+n,b+n);
32  }
33  else {
34  for(size_t n=0; n<nTotElements; n+=nChannels)
35  oResult += L1dist<nChannels>(a+n,b+n);
36  }
37  return oResult;
38 }
39 
41 template<typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L1dist<3>(a,b,nElements,m)) {
42  CV_Assert(nChannels>0 && nChannels<=4);
43  switch(nChannels) {
44  case 1: return L1dist<1>(a,b,nElements,m);
45  case 2: return L1dist<2>(a,b,nElements,m);
46  case 3: return L1dist<3>(a,b,nElements,m);
47  case 4: return L1dist<4>(a,b,nElements,m);
48  default: return 0;
49  }
50 }
51 
53 template<size_t nChannels, typename T> static inline auto L1dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L1dist<nChannels,T>((T*)(0),(T*)(0))) {
54  T a_array[nChannels], b_array[nChannels];
55  for(size_t c=0; c<nChannels; ++c) {
56  a_array[c] = a[(int)c];
57  b_array[c] = b[(int)c];
58  }
59  return L1dist<nChannels>(a_array,b_array);
60 }
61 
63 
65 template<typename T> static inline auto L2sqrdist(T a, T b) -> decltype(L1dist(a,b)) {
66  auto oResult = L1dist(a,b);
67  return oResult*oResult;
68 }
69 
71 template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b) -> decltype(L2sqrdist(*a,*b)) {
72  decltype(L2sqrdist(*a,*b)) oResult = 0;
73  for(size_t c=0; c<nChannels; ++c)
74  oResult += L2sqrdist(a[c],b[c]);
75  return oResult;
76 }
77 
79 template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L2sqrdist<nChannels>(a,b)) {
80  decltype(L2sqrdist<nChannels>(a,b)) oResult = 0;
81  size_t nTotElements = nElements*nChannels;
82  if(m) {
83  for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
84  if(m[i])
85  oResult += L2sqrdist<nChannels>(a+n,b+n);
86  }
87  else {
88  for(size_t n=0; n<nTotElements; n+=nChannels)
89  oResult += L2sqrdist<nChannels>(a+n,b+n);
90  }
91  return oResult;
92 }
93 
95 template<typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L2sqrdist<3>(a,b,nElements,m)) {
96  CV_Assert(nChannels>0 && nChannels<=4);
97  switch(nChannels) {
98  case 1: return L2sqrdist<1>(a,b,nElements,m);
99  case 2: return L2sqrdist<2>(a,b,nElements,m);
100  case 3: return L2sqrdist<3>(a,b,nElements,m);
101  case 4: return L2sqrdist<4>(a,b,nElements,m);
102  default: return 0;
103  }
104 }
105 
107 template<size_t nChannels, typename T> static inline auto L2sqrdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L2sqrdist<nChannels,T>((T*)(0),(T*)(0))) {
108  T a_array[nChannels], b_array[nChannels];
109  for(size_t c=0; c<nChannels; ++c) {
110  a_array[c] = a[(int)c];
111  b_array[c] = b[(int)c];
112  }
113  return L2sqrdist<nChannels>(a_array,b_array);
114 }
115 
117 template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b) {
118  decltype(L2sqrdist(*a,*b)) oResult = 0;
119  for(size_t c=0; c<nChannels; ++c)
120  oResult += L2sqrdist(a[c],b[c]);
121  return sqrt((float)oResult);
122 }
123 
125 template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) {
126  decltype(L2sqrdist<nChannels>(a,b)) oResult = 0;
127  size_t nTotElements = nElements*nChannels;
128  if(m) {
129  for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
130  if(m[i])
131  oResult += L2sqrdist<nChannels>(a+n,b+n);
132  }
133  else {
134  for(size_t n=0; n<nTotElements; n+=nChannels)
135  oResult += L2sqrdist<nChannels>(a+n,b+n);
136  }
137  return sqrt((float)oResult);
138 }
139 
141 template<typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) {
142  CV_Assert(nChannels>0 && nChannels<=4);
143  switch(nChannels) {
144  case 1: return L2dist<1>(a,b,nElements,m);
145  case 2: return L2dist<2>(a,b,nElements,m);
146  case 3: return L2dist<3>(a,b,nElements,m);
147  case 4: return L2dist<4>(a,b,nElements,m);
148  default: return 0;
149  }
150 }
151 
153 template<size_t nChannels, typename T> static inline float L2dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) {
154  T a_array[nChannels], b_array[nChannels];
155  for(size_t c=0; c<nChannels; ++c) {
156  a_array[c] = a[(int)c];
157  b_array[c] = b[(int)c];
158  }
159  return L2dist<nChannels>(a_array,b_array);
160 }
161 
163 
165 template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cdist(const T* curr, const T* bg) {
166  static_assert(nChannels>1,"cdist: requires more than one channel");
167  bool bNonConstDist = false;
168  bool bNonNullDist = (curr[0]!=bg[0]);
169  bool bNonNullBG = (bg[0]>0);
170  for(size_t c=1; c<nChannels; ++c) {
171  bNonConstDist |= (curr[c]!=curr[c-1]) || (bg[c]!=bg[c-1]);
172  bNonNullDist |= (curr[c]!=bg[c]);
173  bNonNullBG |= (bg[c]>0);
174  }
175  if(!bNonConstDist || !bNonNullDist)
176  return 0;
177  if(!bNonNullBG) {
178  size_t nulldist = 0;
179  for(size_t c=0; c<nChannels; ++c)
180  nulldist += curr[c];
181  return nulldist;
182  }
183  size_t curr_sqr = 0;
184  size_t bg_sqr = 0;
185  size_t mix = 0;
186  for(size_t c=0; c<nChannels; ++c) {
187  curr_sqr += curr[c]*curr[c];
188  bg_sqr += bg[c]*bg[c];
189  mix += curr[c]*bg[c];
190  }
191  return (size_t)sqrt((float)(curr_sqr-(mix*mix)/bg_sqr));
192 }
193 
195 template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cdist(const T* curr, const T* bg) {
196  static_assert(nChannels>1,"cdist: requires more than one channel");
197  bool bNonConstDist = false;
198  bool bNonNullDist = (curr[0]!=bg[0]);
199  bool bNonNullBG = (bg[0]>0);
200  for(size_t c=1; c<nChannels; ++c) {
201  bNonConstDist |= (curr[c]!=curr[c-1]) || (bg[c]!=bg[c-1]);
202  bNonNullDist |= (curr[c]!=bg[c]);
203  bNonNullBG |= (bg[c]>0);
204  }
205  if(!bNonConstDist || !bNonNullDist)
206  return 0;
207  if(!bNonNullBG) {
208  float nulldist = 0;
209  for(size_t c=0; c<nChannels; ++c)
210  nulldist += curr[c];
211  return nulldist;
212  }
213  float curr_sqr = 0;
214  float bg_sqr = 0;
215  float mix = 0;
216  for(size_t c=0; c<nChannels; ++c) {
217  curr_sqr += (float)curr[c]*curr[c];
218  bg_sqr += (float)bg[c]*bg[c];
219  mix += (float)curr[c]*bg[c];
220  }
221  if(curr_sqr<(mix*mix)/bg_sqr)
222  return 0;
223  else
224  return (float)sqrt(curr_sqr-(mix*mix)/bg_sqr);
225 }
226 
228 template<size_t nChannels, typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(cdist<nChannels>(a,b)) {
229  decltype(cdist<nChannels>(a,b)) oResult = 0;
230  size_t nTotElements = nElements*nChannels;
231  if(m) {
232  for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i)
233  if(m[i])
234  oResult += cdist<nChannels>(a+n,b+n);
235  }
236  else {
237  for(size_t n=0; n<nTotElements; n+=nChannels)
238  oResult += cdist<nChannels>(a+n,b+n);
239  }
240  return oResult;
241 }
242 
244 template<typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(cdist<3>(a,b,nElements,m)) {
245  CV_Assert(nChannels>0 && nChannels<=4);
246  switch(nChannels) {
247  case 2: return cdist<2>(a,b,nElements,m);
248  case 3: return cdist<3>(a,b,nElements,m);
249  case 4: return cdist<4>(a,b,nElements,m);
250  default: return 0;
251  }
252 }
253 
255 template<size_t nChannels, typename T> static inline auto cdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(cdist<nChannels,T>((T*)(0),(T*)(0))) {
256  T a_array[nChannels], b_array[nChannels];
257  for(size_t c=0; c<nChannels; ++c) {
258  a_array[c] = a[(int)c];
259  b_array[c] = b[(int)c];
260  }
261  return cdist<nChannels>(a_array,b_array);
262 }
263 
265 template<typename T> static inline T cmixdist(T oL1Distance, T oCDistortion) {
266  return (oL1Distance/2+oCDistortion*4);
267 }
268 
270 template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cmixdist(const T* curr, const T* bg) {
271  return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg));
272 }
273 
274 template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cmixdist(const T* curr, const T* bg) {
275  return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg));
276 }
277 
279 
281 static const uchar popcount_LUT8[256] = {
282  0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
283  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
284  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
285  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
286  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
287  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
288  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
289  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
290  1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
291  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
292  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
293  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
294  2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
295  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
296  3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
297  4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
298 };
299 
301 template<typename T> static inline size_t popcount(T x) {
302  size_t nBytes = sizeof(T);
303  size_t nResult = 0;
304  for(size_t l=0; l<nBytes; ++l)
305  nResult += popcount_LUT8[(uchar)(x>>l*8)];
306  return nResult;
307 }
308 
310 template<typename T> static inline size_t hdist(T a, T b) {
311  return popcount(a^b);
312 }
313 
315 template<typename T> static inline size_t gdist(T a, T b) {
316  return L1dist(popcount(a),popcount(b));
317 }
318 
320 template<size_t nChannels, typename T> static inline size_t popcount(const T* x) {
321  size_t nBytes = sizeof(T);
322  size_t nResult = 0;
323  for(size_t c=0; c<nChannels; ++c)
324  for(size_t l=0; l<nBytes; ++l)
325  nResult += popcount_LUT8[(uchar)(*(x+c)>>l*8)];
326  return nResult;
327 }
328 
330 template<size_t nChannels, typename T> static inline size_t hdist(const T* a, const T* b) {
331  T xor_array[nChannels];
332  for(size_t c=0; c<nChannels; ++c)
333  xor_array[c] = a[c]^b[c];
334  return popcount<nChannels>(xor_array);
335 }
336 
338 template<size_t nChannels, typename T> static inline size_t gdist(const T* a, const T* b) {
339  return L1dist(popcount<nChannels>(a),popcount<nChannels>(b));
340 }