Commit f718b904 authored by Richard Torenvliet's avatar Richard Torenvliet

Removed KivY dependency and code #3

parent beedf9a5
...@@ -63,14 +63,6 @@ graph_reconstruction: ...@@ -63,14 +63,6 @@ graph_reconstruction:
--shape_type imm \ --shape_type imm \
--n_components 6 --n_components 6
show_kivy:
python src/main.py \
--show_kivy \
--files data/imm_face_db/*.asf \
--model_texture_file data/pca_texture_model.npy \
--model_shape_file data/pca_shape_model.npy \
--n_components 6
test: test:
python -m py.test -f src/test/*_test.py python -m py.test -f src/test/*_test.py
......
cycler==0.10.0 cycler==0.10.0
Cython==0.24 Cython==0.24
Kivy==1.9.1
Kivy-Garden==0.1.4
matplotlib==1.5.1 matplotlib==1.5.1
numpy==1.11.0 numpy==1.11.0
pyparsing==2.1.2 pyparsing==2.1.2
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
# python std # python std
import argparse import argparse
import logging import logging
import sys
import importlib import importlib
# installed packages # installed packages
...@@ -29,11 +28,6 @@ def add_parser_options(): ...@@ -29,11 +28,6 @@ def add_parser_options():
help='Reconstruct one face with a given pca model' help='Reconstruct one face with a given pca model'
) )
pca_group.add_argument(
'--show_kivy', action='store_true',
help='Reconstruct using kivy as a GUI'
)
pca_group.add_argument( pca_group.add_argument(
'--generate_call_graph', action='store_true', '--generate_call_graph', action='store_true',
help='Generate call graph from the reconstruction' help='Generate call graph from the reconstruction'
...@@ -166,39 +160,6 @@ def save_pca_model_shape(args): ...@@ -166,39 +160,6 @@ def save_pca_model_shape(args):
logger.info('shape pca model saved in %s', args.model_shape_file + '_shape') logger.info('shape pca model saved in %s', args.model_shape_file + '_shape')
def reconstruct_with_model(args):
assert args.files, '--files should be given to allow the image to be shown'
assert args.model_shape_file, '--model_shape_file needs to be provided to get the pca model'
assert args.shape_type, '--shape_type the type of dataset, see datasets module'
dataset_module = import_dataset_module(args.shape_type)
# clear sys args. arguments are conflicting with parseargs
# kivy will parse args upon import and will crash if it finds our
# 'unsupported by kivy' arguments.
sys.argv[1:] = []
from view.reconstruct import ReconstructApp
Vt_shape, s, n_shape_components, mean_value_points, 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()
app.set_values(
args=args,
eigenv_shape=Vt_shape,
eigenv_texture=Vt_texture,
mean_value_points=mean_value_points,
n_shape_components=n_shape_components,
mean_values_texture=mean_values_texture,
n_texture_components=n_texture_components,
triangles=triangles
)
app.run()
def generate_call_graph(args): def generate_call_graph(args):
"""Performance debug function, will be (re)moved later. """ """Performance debug function, will be (re)moved later. """
assert args.model_shape_file, '--model_texture_file needs to be provided to save the pca model' assert args.model_shape_file, '--model_texture_file needs to be provided to save the pca model'
...@@ -284,10 +245,7 @@ def main(): ...@@ -284,10 +245,7 @@ def main():
elif args.save_pca_texture: elif args.save_pca_texture:
save_pca_model_texture(args) save_pca_model_texture(args)
elif args.reconstruct: elif args.reconstruct:
#reconstruct_with_model(args)
show_reconstruction(args) show_reconstruction(args)
elif args.show_kivy:
reconstruct_with_model(args)
elif args.generate_call_graph: elif args.generate_call_graph:
generate_call_graph(args) generate_call_graph(args)
......
import kivy
kivy.require('1.0.7')
import numpy as np
import cv2
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.slider import Slider
from kivy.properties import ObjectProperty
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle, Mesh, Line, Triangle
from kivy.graphics.texture import Texture
from kivy.graphics.instructions import InstructionGroup
from kivy.graphics.context_instructions import Color
from functools import partial
from math import cos, sin, pi
import imm
from utils import utils
from utils.texture import fill_triangle
#import IMMPoints, build_feature_vectors, \
# flatten_feature_vectors
import pca
import aam
class ReconstructCanvas(Widget):
def __init__(self, **kwargs):
super(ReconstructCanvas, self).__init__(**kwargs)
self.canvas.clear()
with self.canvas:
self.texture = InstructionGroup()
def build_texture(self, filename, Vt_texture, input_points, mean_value_points,
mean_values_texture, triangles, n_texture_components):
self.texture.clear()
#image_width, image_height = self.get_rendered_size()
#InputPoints = imm.IMMPoints(filename=filename)
#input_image = InputPoints.get_image()
##buf = np.zeros(input_image.shape, dtype=np.uint8)
##buf = np.repeat(np.array([255, 0, 0]), input_image.shape[0] * input_image.shape[1])
buf = cv2.imread('data/test_data/red_500x500.png')
h, w, c = buf.shape
#InputPoints.get_scaled_points((input_image.shape))
#offset_x, offset_y, w, h = InputPoints.get_bounding_box()
#MeanPoints = imm.IMMPoints(points_list=mean_value_points)
#utils.reconstruct_texture(
# input_image, # src image
# buf, # dst image
# Vt_texture, # Vt
# InputPoints, # shape points input
# MeanPoints, # shape points mean
# mean_values_texture, # mean texture
# triangles, # triangles
# n_texture_components # learned n_texture_components
#)
#ratio_x = image_width / w
#ratio_y = image_height / h
#buf = cv2.resize(np.asarray(buf, np.uint8), (int(image_width), int(image_height)))
#buf = buf[offset_y: offset_y + h, offset_x: offset_x + w]
#size = 64 * 64 * 3
#buf = [int(x * 255 / size) for x in range(size)]
#print buf
#cv2.imshow('original', buf)
#buf = cv2.flip(buf, 0)
# buf = buf.tostring()
#buf = b''.join(map(chr, buf))
#texture = Texture.create(size=self.size, colorfmt='rgb')
#texture.blit_buffer(buf, colorfmt='rgb', bufferfmt='ubyte')
#pos_x = self.center[0] - self.size[0] / 2.0
#pos_y = self.center[1] - self.size[1] / 2.0
texture = Texture.create(size=(w, h), colorfmt="bgr")
#arr = np.ndarray(shape=[16, 16, 3], dtype=np.uint8)
# fill your numpy array here
data = buf.tostring()
texture.blit_buffer(data, bufferfmt="ubyte", colorfmt="bgr")
pos_x = self.center[0] - self.size[0] / 2.0
pos_y = self.center[1] - self.size[1] / 2.0
self.texture.add(
Rectangle(texture=texture, size=(w, h), pos=(pos_x, pos_y))
)
self.canvas.add(self.texture)
self.canvas.ask_update()
class ImageCanvas(Widget):
def __init__(self, **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.canvas.clear()
with self.canvas:
self.image = Image(pos=self.pos, size=self.size, source=self.filename_image)
self.triangles = InstructionGroup()
self.outline = InstructionGroup()
self.bind(pos=self.update_rect, size=self.update_rect)
def get_rendered_size(self):
"""
get the rendered size of the image
Returns:
(tuple) width, height in pixels
"""
return self.image.get_norm_image_size()
def get_image_left(self, image_width):
"""
return the location of the image, calculated from the center of the
canvas, using the image width
"""
return self.center[0] - image_width / 2.0
def get_image_bottom(self, image_height):
"""
return the location of the image, calculated from the center of the
canvas, using the image width
"""
return self.center[1] - image_height / 2.0
def update_rect(self, *args):
self.image.pos = self.pos
self.image.size = self.size
self.image.source = self.filename_image
def update_image(self, filename):
self.filename_image = filename
self.image.source = self.filename_image
self.canvas.ask_update()
def build_line_grid(self, r_shape, triangles):
self.triangles.clear()
image_width, image_height = self.get_rendered_size()
for tri in triangles:
self.triangles.add(Color(0, 0, 1, 1))
points = r_shape[tri]
x = points[:, 0] * image_width + self.get_image_left(image_width)
y = (1.0 - points[:, 1]) * image_height + self.get_image_bottom(image_height)
# draw lines between three points
self.triangles.add(Line(points=[
x[0], y[0], x[1], y[1], x[2], y[2], x[0], y[0]])
)
self.triangles.add(Color(0, 1, 0, 0.5))
self.triangles.add(Line(circle=(x[0], y[0], 3)))
self.triangles.add(Line(circle=(x[1], y[1], 3)))
self.triangles.add(Line(circle=(x[2], y[2], 3)))
self.canvas.add(self.triangles)
self.canvas.ask_update()
def build_mesh(self, r_shape):
vertices = []
xy_vertices = []
for i in range(58):
x = r_shape[i][0] * (self.center[0] + self.image.size[0] / 2.)
y = (1.0 - r_shape[i][1]) * self.center[1] + self.center[1] / 2.
vertices.extend([x, y, 0, 0])
xy_vertices.append([x, y])
xy_vertices = np.array(xy_vertices)
indices = []
indices = aam.get_triangles(xy_vertices[:, 0], xy_vertices[:, 1])
indices = np.ndarray.flatten(indices)
self.mesh.vertices = vertices
self.mesh.indices = indices
class RootWidget(BoxLayout):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
self.files = kwargs['args'].files
self.mean_value_points = kwargs['mean_value_points']
self.mean_values_texture = kwargs['mean_values_texture']
self.eigenv_shape = kwargs['eigenv_shape']
self.eigenv_texture = kwargs['eigenv_texture']
self.triangles = kwargs['triangles']
self.n_shape_components = kwargs['args'].n_components
self.n_texture_components = kwargs['n_texture_components']
self.multipliers = np.ones(self.eigenv_shape.shape[0])
self.texture_multipliers = np.ones(self.eigenv_texture.shape[0])
# 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_texture_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)
def add_texture_sliders(self):
box_layout = self.ids['texture_eigenvalues']
for c in range(10):
slider = Slider(min=-10, max=10, value=0, id=str(c))
box_layout.add_widget(slider)
slider.bind(value=self.update_texture_eigenvalues)
def add_shape_sliders(self):
box_layout = self.ids['eigenvalues']
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)
def reset_sliders(self):
self.multipliers = np.ones(self.eigenv_shape.shape[0])
self.texture_multipliers = np.ones(self.texture_multipliers.shape[0])
box_layout = self.ids['eigenvalues']
for c in box_layout.children:
c.value = 0
texture_eigenvalues = self.ids['texture_eigenvalues']
for c in texture_eigenvalues.children:
c.value = 0
def update_image_viewer(self):
self.filename = self.files[self.index].split('.')[0] + '.jpg'
Vt_shape = np.dot(np.diag(self.multipliers), self.eigenv_shape)
Vt_texture = np.dot(np.diag(self.texture_multipliers), self.eigenv_texture)
input_points = self.shape_list[self.index]
r_shape = pca.reconstruct(
input_points, Vt_shape, self.mean_value_points,
n_components=self.n_shape_components
).reshape((-1, 2))
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['reconstruct_viewer'].build_texture(
self.files[self.index],
self.eigenv_texture,
input_points,
self.mean_value_points,
self.mean_values_texture,
self.triangles,
self.n_texture_components
)
def on_resize(self, *args):
self.update_image_viewer()
def update_n_components(self, slider, index):
self.n_shape_components = int(index)
self.update_image_viewer()
def update_image(self, slider, index):
self.index = int(index)
self.reset_sliders()
self.update_image_viewer()
def update_texture_eigenvalues(self, slider, value):
multiplier_index = int(slider.id)
self.texture_multipliers[multiplier_index] = value
self.update_image_viewer()
def update_eigenvalues(self, slider, value):
multiplier_index = int(slider.id)
self.multipliers[multiplier_index] = value
self.update_image_viewer()
class ReconstructApp(App):
kv_directory = 'src/view/templates'
def __init__(self, **kwargs):
super(ReconstructApp, self).__init__(**kwargs)
def set_values(self, **kwargs):
for k in kwargs.keys():
setattr(self, k, kwargs[k])
def build(self):
return RootWidget(
args=self.args,
eigenv_shape=self.eigenv_shape,
eigenv_texture=self.eigenv_texture,
mean_value_points=self.mean_value_points,
n_shape_components=self.n_shape_components,
mean_values_texture=self.mean_values_texture,
n_texture_components=self.n_texture_components,
triangles=self.triangles
)
if __name__ == '__main__':
ReconstructApp().run()
'''
Mesh test
=========
This demonstrates the use of a mesh mode to distort an image. You should see
a line of buttons across the bottom of a canvas. Pressing them displays
the mesh, a small circle of points, with different mesh.mode settings.
'''
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.graphics import Mesh
from functools import partial
from math import cos, sin, pi
class MeshTestApp(App):
def change_mode(self, mode, *largs):
self.mesh.mode = mode
def build_mesh(self):
""" returns a Mesh of a rough circle. """
vertices = []
indices = []
step = 10
istep = (pi * 2) / float(step)
x = [200, 200, 300, 340]
y = [400, 200, 300, 340]
for i in range(4):
vertices.extend([x[i], y[i], 0, 0])
indices.append(i)
indices = [0, 1, 2, 3]
#for i in range(step):
# x = 300 + cos(istep * i) * 100
# y = 300 + sin(istep * i) * 100
# vertices.extend([x, y, 0, 0])
# indices.append(i)
return Mesh(vertices=vertices, indices=indices)
def build(self):
wid = Widget()
with wid.canvas:
self.mesh = self.build_mesh()
layout = BoxLayout(size_hint=(1, None), height=50)
for mode in ('points', 'line_strip', 'line_loop', 'lines',
'triangle_strip', 'triangle_fan', 'triangles'):
button = Button(text=mode)
button.bind(on_release=partial(self.change_mode, mode))
layout.add_widget(button)
root = BoxLayout(orientation='vertical')
root.add_widget(wid)
root.add_widget(layout)
return root
if __name__ == '__main__':
MeshTestApp().run()
'''
Line (SmoothLine) Experiment
============================
This demonstrates the experimental and unfinished SmoothLine feature
for fast line drawing. You should see a multi-segment
path at the top of the screen, and sliders and buttons along the bottom.
You can click to add new points to the segment, change the transparency
and width of the line, or hit 'Animate' to see a set of sine and cosine
animations. The Cap and Joint buttons don't work: SmoothLine has not
implemented these features yet.
'''
from kivy.app import App
from kivy.properties import OptionProperty, NumericProperty, ListProperty, \
BooleanProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.clock import Clock
from math import cos, sin
Builder.load_string('''
<LinePlayground>:
canvas:
Color:
rgba: .4, .4, 1, root.alpha
SmoothLine:
points: self.points
joint: self.joint
cap: self.cap
width: self.linewidth
close: self.close
Color:
rgba: .8, .8, .8, root.alpha_controlline
SmoothLine:
points: self.points
close: self.close
Color:
rgba: 1, .4, .4, root.alpha
SmoothLine:
points: self.points2
joint: self.joint
cap: self.cap
width: self.linewidth
close: self.close
GridLayout:
cols: 2
size_hint: 1, None
height: 44 * 5
GridLayout:
cols: 2
Label:
text: 'Alpha'
Slider:
value: root.alpha
on_value: root.alpha = float(args[1])
min: 0.
max: 1.
Label:
text: 'Alpha Control Line'
Slider:
value: root.alpha_controlline
on_value: root.alpha_controlline = float(args[1])
min: 0.
max: 1.
Label:
text: 'Width'
Slider:
value: root.linewidth
on_value: root.linewidth = args[1]
min: 1
max: 40
Label:
text: 'Cap'
GridLayout:
rows: 1
ToggleButton:
group: 'cap'
text: 'none'
on_press: root.cap = self.text
ToggleButton:
group: 'cap'
text: 'round'
on_press: root.cap = self.text
ToggleButton:
group: 'cap'
text: 'square'
on_press: root.cap = self.text
Label:
text: 'Joint'
GridLayout:
rows: 1
ToggleButton:
group: 'joint'
text: 'none'
on_press: root.joint = self.text
ToggleButton:
group: 'joint'
text: 'round'
on_press: root.joint = self.text
ToggleButton:
group: 'joint'
text: 'miter'
on_press: root.joint = self.text
ToggleButton:
group: 'joint'
text: 'bevel'
on_press: root.joint = self.text
Label:
text: 'Close'
ToggleButton:
text: 'Close line'
on_press: root.close = self.state == 'down'
AnchorLayout:
GridLayout:
cols: 1
size_hint: None, None
size: self.minimum_size
ToggleButton:
size_hint: None, None
size: 100, 44
text: 'Animate'
on_state: root.animate(self.state == 'down')
Button:
size_hint: None, None
size: 100, 44
text: 'Clear'
on_press: root.points = root.points2 = []
''')
class LinePlayground(FloatLayout):
alpha_controlline = NumericProperty(1.0)
alpha = NumericProperty(0.5)
close = BooleanProperty(False)
points = ListProperty([(500, 500),
[300, 300, 500, 300],
[500, 400, 600, 400]])
points2 = ListProperty([])
joint = OptionProperty('none', options=('round', 'miter', 'bevel', 'none'))
cap = OptionProperty('none', options=('round', 'square', 'none'))
linewidth = NumericProperty(10.0)
dt = NumericProperty(0)
def on_touch_down(self, touch):
if super(LinePlayground, self).on_touch_down(touch):
return True
touch.grab(self)
self.points.append(touch.pos)
return True
def on_touch_move(self, touch):
if touch.grab_current is self:
self.points[-1] = touch.pos
return True
return super(LinePlayground, self).on_touch_move(touch)
def on_touch_up(self, touch):
if touch.grab_current is self:
touch.ungrab(self)
return True
return super(LinePlayground, self).on_touch_up(touch)
def animate(self, do_animation):
if do_animation:
Clock.schedule_interval(self.update_points_animation, 0)
else:
Clock.unschedule(self.update_points_animation)
def update_points_animation(self, dt):
cy = self.height * 0.6
cx = self.width * 0.1
w = self.width * 0.8
step = 20
points = []
points2 = []
self.dt += dt
for i in range(int(w / step)):
x = i * step
points.append(cx + x)
points.append(cy + cos(x / w * 8. + self.dt) * self.height * 0.2)
points2.append(cx + x)
points2.append(cy + sin(x / w * 8. + self.dt) * self.height * 0.2)
self.points = points
self.points2 = points2
class TestLineApp(App):
def build(self):
return LinePlayground()
if __name__ == '__main__':
TestLineApp().run()
# Draw lines between widgets for easy debugging
# <Widget>
# canvas.after:
# Line:
# rectangle: self.x+1,self.y+1,self.width-1,self.height-1
# dash_offset: 5
# dash_length: 3
<ImageCanvas>
<RootWidget>
BoxLayout:
orientation: 'vertical'
BoxLayout:
ImageCanvas
id: image_viewer
ReconstructCanvas
id: reconstruct_viewer
BoxLayout:
orientation: 'vertical'
BoxLayout:
orientation: 'vertical'
size_hint_y: 0.5
Label:
text: "Image {}".format(int(image_slider.value))
Slider:
id: image_slider
min: 0
max: 100
value: 0
Label:
text: "Using {} components".format(int(n_shape_components.value))
Slider:
id: n_shape_components
min: 0
max: 58
value: 0
BoxLayout:
BoxLayout:
orientation: 'vertical'
id: texture_eigenvalues
BoxLayout:
orientation: 'vertical'
id: eigenvalues
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