Commit 265501fa authored by Richard Torenvliet's avatar Richard Torenvliet

Update build script and worked on texture model creation

parent 6ae2cffe
...@@ -2,8 +2,12 @@ ...@@ -2,8 +2,12 @@
Run the following command Run the following command
~~~~ ~~~~
$ make $ make
$ source bin/activate
$ make show_reconstruction
~~~~ ~~~~
Will get the data needed for this tool. Will get the data needed for this tool.
## References ## References
......
TARGETS += data/pca_shape_train_model.npy
.PHONY := train_model show_pca test_model show_reconstruction
data/imm_face_db: data/imm_face_db.tar.gz
(cd data; mkdir -p imm_face_db; \
tar -xvzf imm_face_db.tar.gz -C imm_face_db
)
train_model: data/pca_shape_model.npy data/pca_texture_model.npy
data/imm_face_db.tar.gz:
(cd data; wget http://www.imm.dtu.dk/~aam/datasets/imm_face_db.tar.gz)
data/pca_shape_model.npy:
python src/main.py \
--save_pca_shape \
--asf `./scripts/imm_train_set.sh` \
--model_shape_file data/pca_shape_model
data/pca_texture_model.npy:
python src/main.py \
--save_pca_texture \
--asf `./scripts/imm_train_set.sh` \
--model_texture_file data/pca_texture_model \
--model_shape_file data/pca_shape_model.npy
show_pca:
python src/main.py \
--show_pca \
--asf data/imm_face_db/*.asf \
--model_shape_file data/pca_model.npy
test_model:
python src/main.py \
--reconstruct \
--asf `./scripts/imm_test_set.sh` \
--model_shape_file data/pca_shape_model.npy \
--n_components 6
show_reconstruction:
python src/main.py \
--reconstruct \
--asf data/imm_face_db/*.asf \
--model_shape_file data/pca_shape_model.npy \
--model_texture_file data/pca_texture_model.npy \
--n_components 6
test:
python -m py.test -f src/*_test.py
all: data VIRTUALENV := venv
PYTHON := python2.7
PYTHON_BIN_PATH := /usr/local/bin/$(PYTHON)
SITE_PACKAGES := $(VIRTUALENV)/lib/$(PYTHON)/site-packages
data: data/imm_face_db OPENCV:= $(SITE_PACKAGES)/cv.py $(SITE_PACKAGES)/cv2.so
data/imm_face_db: data/imm_face_db.tar.gz
(cd data; mkdir -p imm_face_db; \
tar -xvzf imm_face_db.tar.gz -C imm_face_db
)
data/imm_face_db.tar.gz: TARGETS:= $(VIRTUALENV) data build
(cd data; wget http://www.imm.dtu.dk/~aam/datasets/imm_face_db.tar.gz) all: $(TARGETS)
train_model: data/pca_train_model.npy include actions.mk
python src/main.py \ include build.mk
--save_pca \
--asf data/imm_face_db/*.asf \
--model_file data/pca_train_model
show_pca: data: data/imm_face_db
python src/main.py \
--show_pca \
--asf data/imm_face_db/*.asf \
--model_file data/pca_model.npy
test_model: build: $(OPENCV)
python src/main.py \ @(source $(VIRTUALENV)/bin/activate; \
--reconstruct \ pip install -r requirements.txt; \
--asf `./scripts/imm_test_set.sh` \ );
--model_file data/pca_train_model.npy \
--n_components 6
show_reconstruction: $(VIRTUALENV):
python src/main.py \ virtualenv -p $(PYTHON_BIN_PATH) venv
--reconstruct \
--asf data/imm_face_db/*.asf \
--model_file data/pca_train_model.npy \
--n_components 6
test: $(SITE_PACKAGES)/cv%:
python -m py.test -f src/*_test.py @/bin/ln -s `scripts/get_site_package_location.sh`/$(shell basename $@) $@
@ls $@
cycler==0.10.0
Cython==0.24
Kivy==1.9.1
Kivy-Garden==0.1.4
matplotlib==1.5.1
numpy==1.11.0
pyparsing==2.1.2
python-dateutil==2.5.3
pytz==2016.4
requests==2.10.0
six==1.10.0
#!/bin/bash
python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"
import logging
from matplotlib.tri import Triangulation from matplotlib.tri import Triangulation
import numpy as np import numpy as np
import cv2 import cv2
import pca import pca
from utils.generate_head_texture import fill_triangle, get_colors_triangle
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(levelname)s %(name)s: %(message)s')
logger = logging.getLogger(__name__)
def get_mean(imm_points):
def get_mean(vector):
""" construct a mean from a matrix of x,y values """ construct a mean from a matrix of x,y values
Args: Args:
imm_points(numpy array) that follows the following structure: imm_points(numpy array) that follows the following structure:
...@@ -36,7 +43,7 @@ def get_mean(imm_points): ...@@ -36,7 +43,7 @@ def get_mean(imm_points):
mean. [[x_mean_0, y_mean_0], ... [x_mean_n, y_mean_n]] mean. [[x_mean_0, y_mean_0], ... [x_mean_n, y_mean_n]]
""" """
return np.mean(imm_points, axis=0) return np.mean(vector, axis=0)
def get_triangles(x_vector, y_vector): def get_triangles(x_vector, y_vector):
...@@ -63,6 +70,97 @@ def build_feature_vectors(files, get_points, flattened=False): ...@@ -63,6 +70,97 @@ def build_feature_vectors(files, get_points, flattened=False):
return points return points
def cartesian2barycentric(r1, r2, r3, r):
x, y = r
x1, y1 = r1
x2, y2 = r2
x3, y3 = r3
a = np.array([[x1, x2, x3], [y1, y2, y3], [1, 1, 1]])
b = np.array([x, y, 1])
return np.linalg.solve(a, b)
def barycentric2cartesian(r1, r2, r3, L):
x1, y1 = r1
x2, y2 = r2
x3, y3 = r3
a = np.array([[x1, x2, x3], [y1, y2, y3], [1, 1, 1]])
b = np.array(L)
return np.asarray(np.dot(a, b), dtype=np.uint32)
def sample_from_triangles(b, points2d_b, triangles, n_samples=20):
all_triangles = []
h, w, c = b.shape
for tri in triangles:
p1_b = points2d_b[tri[0]]
p2_b = points2d_b[tri[1]]
p3_b = points2d_b[tri[2]]
cv2.line(b,
tuple(p1_b),
tuple(p2_b), (0, 255, 0), 1)
cv2.line(b,
tuple(p2_b),
tuple(p3_b), (0, 255, 0), 1)
cv2.line(b,
tuple(p3_b),
tuple(p1_b), (0, 255, 0), 1)
bary_centric_range = np.linspace(0, 1, num=n_samples)
pixels = np.full((n_samples * n_samples, 3), fill_value=-1, dtype=np.int)
L = np.zeros((3, 1))
for s_i, s in enumerate(bary_centric_range):
for t_i, t in enumerate(bary_centric_range):
# make sure the coordinates are inside the triangle
if s + t <= 1:
# build lambda's
L[0] = s
L[1] = t
L[2] = 1 - s - t
# cartesian x, y coordinates inside the triangle
cart_x, cart_y, _ = barycentric2cartesian(p1_b, p2_b, p3_b, L)
pixels[s_i * n_samples + t_i, :] = b[cart_y, cart_x, :]
# cv2.circle(b, tuple([cart_x, cart_y]), 1, color=(0, 255, 100))
all_triangles.append(pixels[np.where(pixels >= 0)])
return np.asarray(all_triangles, dtype=np.uint8)
def build_texture_feature_vector(files, get_image_with_landmarks, triangles):
mean_texture = []
for i, f in enumerate(files[:10]):
image, landmarks = get_image_with_landmarks(f)
h, w, c = image.shape
landmarks[:, 0] = landmarks[:, 0] * w
landmarks[:, 1] = landmarks[:, 1] * h
triangles_colors = sample_from_triangles(
image, landmarks, triangles
)
mean_texture.append(triangles_colors)
logger.info('processed file: {} {}/{}'.format(f, i, len(files)))
# cv2.imshow('image', image)
# k = cv2.waitKey(0) & 0xFF
# if k == 27:
# break
return np.asarray(mean_texture)
def get_pixel_values(image, points): def get_pixel_values(image, points):
h, w, c = image.shape h, w, c = image.shape
...@@ -78,16 +176,16 @@ def get_pixel_values(image, points): ...@@ -78,16 +176,16 @@ def get_pixel_values(image, points):
x, y, w, h = rect x, y, w, h = rect
# pixels = np.zeros((h, w, c), dtype=np.uint8) # pixels = np.zeros((h, w, c), dtype=np.uint8)
for i in np.linspace(0, 1, num=150):
for i in np.linspace(0, 1, num=100): for j in np.linspace(0, 1, num=150):
for j in np.linspace(0, 1, num=100):
y_loc_g = int(i * h + y) y_loc_g = int(i * h + y)
x_loc_g = int(j * w + x) x_loc_g = int(j * w + x)
y_loc = min(int(i * h), h - 1)
x_loc = min(int(j * w), w - 1)
if cv2.pointPolygonTest(hull, (x_loc_g, y_loc_g), measureDist=False) >= 0: if cv2.pointPolygonTest(hull, (x_loc_g, y_loc_g), measureDist=False) >= 0:
image[y_loc_g][x_loc_g][0] = 0
image[y_loc_g][x_loc_g][1] = 0
image[y_loc_g][x_loc_g][2] = 0
pixels.extend(image[y_loc_g][x_loc_g]) pixels.extend(image[y_loc_g][x_loc_g])
return np.asarray(pixels, dtype=np.uint8), hull # return np.asarray(pixels, dtype=np.uint8), hull
return image, hull
import numpy as np import numpy as np
from aam import get_mean, get_pixel_values
import imm_points import imm_points
import cv2
import aam
import pca import pca
...@@ -16,7 +17,7 @@ def test_build_mean_aan(): ...@@ -16,7 +17,7 @@ def test_build_mean_aan():
[2.5, 5.] [2.5, 5.]
]) ])
mean = get_mean(imm_points) mean = aam.get_mean(imm_points)
np.testing.assert_array_equal(mean, expected) np.testing.assert_array_equal(mean, expected)
...@@ -32,7 +33,7 @@ def test_zero_mean_aan(): ...@@ -32,7 +33,7 @@ def test_zero_mean_aan():
[0.5, 0.5, 0.5, 1.0], [0.5, 0.5, 0.5, 1.0],
]) ])
mean = get_mean(imm_points) mean = aam.get_mean(imm_points)
zero_mean = imm_points - mean zero_mean = imm_points - mean
# test that zero mean has indeed zero mean # test that zero mean has indeed zero mean
...@@ -50,6 +51,49 @@ def test_get_pixel_values(): ...@@ -50,6 +51,49 @@ def test_get_pixel_values():
points = imm.get_points() points = imm.get_points()
image = imm.get_image() image = imm.get_image()
pixels, hull = get_pixel_values(image, points) pixels, hull = aam.get_pixel_values(image, points)
def test_sample_from_triangles():
blue_points = [[20, 20], [50, 160], [160, 20],
[50, 20], [60, 200], [180, 20]]
red_points = [[40, 80], [130, 150], [40, 150],
[40, 80], [60, 82], [60, 100]]
# blue_image = cv2.imread('../data/test_data/blue.png')
#red_image = cv2.imread('../data/test_data/red.png')
blue_image = cv2.imread('../data/imm_face_db/01-1m.jpg')
red_image = cv2.imread('../data/imm_face_db/02-1m.jpg')
triangles = [[0, 1, 2]]
for tri in triangles:
cv2.line(blue_image,
tuple(blue_points[tri[0]]),
tuple(blue_points[tri[1]]), (0, 255, 0), 1)
cv2.line(blue_image,
tuple(blue_points[tri[1]]),
tuple(blue_points[tri[2]]), (0, 255, 0), 1)
cv2.line(blue_image,
tuple(blue_points[tri[2]]),
tuple(blue_points[tri[0]]), (0, 255, 0), 1)
for tri in triangles:
cv2.line(red_image,
tuple(red_points[tri[0]]),
tuple(red_points[tri[1]]), (0, 255, 0), 1)
cv2.line(red_image,
tuple(red_points[tri[1]]),
tuple(red_points[tri[2]]), (0, 255, 0), 1)
cv2.line(red_image,
tuple(red_points[tri[2]]),
tuple(red_points[tri[0]]), (0, 255, 0), 1)
all_triangles = aam.sample_from_triangles(
red_image, red_points, triangles
)
assert False cv2.imshow('blue_image', blue_image)
cv2.imshow('red_image', red_image)
cv2.waitKey(0)
...@@ -24,7 +24,6 @@ class IMMPoints(): ...@@ -24,7 +24,6 @@ class IMMPoints():
return self.points return self.points
def get_image(self): def get_image(self):
cv2.imread(self.image_file)
return cv2.imread(self.image_file) return cv2.imread(self.image_file)
def import_file(self, filename): def import_file(self, filename):
...@@ -39,7 +38,8 @@ class IMMPoints(): ...@@ -39,7 +38,8 @@ class IMMPoints():
self.points = np.asarray(self.points, dtype='f') self.points = np.asarray(self.points, dtype='f')
def draw_triangles(self, img, points): def draw_triangles(self, img, points, multiply=True):
if multiply:
h, w, c = img.shape h, w, c = img.shape
points[:, 0] = points[:, 0] * w points[:, 0] = points[:, 0] * w
...@@ -60,8 +60,8 @@ class IMMPoints(): ...@@ -60,8 +60,8 @@ class IMMPoints():
cv2.FONT_HERSHEY_SIMPLEX, .5, (100, 0, 255)) cv2.FONT_HERSHEY_SIMPLEX, .5, (100, 0, 255))
cv2.circle(img, tuple(p), 3, color=(0, 255, 100)) cv2.circle(img, tuple(p), 3, color=(0, 255, 100))
def show_on_img(self, img, window_name='image'): def show_on_img(self, img, window_name='image', multiply=True):
self.draw_triangles(img, self.points) self.draw_triangles(img, self.points, multiply=multiply)
def show(self, window_name='image'): def show(self, window_name='image'):
"""show the image and datapoints on the image""" """show the image and datapoints on the image"""
...@@ -83,6 +83,11 @@ def get_imm_landmarks(files): ...@@ -83,6 +83,11 @@ def get_imm_landmarks(files):
return np.asarray(points) return np.asarray(points)
def get_imm_image_with_landmarks(filename):
imm = IMMPoints(filename=filename)
return imm.get_image(), imm.get_points()
def add_parser_options(): def add_parser_options():
parser = argparse.ArgumentParser(description='IMMPoints tool') parser = argparse.ArgumentParser(description='IMMPoints tool')
......
...@@ -22,8 +22,13 @@ def add_parser_options(): ...@@ -22,8 +22,13 @@ def add_parser_options():
) )
pca_group.add_argument( pca_group.add_argument(
'--save_pca', action='store_true', '--save_pca_shape', action='store_true',
help='save the pca model' help='save the pca shape model'
)
pca_group.add_argument(
'--save_pca_texture', action='store_true',
help='save the pca texture model'
) )
pca_group.add_argument( pca_group.add_argument(
...@@ -42,14 +47,53 @@ def add_parser_options(): ...@@ -42,14 +47,53 @@ def add_parser_options():
) )
pca_group.add_argument( pca_group.add_argument(
'--model_file', type=str, '--model_shape_file', type=str,
help='pca model file that contains or is going to contain the pca model' help='pca model file that contains or is going to contain the pca shape model'
)
pca_group.add_argument(
'--model_texture_file', type=str,
help='pca model file that contains or is going to contain the pca texture model'
) )
return parser return parser
def save_pca_model(args): def save_pca_model_texture(args):
"""
save the U, s, Vt and mean of all the asf datafiles given by the asf
files.
It is saved in the following way:
np.load(filename, np.assary([Vt, mean_values])
And accessed by:
Vtm = np.load(args.model_file_texture)
Vt = Vtm[0]
mean_values = Vtm[1][0]
"""
assert args.asf, '--asf files should be given'
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, mean_values, triangles = pca.load(args.model_shape_file)
textures = aam.build_texture_feature_vector(
args.asf, imm.get_imm_image_with_landmarks, triangles
)
mean_texture = aam.get_mean(textures)
_, _, Vt = pca.pca(textures, mean_texture)
pca.save(Vt, mean_texture, triangles, args.model_texture_file)
logger.info('texture pca model saved in %s', args.model_texture_file)
def save_pca_model_shape(args):
""" """
save the U, s, Vt and mean of all the asf datafiles given by the asf save the U, s, Vt and mean of all the asf datafiles given by the asf
files. files.
...@@ -60,36 +104,32 @@ def save_pca_model(args): ...@@ -60,36 +104,32 @@ def save_pca_model(args):
And accessed by: And accessed by:
Vtm = np.load(args.model_file) Vtm = np.load(args.model_shape_file)
Vt = Vtm[0] Vt = Vtm[0]
mean_values = Vtm[1][0] mean_values = Vtm[1][0]
""" """
assert args.asf, '--asf files should be given' assert args.asf, '--asf files should be given'
assert args.model_file, '--model_file needs to be provided to save the pca model' assert args.model_shape_file, '--model_shape_file needs to be provided to save the pca model'
points = aam.build_feature_vectors(args.asf, points = aam.build_feature_vectors(args.asf,
imm.get_imm_landmarks, flattened=True) imm.get_imm_landmarks, flattened=True)
mean_values = aam.get_mean(points) mean_values = aam.get_mean(points)
_, _, Vt = pca.pca(points, mean_values) _, _, Vt = pca.pca(points, mean_values)
pca.save(Vt, mean_values, args.model_file) mean_xy = mean_values.reshape((-1, 2))
triangles = aam.get_triangles(mean_xy[:, 0], mean_xy[:, 1])
logger.info('saved pca model in %s', args.model_file) pca.save(Vt, mean_values, triangles, args.model_shape_file)
logger.info('shape pca model saved in %s', args.model_shape_file + '_shape')
def show_pca_model(args):
assert args.asf, '--asf files should be given to allow the image to be shown'
assert args.model_file, '--model_file needs to be provided to get the pca model'
Vt, mean_values = pca.load(args.model_file)
def reconstruct_with_model(args): def reconstruct_with_model(args):
assert args.asf, '--asf files should be given to allow the image to be shown' assert args.asf, '--asf files should be given to allow the image to be shown'
assert args.model_file, '--model_file needs to be provided to get the pca model' assert args.model_shape_file, '--model_shape_file needs to be provided to get the pca model'
# clear sys args. arguments are conflicting with parseargs # clear sys args. arguments are conflicting with parseargs
# kivy will parse args upon import and will crash if it finds our # kivy will parse args upon import and will crash if it finds our
...@@ -97,24 +137,33 @@ def reconstruct_with_model(args): ...@@ -97,24 +137,33 @@ def reconstruct_with_model(args):
sys.argv[1:] = [] sys.argv[1:] = []
from view.reconstruct import ReconstructApp 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)
app = ReconstructApp()
app.set_values(
args=args,
eigenv_shape=Vt_shape,
eigenv_texture=Vt_texture,
mean_values_shape=mean_values_shape,
mean_values_texture=mean_values_texture,
triangles=triangles
)
Vt, mean_values = pca.load(args.model_file) app.run()
ReconstructApp(
args=args, eigen_vectors=Vt, mean_values=mean_values,
).run()
def main(): def main():
parser = add_parser_options() parser = add_parser_options()
args = parser.parse_args() args = parser.parse_args()
if args.show_pca: if args.save_pca_shape:
show_pca_model(args) save_pca_model_shape(args)
elif args.save_pca: elif args.save_pca_texture:
save_pca_model(args) save_pca_model_texture(args)
elif args.reconstruct: elif args.reconstruct:
reconstruct_with_model(args) reconstruct_with_model(args)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
...@@ -36,7 +36,7 @@ def reconstruct(feature_vector, Vt, mean_values, n_components=10): ...@@ -36,7 +36,7 @@ def reconstruct(feature_vector, Vt, mean_values, n_components=10):
return np.dot(Vt[:n_components].T, yk) + mean_values return np.dot(Vt[:n_components].T, yk) + mean_values
def save(Vt, mean_values, filename): def save(Vt, mean_values, triangles, filename):
""" """
Store the U, s, Vt and mean of all the asf datafiles given by the asf Store the U, s, Vt and mean of all the asf datafiles given by the asf
files. files.
...@@ -49,9 +49,10 @@ def save(Vt, mean_values, filename): ...@@ -49,9 +49,10 @@ def save(Vt, mean_values, filename):
Vt = Vtm[0] Vt = Vtm[0]
mean_values = Vtm[1][0] mean_values = Vtm[1][0]
triangles = Vtm[2]
""" """
saving = np.asarray([Vt, [mean_values]]) saving = np.asarray([Vt, [mean_values], triangles])
np.save(filename, saving) np.save(filename, saving)
...@@ -76,8 +77,9 @@ def load(filename): ...@@ -76,8 +77,9 @@ def load(filename):
Vt = Vtm[0] Vt = Vtm[0]
mean_values = Vtm[1][0] mean_values = Vtm[1][0]
triangles = Vtm[2]
return Vt, mean_values return Vt, mean_values, triangles
def flatten_feature_vectors(data): def flatten_feature_vectors(data):
......
This diff is collapsed.
cimport cython
import numpy as np
cimport numpy as np
from cpython cimport array as c_array
DTYPE_Int = np.int
ctypedef np.int_t DTYPE_t
cdef inline float cross_product(int v1_x, int v1_y, int v2_x, int v2_y):
# Cross product of two 2d vectors
return (v1_x * v2_y) - (v1_y * v2_x)
@cython.boundscheck(False)
@cython.wraparound(False)
def fill_triangle(np.ndarray[unsigned char, ndim=3] src,
np.ndarray[unsigned char, ndim=3] dst,
int x1, int y1, int x2, int y2, int x3, int y3):
"""
Fill a triangle by applying the Barycentric Algorithm for deciding if a
point lies inside or outside a triangle.
"""
# Get the bounding box of the triangle
cdef int x_min = min(x1, min(x2, x3))
cdef int x_max = max(x1, max(x2, x3))
cdef int y_min = min(y1, min(y2, y3))
cdef int y_max = max(y1, max(y2, y3))
cdef int vs1_x = x2 - x1
cdef int vs1_y = y2 - y1
cdef int vs2_x = x3 - x1
cdef int vs2_y = y3 - y1
cdef float s
cdef float t
for y in xrange(y_min, y_max):
for x in xrange(x_min, x_max):
q_x = x - x1
q_y = y - y1
s = cross_product(q_x, q_y, vs2_x, vs2_y) / \
cross_product(vs1_x, vs1_y, vs2_x, vs2_y)
t = cross_product(vs1_x, vs1_y, q_x, q_y) / \
cross_product(vs1_x, vs1_y, vs2_x, vs2_y)
if s >= 0 and t >= 0 and s + t <= 1:
dst[y, x, :] = src[y, x, :]
def get_colors_triangle(np.ndarray[unsigned char, ndim=3] src,
np.ndarray[unsigned char, ndim=3] dst,
int x1, int y1, int x2, int y2, int x3, int y3):
"""
Fill a triangle by applying the Barycentric Algorithm for deciding if a
point lies inside or outside a triangle.
"""
# Get the bounding box of the triangle
cdef int x_min = min(x1, min(x2, x3))
cdef int x_max = max(x1, max(x2, x3))
cdef int y_min = min(y1, min(y2, y3))
cdef int y_max = max(y1, max(y2, y3))
cdef int vs1_x = x2 - x1
cdef int vs1_y = y2 - y1
cdef int vs2_x = x3 - x1
cdef int vs2_y = y3 - y1
cdef float s
cdef float t
y_count = 0
x_count = 0
for y in xrange(y_min, y_max):
for x in xrange(x_min, x_max):
a = np.ndarray([[x1, x2, x3], [y1, y2, y3], [1, 1, 1]], dtype=DTYPE_Int)
b = np.ndarray([x, y, 1], dtype=DTYPE_Int)
L = np.solve(a, b)
#L[0]
#if s >= 0 and t >= 0 and s + t <= 1:
# dst[y_count * x_max + x_count] = src[y, x, :]
# y_count += 1
# x_count += 1
import numpy as np
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
extensions = [
Extension(
"generate_head_texture",
["generate_head_texture.pyx"],
include_dirs=[np.get_include()],
)]
setup(
ext_modules=cythonize(extensions),
)
import cv2
class ViewState():
def __init__(self):
self.variables = {}
def update(self, key, value):
self.variables[key] = value
def init_eigenvalue_trackbars(n_components, s, callback, window='image'):
cv2.namedWindow(window)
for i in range(n_components):
cv2.createTrackbar('{}'.format(i), 'eigenvalues', 50, 100, callback)
def eigenCallback(x):
global reconstructed
imm_orig = IMMPoints(filename=args.asf[index])
img = cv2.imread('data/imm_face_db/' + imm_orig.filename)
yk = np.dot(Vt[:n_components], X[index].T)
reconstructed = (np.dot(Vt[:n_components].T, yk) + mean_values).reshape((58, 2))
imm_orig.show_on_img(img)
cv2.imshow('image', img)
import cv2
from imm_points import IMMPoints
state = {}
def cb(index):
state['index'] = index
imm_orig = IMMPoints(filename=index)
state['imm_original'] = imm_orig
img = cv2.imread('data/imm_face_db/' + imm_orig.filename)
imm_orig.show_on_img(img)
cv2.imshow('image', img)
...@@ -28,6 +28,7 @@ class ImageCanvas(Widget): ...@@ -28,6 +28,7 @@ class ImageCanvas(Widget):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(ImageCanvas, self).__init__(**kwargs) super(ImageCanvas, self).__init__(**kwargs)
# TODO: don't init with a picture, we shouldnt have that knowlegde
self.filename_image = 'data/imm_face_db/40-1m.jpg' self.filename_image = 'data/imm_face_db/40-1m.jpg'
self.canvas.clear() self.canvas.clear()
...@@ -35,6 +36,7 @@ class ImageCanvas(Widget): ...@@ -35,6 +36,7 @@ class ImageCanvas(Widget):
self.image = Image(pos=self.pos, size=self.size, source=self.filename_image) self.image = Image(pos=self.pos, size=self.size, source=self.filename_image)
self.mesh = Mesh(mode='triangle_fan') self.mesh = Mesh(mode='triangle_fan')
self.triangles = InstructionGroup() self.triangles = InstructionGroup()
self.texture = InstructionGroup()
self.outline = InstructionGroup() self.outline = InstructionGroup()
self.bind(pos=self.update_rect, size=self.update_rect) self.bind(pos=self.update_rect, size=self.update_rect)
...@@ -71,15 +73,24 @@ class ImageCanvas(Widget): ...@@ -71,15 +73,24 @@ class ImageCanvas(Widget):
self.image.source = self.filename_image self.image.source = self.filename_image
self.canvas.ask_update() self.canvas.ask_update()
def build_line_grid(self, reconstructed): def build_texture(self, r_texture, triangles):
self.texture.clear()
image_width, image_height = self.get_rendered_size()
self.triangles.add(Line(circle=(100, 200, 10)))
self.canvas.add(self.texture)
self.canvas.ask_update()
def build_line_grid(self, r_shape, triangles):
self.triangles.clear() self.triangles.clear()
image_width, image_height = self.get_rendered_size() image_width, image_height = self.get_rendered_size()
triangles = aam.get_triangles(reconstructed[:, 0], reconstructed[:, 1])
for tri in triangles: for tri in triangles:
self.triangles.add(Color(0, 0, 1, 1)) self.triangles.add(Color(0, 0, 1, 1))
points = reconstructed[tri] points = r_shape[tri]
x = points[:, 0] * image_width + self.get_image_left(image_width) x = points[:, 0] * image_width + self.get_image_left(image_width)
y = (1.0 - points[:, 1]) * image_height + self.get_image_bottom(image_height) y = (1.0 - points[:, 1]) * image_height + self.get_image_bottom(image_height)
...@@ -96,13 +107,13 @@ class ImageCanvas(Widget): ...@@ -96,13 +107,13 @@ class ImageCanvas(Widget):
self.canvas.add(self.triangles) self.canvas.add(self.triangles)
self.canvas.ask_update() self.canvas.ask_update()
def build_mesh(self, reconstructed): def build_mesh(self, r_shape):
vertices = [] vertices = []
xy_vertices = [] xy_vertices = []
for i in range(58): for i in range(58):
x = reconstructed[i][0] * (self.center[0] + self.image.size[0] / 2.) x = r_shape[i][0] * (self.center[0] + self.image.size[0] / 2.)
y = (1.0 - reconstructed[i][1]) * self.center[1] + self.center[1] / 2. y = (1.0 - r_shape[i][1]) * self.center[1] + self.center[1] / 2.
vertices.extend([x, y, 0, 0]) vertices.extend([x, y, 0, 0])
xy_vertices.append([x, y]) xy_vertices.append([x, y])
...@@ -122,10 +133,13 @@ class RootWidget(BoxLayout): ...@@ -122,10 +133,13 @@ class RootWidget(BoxLayout):
super(RootWidget, self).__init__(**kwargs) super(RootWidget, self).__init__(**kwargs)
self.images = kwargs['args'].asf self.images = kwargs['args'].asf
self.mean_values = kwargs['mean_values'] self.mean_values_shape = kwargs['mean_values_shape']
self.Vt = kwargs['eigen_vectors'] self.mean_texture_shape = kwargs['mean_values_texture']
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_components = kwargs['args'].n_components
self.multipliers = np.ones(self.Vt.shape[1]) self.multipliers = np.ones(self.eigenv_shape.shape[1])
# slider index # slider index
self.index = 0 self.index = 0
...@@ -142,8 +156,8 @@ class RootWidget(BoxLayout): ...@@ -142,8 +156,8 @@ class RootWidget(BoxLayout):
self.ids['image_viewer'].bind(size=self.on_resize) self.ids['image_viewer'].bind(size=self.on_resize)
box_layout = self.ids['eigenvalues'] box_layout = self.ids['eigenvalues']
self.landmark_list = aam.build_feature_vectors(self.images, self.landmark_list = aam.build_feature_vectors(
imm.get_imm_landmarks, flattened=True) self.images, imm.get_imm_landmarks, flattened=True)
for c in range(self.n_components): for c in range(self.n_components):
slider = Slider(min=-10, max=10, value=0, id=str(c)) slider = Slider(min=-10, max=10, value=0, id=str(c))
...@@ -159,18 +173,17 @@ class RootWidget(BoxLayout): ...@@ -159,18 +173,17 @@ class RootWidget(BoxLayout):
def update_image_viewer(self): def update_image_viewer(self):
self.filename = self.images[self.index].split('.')[0] + '.jpg' self.filename = self.images[self.index].split('.')[0] + '.jpg'
Vt = np.dot(np.diag(self.multipliers), self.Vt) Vt_shape = np.dot(np.diag(self.multipliers), self.eigenv_shape)
reconstruction = pca.reconstruct( r_shape = pca.reconstruct(
self.landmark_list[self.index], Vt, self.mean_values, self.landmark_list[self.index], Vt_shape, self.mean_values_shape,
n_components=self.n_components n_components=self.n_components
) ).reshape((-1, 2))
reconstruction = reconstruction.reshape((-1, 2))
self.ids['image_viewer'].update_rect() self.ids['image_viewer'].update_rect()
self.ids['image_viewer'].update_image(self.filename) self.ids['image_viewer'].update_image(self.filename)
self.ids['image_viewer'].build_line_grid(reconstruction) self.ids['image_viewer'].build_line_grid(r_shape, self.triangles)
# self.ids['image_viewer'].build_texture(r_shape, self.triangles)
def on_resize(self, *args): def on_resize(self, *args):
self.update_image_viewer() self.update_image_viewer()
...@@ -194,16 +207,20 @@ class ReconstructApp(App): ...@@ -194,16 +207,20 @@ class ReconstructApp(App):
kv_directory = 'src/view/templates' kv_directory = 'src/view/templates'
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.eigen_vectors = kwargs['eigen_vectors']
self.mean_values = kwargs['mean_values']
self.args = kwargs['args']
super(ReconstructApp, self).__init__(**kwargs) super(ReconstructApp, self).__init__(**kwargs)
def set_values(self, **kwargs):
for k in kwargs.keys():
setattr(self, k, kwargs[k])
def build(self): def build(self):
return RootWidget( return RootWidget(
args=self.args, eigen_vectors=self.eigen_vectors, args=self.args,
mean_values=self.mean_values eigenv_shape=self.eigenv_shape,
eigenv_texture=self.eigenv_texture,
mean_values_shape=self.mean_values_shape,
mean_values_texture=self.mean_values_texture,
triangles=self.triangles
) )
if __name__ == '__main__': if __name__ == '__main__':
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment