Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
py-3d-face-reconstruction
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
py-3d-face-reconstruction
Commits
f7da1d93
Commit
f7da1d93
authored
Jun 15, 2016
by
Richard Torenvliet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactoring a bit
parent
3c33b0b3
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
122 additions
and
75 deletions
+122
-75
actions.mk
actions.mk
+3
-1
src/main.py
src/main.py
+13
-21
src/pca.py
src/pca.py
+24
-9
src/utils/triangles.py
src/utils/triangles.py
+1
-1
src/view/reconstruct.py
src/view/reconstruct.py
+79
-41
src/view/templates/reconstruct.kv
src/view/templates/reconstruct.kv
+2
-2
No files found.
actions.mk
View file @
f7da1d93
...
...
@@ -6,7 +6,9 @@ data/imm_face_db: data/imm_face_db.tar.gz
tar
-xvzf
imm_face_db.tar.gz
-C
imm_face_db
)
train_model
:
data/pca_shape_model.npy data/pca_texture_model.npy
train_model
:
train_shape
train_texture
:
data/pca_texture_model.npy
train_shape
:
data/pca_shape_model.npy
data/imm_face_db.tar.gz
:
(
cd
data
;
wget http://www.imm.dtu.dk/~aam/datasets/imm_face_db.tar.gz
)
...
...
src/main.py
View file @
f7da1d93
...
...
@@ -84,16 +84,16 @@ def save_pca_model_texture(args):
assert
args
.
model_shape_file
,
'--model_texture_file needs to be provided to save the pca model'
assert
args
.
model_texture_file
,
'--model_texture_file needs to be provided to save the pca model'
Vt
,
s
,
mean_shape
,
triangles
=
pca
.
load
(
args
.
model_shape_file
)
Vt
,
s
,
n_components
,
mean_shape
,
triangles
=
pca
.
load
(
args
.
model_shape_file
)
textures
=
aam
.
build_texture_feature_vectors
(
args
.
files
,
imm
.
get_imm_image_with_landmarks
,
mean_shape
,
triangles
)
mean_texture
=
aam
.
get_mean
(
textures
)
_
,
s
,
Vt
=
pca
.
pca
(
textures
,
mean_texture
)
_
,
s
,
Vt
,
n_components
=
pca
.
pca
(
textures
,
mean_texture
)
pca
.
save
(
Vt
,
s
,
mean_texture
,
triangles
,
args
.
model_texture_file
)
pca
.
save
(
Vt
,
s
,
n_components
,
mean_texture
,
triangles
,
args
.
model_texture_file
)
logger
.
info
(
'texture pca model saved in %s'
,
args
.
model_texture_file
)
...
...
@@ -123,12 +123,12 @@ def save_pca_model_shape(args):
mean_values
=
aam
.
get_mean
(
points
)
_
,
s
,
Vt
=
pca
.
pca
(
points
,
mean_values
)
_
,
s
,
Vt
,
n_components
=
pca
.
pca
(
points
,
mean_values
)
mean_xy
=
mean_values
.
reshape
((
-
1
,
2
))
triangles
=
aam
.
get_triangles
(
mean_xy
[:,
0
],
mean_xy
[:,
1
])
pca
.
save
(
Vt
,
s
,
mean_values
,
triangles
,
args
.
model_shape_file
)
pca
.
save
(
Vt
,
s
,
n_components
,
mean_values
,
triangles
,
args
.
model_shape_file
)
logger
.
info
(
'shape pca model saved in %s'
,
args
.
model_shape_file
+
'_shape'
)
...
...
@@ -142,8 +142,9 @@ def reconstruct_with_model(args):
sys
.
argv
[
1
:]
=
[]
from
view.reconstruct
import
ReconstructApp
Vt_shape
,
mean_values_shape
,
triangles
=
pca
.
load
(
args
.
model_shape_file
)
Vt_texture
,
mean_values_texture
,
_
=
pca
.
load
(
args
.
model_texture_file
)
Vt_shape
,
s
,
n_shape_components
,
mean_values_shape
,
triangles
=
pca
.
load
(
args
.
model_shape_file
)
Vt_texture
,
s_texture
,
n_texture_components
,
mean_values_texture
,
_
=
pca
.
load
(
args
.
model_texture_file
)
app
=
ReconstructApp
()
...
...
@@ -152,7 +153,9 @@ def reconstruct_with_model(args):
eigenv_shape
=
Vt_shape
,
eigenv_texture
=
Vt_texture
,
mean_values_shape
=
mean_values_shape
,
n_shape_components
=
n_shape_components
,
mean_values_texture
=
mean_values_texture
,
n_texture_components
=
n_texture_components
,
triangles
=
triangles
)
...
...
@@ -165,19 +168,8 @@ def show_pca_model(args):
from
utils.triangles
import
draw_shape
,
draw_texture
Vt_shape
,
s
,
mean_values_shape
,
triangles
=
pca
.
load
(
args
.
model_shape_file
)
Vt_texture
,
s_texture
,
mean_values_texture
,
_
=
pca
.
load
(
args
.
model_texture_file
)
# calculate n_components which captures 90 percent of the variance
total
=
s_texture
.
sum
()
subtotal
=
0.0
i
=
0
while
(
subtotal
*
100.0
)
/
total
<=
90.0
:
subtotal
+=
s_texture
[
i
]
i
+=
1
n_components
=
i
Vt_shape
,
s
,
n_shape_components
,
mean_values_shape
,
triangles
=
pca
.
load
(
args
.
model_shape_file
)
Vt_texture
,
s_texture
,
n_texture_components
,
mean_values_texture
,
_
=
pca
.
load
(
args
.
model_texture_file
)
image
=
np
.
full
((
480
,
640
,
3
),
fill_value
=
255
,
dtype
=
np
.
uint8
)
...
...
@@ -195,7 +187,7 @@ def show_pca_model(args):
while
True
:
draw_texture
(
input_image
,
image
,
Vt_texture
,
input_points
,
mean_values_shape
,
mean_values_texture
,
triangles
)
mean_values_texture
,
triangles
,
n_texture_components
)
#draw_shape(image, mean_values_shape, triangles, multiply=False)
cv2
.
imshow
(
'input_image'
,
input_image
)
...
...
src/pca.py
View file @
f7da1d93
import
numpy
as
np
def
pca
(
data
,
mean_values
):
def
pca
(
data
,
mean_values
,
variance_percentage
=
90
):
"""
Perform Singlar Value Decomposition
...
...
@@ -14,10 +14,21 @@ def pca(data, mean_values):
zero_mean
=
data
-
mean_values
U
,
s
,
Vt
=
np
.
linalg
.
svd
(
zero_mean
,
full_matrices
=
False
)
return
U
,
s
,
Vt
# calculate n_components which captures 90 percent of the variance
total
=
s
.
sum
()
subtotal
=
0.0
i
=
0
while
(
subtotal
*
100.0
)
/
total
<=
variance_percentage
:
subtotal
+=
s
[
i
]
i
+=
1
def
reconstruct
(
feature_vector
,
Vt
,
mean_values
,
n_components
=
10
):
n_components
=
i
return
U
,
s
,
Vt
,
n_components
def
reconstruct
(
feature_vector
,
Vt
,
mean_values
,
n_components
=
None
):
"""
Reconstruct with U, s, Vt
...
...
@@ -28,15 +39,18 @@ def reconstruct(feature_vector, Vt, mean_values, n_components=10):
Vt (numpy ndarray): Two dimensional array with dimensions
(n_features, n_features)
mean_values (numpy ndarray): mean values of the features of the model,
this should have dimensions (n_featurs, )
this should have dimensions (n_featur
e
s, )
"""
if
n_components
is
None
:
n_components
=
Vt
.
shape
[
1
]
zm
=
feature_vector
-
mean_values
yk
=
np
.
dot
(
Vt
[:
n_components
],
zm
.
T
)
return
np
.
dot
(
Vt
[:
n_components
].
T
,
yk
)
+
mean_values
def
save
(
Vt
,
s
,
mean_values
,
triangles
,
filename
):
def
save
(
Vt
,
s
,
n_components
,
mean_values
,
triangles
,
filename
):
"""
Store the U, s, Vt and mean of all the asf datafiles given by the asf
files.
...
...
@@ -52,7 +66,7 @@ def save(Vt, s, mean_values, triangles, filename):
triangles = Vtm[2]
"""
saving
=
np
.
asarray
([
Vt
,
s
,
[
mean_values
],
triangles
])
saving
=
np
.
asarray
([
Vt
,
s
,
n_components
,
[
mean_values
],
triangles
])
np
.
save
(
filename
,
saving
)
...
...
@@ -77,10 +91,11 @@ def load(filename):
Vt
=
Vtm
[
0
]
s
=
Vtm
[
1
]
mean_values
=
Vtm
[
2
][
0
]
triangles
=
Vtm
[
3
]
n_components
=
Vtm
[
2
]
mean_values
=
Vtm
[
3
][
0
]
triangles
=
Vtm
[
4
]
return
Vt
,
s
,
mean_values
,
triangles
return
Vt
,
s
,
n_components
,
mean_values
,
triangles
def
flatten_feature_vectors
(
data
,
dim
=
0
):
...
...
src/utils/triangles.py
View file @
f7da1d93
...
...
@@ -67,7 +67,7 @@ def draw_shape(image, points, triangles, multiply=True):
cv2
.
circle
(
image
,
tuple
(
p
),
3
,
color
=
(
0
,
255
,
100
))
def
draw_texture
(
src
,
dest
,
Vt
,
points2d_src
,
points2d_dst
,
texture
,
triangles
):
def
draw_texture
(
src
,
dest
,
Vt
,
points2d_src
,
points2d_dst
,
texture
,
triangles
,
n_components
):
# texture = np.asarray(texture, dtype=np.uint8).reshape((-1, 3))
texture
=
np
.
asarray
(
texture
,
np
.
uint8
)
offset
=
0
...
...
src/view/reconstruct.py
View file @
f7da1d93
...
...
@@ -20,6 +20,8 @@ from functools import partial
from
math
import
cos
,
sin
,
pi
import
imm_points
as
imm
from
utils.triangles
import
draw_texture
from
utils.generate_head_texture
import
fill_triangle
#import IMMPoints, build_feature_vectors, \
# flatten_feature_vectors
import
pca
...
...
@@ -76,48 +78,53 @@ class ImageCanvas(Widget):
self
.
canvas
.
ask_update
()
def
build_texture
(
self
,
r_shape
,
r_texture
,
triangles
):
self
.
texture
.
clear
()
return
#self.texture.clear()
image_width
,
image_height
=
self
.
get_rendered_size
()
#
image_width, image_height = self.get_rendered_size()
bary_centric_range
=
np
.
linspace
(
0
,
1
,
num
=
20
)
texture
=
Texture
.
create
(
size
=
(
image_width
,
image_height
),
colorfmt
=
'bgr'
)
buf
=
np
.
zeros
((
image_width
,
image_height
,
3
),
dtype
=
np
.
uint8
)
#
bary_centric_range = np.linspace(0, 1, num=20)
#
texture = Texture.create(size=(image_width, image_height), colorfmt='bgr')
#
buf = np.zeros((image_width, image_height, 3), dtype=np.uint8)
for
tri
in
triangles
[:
1
]:
points
=
r_shape
[
tri
]
pixels
=
r_texture
[
tri
].
reshape
((
-
1
,
3
))
#offset = 0
x
=
points
[:,
0
]
*
image_width
+
self
.
get_image_left
(
image_width
)
y
=
(
1.0
-
points
[:,
1
])
*
image_height
+
self
.
get_image_bottom
(
image_height
)
#for t, tri in enumerate(triangles):
# src_p1, src_p2, src_p3 = r_shape[tri]
# x = r_shape[:, 0] * image_width + self.get_image_left(image_width)
# y = (1.0 - r_shape[:, 1]) * image_height + self.get_image_bottom(image_height)
p1
=
[
x
[
0
],
y
[
0
]]
p2
=
[
x
[
1
],
y
[
1
]]
p3
=
[
x
[
2
],
y
[
2
]]
# for t, tri in enumerate(triangles):
# offset += fill_triangle(
# r_texture, buf,
# src_p1[0], src_p1[1],
# src_p2[0], src_p2[1],
# src_p3[0], src_p3[1],
# dst_p1[0], dst_p1[1],
# dst_p2[0], dst_p2[1],
# dst_p3[0], dst_p3[1],
# offset,
# t
# )
L
=
np
.
zeros
((
3
,
1
))
# print offset
for
s_i
,
s
in
enumerate
(
bary_centric_range
):
for
t_i
,
t
in
enumerate
(
bary_centric_range
):
if
s
+
t
<=
1
:
# build lambda's
L
[
0
]
=
s
L
[
1
]
=
t
L
[
2
]
=
1
-
s
-
t
# #p1 = [x[0], y[0]]
# #p2 = [x[1], y[1]]
# #p3 = [x[2], y[2]]
cart_x
,
cart_y
,
_
=
aam
.
barycentric2cartesian
(
p1
,
p2
,
p3
,
L
)
buf
[
s_i
,
t_i
,
:]
=
pixels
[
s_i
*
20
+
t_i
,
:]
#buf = b''.join(map(chr, buf))
cv2
.
imshow
(
'image'
,
buf
)
cv2
.
waitKey
(
0
)
#
#
buf = b''.join(map(chr, buf))
#
cv2.imshow('image', buf)
#
cv2.waitKey(0)
#texture.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')
#self.texture.add(Rectangle(texture=texture, pos=(0, 100),
# size=(image_width, image_height)))
self
.
canvas
.
add
(
self
.
texture
)
self
.
canvas
.
ask_update
()
#
self.canvas.add(self.texture)
#
self.canvas.ask_update()
def
build_line_grid
(
self
,
r_shape
,
triangles
):
...
...
@@ -175,28 +182,40 @@ class RootWidget(BoxLayout):
self
.
eigenv_shape
=
kwargs
[
'eigenv_shape'
]
self
.
eigenv_texture
=
kwargs
[
'eigenv_texture'
]
self
.
triangles
=
kwargs
[
'triangles'
]
self
.
n_components
=
kwargs
[
'args'
].
n_components
self
.
n_shape_components
=
kwargs
[
'args'
].
n_components
self
.
n_texture_components
=
kwargs
[
'n_texture_components'
]
self
.
multipliers
=
np
.
ones
(
self
.
eigenv_shape
.
shape
[
1
])
self
.
mean_values_shape_reshaped
=
np
.
copy
(
self
.
mean_values_shape
).
reshape
((
58
,
2
))
# slider index
self
.
index
=
0
self
.
filename
=
''
self
.
shape_list
=
aam
.
build_shape_feature_vectors
(
self
.
files
,
imm
.
get_imm_points
,
flattened
=
True
)
# sliders
self
.
add_shape_sliders
()
self
.
add_image_slider
()
self
.
add_components_slider
()
# ======= #
# event binders
self
.
ids
[
'image_viewer'
].
bind
(
size
=
self
.
on_resize
)
def
add_components_slider
(
self
):
n_components_slider
=
self
.
ids
[
'n_shape_components'
]
n_components_slider
.
value
=
self
.
n_shape_components
n_components_slider
.
bind
(
value
=
self
.
update_n_components
)
def
add_image_slider
(
self
):
image_slider
=
self
.
ids
[
'image_slider'
]
image_slider
.
max
=
len
(
self
.
files
)
-
1
image_slider
.
bind
(
value
=
self
.
update_image
)
n_components_slider
=
self
.
ids
[
'n_components'
]
n_components_slider
.
value
=
self
.
n_components
n_components_slider
.
bind
(
value
=
self
.
update_n_components
)
self
.
ids
[
'image_viewer'
].
bind
(
size
=
self
.
on_resize
)
def
add_shape_sliders
(
self
):
box_layout
=
self
.
ids
[
'eigenvalues'
]
self
.
shape_list
=
aam
.
build_shape_feature_vectors
(
self
.
files
,
imm
.
get_imm_points
,
flattened
=
True
)
for
c
in
range
(
self
.
n_components
):
for
c
in
range
(
self
.
n_shape_components
):
slider
=
Slider
(
min
=-
10
,
max
=
10
,
value
=
0
,
id
=
str
(
c
))
box_layout
.
add_widget
(
slider
)
slider
.
bind
(
value
=
self
.
update_eigenvalues
)
...
...
@@ -215,10 +234,26 @@ class RootWidget(BoxLayout):
r_shape
=
pca
.
reconstruct
(
self
.
shape_list
[
self
.
index
],
Vt_shape
,
self
.
mean_values_shape
,
n_components
=
self
.
n_components
n_components
=
self
.
n_
shape_
components
).
reshape
((
-
1
,
2
))
# image = cv2.imread(self.filename)
#image = cv2.imread(self.filename)
#h, w = image.shape[0], image.shape[1]
#mean_values_shape = np.copy(self.mean_values_shape_reshaped)
#mean_values_shape[:, 0] = mean_values_shape[:, 0] * w
#mean_values_shape[:, 1] = mean_values_shape[:, 1] * h
#texture = aam.sample_from_triangles(
# image, r_shape, mean_values_shape, self.triangles
#)
#r_texture = pca.reconstruct(
# texture, self.eigenv_texture, self.mean_values_texture
#)
#r_texture = np.asarray(texture, np.uint8)
# pixels = aam.sample_from_triangles(image, r_shape, self.triangles)
# pixels = np.ndarray.flatten(pixels)
...
...
@@ -230,12 +265,13 @@ class RootWidget(BoxLayout):
self
.
ids
[
'image_viewer'
].
update_rect
()
self
.
ids
[
'image_viewer'
].
update_image
(
self
.
filename
)
self
.
ids
[
'image_viewer'
].
build_line_grid
(
r_shape
,
self
.
triangles
)
#self.ids['image_viewer'].build_texture(r_shape, r_texture, self.triangles)
def
on_resize
(
self
,
*
args
):
self
.
update_image_viewer
()
def
update_n_components
(
self
,
slider
,
index
):
self
.
n_components
=
int
(
index
)
self
.
n_
shape_
components
=
int
(
index
)
self
.
update_image_viewer
()
def
update_image
(
self
,
slider
,
index
):
...
...
@@ -265,7 +301,9 @@ class ReconstructApp(App):
eigenv_shape
=
self
.
eigenv_shape
,
eigenv_texture
=
self
.
eigenv_texture
,
mean_values_shape
=
self
.
mean_values_shape
,
n_shape_components
=
self
.
n_shape_components
,
mean_values_texture
=
self
.
mean_values_texture
,
n_texture_components
=
self
.
n_texture_components
,
triangles
=
self
.
triangles
)
...
...
src/view/templates/reconstruct.kv
View file @
f7da1d93
...
...
@@ -27,9 +27,9 @@
max: 100
value: 0
Label:
text: "Using {} components".format(int(n_components.value))
text: "Using {} components".format(int(n_
shape_
components.value))
Slider:
id: n_components
id: n_
shape_
components
min: 0
max: 58
value: 0
...
...
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