Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
eos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Richard Torenvliet
eos
Commits
949c8db1
Commit
949c8db1
authored
Apr 03, 2017
by
Richard Torenvliet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
First version testing the multi-frame chain with bufferedVideoIterator
parent
6690296f
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
316 additions
and
46 deletions
+316
-46
include/eos/core/landmark_utils.hpp
include/eos/core/landmark_utils.hpp
+51
-14
include/eos/fitting/fitting.hpp
include/eos/fitting/fitting.hpp
+21
-1
include/eos/video/BufferedVideoIterator.hpp
include/eos/video/BufferedVideoIterator.hpp
+1
-1
include/eos/video/Keyframe.hpp
include/eos/video/Keyframe.hpp
+89
-7
utils/accuracy-evaluation.cpp
utils/accuracy-evaluation.cpp
+154
-23
No files found.
include/eos/core/landmark_utils.hpp
View file @
949c8db1
...
@@ -84,6 +84,29 @@ namespace eos {
...
@@ -84,6 +84,29 @@ namespace eos {
return
landmarks
;
return
landmarks
;
}
}
/**
* Read strings from a given file and return them as a vector of strings.
*
* @param filename
* @return
*/
std
::
vector
<
std
::
string
>
file_to_string_vector
(
std
::
string
filename
)
{
std
::
ifstream
file
(
filename
);
if
(
!
file
.
is_open
())
{
throw
std
::
runtime_error
(
string
(
"Could not open annotation list file: "
+
filename
));
}
string
line
;
std
::
vector
<
std
::
string
>
output
;
while
(
getline
(
file
,
line
))
{
std
::
cout
<<
line
<<
std
::
endl
;
output
.
push_back
(
line
);
}
return
output
;
}
/**
/**
* Helper function, gathers matching model_points with given landmarks and LandmarkMapper.
* Helper function, gathers matching model_points with given landmarks and LandmarkMapper.
*
*
...
@@ -115,22 +138,32 @@ namespace eos {
...
@@ -115,22 +138,32 @@ namespace eos {
}
}
/**
/**
* Load annotations, return all annotations as image points (vectors of Vec2f).
* Load annotations, return all annotations as a vector of LandmarkCollection (vectors of Vec2f).
* Supports either a given template, any cv::Vec2f / Eigen::Vector2f will work.
*
* Returns the annotations as a list of files, useful for later use if read_from_file flag is set to true.
* This flag will read the filepaths from the given annotation file, probably depends on the command line args.
*
*
* @tparam vec2f
* @param annotations
* @param annotations
* @param mappingsfile
* @param mapper
* @throws std::runtime_error in case of faulty annotation file
* @param morphable_model
* @return std::vector<std::vector<cv::Vec2f>> image_points in a vector of OpenCV float pairs (Vec2f).
* @param read_from_file
* @return
*/
*/
template
<
typename
vec2f
,
typename
vec3f
>
template
<
typename
vec2f
>
std
::
vector
<
core
::
LandmarkCollection
<
vec2f
>>
load_annotations
(
std
::
vector
<
std
::
string
>
annotations
,
fs
::
path
mappingsfile
)
{
std
::
pair
<
std
::
vector
<
core
::
LandmarkCollection
<
vec2f
>>
,
std
::
vector
<
std
::
string
>>
//std::vector <std::vector<vec2f>> image_points; // the corresponding 2D landmark points of all annotation files.
load_annotations
(
eos
::
core
::
LandmarkMapper
landmark_mapper
=
eos
::
core
::
LandmarkMapper
(
mappingsfile
);
std
::
vector
<
std
::
string
>
annotations
,
core
::
LandmarkMapper
mapper
,
morphablemodel
::
MorphableModel
morphable_model
,
bool
read_from_file
=
false
)
{
std
::
vector
<
core
::
LandmarkCollection
<
vec2f
>>
landmark_collection_list
;
std
::
vector
<
core
::
LandmarkCollection
<
vec2f
>>
landmark_collection_list
;
// These will be the final 2D and 3D points used for the fitting:
// load file names from one file.
std
::
vector
<
vec3f
>
model_points
;
// the points in the 3D shape model
std
::
vector
<
std
::
string
>
annotation_files
;
std
::
vector
<
int
>
vertex_indices
;
// their vertex indices
if
(
read_from_file
)
{
annotations
=
file_to_string_vector
(
annotations
[
0
]);
}
for
(
int
i
=
0
;
i
<
annotations
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
annotations
.
size
();
i
++
)
{
eos
::
core
::
LandmarkCollection
<
vec2f
>
landmarks
;
eos
::
core
::
LandmarkCollection
<
vec2f
>
landmarks
;
...
@@ -142,13 +175,17 @@ namespace eos {
...
@@ -142,13 +175,17 @@ namespace eos {
throw
std
::
runtime_error
(
"Error reading the landmarks: "
+
annotations
[
i
]);
throw
std
::
runtime_error
(
"Error reading the landmarks: "
+
annotations
[
i
]);
}
}
core
::
LandmarkCollection
<
vec2f
>
image_points
;
// Sub-select all the landmarks which we have a mapping for (i.e. that are defined in the 3DMM):
// Sub-select all the landmarks which we have a mapping for (i.e. that are defined in the 3DMM):
for
(
int
j
=
0
;
j
<
landmarks
.
size
();
j
++
)
{
for
(
int
i
=
0
;
i
<
landmarks
.
size
();
++
i
)
{
landmark_collection_list
.
emplace_back
(
landmarks
);
image_points
.
emplace_back
(
landmarks
[
i
]
);
}
}
landmark_collection_list
.
push_back
(
image_points
);
}
}
return
landmark_collection_list
;
return
std
::
make_pair
(
landmark_collection_list
,
annotations
)
;
}
}
}
}
}
}
...
...
include/eos/fitting/fitting.hpp
View file @
949c8db1
...
@@ -464,6 +464,7 @@ inline std::pair<std::vector<core::Mesh>, std::vector<fitting::RenderingParamete
...
@@ -464,6 +464,7 @@ inline std::pair<std::vector<core::Mesh>, std::vector<fitting::RenderingParamete
std
::
vector
<
float
>&
pca_shape_coefficients
,
std
::
vector
<
float
>&
pca_shape_coefficients
,
std
::
vector
<
std
::
vector
<
float
>>&
blendshape_coefficients
,
std
::
vector
<
std
::
vector
<
float
>>&
blendshape_coefficients
,
std
::
vector
<
std
::
vector
<
cv
::
Vec2f
>>&
fitted_image_points
)
{
std
::
vector
<
std
::
vector
<
cv
::
Vec2f
>>&
fitted_image_points
)
{
assert
(
blendshapes
.
size
()
>
0
);
assert
(
blendshapes
.
size
()
>
0
);
assert
(
num_iterations
>
0
);
// Can we allow 0, for only the initial pose-fit?
assert
(
num_iterations
>
0
);
// Can we allow 0, for only the initial pose-fit?
assert
(
pca_shape_coefficients
.
size
()
<=
morphable_model
.
get_shape_model
().
get_num_principal_components
());
assert
(
pca_shape_coefficients
.
size
()
<=
morphable_model
.
get_shape_model
().
get_num_principal_components
());
...
@@ -475,7 +476,6 @@ inline std::pair<std::vector<core::Mesh>, std::vector<fitting::RenderingParamete
...
@@ -475,7 +476,6 @@ inline std::pair<std::vector<core::Mesh>, std::vector<fitting::RenderingParamete
using
Eigen
::
VectorXf
;
using
Eigen
::
VectorXf
;
using
Eigen
::
MatrixXf
;
using
Eigen
::
MatrixXf
;
if
(
!
num_shape_coefficients_to_fit
)
{
if
(
!
num_shape_coefficients_to_fit
)
{
num_shape_coefficients_to_fit
=
morphable_model
.
get_shape_model
().
get_num_principal_components
();
num_shape_coefficients_to_fit
=
morphable_model
.
get_shape_model
().
get_num_principal_components
();
}
}
...
@@ -691,6 +691,26 @@ inline std::pair<std::vector<core::Mesh>, std::vector<fitting::RenderingParamete
...
@@ -691,6 +691,26 @@ inline std::pair<std::vector<core::Mesh>, std::vector<fitting::RenderingParamete
);
);
};
};
inline
std
::
pair
<
std
::
vector
<
core
::
Mesh
>
,
std
::
vector
<
fitting
::
RenderingParameters
>>
fit_shape_and_pose_multi_2
(
const
morphablemodel
::
MorphableModel
&
morphable_model
,
const
std
::
vector
<
morphablemodel
::
Blendshape
>&
blendshapes
,
const
std
::
vector
<
core
::
LandmarkCollection
<
cv
::
Vec2f
>>&
landmarks
,
const
core
::
LandmarkMapper
&
landmark_mapper
,
int
image_width
,
int
image_height
,
int
num_images
,
const
morphablemodel
::
EdgeTopology
&
edge_topology
,
const
fitting
::
ContourLandmarks
&
contour_landmarks
,
const
fitting
::
ModelContour
&
model_contour
,
int
num_iterations
,
boost
::
optional
<
int
>
num_shape_coefficients_to_fit
,
float
lambda
,
boost
::
optional
<
fitting
::
RenderingParameters
>
initial_rendering_params
,
std
::
vector
<
float
>&
pca_shape_coefficients
,
std
::
vector
<
std
::
vector
<
float
>>&
blendshape_coefficients
,
std
::
vector
<
std
::
vector
<
cv
::
Vec2f
>>&
fitted_image_points
)
{
}
}
/* namespace fitting */
}
/* namespace fitting */
}
/* namespace eos */
}
/* namespace eos */
...
...
include/eos/video/BufferedVideoIterator.hpp
View file @
949c8db1
...
@@ -43,7 +43,7 @@ using namespace std;
...
@@ -43,7 +43,7 @@ using namespace std;
namespace
eos
{
namespace
eos
{
namespace
video
{
namespace
video
{
// TODO: maybe move video iterator here.. or remove fil
e
.
// TODO: maybe move video iterator here.. or remove fil.
}
}
}
}
...
...
include/eos/video/Keyframe.hpp
View file @
949c8db1
...
@@ -58,9 +58,10 @@ public:
...
@@ -58,9 +58,10 @@ public:
* @param frame
* @param frame
* @param score
* @param score
*/
*/
Keyframe
(
float
score
,
cv
::
Mat
frame
)
{
Keyframe
(
float
score
,
cv
::
Mat
frame
,
int
frame_number
)
{
this
->
score
=
score
;
this
->
score
=
score
;
this
->
frame
=
frame
;
this
->
frame
=
frame
;
this
->
frame_number
=
frame_number
;
}
}
/**
/**
...
@@ -78,6 +79,7 @@ public:
...
@@ -78,6 +79,7 @@ public:
float
score
=
0.0
f
;
float
score
=
0.0
f
;
cv
::
Mat
frame
;
cv
::
Mat
frame
;
fitting
::
FittingResult
fitting_result
;
fitting
::
FittingResult
fitting_result
;
int
frame_number
;
};
};
/**
/**
...
@@ -319,19 +321,18 @@ public:
...
@@ -319,19 +321,18 @@ public:
BufferedVideoIterator
(
std
::
string
videoFilePath
,
int
max_frames
=
5
,
int
min_frames
=
4
)
{
BufferedVideoIterator
(
std
::
string
videoFilePath
,
int
max_frames
=
5
,
int
min_frames
=
4
)
{
std
::
ifstream
file
(
videoFilePath
);
std
::
ifstream
file
(
videoFilePath
);
std
::
cout
<<
"video file path: "
<<
videoFilePath
<<
std
::
endl
;
if
(
!
file
.
is_open
())
{
if
(
!
file
.
is_open
())
{
throw
std
::
runtime_error
(
"Error opening given file: "
+
videoFilePath
);
throw
std
::
runtime_error
(
"Error opening given file: "
+
videoFilePath
);
}
}
cv
::
VideoCapture
cap
(
videoFilePath
);
// open video file
cv
::
VideoCapture
tmp_
cap
(
videoFilePath
);
// open video file
if
(
!
cap
.
isOpened
())
{
// check if we succeeded
if
(
!
tmp_
cap
.
isOpened
())
{
// check if we succeeded
throw
std
::
runtime_error
(
"Could not play video"
);
throw
std
::
runtime_error
(
"Could not play video"
);
}
}
width
=
static_cast
<
int
>
(
cap
.
get
(
CV_CAP_PROP_FRAME_HEIGHT
));
this
->
cap
=
tmp_cap
;
height
=
static_cast
<
int
>
(
cap
.
get
(
CV_CAP_PROP_FRAME_HEIGHT
));
this
->
max_frames
=
max_frames
;
this
->
max_frames
=
max_frames
;
this
->
min_frames
=
min_frames
;
this
->
min_frames
=
min_frames
;
}
}
...
@@ -350,15 +351,22 @@ public:
...
@@ -350,15 +351,22 @@ public:
cv
::
Mat
frame
;
cv
::
Mat
frame
;
cap
>>
frame
;
cap
>>
frame
;
if
(
frame
.
empty
())
{
frame_buffer
=
next
();
return
frame_buffer
;
}
// Pop if we exceeded max_frames.
// Pop if we exceeded max_frames.
if
(
n_frames
>
max_frames
)
{
if
(
n_frames
>
max_frames
)
{
frame_buffer
.
pop_front
();
frame_buffer
.
pop_front
();
n_frames
--
;
}
}
float
lap_score
=
static_cast
<
float
>
(
variance_of_laplacian
(
frame
));
float
lap_score
=
static_cast
<
float
>
(
variance_of_laplacian
(
frame
));
if
(
lap_score
<
laplacian_threshold
)
{
if
(
lap_score
<
laplacian_threshold
)
{
frame_buffer
.
push_back
(
Keyframe
(
lap_score
,
frame
));
total_frames_processed
++
;
frame_buffer
.
push_back
(
Keyframe
(
lap_score
,
frame
,
total_frames_processed
));
}
}
n_frames
++
;
n_frames
++
;
...
@@ -379,11 +387,13 @@ private:
...
@@ -379,11 +387,13 @@ private:
std
::
deque
<
Keyframe
>
frame_buffer
;
std
::
deque
<
Keyframe
>
frame_buffer
;
// TODO: make set-able
// TODO: make set-able
long
total_frames_processed
=
1
;
// total frames in buffer
// total frames in buffer
long
n_frames
=
1
;
long
n_frames
=
1
;
// min frames to load at the start.
// min frames to load at the start.
long
min_frames
=
3
;
long
min_frames
=
3
;
// keep max_frames into the buffer.
// keep max_frames into the buffer.
long
max_frames
=
5
;
long
max_frames
=
5
;
...
@@ -394,6 +404,78 @@ private:
...
@@ -394,6 +404,78 @@ private:
double
laplacian_threshold
=
10000000
;
double
laplacian_threshold
=
10000000
;
};
};
/**
* @brief Merges isomaps from a live video with a weighted averaging, based
* on the view angle of each vertex to the camera.
*
* An optional merge_threshold can be specified upon construction. Pixels with
* a view-angle above that threshold will be completely discarded. All pixels
* below the threshold are merged with a weighting based on its vertex view-angle.
* Assumes the isomaps to be 512x512.
*/
class
WeightedIsomapAveraging
{
public:
/**
* @brief Constructs a new object that will hold the current averaged isomap and
* be able to add frames from a live video and merge them on-the-fly.
*
* The threshold means: Each triangle with a view angle smaller than the given angle will be used to merge.
* The default threshold (90°) means all triangles, as long as they're a little bit visible, are merged.
*
* @param[in] merge_threshold View-angle merge threshold, in degrees, from 0 to 90.
*/
WeightedIsomapAveraging
(
float
merge_threshold
=
90.0
f
)
{
assert
(
merge_threshold
>=
0.
f
&&
merge_threshold
<=
90.
f
);
visibility_counter
=
cv
::
Mat
::
zeros
(
512
,
512
,
CV_32SC1
);
merged_isomap
=
cv
::
Mat
::
zeros
(
512
,
512
,
CV_32FC4
);
// map 0° to 255, 90° to 0:
float
alpha_thresh
=
(
-
255.
f
/
90.
f
)
*
merge_threshold
+
255.
f
;
if
(
alpha_thresh
<
0.
f
)
// could maybe happen due to float inaccuracies / rounding?
alpha_thresh
=
0.0
f
;
threshold
=
static_cast
<
unsigned
char
>
(
alpha_thresh
);
};
/**
* @brief Merges the given new isomap with all previously processed isomaps.
*
* @param[in] isomap The new isomap to add.
* @return The merged isomap of all images processed so far, as 8UC4.
*/
cv
::
Mat
add_and_merge
(
const
cv
::
Mat
&
isomap
)
{
// Merge isomaps, add the current to the already merged, pixel by pixel:
for
(
int
r
=
0
;
r
<
isomap
.
rows
;
++
r
)
{
for
(
int
c
=
0
;
c
<
isomap
.
cols
;
++
c
)
{
if
(
isomap
.
at
<
cv
::
Vec4b
>
(
r
,
c
)[
3
]
<=
threshold
)
{
continue
;
// ignore this pixel, not visible in the extracted isomap of this current frame
}
// we're sure to have a visible pixel, merge it:
// merged_pixel = (old_average * visible_count + new_pixel) / (visible_count + 1)
merged_isomap
.
at
<
cv
::
Vec4f
>
(
r
,
c
)[
0
]
=
(
merged_isomap
.
at
<
cv
::
Vec4f
>
(
r
,
c
)[
0
]
*
visibility_counter
.
at
<
int
>
(
r
,
c
)
+
isomap
.
at
<
cv
::
Vec4b
>
(
r
,
c
)[
0
])
/
(
visibility_counter
.
at
<
int
>
(
r
,
c
)
+
1
);
merged_isomap
.
at
<
cv
::
Vec4f
>
(
r
,
c
)[
1
]
=
(
merged_isomap
.
at
<
cv
::
Vec4f
>
(
r
,
c
)[
1
]
*
visibility_counter
.
at
<
int
>
(
r
,
c
)
+
isomap
.
at
<
cv
::
Vec4b
>
(
r
,
c
)[
1
])
/
(
visibility_counter
.
at
<
int
>
(
r
,
c
)
+
1
);
merged_isomap
.
at
<
cv
::
Vec4f
>
(
r
,
c
)[
2
]
=
(
merged_isomap
.
at
<
cv
::
Vec4f
>
(
r
,
c
)[
2
]
*
visibility_counter
.
at
<
int
>
(
r
,
c
)
+
isomap
.
at
<
cv
::
Vec4b
>
(
r
,
c
)[
2
])
/
(
visibility_counter
.
at
<
int
>
(
r
,
c
)
+
1
);
merged_isomap
.
at
<
cv
::
Vec4f
>
(
r
,
c
)[
3
]
=
255
;
// as soon as we've seen the pixel visible once, we set it to visible.
++
visibility_counter
.
at
<
int
>
(
r
,
c
);
}
}
cv
::
Mat
merged_isomap_uchar
;
merged_isomap
.
convertTo
(
merged_isomap_uchar
,
CV_8UC4
);
return
merged_isomap_uchar
;
};
private:
cv
::
Mat
visibility_counter
;
cv
::
Mat
merged_isomap
;
unsigned
char
threshold
;
};
}
/* namespace video */
}
/* namespace video */
}
/* namespace eos */
}
/* namespace eos */
...
...
utils/accuracy-evaluation.cpp
View file @
949c8db1
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
* limitations under the License.
* limitations under the License.
*/
*/
#include "eos/core/landmark_utils.hpp"
#include "eos/core/landmark_utils.hpp"
#include "eos/render/render.hpp"
#include "eos/morphablemodel/morphablemodel.hpp"
#include "eos/morphablemodel/morphablemodel.hpp"
#include "eos/morphablemodel/blendshape.hpp"
#include "eos/morphablemodel/blendshape.hpp"
#include "eos/fitting/fitting.hpp"
#include "eos/fitting/fitting.hpp"
...
@@ -30,6 +31,7 @@
...
@@ -30,6 +31,7 @@
#include "boost/program_options.hpp"
#include "boost/program_options.hpp"
#include "boost/filesystem.hpp"
#include "boost/filesystem.hpp"
#include "glm/gtx/string_cast.hpp"
#include <vector>
#include <vector>
#include <iostream>
#include <iostream>
...
@@ -41,6 +43,7 @@ namespace fs = boost::filesystem;
...
@@ -41,6 +43,7 @@ namespace fs = boost::filesystem;
using
eos
::
core
::
Landmark
;
using
eos
::
core
::
Landmark
;
using
eos
::
core
::
LandmarkCollection
;
using
eos
::
core
::
LandmarkCollection
;
using
eos
::
video
::
BufferedVideoIterator
;
using
eos
::
video
::
BufferedVideoIterator
;
using
eos
::
video
::
WeightedIsomapAveraging
;
using
cv
::
Mat
;
using
cv
::
Mat
;
using
cv
::
Vec2f
;
using
cv
::
Vec2f
;
using
cv
::
Vec3f
;
using
cv
::
Vec3f
;
...
@@ -48,7 +51,6 @@ using cv::Vec4f;
...
@@ -48,7 +51,6 @@ using cv::Vec4f;
using
std
::
vector
;
using
std
::
vector
;
using
std
::
string
;
using
std
::
string
;
using
namespace
cv
;
using
namespace
cv
;
/**
/**
...
@@ -79,6 +81,119 @@ void draw_wireframe(cv::Mat image, const eos::core::Mesh& mesh, glm::mat4x4 mode
...
@@ -79,6 +81,119 @@ void draw_wireframe(cv::Mat image, const eos::core::Mesh& mesh, glm::mat4x4 mode
}
}
};
};
void
evaluate_results
(
std
::
deque
<
eos
::
video
::
Keyframe
>
key_frames
,
std
::
vector
<
fitting
::
RenderingParameters
>
rendering_paramss
,
std
::
vector
<
core
::
LandmarkCollection
<
cv
::
Vec2f
>>
landmark_list
,
morphablemodel
::
MorphableModel
morphable_model
,
vector
<
core
::
Mesh
>
meshs
,
std
::
vector
<
float
>
pca_shape_coefficients
,
std
::
vector
<
std
::
vector
<
float
>>
blend_shape_coefficients
,
std
::
vector
<
std
::
vector
<
cv
::
Vec2f
>>
fitted_image_points
,
std
::
vector
<
std
::
string
>
annotations
,
int
n_iter
)
{
WeightedIsomapAveraging
isomap_averaging
(
60.
f
);
// merge all triangles that are facing <60° towards the camera
Mat
merged_isomap
;
fs
::
path
outputfilebase
=
annotations
[
0
];
// The 3D head pose can be recovered as follows:
for
(
uint
i
=
0
;
i
<
key_frames
.
size
();
++
i
)
{
float
yaw_angle
=
glm
::
degrees
(
glm
::
yaw
(
rendering_paramss
[
i
].
get_rotation
()));
int
frame_number
=
key_frames
[
i
].
frame_number
;
Mat
frame
=
key_frames
[
i
].
frame
;
int
frame_width
=
frame
.
cols
;
int
frame_height
=
frame
.
rows
;
// and similarly for pitch and roll.
// Extract the texture from the image using given mesh and camera parameters:
Mat
affine_from_ortho
=
fitting
::
get_3x4_affine_camera_matrix
(
rendering_paramss
[
i
],
frame_width
,
frame_height
);
// Draw the loaded landmarks:
Mat
isomap
=
render
::
extract_texture
(
meshs
[
i
],
affine_from_ortho
,
frame
);
Mat
outimg
=
frame
.
clone
();
std
::
cout
<<
"processing:"
<<
frame_number
<<
std
::
endl
;
for
(
auto
&&
lm
:
landmark_list
[
frame_number
])
{
cv
::
rectangle
(
outimg
,
cv
::
Point2f
(
lm
.
coordinates
[
0
]
-
2.0
f
,
lm
.
coordinates
[
1
]
-
2.0
f
),
cv
::
Point2f
(
lm
.
coordinates
[
0
],
lm
.
coordinates
[
1
]
+
2.0
f
),
{
255
,
0
,
0
}
);
}
// Draw the fitted mesh as wireframe, and save the image:
draw_wireframe
(
outimg
,
meshs
[
i
],
rendering_paramss
[
i
].
get_modelview
(),
rendering_paramss
[
i
].
get_projection
(),
fitting
::
get_opencv_viewport
(
frame_width
,
frame_height
)
);
fs
::
path
outputfile
=
annotations
[
i
];
outputfile
.
replace_extension
(
".annotated.png"
);
cv
::
imwrite
(
outputfile
.
string
(),
outimg
);
// save frontal rendering with texture:
Mat
frontal_rendering
;
glm
::
mat4
modelview_frontal
=
glm
::
mat4
(
1.0
);
core
::
Mesh
neutral_expression
=
morphablemodel
::
sample_to_mesh
(
morphable_model
.
get_shape_model
().
draw_sample
(
pca_shape_coefficients
),
morphable_model
.
get_color_model
().
get_mean
(),
morphable_model
.
get_shape_model
().
get_triangle_list
(),
morphable_model
.
get_color_model
().
get_triangle_list
(),
morphable_model
.
get_texture_coordinates
()
);
std
::
tie
(
frontal_rendering
,
std
::
ignore
)
=
eos
::
render
::
render
(
neutral_expression
,
modelview_frontal
,
glm
::
ortho
(
-
130.0
f
,
130.0
f
,
-
130.0
f
,
130.0
f
),
256
,
256
,
render
::
create_mipmapped_texture
(
isomap
),
true
,
false
,
false
);
cv
::
imshow
(
"frame"
,
isomap
);
outputfile
.
replace_extension
(
".frontal.png"
);
cv
::
imwrite
(
outputfile
.
string
(),
frontal_rendering
);
outputfile
.
replace_extension
(
""
);
// And save the isomap:
if
(
!
isomap
.
empty
())
{
// And save the isomap:
outputfile
.
replace_extension
(
".isomap.png"
);
cv
::
imwrite
(
outputfile
.
string
(),
isomap
);
// merge the isomaps:
merged_isomap
=
isomap_averaging
.
add_and_merge
(
isomap
);
cv
::
imwrite
(
outputfile
.
string
(),
isomap
);
}
}
// save the merged isomap:
fs
::
path
outputfile
=
outputfilebase
;
outputfile
+=
fs
::
path
(
"merged.isomap.png"
);
cv
::
imwrite
(
outputfile
.
string
(),
merged_isomap
);
outputfile
.
replace_extension
(
""
);
// save the frontal rendering with merged isomap:
Mat
frontal_rendering
;
glm
::
mat4
modelview_frontal
=
glm
::
mat4
(
1.0
);
core
::
Mesh
neutral_expression
=
morphablemodel
::
sample_to_mesh
(
morphable_model
.
get_shape_model
().
draw_sample
(
pca_shape_coefficients
),
morphable_model
.
get_color_model
().
get_mean
(),
morphable_model
.
get_shape_model
().
get_triangle_list
(),
morphable_model
.
get_color_model
().
get_triangle_list
(),
morphable_model
.
get_texture_coordinates
());
std
::
tie
(
frontal_rendering
,
std
::
ignore
)
=
render
::
render
(
neutral_expression
,
modelview_frontal
,
glm
::
ortho
(
-
130.0
f
,
130.0
f
,
-
130.0
f
,
130.0
f
),
512
,
512
,
render
::
create_mipmapped_texture
(
merged_isomap
),
true
,
false
,
false
);
outputfile
.
replace_extension
(
".frontal.png"
);
cv
::
imwrite
(
outputfile
.
string
(),
frontal_rendering
);
outputfile
.
replace_extension
(
""
);
// Save the mesh as textured obj:
std
::
string
obj_filename
=
"_"
+
std
::
to_string
(
n_iter
)
+
".obj"
;
outputfile
.
replace_extension
(
obj_filename
.
c_str
());
core
::
write_textured_obj
(
morphable_model
.
draw_sample
(
pca_shape_coefficients
,
std
::
vector
<
float
>
()),
outputfile
.
string
());
std
::
cout
<<
"Finished fitting and wrote result mesh and isomap to files with basename "
<<
outputfilebase
<<
"."
<<
std
::
endl
;
}
/**
/**
* This app demonstrates estimation of the camera and fitting of the shape
* This app demonstrates estimation of the camera and fitting of the shape
* model of a 3D Morphable Model from an ibug LFPW image with its landmarks.
* model of a 3D Morphable Model from an ibug LFPW image with its landmarks.
...
@@ -92,6 +207,9 @@ int main(int argc, char *argv[]) {
...
@@ -92,6 +207,9 @@ int main(int argc, char *argv[]) {
fs
::
path
modelfile
,
isomapfile
,
videofile
,
landmarksfile
,
mappingsfile
,
contourfile
,
edgetopologyfile
,
blendshapesfile
,
outputfile
;
fs
::
path
modelfile
,
isomapfile
,
videofile
,
landmarksfile
,
mappingsfile
,
contourfile
,
edgetopologyfile
,
blendshapesfile
,
outputfile
;
std
::
vector
<
std
::
string
>
annotations
;
std
::
vector
<
std
::
string
>
annotations
;
// get annotaitions from one file
bool
get_annotations
=
false
;
try
{
try
{
po
::
options_description
desc
(
"Allowed options"
);
po
::
options_description
desc
(
"Allowed options"
);
desc
.
add_options
()
desc
.
add_options
()
...
@@ -101,7 +219,9 @@ int main(int argc, char *argv[]) {
...
@@ -101,7 +219,9 @@ int main(int argc, char *argv[]) {
"a Morphable Model stored as cereal BinaryArchive"
)
"a Morphable Model stored as cereal BinaryArchive"
)
(
"video,i"
,
po
::
value
<
fs
::
path
>
(
&
videofile
)
->
required
(),
(
"video,i"
,
po
::
value
<
fs
::
path
>
(
&
videofile
)
->
required
(),
"an input image"
)
"an input image"
)
(
"annotations,l"
,
po
::
value
<
vector
<
std
::
string
>>
(
&
annotations
)
->
multitoken
(),
(
"get_annotations,g"
,
po
::
bool_switch
(
&
get_annotations
)
->
default_value
(
false
),
"read .pts annotation file locations from one file, one file path per line"
)
(
"annotations,l"
,
po
::
value
<
vector
<
std
::
string
>>
(
&
annotations
)
->
multitoken
()
->
default_value
(
"../bin/data/vid_annot_pts_files.txt"
),
".pts annotation files per frame of video"
)
".pts annotation files per frame of video"
)
(
"mapping,p"
,
po
::
value
<
fs
::
path
>
(
&
mappingsfile
)
->
required
()
->
default_value
(
"../share/ibug2did.txt"
),
(
"mapping,p"
,
po
::
value
<
fs
::
path
>
(
&
mappingsfile
)
->
required
()
->
default_value
(
"../share/ibug2did.txt"
),
"2D landmarks for the image, in ibug .pts format"
)
"2D landmarks for the image, in ibug .pts format"
)
...
@@ -140,10 +260,13 @@ int main(int argc, char *argv[]) {
...
@@ -140,10 +260,13 @@ int main(int argc, char *argv[]) {
return
EXIT_FAILURE
;
return
EXIT_FAILURE
;
}
}
// Load landmarks, LandmarkMapper and the Morphable Model:
core
::
LandmarkMapper
landmark_mapper
=
core
::
LandmarkMapper
(
mappingsfile
);
// load all annotation files into lists of landmarks
// load all annotation files into lists of landmarks
vector
<
core
::
LandmarkCollection
<
cv
::
Vec2f
>>
landmark_list
;
vector
<
core
::
LandmarkCollection
<
cv
::
Vec2f
>>
landmark_list
;
try
{
try
{
landmark_list
=
eos
::
core
::
load_annotations
<
cv
::
Vec2f
,
cv
::
Vec3f
>
(
annotations
,
mappingsfile
);
std
::
tie
(
landmark_list
,
annotations
)
=
eos
::
core
::
load_annotations
<
cv
::
Vec2f
>
(
annotations
,
landmark_mapper
,
morphable_model
,
get_annotations
);
}
catch
(
const
std
::
runtime_error
&
e
)
{
}
catch
(
const
std
::
runtime_error
&
e
)
{
std
::
cout
<<
e
.
what
()
<<
std
::
endl
;
std
::
cout
<<
e
.
what
()
<<
std
::
endl
;
return
EXIT_FAILURE
;
return
EXIT_FAILURE
;
...
@@ -159,20 +282,14 @@ int main(int argc, char *argv[]) {
...
@@ -159,20 +282,14 @@ int main(int argc, char *argv[]) {
// The edge topology is used to speed up computation of the occluding face contour fitting:
// The edge topology is used to speed up computation of the occluding face contour fitting:
morphablemodel
::
EdgeTopology
edge_topology
=
morphablemodel
::
load_edge_topology
(
edgetopologyfile
.
string
());
morphablemodel
::
EdgeTopology
edge_topology
=
morphablemodel
::
load_edge_topology
(
edgetopologyfile
.
string
());
// Load landmarks, LandmarkMapper and the Morphable Model:
LandmarkCollection
<
cv
::
Vec2f
>
landmarks
;
core
::
LandmarkMapper
landmark_mapper
=
core
::
LandmarkMapper
(
mappingsfile
);
// These will be the final 2D and 3D points used for the fitting:
// These will be the final 2D and 3D points used for the fitting:
vector
<
cv
::
Vec3f
>
model_points
;
// the points in the 3D shape model
vector
<
cv
::
Vec3f
>
model_points
;
// the points in the 3D shape model
vector
<
int
>
vertex_indices
;
// their vertex indices
vector
<
int
>
vertex_indices
;
// their vertex indices
vector
<
core
::
Mesh
>
meshs
;
vector
<
core
::
Mesh
>
meshs
;
vector
<
fitting
::
RenderingParameters
>
rendering_paramss
;
vector
<
fitting
::
RenderingParameters
>
rendering_paramss
;
// std::tie(model_points, vertex_indices) = eos::core::load_model_data<cv::Vec2f, cv::Vec3f>(landmarks, morphable_model, landmark_mapper);
BufferedVideoIterator
vid_iterator
;
BufferedVideoIterator
vid_iterator
;
try
{
try
{
vid_iterator
=
BufferedVideoIterator
(
videofile
.
string
());
vid_iterator
=
BufferedVideoIterator
(
videofile
.
string
());
}
catch
(
std
::
runtime_error
&
e
)
{
}
catch
(
std
::
runtime_error
&
e
)
{
...
@@ -185,28 +302,27 @@ int main(int argc, char *argv[]) {
...
@@ -185,28 +302,27 @@ int main(int argc, char *argv[]) {
int
frame_height
=
vid_iterator
.
height
;
int
frame_height
=
vid_iterator
.
height
;
// test with loading 10 frames subsequently.
// test with loading 10 frames subsequently.
std
::
deque
<
eos
::
video
::
Keyframe
>
frames
=
vid_iterator
.
next
();
std
::
deque
<
eos
::
video
::
Keyframe
>
key_
frames
=
vid_iterator
.
next
();
std
::
vector
<
float
>
pca_shape_coefficients
;
std
::
vector
<
float
>
pca_shape_coefficients
;
std
::
vector
<
std
::
vector
<
float
>>
blend_shape_coefficients
;
std
::
vector
<
std
::
vector
<
float
>>
blend_shape_coefficients
;
std
::
vector
<
std
::
vector
<
cv
::
Vec2f
>>
fitted_image_points
;
std
::
vector
<
std
::
vector
<
cv
::
Vec2f
>>
fitted_image_points
;
int
n_frames
=
static_cast
<
int
>
(
frames
.
size
());
int
n_iter
=
0
;
while
(
!
(
frames
.
empty
()))
{
if
(
n_frames
==
100
)
{
while
(
!
(
key_frames
.
empty
()))
{
if
(
n_iter
==
10
)
{
break
;
break
;
}
}
int
frame_count
=
0
;
std
::
cout
<<
std
::
endl
<<
"frames in buffer: "
<<
frames
.
size
()
<<
std
::
endl
;
std
::
tie
(
meshs
,
rendering_paramss
)
=
fitting
::
fit_shape_and_pose_multi
(
std
::
tie
(
meshs
,
rendering_paramss
)
=
fitting
::
fit_shape_and_pose_multi
(
morphable_model
,
morphable_model
,
blend_shapes
,
blend_shapes
,
landmark_list
,
landmark_list
,
landmark_mapper
,
landmark_mapper
,
frame_width
,
key_frames
[
0
].
frame
.
cols
,
frame_height
,
key_frames
[
0
].
frame
.
rows
,
static_cast
<
int
>
(
frames
.
size
()),
static_cast
<
int
>
(
key_
frames
.
size
()),
edge_topology
,
edge_topology
,
ibug_contour
,
ibug_contour
,
model_contour
,
model_contour
,
...
@@ -219,15 +335,30 @@ int main(int argc, char *argv[]) {
...
@@ -219,15 +335,30 @@ int main(int argc, char *argv[]) {
fitted_image_points
fitted_image_points
);
);
frames
=
vid_iterator
.
next
();
evaluate_results
(
key_frames
,
rendering_paramss
,
landmark_list
,
morphable_model
,
meshs
,
pca_shape_coefficients
,
blend_shape_coefficients
,
fitted_image_points
,
annotations
,
n_iter
);
key_frames
=
vid_iterator
.
next
();
n_iter
++
;
}
return
EXIT_SUCCESS
;
n_frames
++
;
}
// // iterator through all frames, not needed persee.
// // iterator through all frames, not needed persee.
// for (std::deque<eos::video::Keyframe>::iterator it = frames.begin(); it!=frames.end(); ++it) {
// for (std::deque<eos::video::Keyframe>::iterator it = frames.begin(); it!=frames.end(); ++it) {
// std::cout << it->score << " ";
// std::cout << it->score << " ";
// frame_count++;
// frame_count++;
// }
// }
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment