Skip to content

Commit 328fead

Browse files
authored
Merge pull request #169 from AIRLegend/dev
Release 0.7.0
2 parents bc847f9 + bf46efa commit 328fead

29 files changed

+1116
-197
lines changed

AITracker/AITracker.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@
190190
<AdditionalIncludeDirectories>$(SolutionDir)Dependencies\OpenCV\include\;$(SolutionDir)Dependencies\onnxruntime\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
191191
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
192192
<Optimization>MaxSpeed</Optimization>
193+
<WholeProgramOptimization>true</WholeProgramOptimization>
193194
</ClCompile>
194195
<Link>
195196
<SubSystem>Console</SubSystem>
@@ -247,6 +248,7 @@
247248
<ClInclude Include="src\imageprocessor.h" />
248249
<ClInclude Include="src\data.h" />
249250
<ClInclude Include="src\model.h" />
251+
<ClInclude Include="src\_inference.h" />
250252
</ItemGroup>
251253
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
252254
<ImportGroup Label="ExtensionTargets">

AITracker/AITracker.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,8 @@
4747
<ClInclude Include="src\filters.h">
4848
<Filter>Archivos de encabezado</Filter>
4949
</ClInclude>
50+
<ClInclude Include="src\_inference.h">
51+
<Filter>Archivos de encabezado</Filter>
52+
</ClInclude>
5053
</ItemGroup>
5154
</Project>

AITracker/src/PositionSolver.cpp

Lines changed: 161 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,26 @@ PositionSolver::PositionSolver(
2323
this->prior_yaw = -1.57;
2424
this->prior_distance = prior_distance * -2.0;
2525

26+
this->width = width;
27+
this->height = height;
28+
2629
this->rv[0] = this->prior_pitch;
2730
this->rv[1] = this->prior_yaw;
2831
this->rv[2] = -1.57;
2932
this->tv[2] = this->prior_distance;
3033

34+
//head3dScale = (cv::Mat_<double>(3, 3) <<
35+
// y_scale, 0.0, 0, // pitch is rv[0], pitch involves y-axis
36+
// 0.0, x_scale, 0, // yaw is rv[1], yaw involves x-axis
37+
// 0.0, 0.0, z_scale
38+
//);
39+
40+
3141
head3dScale = (cv::Mat_<double>(3, 3) <<
3242
y_scale, 0.0, 0, // pitch is rv[0], pitch involves y-axis
3343
0.0, x_scale, 0, // yaw is rv[1], yaw involves x-axis
3444
0.0, 0.0, z_scale
35-
);
45+
);
3646

3747
this->complex = complex;
3848

@@ -67,9 +77,9 @@ PositionSolver::PositionSolver(
6777
landmark_points_buffer = cv::Mat((int)contour_indices.size(), 1, CV_32FC2);
6878

6979
mat3dcontour = (cv::Mat_<double>((int)contour_indices.size(), 3) <<
70-
0.45517698, -0.30089578, 0.76442945,
71-
0.44899884, -0.16699584, 0.76514298,
72-
0.43743154, -0.02265548, 0.73926717,
80+
0.45517698, -0.30089578, 0.76442945, //0
81+
0.44899884, -0.16699584, 0.76514298, //1
82+
0.43743154, -0.02265548, 0.73926717,
7383
0.41503343, 0.08894145, 0.74794745,
7484
0.38912359, 0.23238003, 0.70478839,
7585
0.3346301, 0.36126539, 0.61558759,
@@ -159,7 +169,11 @@ PositionSolver::PositionSolver(
159169

160170
camera_distortion = (cv::Mat_<double>(4, 1) << 0, 0, 0, 0);
161171

162-
mat3dcontour = mat3dcontour * head3dScale;
172+
//mat3dcontour = mat3dcontour * head3dScale;
173+
174+
cv::transpose(mat3dcontour, mat3dcontour);
175+
mat3dcontour = head3dScale * mat3dcontour;
176+
cv::transpose(mat3dcontour, mat3dcontour);
163177

164178
if(complex) std::cout << "Using complex solver" << std::endl;
165179
}
@@ -173,7 +187,7 @@ void PositionSolver::solve_rotation(FaceData* face_data)
173187
for (int i = 0; i < contour_indices.size(); i++)
174188
{
175189
contour_idx = contour_indices[i];
176-
landmark_points_buffer.at<float>(i, j) = (float)(int)face_data->landmark_coords[2 * contour_idx + j]; // fix complation warnings.
190+
landmark_points_buffer.at<float>(i, j) = (float)face_data->landmark_coords[2 * contour_idx + j]; // fix complation warnings.
177191
}
178192
}
179193

@@ -190,7 +204,6 @@ void PositionSolver::solve_rotation(FaceData* face_data)
190204
cv::SOLVEPNP_ITERATIVE
191205
);
192206

193-
194207
get_euler(rvec, tvec);
195208

196209

