12#include "bootPoints.hpp"
13#include "FgSerial.hpp"
20string const Fg3InitPoints::labels[] =
42 "EYE_LID_UPPER_RIGHT",
44 "EYE_LID_LOWER_RIGHT",
55Fg3InitPoints::Fg3InitPoints()
57 for (uint ii=0; ii<LM3_SIZE; ii++) {
59 m_pos[ii] = FutVect2IC(0);
71inline bool opX(
const FutVect2IC a,
const FutVect2IC b)
75inline bool opY(
const FutVect2IC a,
const FutVect2IC b)
80bool Fg3InitPoints::set(vector<FutVect2IC> pts)
82 static_assert(LM3_SIZE == 31,
"This algorithm is specific to the particular layout of bpts");
83 for (uint ii=0; ii<LM3_SIZE; ii++)
85 size_t num = pts.size();
95 return setV31Frontal(pts);
97 return setV31Profile(pts);
103 return setPsProfile(pts);
105 return setPsFrontal(pts);
113void Fg3InitPoints::getCropVals(
118 bool anyValid =
false;
119 lo.x1 = hi.x1 =
static_cast<float>(m_pos[LM3_NOSE_TIP].x1);
120 lo.x2 = hi.x2 =
static_cast<float>(m_pos[LM3_NOSE_TIP].x2);
121 for (uint ii=0; ii<LM3_SIZE; ii++)
127 lo.x1 = hi.x1 =
static_cast<float>(m_pos[ii].x1);
128 lo.x2 = hi.x2 =
static_cast<float>(m_pos[ii].x2);
133 if (
static_cast<float>(m_pos[ii].x1) < lo.x1)
134 lo.x1 =
static_cast<float>(m_pos[ii].x1);
135 if (
static_cast<float>(m_pos[ii].x1) > hi.x1)
136 hi.x1 =
static_cast<float>(m_pos[ii].x1);
137 if (
static_cast<float>(m_pos[ii].x2) < lo.x2)
138 lo.x2 =
static_cast<float>(m_pos[ii].x2);
139 if (
static_cast<float>(m_pos[ii].x2) > hi.x2)
140 hi.x2 =
static_cast<float>(m_pos[ii].x2);
148 FutVect2FC centre = (lo + hi) / 2.0f;
149 float size = hi.x2 - lo.x2;
151 if (m_angle == VA3_VFRONTAL)
153 lo.x1 = centre.x1 - size * 0.8f;
154 hi.x1 = centre.x1 + size * 0.8f;
155 lo.x2 = centre.x2 - size * 0.95f;
156 hi.x2 = centre.x2 + size * 0.65f;
158 else if (m_angle == VA3_FRONTAL)
160 lo.x1 = centre.x1 - size * 0.8f;
161 hi.x1 = centre.x1 + size * 0.8f;
162 lo.x2 = centre.x2 - size * 0.9f;
163 hi.x2 = centre.x2 + size * 0.7f;
165 else if (m_angle == VA3_UPWARD)
167 lo.x1 = centre.x1 - size * 1.15f;
168 hi.x1 = centre.x1 + size * 1.15f;
169 lo.x2 = centre.x2 - size * 1.1f;
170 hi.x2 = centre.x2 + size * 1.2f;
172 else if (m_angle == VA3_THIRTY_RIGHT)
174 lo.x1 = centre.x1 - size * 1.0f;
175 hi.x1 = centre.x1 + size * 0.8f;
176 lo.x2 = centre.x2 - size * 1.0f;
177 hi.x2 = centre.x2 + size * 0.8f;
179 else if (m_angle == VA3_THIRTY_LEFT)
181 lo.x1 = centre.x1 - size * 0.8f;
182 hi.x1 = centre.x1 + size * 1.0f;
183 lo.x2 = centre.x2 - size * 1.0f;
184 hi.x2 = centre.x2 + size * 0.8f;
186 else if (m_angle == VA3_VPROFILE_RIGHT)
188 lo.x1 = centre.x1 - size * 0.83f;
189 hi.x1 = centre.x1 + size * 0.53f;
190 lo.x2 = centre.x2 - size * 0.76f;
191 hi.x2 = centre.x2 + size * 0.60f;
193 else if (m_angle == VA3_VPROFILE_LEFT)
195 lo.x1 = centre.x1 - size * 0.53f;
196 hi.x1 = centre.x1 + size * 0.83f;
197 lo.x2 = centre.x2 - size * 0.76f;
198 hi.x2 = centre.x2 + size * 0.60f;
200 else if (m_angle == VA3_PROFILE_RIGHT)
202 lo.x1 = centre.x1 - size * 0.8f;
203 hi.x1 = centre.x1 + size * 0.7f;
204 lo.x2 = centre.x2 - size * 0.8f;
205 hi.x2 = centre.x2 + size * 0.7f;
207 else if (m_angle == VA3_PROFILE_LEFT)
209 lo.x1 = centre.x1 - size * 0.7f;
210 hi.x1 = centre.x1 + size * 0.8f;
211 lo.x2 = centre.x2 - size * 0.8f;
212 hi.x2 = centre.x2 + size * 0.7f;
214 else if (m_angle == VA3_PS_FRONTAL)
217 lo.x1 = centre.x1 - size * 1.4f;
218 hi.x1 = centre.x1 + size * 1.4f;
219 lo.x2 = centre.x2 - size * 1.25f;
220 hi.x2 = centre.x2 + size * 1.55f;
222 else if (m_angle == VA3_PS_PROFILE_LEFT)
225 lo.x1 = centre.x1 - size * 0.7f;
226 hi.x1 = centre.x1 + size * 0.8f;
227 lo.x2 = centre.x2 - size * 0.8f;
228 hi.x2 = centre.x2 + size * 0.7f;
230 else if (m_angle == VA3_PS_PROFILE_RIGHT)
233 lo.x1 = centre.x1 - size * 0.8f;
234 hi.x1 = centre.x1 + size * 0.7f;
235 lo.x2 = centre.x2 - size * 0.8f;
236 hi.x2 = centre.x2 + size * 0.7f;
249float Fg3InitPoints::getPan()
const
251 if (m_angle == VA3_VPROFILE_LEFT)
252 return fr2DegsToRads(60.0f);
253 else if (m_angle == VA3_VPROFILE_RIGHT)
254 return fr2DegsToRads(-60.0f);
255 else if (m_angle == VA3_PROFILE_LEFT)
256 return fr2DegsToRads(90.0f);
257 else if (m_angle == VA3_PROFILE_RIGHT)
258 return fr2DegsToRads(-90.0f);
259 else if (m_angle == VA3_PS_PROFILE_LEFT)
260 return fr2DegsToRads(90.0f);
261 else if (m_angle == VA3_PS_PROFILE_RIGHT)
262 return fr2DegsToRads(-90.0f);
266std::string Fg3InitPoints::getLabel(LandmrkV3 type)
268 FGASSERT(type < LM3_SIZE);
274bool Fg3InitPoints::setVFrontal(vector<FutVect2IC> & pts)
276 FGASSERT(pts.size() == 14);
277 m_angle = VA3_VFRONTAL;
279 for (uint ii=0; ii<LM3_SIZE; ii++)
282 sort(pts.begin(),pts.end(),opY);
283 m_pos[LM3_CHIN] = pts[pts.size()-2];
284 m_pos[LM3_THROAT_TOP] = pts[pts.size()-1];
285 m_valid[LM3_CHIN] =
true;
286 m_valid[LM3_THROAT_TOP] =
true;
288 vector<FutVect2IC> vtmp = futSubVec(pts,0,3);
289 sort(vtmp.begin(),vtmp.end(),opX);
290 m_pos[LM3_EYE_RIGHT_OUTER] = vtmp[0];
291 m_pos[LM3_EYE_RIGHT_INNER] = vtmp[1];
292 m_pos[LM3_EYE_LEFT_INNER] = vtmp[2];
293 m_pos[LM3_EYE_LEFT_OUTER] = vtmp[3];
294 m_valid[LM3_EYE_RIGHT_OUTER] =
true;
295 m_valid[LM3_EYE_RIGHT_INNER] =
true;
296 m_valid[LM3_EYE_LEFT_INNER] =
true;
297 m_valid[LM3_EYE_LEFT_OUTER] =
true;
299 pts = futSubVec(pts,4,pts.size()-3);
301 sort(pts.begin(),pts.end(),opX);
302 m_pos[LM3_CHEEKBONE_RIGHT] = pts[0];
303 m_pos[LM3_CHEEKBONE_LEFT] = pts[pts.size()-1];
304 m_valid[LM3_CHEEKBONE_RIGHT] =
true;
305 m_valid[LM3_CHEEKBONE_LEFT] =
true;
307 pts = futSubVec(pts,1,
static_cast<uint
>(pts.size()-2));
309 sort(pts.begin(),pts.end(),opY);
310 vtmp = futSubVec(pts,pts.size()-2,pts.size()-1);
311 sort(vtmp.begin(),vtmp.end(),opX);
312 m_pos[LM3_MOUTH_RIGHT] = vtmp[0];
313 m_pos[LM3_MOUTH_LEFT] = vtmp[1];
314 m_valid[LM3_MOUTH_RIGHT] =
true;
315 m_valid[LM3_MOUTH_LEFT] =
true;
317 pts = futSubVec(pts,0,pts.size()-3);
319 sort(pts.begin(),pts.end(),opX);
320 m_pos[LM3_NARE_RIGHT] = pts[0];
321 m_pos[LM3_NARE_LEFT] = pts[3];
322 m_valid[LM3_NARE_RIGHT] =
true;
323 m_valid[LM3_NARE_LEFT] =
true;
325 pts = futSubVec(pts,1,2);
327 FGASSERT(pts.size() == 2);
329 sort(pts.begin(),pts.end(),opY);
330 m_pos[LM3_NOSE_TIP] = pts[0];
331 m_pos[LM3_NOSE_BASE] = pts[1];
332 m_valid[LM3_NOSE_TIP] =
true;
333 m_valid[LM3_NOSE_BASE] =
true;
340bool Fg3InitPoints::setVProfile(std::vector<FutVect2IC> & pts)
342 FGASSERT(pts.size() == 9);
343 for (uint ii=0; ii<LM3_SIZE; ii++)
345 sort(pts.begin(),pts.end(),opY);
346 m_pos[LM3_CHIN] = pts[7];
347 m_pos[LM3_THROAT_TOP] = pts[8];
348 m_valid[LM3_CHIN] =
true;
349 m_valid[LM3_THROAT_TOP] =
true;
350 vector<FutVect2IC> vtmp;
351 vtmp = futSubVec(pts,3,5);
352 sort(vtmp.begin(),vtmp.end(),opX);
353 m_pos[LM3_NOSE_BASE] = vtmp[1];
354 m_valid[LM3_NOSE_BASE] =
true;
355 vector<FutVect2IC> vtmp2;
356 vtmp2 = futSubVec(pts,1,2);
357 sort(vtmp2.begin(),vtmp2.end(),opX);
358 FutVect2IC eye = (pts[1] + pts[2]) / 2;
362 if (vtmp[1].x1 < eye.x1) {
363 m_angle = VA3_VPROFILE_LEFT;
364 m_pos[LM3_BROW_RIGHT] = pts[0];
365 m_pos[LM3_NOSE_TIP] = vtmp[0];
366 m_pos[LM3_NARE_LEFT] = vtmp[2];
367 m_pos[LM3_EYE_LEFT_INNER] = vtmp2[0];
368 m_pos[LM3_EYE_LEFT_OUTER] = vtmp2[1];
369 m_pos[LM3_MOUTH_LEFT] = pts[6];
370 m_valid[LM3_BROW_RIGHT] =
true;
371 m_valid[LM3_NOSE_TIP] =
true;
372 m_valid[LM3_NARE_LEFT] =
true;
373 m_valid[LM3_EYE_LEFT_INNER] =
true;
374 m_valid[LM3_EYE_LEFT_OUTER] =
true;
375 m_valid[LM3_MOUTH_LEFT] =
true;
378 m_angle = VA3_VPROFILE_RIGHT;
379 m_pos[LM3_BROW_LEFT] = pts[0];
380 m_pos[LM3_NOSE_TIP] = vtmp[2];
381 m_pos[LM3_NARE_RIGHT] = vtmp[0];
382 m_pos[LM3_EYE_RIGHT_INNER] = vtmp2[1];
383 m_pos[LM3_EYE_RIGHT_OUTER] = vtmp2[0];
384 m_pos[LM3_MOUTH_RIGHT] = pts[6];
385 m_valid[LM3_BROW_LEFT] =
true;
386 m_valid[LM3_NOSE_TIP] =
true;
387 m_valid[LM3_NARE_RIGHT] =
true;
388 m_valid[LM3_EYE_RIGHT_OUTER] =
true;
389 m_valid[LM3_EYE_RIGHT_INNER] =
true;
390 m_valid[LM3_MOUTH_RIGHT] =
true;
396bool Fg3InitPoints::setPsFrontal(vector<FutVect2IC> &pts)
398 FGASSERT(pts.size() == 5);
399 for (
size_t ii=0; ii<LM3_SIZE; ++ii) {
400 m_pos[ii] = FutVect2IC(0);
403 sort(pts.begin(),pts.end(),opY);
405 if (pts[0].x1 > pts[1].x1)
407 if (pts[3].x1 > pts[4].x1)
409 m_pos[LM3_EYE_RIGHT_CENTRE] = pts[0];
410 m_pos[LM3_EYE_LEFT_CENTRE] = pts[1];
411 m_pos[LM3_NOSE_TIP] = pts[2];
412 m_pos[LM3_MOUTH_RIGHT] = pts[3];
413 m_pos[LM3_MOUTH_LEFT] = pts[4];
414 m_valid[LM3_EYE_RIGHT_CENTRE] =
true;
415 m_valid[LM3_EYE_LEFT_CENTRE] =
true;
416 m_valid[LM3_NOSE_TIP] =
true;
417 m_valid[LM3_MOUTH_RIGHT] =
true;
418 m_valid[LM3_MOUTH_LEFT] =
true;
419 m_angle = VA3_PS_FRONTAL;
425bool Fg3InitPoints::setPsProfile(vector<FutVect2IC> & pts)
427 FGASSERT(pts.size() == 6);
428 for (uint ii=0; ii<LM3_SIZE; ii++)
430 sort(pts.begin(),pts.end(),opY);
431 m_pos[LM3_NOSE_TIP] = pts[2];
432 m_valid[LM3_NOSE_TIP] =
true;
433 if (pts[2].x1 < pts[3].x1) {
434 m_angle = VA3_PS_PROFILE_LEFT;
435 m_pos[LM3_MOUTH_LEFT] = pts[3];
436 m_valid[LM3_MOUTH_LEFT] =
true;
439 m_angle = VA3_PS_PROFILE_RIGHT;
440 m_pos[LM3_MOUTH_RIGHT] = pts[3];
441 m_valid[LM3_MOUTH_RIGHT] =
true;
443 vector<FutVect2IC> vtmp = futSubVec(pts,0,1);
444 sort(vtmp.begin(),vtmp.end(),opX);
445 if (m_angle == VA3_PS_PROFILE_LEFT) {
446 m_pos[LM3_BROW_CENTRE] = vtmp[0];
447 m_valid[LM3_BROW_CENTRE] =
true;
448 m_pos[LM3_EYE_LEFT_OUTER] = vtmp[1];
449 m_valid[LM3_EYE_LEFT_OUTER] =
true;
452 m_pos[LM3_BROW_CENTRE] = vtmp[1];
453 m_valid[LM3_BROW_CENTRE] =
true;
454 m_pos[LM3_EYE_RIGHT_OUTER] = vtmp[0];
455 m_valid[LM3_EYE_RIGHT_OUTER] =
true;
457 vtmp = futSubVec(pts,4,5);
458 sort(vtmp.begin(),vtmp.end(),opX);
459 if (m_angle == VA3_PS_PROFILE_LEFT) {
460 m_pos[LM3_CHIN] = vtmp[0];
461 m_valid[LM3_CHIN] =
true;
462 m_pos[LM3_THROAT_TOP] = vtmp[1];
463 m_valid[LM3_THROAT_TOP] =
true;
466 m_pos[LM3_CHIN] = vtmp[1];
467 m_valid[LM3_CHIN] =
true;
468 m_pos[LM3_THROAT_TOP] = vtmp[0];
469 m_valid[LM3_THROAT_TOP] =
true;
475bool Fg3InitPoints::setV31Frontal( vector<FutVect2IC> & pts)
477 FGASSERT(pts.size() == 11);
478 m_angle = VA3_FRONTAL;
479 for (uint ii=0; ii<LM3_SIZE; ii++)
481 sort(pts.begin(),pts.end(),opY);
482 m_pos[LM3_CHIN_LOWER] = pts[10];
483 m_valid[LM3_CHIN_LOWER]=
true;
484 vector<FutVect2IC> vtmp = futSubVec(pts,6,9);
485 sort(vtmp.begin(),vtmp.end(),opX);
486 m_pos[LM3_JAW_OUTER_RIGHT] = vtmp[0];
487 m_pos[LM3_MOUTH_RIGHT] = vtmp[1];
488 m_pos[LM3_MOUTH_LEFT] = vtmp[2];
489 m_pos[LM3_JAW_OUTER_LEFT] = vtmp[3];
490 m_valid[LM3_JAW_OUTER_RIGHT] =
true;
491 m_valid[LM3_MOUTH_RIGHT] =
true;
492 m_valid[LM3_MOUTH_LEFT] =
true;
493 m_valid[LM3_JAW_OUTER_LEFT] =
true;
494 pts = futSubVec(pts,0,5);
495 sort(pts.begin(),pts.end(),opX);
496 m_pos[LM3_CHEEKBONE_RIGHT] = pts[0];
497 m_pos[LM3_CHEEKBONE_LEFT] = pts[5];
498 m_valid[LM3_CHEEKBONE_RIGHT] =
true;
499 m_valid[LM3_CHEEKBONE_LEFT] =
true;
500 pts = futSubVec(pts,1,4);
501 sort(pts.begin(),pts.end(),opY);
502 vtmp = futSubVec(pts,2,3);
503 sort(vtmp.begin(),vtmp.end(),opX);
504 m_pos[LM3_NARE_RIGHT] = vtmp[0];
505 m_pos[LM3_NARE_LEFT] = vtmp[1];
506 m_valid[LM3_NARE_RIGHT] =
true;
507 m_valid[LM3_NARE_LEFT] =
true;
508 pts = futSubVec(pts,0,1);
509 sort(pts.begin(),pts.end(),opX);
510 m_pos[LM3_EYE_RIGHT_CENTRE] = pts[0];
511 m_pos[LM3_EYE_LEFT_CENTRE] = pts[1];
512 m_valid[LM3_EYE_RIGHT_CENTRE] =
true;
513 m_valid[LM3_EYE_LEFT_CENTRE] =
true;
518bool Fg3InitPoints::setV31Profile(
const std::vector<FutVect2IC> & ptsIn)
520 vector<FutVect2IC> pts = ptsIn;
521 FGASSERT(pts.size() == 9);
522 for (uint ii=0; ii<LM3_SIZE; ii++)
524 vector<FutVect2IC> vtmp,vtmp2;
526 sort(pts.begin(),pts.end(),opY);
528 vtmp = futSubVec(pts,0,2);
529 sort(vtmp.begin(),vtmp.end(),opX);
530 vtmp2 = futSubVec(pts,3,4);
531 sort(vtmp2.begin(),vtmp2.end(),opX);
532 if (vtmp[2].x1 > vtmp2[1].x1)
537 m_angle = VA3_PROFILE_RIGHT;
538 m_pos[LM3_EYE_RIGHT_OUTER] = vtmp[0];
539 m_valid[LM3_EYE_RIGHT_OUTER] =
true;
540 vtmp = futSubVec(vtmp,1,2);
543 m_angle = VA3_PROFILE_LEFT;
544 m_pos[LM3_EYE_LEFT_OUTER] = vtmp[2];
545 m_valid[LM3_EYE_LEFT_OUTER] =
true;
546 vtmp = futSubVec(vtmp,0,1);
548 sort(vtmp.begin(),vtmp.end(),opY);
549 m_pos[LM3_SELLION] = vtmp[0];
550 m_pos[LM3_NOSE_BRIDGE] = vtmp[1];
551 m_valid[LM3_SELLION] =
true;
552 m_valid[LM3_NOSE_BRIDGE] =
true;
553 vtmp = futSubVec(pts,3,4);
554 sort(vtmp.begin(),vtmp.end(),opX);
556 m_pos[LM3_NOSE_TIP] = vtmp[1];
557 m_pos[LM3_NOSE_BASE] = vtmp[0];
560 m_pos[LM3_NOSE_TIP] = vtmp[0];
561 m_pos[LM3_NOSE_BASE] = vtmp[1];
563 m_valid[LM3_NOSE_TIP] =
true;
564 m_valid[LM3_NOSE_BASE] =
true;
565 vtmp = futSubVec(pts,7,8);
566 sort(vtmp.begin(),vtmp.end(),opX);
568 m_pos[LM3_THROAT_TOP] = vtmp[0];
569 m_pos[LM3_CHIN] = vtmp[1];
572 m_pos[LM3_THROAT_TOP] = vtmp[1];
573 m_pos[LM3_CHIN] = vtmp[0];
575 m_valid[LM3_THROAT_TOP] =
true;
576 m_valid[LM3_CHIN] =
true;
577 m_pos[LM3_LIP_TIP_UPPER] = pts[5];
578 m_pos[LM3_LIP_TIP_LOWER] = pts[6];
579 m_valid[LM3_LIP_TIP_UPPER] =
true;
580 m_valid[LM3_LIP_TIP_LOWER] =
true;
584bool Fg3InitPoints::empty()
const
586 for (uint ii=0; ii<LM3_SIZE; ++ii)
592NameVec2Fs Fg3InitPoints::asNameVecs()
const
595 for (
size_t ii=0; ii<LM3_SIZE; ++ii) {
597 FutVect2IC v = m_pos[ii];
599 ret.emplace_back(labels[ii],mapCast<float>(p));