11#include "Fg3PhotofitUtil.hpp"
13#include "FgFileSystem.hpp"
14#include "FgGuiApi.hpp"
20#define FMOSYNTH_TOP_SL_SIZE 512
22Fg3InitPoints getSetLandmarks(String8
const & photoFile,ImgRgba8
const & photo)
24 String8 lmsFile = pathToDirBase(photoFile)+
".lms.txt";
25 Svec<FutVect2IC> lmPoss;
26 if (fileExists(lmsFile)) {
27 FaceLmPos2Fs flmPoss = toFaceLmPoss(loadLandmarks(lmsFile));
28 FaceLms flms = mapMember(flmPoss,&FaceLmPos2F::lm);
29 for (FaceView fv : getAllE<FaceView>()) {
30 FaceLms viewLms = mapMember(getV3LmAtts(fv),&FaceLmAtt::type);
31 if (containsAll(flms,viewLms)) {
32 for (FaceLm lm : viewLms) {
33 FaceLmPos2F lmPos = findFirst(flmPoss,lm);
34 lmPoss.emplace_back(lmPos.pos[0],lmPos.pos[1]);
40 Fg3InitPoints landmarks;
41 landmarks.set(lmPoss);
42 if (landmarks.empty()) {
44 "Select the bootstrap points by left-clicking on the displayed photograph window.\n"
45 "Follow the guidlines shown in the Modeller or in the SDK documentation.\n"
46 "When finished, close the photograph window. If the window re-opens with the same\n"
47 "photograph, you have not selected the correct number of points.\n"
48 "Right-click and drag up/down to scale the image.\n";
51 String8 store = getDirUserAppDataLocal({
"FaceGen",
"fg3pf"});
52 IPT<ImgRgba8> imgN = makeIPT(photo);
53 IPT<NameVec2Fs> ptsIucsN = makeIPT(NameVec2Fs{});
54 auto leftClickFn = [ptsIucsN](Vec2F iucs,Vec2UI){ptsIucsN.ref().emplace_back(
"",iucs); };
55 GuiPtr guiImg = guiImageCtrls(imgN,ptsIucsN,
false,leftClickFn).win;
57 guiStartImpl(makeIPT<String8>(
"fg3pf"),guiImg,store);
59 catch (FgExceptionNotImplemented & e) {
60 e.contexts.emplace_back(
"No GUI, use a .lms.txt file to specify the landmark points.");
63 AxAffine2F iucsToPacs = cIucsToPacs<float>(photo.dims());
64 vector<FutVect2IC> ptsIrcs;
65 for (NameVec2F iucs : ptsIucsN.val()) {
66 Vec2F pacs = iucsToPacs * iucs.vec;
68 p.x1 = std::floor(pacs[0]);
69 p.x2 = std::floor(pacs[1]);
73 fgThrow(
"User abort");
74 done = landmarks.set(ptsIrcs);
76 saveLandmarks(landmarks.asNameVecs(),lmsFile);
80 landmarks.getCropVals(lo,hi);
81 if ((hi.x2 - lo.x2) < (
float)FMOSYNTH_TOP_SL_SIZE / 8.0f)
82 fgout << fgnl <<
"Warning: " << photoFile <<
" is too small for fitting";
83 else if ((hi.x2 - lo.x2) < (
float)FMOSYNTH_TOP_SL_SIZE / 2.0f)
84 fgout << fgnl <<
"Warning: " << photoFile <<
" is too small for optimal fitting.";
85 if ((hi.x2 - lo.x2) < (
float)FMOSYNTH_TOP_SL_SIZE)
86 fgout << fgnl <<
"Warning: " << photoFile <<
" is too small for optimal detail extraction.";
93 for (
int jj=0; jj<LM3_SIZE; jj++) {
94 if (src.m_valid[jj]) {
95 dst.
pointX[numPts] = uint(src.m_pos[jj].x1 + 0.5f);
96 dst.
pointY[numPts] = uint(src.m_pos[jj].x2 + 0.5f);
103FgppUserDataS cFgppUserData(ImgRgba8
const & photo,Fg3InitPoints
const & landmarks)
106 data.
width = photo.width();
107 data.
height = photo.height();
110 copyPoints(landmarks,data);
114FaceLmAtts
const & getV3LmAtts(FaceView view)
116 static Arr<FaceLmAtts,3> ret {
118 {FaceLm::pupilCentreL,
"EYE_LEFT_CENTRE"},
119 {FaceLm::pupilCentreR,
"EYE_RIGHT_CENTRE"},
120 {FaceLm::cheekboneL,
"CHEEKBONE_LEFT"},
121 {FaceLm::cheekboneR,
"CHEEKBONE_RIGHT"},
122 {FaceLm::alarOuterL,
"NARE_LEFT"},
123 {FaceLm::alarOuterR,
"NARE_RIGHT"},
124 {FaceLm::mouthCornerL,
"MOUTH_LEFT"},
125 {FaceLm::mouthCornerR,
"MOUTH_RIGHT"},
126 {FaceLm::jawOuterL,
"JAW_OUTER_LEFT"},
127 {FaceLm::jawOuterR,
"JAW_OUTER_RIGHT"},
128 {FaceLm::chinBottom,
"CHIN_LOWER"},
131 {FaceLm::exocanthionL,
"EYE_LEFT_OUTER"},
132 {FaceLm::sellion,
"SELLION"},
133 {FaceLm::noseBridgeMiddle,
"NOSE_BRIDGE"},
134 {FaceLm::noseTip,
"NOSE_TIP"},
135 {FaceLm::subNasale,
"NOSE_BASE"},
136 {FaceLm::lipUpperFront,
"LIP_TIP_UPPER"},
137 {FaceLm::lipLowerFront,
"LIP_TIP_LOWER"},
138 {FaceLm::chinFront,
"CHIN"},
139 {FaceLm::jawBottom,
"THROAT_TOP"},
142 {FaceLm::exocanthionR,
"EYE_RIGHT_OUTER"},
143 {FaceLm::sellion,
"SELLION"},
144 {FaceLm::noseBridgeMiddle,
"NOSE_BRIDGE"},
145 {FaceLm::noseTip,
"NOSE_TIP"},
146 {FaceLm::subNasale,
"NOSE_BASE"},
147 {FaceLm::lipUpperFront,
"LIP_TIP_UPPER"},
148 {FaceLm::lipLowerFront,
"LIP_TIP_LOWER"},
149 {FaceLm::chinFront,
"CHIN"},
150 {FaceLm::jawBottom,
"THROAT_TOP"},
153 return ret[size_t(view)];
156ViewLmPoss parseLmsV3(Vec2Fs
const & pacs)
159 auto ltX = [](Vec2F l,Vec2F r){
return l[0] < r[0]; };
160 auto ltY = [](Vec2F l,Vec2F r){
return l[1] < r[1]; };
161 Vec2Fs ptsY = sortAll(pacs,ltY);
162 if (ptsY.size() == 9) {
163 bool right = ptsY[8][0] < ptsY[7][0];
164 ret.lms.emplace_back(FaceLm::lipUpperFront,ptsY[5]);
165 ret.lms.emplace_back(FaceLm::lipLowerFront,ptsY[6]);
166 ret.lms.emplace_back(FaceLm::chinFront,ptsY[7]);
167 ret.lms.emplace_back(FaceLm::jawBottom,ptsY[8]);
168 Vec2Fs sv05X = sortAll(cSubvec(ptsY,0,5),ltX);
170 ret.view = FaceView::right;
171 ret.lms.emplace_back(FaceLm::exocanthionR,sv05X[0]);
172 ret.lms.emplace_back(FaceLm::noseTip,sv05X[4]);
175 ret.view = FaceView::left;
176 ret.lms.emplace_back(FaceLm::noseTip,sv05X[0]);
177 ret.lms.emplace_back(FaceLm::exocanthionL,sv05X[4]);
179 Vec2Fs sv05X13Y = sortAll(cSubvec(sv05X,1,3),ltY);
180 ret.lms.emplace_back(FaceLm::sellion,sv05X13Y[0]);
181 ret.lms.emplace_back(FaceLm::noseBridgeMiddle,sv05X13Y[1]);
182 ret.lms.emplace_back(FaceLm::subNasale,sv05X13Y[2]);
184 else if (ptsY.size() == 11) {
185 ret.view = FaceView::front;
186 ret.lms.emplace_back(FaceLm::chinBottom,ptsY.back());
187 Vec2Fs sv64X = sortAll(cSubvec(ptsY,6,4),ltX);
188 ret.lms.emplace_back(FaceLm::jawOuterR,sv64X[0]);
189 ret.lms.emplace_back(FaceLm::mouthCornerR,sv64X[1]);
190 ret.lms.emplace_back(FaceLm::mouthCornerL,sv64X[2]);
191 ret.lms.emplace_back(FaceLm::jawOuterL,sv64X[3]);
192 Vec2Fs sv06X = sortAll(cSubvec(ptsY,0,6),ltX);
193 ret.lms.emplace_back(FaceLm::cheekboneR,sv06X[0]);
194 ret.lms.emplace_back(FaceLm::cheekboneL,sv06X[5]);
195 Vec2Fs sv06X14Y = sortAll(cSubvec(sv06X,1,4),ltY);
196 Vec2Fs sv06X14Y22X = sortAll(cSubvec(sv06X14Y,2,2),ltX);
197 ret.lms.emplace_back(FaceLm::alarOuterR,sv06X14Y22X[0]);
198 ret.lms.emplace_back(FaceLm::alarOuterL,sv06X14Y22X[1]);
199 Vec2Fs sv06X14Y02X = sortAll(cSubvec(sv06X14Y,0,2),ltX);
200 ret.lms.emplace_back(FaceLm::pupilCentreR,sv06X14Y02X[0]);
201 ret.lms.emplace_back(FaceLm::pupilCentreL,sv06X14Y02X[1]);
204 fgThrow(
"Not a valid number of landmarks for V3");
Arguments for the Photofit.
unsigned int height
Height of image in pixels.
unsigned int pointY[11]
The Y values of the boostrap points in pixel coordinates (0,0) at top left pixel.
unsigned int width
Width of image in pixels.
unsigned int pointX[11]
The X values of the boostrap points in pixel coordinates (0,0) at top left pixel.