@@ -200,16 +213,13 @@ void PositionSolver::solve_rotation(FaceData* face_data)
200213
face_data->translation[i] = tvec.at<double>(i, 0) * 10; // scale solvePnP coordinates to opentrack units in centimeters
201214
}
202215

203-
// We dont want the Z axis oversaturated since opentrack has +/-600 centimeter range
204-
face_data->translation[2] /= 100;
216+
correct_rotation(*face_data);
217+
clip_rotations(*face_data);
205218

206219
#ifdef _DEBUG
207220
std::cout << face_data->to_string() << std::endl; // disable copy constructor and output to std::cout
208221
#endif
209222

210-
correct_rotation(*face_data);
211-
clip_rotations(*face_data);
212-
213223
}
214224

215225
void PositionSolver::set_prior_pitch(float new_pitch)
@@ -230,6 +240,45 @@ void PositionSolver::set_prior_distance(float new_distance)
230240
this->tv[2] = this->prior_distance;
231241
}
232242

243+
void PositionSolver::calibrate_head_scale(FaceData& face_data)
244+
{
245+
std::tuple<double, double> face_dims = get_3dhead_dims();
246+
double width = std::get<0>(face_dims);
247+
double height = std::get<1>(face_dims);
248+
249+
double real_ratio = width / height;
250+
251+
std::tuple<double, double> model_dims = get_3dhead_dims();
252+
double model_width = std::get<0>(model_dims);
253+
double model_height = std::get<1>(model_dims);
254+
255+
double model_ratio = model_width / model_height;
256+
257+
double scale = (model_height * real_ratio) / height;
258+
259+
head3dScale.at<double>(0, 0) = scale;
260+
}
261+
262+
double PositionSolver::get_x_scale()
263+
{
264+
return head3dScale.at<double>(1, 1);
265+
}
266+
267+
std::tuple<double, double> PositionSolver::get_3dhead_dims()
268+
{
269+
// indices of the matrix rows, not actual points!
270+
double model_width = abs(mat3dcontour.at<double>(0, 0) - mat3dcontour.at<double>(8, 0)); // 0 - 16
271+
double model_height = abs(mat3dcontour.at<double>(9, 1) - mat3dcontour.at<double>(4, 1)); // 27 -8
272+
return std::tuple<double, double>(model_width, model_height);
273+
}
274+
275+
std::tuple<double, double> PositionSolver::get_2dhead_dims(FaceData& face_data)
276+
{
277+
double width = abs(face_data.landmark_coords[0 + 1] - face_data.landmark_coords[16 * 2 + 1]);
278+
double height = abs(face_data.landmark_coords[27 * 2 + 0] - face_data.landmark_coords[8 * 2 + 0]);
279+
return std::tuple<double, double>(width, height);
280+
}
281+
233282

