misc.h
14.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
// misc.h: miscellaneous definitions for Stasm
//
// Copyright (C) 2005-2013, Stephen Milborrow
#ifndef STASM_MISC_H
#define STASM_MISC_H
namespace stasm
{
using cv::Rect;
using std::vector;
using std::string;
typedef vector<int> vec_int;
typedef vector<double> vec_double;
typedef vector<cv::Rect> vec_Rect;
typedef unsigned char byte;
typedef cv::Mat_<double> MAT; // a matrix with double elements
typedef cv::Mat_<double> VEC; // by convention indicates one-dim matrix
typedef cv::Mat_<double> Shape; // by convention an N x 2 matrix holding a shape
typedef cv::Mat_<byte> Image; // a gray image (a matrix of bytes)
typedef cv::Vec3b RGBV; // a vec of three bytes: red(0), green, and blue(2)
typedef cv::Mat_<RGBV> CImage; // an RGB image (for apps and debugging, unneeded for ASM)
static const int IX = 0; // X,Y index in shape matrices. For clarity by
static const int IY = 1; // convention we use these rather than 0 and 1.
static const int SLEN = 260; // generic string length
// big enough for any Windows path (MAX_PATH is 260)
static const int SBIG = 10000; // long string length, enough for big printfs
#ifndef _MAX_PATH // definitions copied verbatim from Microsoft stdlib.h
#define _MAX_PATH 260 /* max. length of full pathname */
#define _MAX_DRIVE 3 /* max. length of drive component */
#define _MAX_DIR 256 /* max. length of path component */
#define _MAX_FNAME 256 /* max. length of file name component */
#define _MAX_EXT 256 /* max. length of extension component */
#endif
// Secure form of strcpy and friends (prevent buffer overrun).
// The CV_DbgAssert catches an easy programming error where
// we mistakenly take the size of a pointer.
#if _MSC_VER // microsoft compiler
#define STRCPY(dest, src) \
{ \
CV_DbgAssert(sizeof(dest) > 8); \
strcpy_s(dest, sizeof(dest), src); \
}
#define STRCAT(dest, src) \
{ \
CV_DbgAssert(sizeof(dest) > 8); \
strcat_s(dest, sizeof(dest), src); \
}
#define VSPRINTF(dest, format, args) \
{ \
CV_DbgAssert(sizeof(dest) > 8); \
vsnprintf_s(dest, sizeof(dest), _TRUNCATE, format, args); \
}
#else
#define STRCPY(dest, src) \
{ \
CV_DbgAssert(sizeof(dest) > 8); \
strncpy_(dest, src, sizeof(dest)); \
}
#define STRCAT(dest, src) \
{ \
CV_DbgAssert(sizeof(dest) > 8); \
strncat(dest, sizeof(dest), src); \
}
#define VSPRINTF(dest, format, args) \
{ \
CV_DbgAssert(sizeof(dest) > 8); \
vsnprintf(dest, sizeof(dest), format, args); \
}
#endif
// A macro to disallow the copy constructor and operator= functions.
// This is used in the private declarations for a class where those member
// functions have not been explicitly defined. This macro prevents use of
// the implicitly defined functions (the compiler will complain if you try
// to use them).
// This is often just paranoia. The implicit functions may actually be ok
// for the class in question, but shouldn't be used until that is checked.
// For details, See Item 6 Meyers Effective C++ and the Google C++ Style Guide.
#define DISALLOW_COPY_AND_ASSIGN(ClassName) \
ClassName(const ClassName&); \
void operator=(const ClassName&)
template <typename T> int NELEMS(const T& x) // number of elems in an array
{
return int(sizeof(x) / sizeof((x)[0]));
}
// The NSIZE and STRNLEN utility functions prevent the following
// warnings from certain compilers:
// o signed/unsigned mismatch
// o conversion from 'size_t' to 'int', possible loss of data
// Alternatives would be to use typecasts directly in the code
// or pedantically use size_t instead of int.
static inline int NSIZE(const MAT& m) // nrows * ncols
{
return int((m).total());
}
template <typename T> int NSIZE(const T& x) // size of any STL container
{
return int(x.size());
}
static inline int STRNLEN(const char* s, int n)
{
return int(strnlen(s, n));
}
template <typename T> T SQ(const T x) // define SQ(x)
{
return x * x;
}
template <typename T> T ABS(const T x) // define ABS(x)
{
// portable across compilers unlike "abs"
return x < 0? -x: x;
}
template <typename T> T Clamp(const T x, const T min, const T max)
{
return MIN(MAX(x, min), max);
}
// Equal() returns true if x == y within reasonable tolerance.
// The 1e-7 is arbitrary but approximately equals FLT_EPSILON.
// (If one or both of the numbers are NANs then the test fails, even if
// they are equal NANs. Which is not necessarily desireable behaviour.)
static inline bool Equal(const double x, const double y, const double max = 1e-7)
{
return ABS(x-y) < max;
}
static inline bool IsZero(const double x, const double max = 1e-7)
{
return Equal(x, 0, max);
}
static inline double RadsToDegrees(const double rads)
{
return 180 * rads / 3.14159265358979323846264338328;
}
static const int INVALID = 99999; // used to specify unavail eye locations, etc
template <typename T> bool Valid(const T x)
{
return x != INVALID && x != -INVALID;
}
// For reference, the fields of an OpenCV Mat are as follows.
// See \OpenCV\build\include\opencv2\core\core.hpp for details.
//
// int flags; // magic signature, continuity flag, depth, number of chans
// int dims; // matrix dimensionality, >= 2
// int rows, cols; // number of rows and columns or (-1, -1)
// uchar* data; // the data
// int* refcount; // pointer to ref counter, NULL if user-allocated
// uchar* datastart; // fields used in locateROI and adjustROI
// uchar* dataend;
// uchar* datalimit;
// MatAllocator* allocator; // custom allocator
// MSize size;
// MStep step;
static inline double* Buf(const MAT& mat) // access MAT data buffer
{
return (double*)(mat.data);
}
static inline VEC AsColVec(const MAT& mat) // view entire matrix as a col vector
{
CV_Assert(mat.isContinuous());
return MAT(mat.rows * mat.cols, 1, Buf(mat));
}
static inline VEC AsRowVec(const MAT& mat) // view entire matrix as a row vector
{
CV_Assert(mat.isContinuous());
return MAT(1, mat.rows * mat.cols, Buf(mat));
}
// Note on unused points:
//
// Unused points (a.k.a. missing points) points are indicated
// by setting both x and y equal to zero.
// Thus if there is a valid point that happens actually to
// be at 0,0 (rare) we must offset x slightly to ensure that the
// point is seen by Stasm as used. Hence XJITTER.
//
// XJITTER is one tenth of a pixel, which is big enough to be
// visible when saved in a shapefile with one decimal digit.
//
// Unused points are mostly useful during training (it is not unusual for a
// landmark to be obscured in a training face). They are also used during
// a search with pinned points (non-pinned points are marked as unused in
// the shape which specifies the pinned points).
static const double XJITTER = .1;
static inline bool PointUsed(const double x, const double y)
{
return !IsZero(x, XJITTER) || !IsZero(y, XJITTER);
}
static inline bool PointUsed(const Shape& shape, int ipoint)
{
return PointUsed(shape(ipoint, IX), shape(ipoint, IY));
}
static inline double PointDist(
double x1, // in
double y1, // in
double x2, // in
double y2) // in
{
CV_Assert(PointUsed(x1, y1));
CV_Assert(PointUsed(x2, y2));
return sqrt(SQ(x1 - x2) + SQ(y1 - y2));
}
static inline double PointDist(
const Shape& shape1, // in: the first shape
const Shape& shape2, // in: the second shape
int ipoint) // in: the point
{
return PointDist(shape1(ipoint, IX), shape1(ipoint, IY),
shape2(ipoint, IX), shape2(ipoint, IY));
}
static inline double PointDist(
const Shape& shape, // in
int ipoint1, // in: the first point
int ipoint2) // in: the second point
{
return PointDist(shape(ipoint1, IX), shape(ipoint1, IY),
shape(ipoint2, IX), shape(ipoint2, IY));
}
// note: in frontal-model-only Stasm, the only valid value for EYAW is EYAW00
enum EYAW
{
EYAW_45 = -3, // yaw -45 degrees (left facing strong three-quarter pose)
EYAW_22 = -2, // yaw -22 degrees (left facing mild three-quarter pose)
EYAW00 = 1, // yaw 0 degrees (frontal pose)
EYAW22 = 2, // yaw 22 degrees (right facing mild three-quarter pose)
EYAW45 = 3 // yaw 45 degrees (right facing strong three-quarter pose)
};
enum ESTART // do we use the detected eyes or mouth to help position the startshape?
// note: gaps in enum numbering are for compat with other Stasm versions
{
ESTART_RECT_ONLY = 1, // use just the face det rect to align the start shape
ESTART_EYES = 2, // use eyes if available (as well as face rect)
ESTART_EYE_AND_MOUTH = 4 // uses eye(s) and mouth if both available
};
#if MOD_3 || MOD_A || MOD_A_EMU // experimental versions
static double EYAW_TO_USE_DET22 = 14; // what estimated yaw requires the yaw22 mod
static double EYAW_TO_USE_DET45 = 35; // ditto for yaw45 model
#endif
struct DetPar // the structure describing a face detection
{
double x, y; // center of detector shape
double width, height; // width and height of detector shape
double lex, ley; // center of left eye, left and right are wrt the viewer
double rex, rey; // ditto for right eye
double mouthx, mouthy; // center of mouth
double rot; // in-plane rotation
double yaw; // yaw
EYAW eyaw; // yaw as an enum
DetPar() // constructor sets all fields to INVALID
: x(INVALID),
y(INVALID),
width(INVALID),
height(INVALID),
lex(INVALID),
ley(INVALID),
rex(INVALID),
rey(INVALID),
mouthx(INVALID),
mouthy(INVALID),
rot(INVALID),
yaw(INVALID),
eyaw(EYAW(INVALID))
{
};
};
//-----------------------------------------------------------------------------
const char* ssprintf(const char* format, ...);
void strncpy_(char* dest, const char* src, int n);
void ToLowerCase(char* s);
void ConvertBackslashesToForwardAndStripFinalSlash(char* s);
const char* Base(const char* path);
const char* BaseExt(const char* path);
void splitpath(
const char* path,
char* drive, char* dir, char* base, char* ext);
void makepath(
char* path,
const char* drive, const char* dir, const char* base, const char* ext);
void LogShape(const MAT& mat, const char* matname);
MAT DimKeep(const MAT& mat, int nrows, int ncols);
const MAT ArrayAsMat(int ncols, int nrows, const double* data);
void RoundMat(MAT& mat); // round mat entries to integers
Shape JitterPointsAt00(const Shape& shape);
double ForcePinnedPoints( // force pinned landmarks in shape to their pinned posn
Shape& shape, // io
const Shape pinnedshape); // in
void ShapeMinMax(
double& xmin, // out
double& xmax, // out
double& ymin, // out
double& ymax, // out
const Shape& shape); // in
double ShapeWidth(const Shape& shape); // width of shape in pixels
double ShapeHeight(const Shape& shape); // height of shape in pixels
void AlignShapeInPlace( // affine transform of shape
Shape& shape, // io
const MAT& alignment_mat); // in
void AlignShapeInPlace( // affine transform of shape
Shape& shape, // io
double x0, double y0, double z0, // in
double x1, double y1, double z1); // in
Shape AlignShape( // return transformed shape, affine transform
const Shape& shape, // in
const MAT& alignment_mat); // in
Shape AlignShape( // return transformed shape, affine transform
const Shape& shape, // in
double x0, double y0, double z0, // in
double x1, double y1, double z1); // in
const MAT AlignmentMat( // return similarity transf to align shape to anchorshape
const Shape& shape, // in
const Shape& anchorshape, // in
const double* weights=NULL); // in: if NULL (default) all points equal weight
void DrawShape( // draw a shape on an image
CImage& img, // io
const Shape& shape, // in
unsigned color=0xff0000, // in: rrggbb e.g. 0xff0000 is red
bool dots=false, // in: true for dots only
int linewidth=0); // in: default 0 means automatic
void ImgPrintf( // printf on image
CImage& img, // io
double ix, // in
double iy, // in
unsigned color, // in: rrggbb e.g. 0xff0000 is red
double size, // in: relative font size, 1 is standard size
const char* format, // in
...); // in
void DesaturateImg(
CImage& img); // io: convert to gray (but still an RGB image)
void ForceRectIntoImg( // force rectangle into image
int& ix, // io
int& iy, // io
int& ncols, // io
int& nrows, // io
const Image& img); // in
void ForceRectIntoImg( // force rectangle into image
Rect& rect, // io
const Image& img); // in
Image FlipImg(const Image& img); // in: flip image horizontally (mirror image)
void FlipImgInPlace(Image& img); // io: flip image horizontally (mirror image)
void OpenDetector( // open face or feature detector from its XML file
cv::CascadeClassifier& cascade, // out
const char* filename, // in: basename.ext of cascade
const char* datadir); // in
vec_Rect Detect( // detect faces or facial features
const Image& img, // in
cv::CascadeClassifier* cascade, // in
const Rect* searchrect, // in: search in this region, can be NULL
double scale_factor, // in
int min_neighbors, // in
int flags, // in
int minwidth_pixels); // in: reduces false positives
// TODO Following commented out to avoid circular dependency.
// int EyawAsModIndex(EYAW eyaw, const vec_Mod& mods);
bool IsLeftFacing(EYAW eyaw); // true if eyaw is for a left facing face
EYAW DegreesAsEyaw( // this determines what model is best for a given yaw
double yaw, // in: yaw in degrees, negative if left facing
int nmods); // in
const char* EyawAsString(EYAW eyaw);
DetPar FlipDetPar( // mirror image of detpar
const DetPar& detpar, // in
int imgwidth); // in
} // namespace stasm
#endif // STASM_MISC_H