234283
void PositionSolver::get_euler(cv::Mat& rvec, cv::Mat& tvec)
235284
{
@@ -254,19 +303,32 @@ void PositionSolver::get_euler(cv::Mat& rvec, cv::Mat& tvec)
254303

255304
void PositionSolver::correct_rotation(FaceData& face_data)
256305
{
257-
float distance = (float) -(face_data.translation[2]);
306+
float distance = (float) abs(face_data.translation[2]);
258307
float lateral_offset = (float)face_data.translation[1];
259308
float verical_offset = (float)face_data.translation[0];
260309

261-
float correction_yaw = (float)(std::atan(lateral_offset / distance) * TO_DEG); // (lateral_offset / distance) is already tangent, so only need atan to obtain radians
262-
float correction_pitch = (float)(std::atan(verical_offset / distance) * TO_DEG); // (verical_offset / distance) is already tangent, so only need atan to obtain radians
310+
//float correction_yaw = (float)std::atan((distance / abs(lateral_offset))) * TO_DEG;
311+
//float correction_pitch = (float)(distance / std::atan(verical_offset) * TO_DEG);
312+
313+
314+
float correction_yaw = 90.0f - (float)std::atan2(distance, abs(lateral_offset)) * TO_DEG;
315+
float correction_pitch = 90.0f - (float)std::atan2(distance, abs(verical_offset)) * TO_DEG;
316+
317+
if (lateral_offset < 0)
318+
correction_yaw *= -1;
319+
320+
if (verical_offset < 0)
321+
correction_pitch *= -1;
263322

264323
face_data.rotation[1] += correction_yaw;
265324
face_data.rotation[0] += correction_pitch;
266325

267326
// Note: We could saturate pitch here, but its better to let the user do it via Opentrack.
268327
// The coefficient could be problematic for some users.
269328
//face_data.rotation[0] = face_data.rotation[0] * 1.5;
329+
330+
// We dont want the Z axis oversaturated since opentrack has +/-600 centimeter range
331+
face_data.translation[2] /= 10;
270332
}
271333

272334

@@ -282,10 +344,89 @@ void PositionSolver::clip_rotations(FaceData& face_data)
282344
face_data.rotation[0] = 90.0;
283345
else if (face_data.rotation[0] <= -90.0)
284346
face_data.rotation[0] = -90.0;
285-
// Limit roll between -90.0 and +90.0
286-
if (face_data.rotation[2] >= 90.0)
287-
face_data.rotation[2] = 90.0;
288-
else if (face_data.rotation[2] <= -90.0)
289-
face_data.rotation[2] = -90.0;
347+
// Limit roll between 0.0 and +180.0
348+
if (face_data.rotation[2] >= 180.0)
349+
face_data.rotation[2] = 180.0;
350+
else if (face_data.rotation[2] <= 0.0)
351+
face_data.rotation[2] = 0.0;
352+
}
353+
354+
355+
356+
/*
357+
* SIMPLE POSITION SOLVER
358+
*/
359+
SimplePositionSolver::SimplePositionSolver(int im_width, int im_height, float prior_pitch, float prior_yaw, float prior_distance, bool complex, float fov, float x_scale, float y_scale, float z_scale):
360+
PositionSolver(im_width, im_height,prior_pitch, prior_yaw, prior_distance, complex, fov, x_scale, y_scale, z_scale)
361+
{
362+
contour_indices = { 0,1,2,3,8,13,14,15,16,27,28,29,30,39,42,57 }; // 57 == 55 in the 3d model
363+
364+
landmark_points_buffer = cv::Mat((int)contour_indices.size(), 1, CV_32FC2);
365+
366+
mat3dcontour = (cv::Mat_<double>((int)contour_indices.size(), 3) <<
367+
0.4551769692672, 0.300895790030204, -0.764429433974752,
368+
0.448998827123556, 0.166995837790733, -0.765143004071253,
369+
0.437431554952677, 0.022655479179981, -0.739267175112735,
370+
0.415033422928434, -0.088941454648772, -0.747947437846473,
371+
0., -0.621079019321682, -0.287294770748887,
372+
-0.415033422928434, -0.088941454648772, -0.747947437846473,
373+
-0.437431554952677, 0.022655479179981, -0.739267175112735,
374+
-0.448998827123556, 0.166995837790733, -0.765143004071253,
375+
-0.4551769692672, 0.300895790030204, -0.764429433974752,
376+
0., 0.293332603215811, -0.137582088779393,
377+
0., 0.194828701837823, -0.069158109325951,
378+
0., 0.103844017393155, -0.009151819844964,
379+
0., 0., 0.,
380+
0.131229723798772, 0.284447361805627, -0.234239149487417,
381+
-0.131229723798772, 0.284447361805627, -0.234239149487417,
382+
0., -0.343742581679188, -0.113925986025684
383+
);
384+
385+
// This 3d model is "inverted", so we need to also invert scales
386+
head3dScale = (cv::Mat_<double>(3, 3) <<
387+
y_scale, 0.0, 0, // pitch is rv[0], pitch involves y-axis
388+
0.0, x_scale, 0, // yaw is rv[1], yaw involves x-axis
389+
0.0, 0.0, z_scale
390+
);
391+
392+
cv::transpose(mat3dcontour, mat3dcontour);
393+
mat3dcontour = head3dScale * mat3dcontour;
394+
cv::transpose(mat3dcontour, mat3dcontour);
395+
}
396+
397+
398+
399+
std::tuple<double, double> SimplePositionSolver::get_3dhead_dims()
400+
{
401+
// indices of the matrix rows, not actual points!
402+
double model_width = abs(mat3dcontour.at<double>(0, 0) - mat3dcontour.at<double>(8, 0)); // 0 - 16
403+
double model_height = abs(mat3dcontour.at<double>(9, 1) - mat3dcontour.at<double>(4, 1)); // 27 -8
404+
return std::tuple<double, double>(model_width, model_height);
405+
}
406+
407+
std::tuple<double, double> SimplePositionSolver::get_2dhead_dims(FaceData& face_data)
408+
{
409+
double width = abs(face_data.landmark_coords[0 + 1] - face_data.landmark_coords[16 * 2 + 1]);
410+
double height = abs(face_data.landmark_coords[27 * 2 + 0] - face_data.landmark_coords[8 * 2 + 0]);
411+
return std::tuple<double, double>(width, height);
290412
}
291413

414+
415+
void SimplePositionSolver::correct_rotation(FaceData& face_data)
416+
{
417+
// For some reason the solver gets rest "Pitch" as "-180 deg", which is the same
418+
// as "0 deg", which is what the other solvers find.
419+
// For the moment this method will be overriden beacuse it's very possible that
420+
// this simpler model will change (soon).
421+
422+
if(abs(face_data.rotation[0]) > 90)
423+
if (face_data.rotation[0] >= -180 && face_data.rotation[0] <= 0) {
424+
face_data.rotation[0] += 180;
425+
}
426+
else if (face_data.rotation[0] > 0 && face_data.rotation[0] <= 180)
427+
{
428+
face_data.rotation[0] -= 180;
429+
}
430+
431+
PositionSolver::correct_rotation(face_data);
432+
}

0 commit comments

Comments
 (0)