Skip to content

Commit

Permalink
uploading test code
Browse files Browse the repository at this point in the history
  • Loading branch information
DenisTome committed Apr 27, 2017
0 parents commit ce4014a
Show file tree
Hide file tree
Showing 18 changed files with 1,988 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
@@ -0,0 +1,8 @@
*.pyc
*~
*.so
*.cpp

# folders
saved_sessions
utils/external/build
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions README.md
@@ -0,0 +1,35 @@
# Lifting from the Deep
Denis Tome', Chris Russell, Lourdes Agapito

[Lifting from the Deep: Convolutional 3D Pose Estimation from a Single Image](https://arxiv.org/abs/1701.00295), CVPR 2017

This project is licensed under the terms of the GNU GPLv3 license. By using the software, you are agreeing to the terms of the license agreement ([link](https://github.com/DenisTome/Lifting-from-the-Deep-release/blob/master/LICENSE)).

![Teaser?](https://github.com/DenisTome/Lifting-from-the-Deep-release/blob/master/images/teaser-github.png)
## Dependencies

- [Tensorflow](https://www.tensorflow.org/)
- [Cython](http://cython.readthedocs.io/en/latest/src/quickstart/install.html)

## Models

The architecture extends the one proposed in [Convolutional Pose Machines (CPM)](https://github.com/shihenw/convolutional-pose-machines-release).

For this demo, CPM's caffe-models trained on the MPI datasets ([link](https://github.com/shihenw/convolutional-pose-machines-release/tree/master/model)) are used for **2D pose estimation**, whereas for **3D pose estimation** our probabilistic 3D pose model is trained on the [Human3.6M dataset](http://vision.imar.ro/human3.6m/description.php).

## Testing
- First, run `setup.sh` to retreive the trained models and to install the external utilities.
- Run `demo.py` to evaluate the test image.

## Additional material
- Project [webpage](http://visual.cs.ucl.ac.uk/pubs/liftingFromTheDeep/)
- Some [videos](https://youtu.be/tKfkGttx0qs).

## Citation

@article{tome2017lifting,
title={Lifting from the Deep: Convolutional 3D Pose Estimation from a Single Image},
author={Tome, Denis and Russell, Chris and Agapito, Lourdes},
journal={arXiv preprint arXiv:1701.00295},
year={2017}
}
195 changes: 195 additions & 0 deletions cpm.py
@@ -0,0 +1,195 @@
import tensorflow as tf
import tensorflow.contrib.layers as layers


def inference_person(image):
with tf.variable_scope('PersonNet'):
conv1_1 = layers.conv2d(image, 64, 3, 1, activation_fn=None, scope='conv1_1')
conv1_1 = tf.nn.relu(conv1_1)
conv1_2 = layers.conv2d(conv1_1, 64, 3, 1, activation_fn=None, scope='conv1_2')
conv1_2 = tf.nn.relu(conv1_2)
pool1_stage1 = layers.max_pool2d(conv1_2, 2, 2)
conv2_1 = layers.conv2d(pool1_stage1, 128, 3, 1, activation_fn=None, scope='conv2_1')
conv2_1 = tf.nn.relu(conv2_1)
conv2_2 = layers.conv2d(conv2_1, 128, 3, 1, activation_fn=None, scope='conv2_2')
conv2_2 = tf.nn.relu(conv2_2)
pool2_stage1 = layers.max_pool2d(conv2_2, 2, 2)
conv3_1 = layers.conv2d(pool2_stage1, 256, 3, 1, activation_fn=None, scope='conv3_1')
conv3_1 = tf.nn.relu(conv3_1)
conv3_2 = layers.conv2d(conv3_1, 256, 3, 1, activation_fn=None, scope='conv3_2')
conv3_2 = tf.nn.relu(conv3_2)
conv3_3 = layers.conv2d(conv3_2, 256, 3, 1, activation_fn=None, scope='conv3_3')
conv3_3 = tf.nn.relu(conv3_3)
conv3_4 = layers.conv2d(conv3_3, 256, 3, 1, activation_fn=None, scope='conv3_4')
conv3_4 = tf.nn.relu(conv3_4)
pool3_stage1 = layers.max_pool2d(conv3_4, 2, 2)
conv4_1 = layers.conv2d(pool3_stage1, 512, 3, 1, activation_fn=None, scope='conv4_1')
conv4_1 = tf.nn.relu(conv4_1)
conv4_2 = layers.conv2d(conv4_1, 512, 3, 1, activation_fn=None, scope='conv4_2')
conv4_2 = tf.nn.relu(conv4_2)
conv4_3 = layers.conv2d(conv4_2, 512, 3, 1, activation_fn=None, scope='conv4_3')
conv4_3 = tf.nn.relu(conv4_3)
conv4_4 = layers.conv2d(conv4_3, 512, 3, 1, activation_fn=None, scope='conv4_4')
conv4_4 = tf.nn.relu(conv4_4)
conv5_1 = layers.conv2d(conv4_4, 512, 3, 1, activation_fn=None, scope='conv5_1')
conv5_1 = tf.nn.relu(conv5_1)
conv5_2_CPM = layers.conv2d(conv5_1, 128, 3, 1, activation_fn=None, scope='conv5_2_CPM')
conv5_2_CPM = tf.nn.relu(conv5_2_CPM)
conv6_1_CPM = layers.conv2d(conv5_2_CPM, 512, 1, 1, activation_fn=None, scope='conv6_1_CPM')
conv6_1_CPM = tf.nn.relu(conv6_1_CPM)
conv6_2_CPM = layers.conv2d(conv6_1_CPM, 1, 1, 1, activation_fn=None, scope='conv6_2_CPM')
concat_stage2 = tf.concat(3, [conv6_2_CPM, conv5_2_CPM])
Mconv1_stage2 = layers.conv2d(concat_stage2, 128, 7, 1, activation_fn=None, scope='Mconv1_stage2')
Mconv1_stage2 = tf.nn.relu(Mconv1_stage2)
Mconv2_stage2 = layers.conv2d(Mconv1_stage2, 128, 7, 1, activation_fn=None, scope='Mconv2_stage2')
Mconv2_stage2 = tf.nn.relu(Mconv2_stage2)
Mconv3_stage2 = layers.conv2d(Mconv2_stage2, 128, 7, 1, activation_fn=None, scope='Mconv3_stage2')
Mconv3_stage2 = tf.nn.relu(Mconv3_stage2)
Mconv4_stage2 = layers.conv2d(Mconv3_stage2, 128, 7, 1, activation_fn=None, scope='Mconv4_stage2')
Mconv4_stage2 = tf.nn.relu(Mconv4_stage2)
Mconv5_stage2 = layers.conv2d(Mconv4_stage2, 128, 7, 1, activation_fn=None, scope='Mconv5_stage2')
Mconv5_stage2 = tf.nn.relu(Mconv5_stage2)
Mconv6_stage2 = layers.conv2d(Mconv5_stage2, 128, 1, 1, activation_fn=None, scope='Mconv6_stage2')
Mconv6_stage2 = tf.nn.relu(Mconv6_stage2)
Mconv7_stage2 = layers.conv2d(Mconv6_stage2, 1, 1, 1, activation_fn=None, scope='Mconv7_stage2')
concat_stage3 = tf.concat(3, [Mconv7_stage2, conv5_2_CPM])
Mconv1_stage3 = layers.conv2d(concat_stage3, 128, 7, 1, activation_fn=None, scope='Mconv1_stage3')
Mconv1_stage3 = tf.nn.relu(Mconv1_stage3)
Mconv2_stage3 = layers.conv2d(Mconv1_stage3, 128, 7, 1, activation_fn=None, scope='Mconv2_stage3')
Mconv2_stage3 = tf.nn.relu(Mconv2_stage3)
Mconv3_stage3 = layers.conv2d(Mconv2_stage3, 128, 7, 1, activation_fn=None, scope='Mconv3_stage3')
Mconv3_stage3 = tf.nn.relu(Mconv3_stage3)
Mconv4_stage3 = layers.conv2d(Mconv3_stage3, 128, 7, 1, activation_fn=None, scope='Mconv4_stage3')
Mconv4_stage3 = tf.nn.relu(Mconv4_stage3)
Mconv5_stage3 = layers.conv2d(Mconv4_stage3, 128, 7, 1, activation_fn=None, scope='Mconv5_stage3')
Mconv5_stage3 = tf.nn.relu(Mconv5_stage3)
Mconv6_stage3 = layers.conv2d(Mconv5_stage3, 128, 1, 1, activation_fn=None, scope='Mconv6_stage3')
Mconv6_stage3 = tf.nn.relu(Mconv6_stage3)
Mconv7_stage3 = layers.conv2d(Mconv6_stage3, 1, 1, 1, activation_fn=None, scope='Mconv7_stage3')
concat_stage4 = tf.concat(3, [Mconv7_stage3, conv5_2_CPM])
Mconv1_stage4 = layers.conv2d(concat_stage4, 128, 7, 1, activation_fn=None, scope='Mconv1_stage4')
Mconv1_stage4 = tf.nn.relu(Mconv1_stage4)
Mconv2_stage4 = layers.conv2d(Mconv1_stage4, 128, 7, 1, activation_fn=None, scope='Mconv2_stage4')
Mconv2_stage4 = tf.nn.relu(Mconv2_stage4)
Mconv3_stage4 = layers.conv2d(Mconv2_stage4, 128, 7, 1, activation_fn=None, scope='Mconv3_stage4')
Mconv3_stage4 = tf.nn.relu(Mconv3_stage4)
Mconv4_stage4 = layers.conv2d(Mconv3_stage4, 128, 7, 1, activation_fn=None, scope='Mconv4_stage4')
Mconv4_stage4 = tf.nn.relu(Mconv4_stage4)
Mconv5_stage4 = layers.conv2d(Mconv4_stage4, 128, 7, 1, activation_fn=None, scope='Mconv5_stage4')
Mconv5_stage4 = tf.nn.relu(Mconv5_stage4)
Mconv6_stage4 = layers.conv2d(Mconv5_stage4, 128, 1, 1, activation_fn=None, scope='Mconv6_stage4')
Mconv6_stage4 = tf.nn.relu(Mconv6_stage4)
Mconv7_stage4 = layers.conv2d(Mconv6_stage4, 1, 1, 1, activation_fn=None, scope='Mconv7_stage4')
return Mconv7_stage4


def inference_pose(image, center_map):
with tf.variable_scope('PoseNet'):
pool_center_lower = layers.avg_pool2d(center_map, 9, 8, padding='SAME')
conv1_1 = layers.conv2d(image, 64, 3, 1, activation_fn=None, scope='conv1_1')
conv1_1 = tf.nn.relu(conv1_1)
conv1_2 = layers.conv2d(conv1_1, 64, 3, 1, activation_fn=None, scope='conv1_2')
conv1_2 = tf.nn.relu(conv1_2)
pool1_stage1 = layers.max_pool2d(conv1_2, 2, 2)
conv2_1 = layers.conv2d(pool1_stage1, 128, 3, 1, activation_fn=None, scope='conv2_1')
conv2_1 = tf.nn.relu(conv2_1)
conv2_2 = layers.conv2d(conv2_1, 128, 3, 1, activation_fn=None, scope='conv2_2')
conv2_2 = tf.nn.relu(conv2_2)
pool2_stage1 = layers.max_pool2d(conv2_2, 2, 2)
conv3_1 = layers.conv2d(pool2_stage1, 256, 3, 1, activation_fn=None, scope='conv3_1')
conv3_1 = tf.nn.relu(conv3_1)
conv3_2 = layers.conv2d(conv3_1, 256, 3, 1, activation_fn=None, scope='conv3_2')
conv3_2 = tf.nn.relu(conv3_2)
conv3_3 = layers.conv2d(conv3_2, 256, 3, 1, activation_fn=None, scope='conv3_3')
conv3_3 = tf.nn.relu(conv3_3)
conv3_4 = layers.conv2d(conv3_3, 256, 3, 1, activation_fn=None, scope='conv3_4')
conv3_4 = tf.nn.relu(conv3_4)
pool3_stage1 = layers.max_pool2d(conv3_4, 2, 2)
conv4_1 = layers.conv2d(pool3_stage1, 512, 3, 1, activation_fn=None, scope='conv4_1')
conv4_1 = tf.nn.relu(conv4_1)
conv4_2 = layers.conv2d(conv4_1, 512, 3, 1, activation_fn=None, scope='conv4_2')
conv4_2 = tf.nn.relu(conv4_2)
conv4_3_CPM = layers.conv2d(conv4_2, 256, 3, 1, activation_fn=None, scope='conv4_3_CPM')
conv4_3_CPM = tf.nn.relu(conv4_3_CPM)
conv4_4_CPM = layers.conv2d(conv4_3_CPM, 256, 3, 1, activation_fn=None, scope='conv4_4_CPM')
conv4_4_CPM = tf.nn.relu(conv4_4_CPM)
conv4_5_CPM = layers.conv2d(conv4_4_CPM, 256, 3, 1, activation_fn=None, scope='conv4_5_CPM')
conv4_5_CPM = tf.nn.relu(conv4_5_CPM)
conv4_6_CPM = layers.conv2d(conv4_5_CPM, 256, 3, 1, activation_fn=None, scope='conv4_6_CPM')
conv4_6_CPM = tf.nn.relu(conv4_6_CPM)
conv4_7_CPM = layers.conv2d(conv4_6_CPM, 128, 3, 1, activation_fn=None, scope='conv4_7_CPM')
conv4_7_CPM = tf.nn.relu(conv4_7_CPM)
conv5_1_CPM = layers.conv2d(conv4_7_CPM, 512, 1, 1, activation_fn=None, scope='conv5_1_CPM')
conv5_1_CPM = tf.nn.relu(conv5_1_CPM)
conv5_2_CPM = layers.conv2d(conv5_1_CPM, 15, 1, 1, activation_fn=None, scope='conv5_2_CPM')
concat_stage2 = tf.concat(3, [conv5_2_CPM, conv4_7_CPM, pool_center_lower])
Mconv1_stage2 = layers.conv2d(concat_stage2, 128, 7, 1, activation_fn=None, scope='Mconv1_stage2')
Mconv1_stage2 = tf.nn.relu(Mconv1_stage2)
Mconv2_stage2 = layers.conv2d(Mconv1_stage2, 128, 7, 1, activation_fn=None, scope='Mconv2_stage2')
Mconv2_stage2 = tf.nn.relu(Mconv2_stage2)
Mconv3_stage2 = layers.conv2d(Mconv2_stage2, 128, 7, 1, activation_fn=None, scope='Mconv3_stage2')
Mconv3_stage2 = tf.nn.relu(Mconv3_stage2)
Mconv4_stage2 = layers.conv2d(Mconv3_stage2, 128, 7, 1, activation_fn=None, scope='Mconv4_stage2')
Mconv4_stage2 = tf.nn.relu(Mconv4_stage2)
Mconv5_stage2 = layers.conv2d(Mconv4_stage2, 128, 7, 1, activation_fn=None, scope='Mconv5_stage2')
Mconv5_stage2 = tf.nn.relu(Mconv5_stage2)
Mconv6_stage2 = layers.conv2d(Mconv5_stage2, 128, 1, 1, activation_fn=None, scope='Mconv6_stage2')
Mconv6_stage2 = tf.nn.relu(Mconv6_stage2)
Mconv7_stage2 = layers.conv2d(Mconv6_stage2, 15, 1, 1, activation_fn=None, scope='Mconv7_stage2')
concat_stage3 = tf.concat(3, [Mconv7_stage2, conv4_7_CPM, pool_center_lower])
Mconv1_stage3 = layers.conv2d(concat_stage3, 128, 7, 1, activation_fn=None, scope='Mconv1_stage3')
Mconv1_stage3 = tf.nn.relu(Mconv1_stage3)
Mconv2_stage3 = layers.conv2d(Mconv1_stage3, 128, 7, 1, activation_fn=None, scope='Mconv2_stage3')
Mconv2_stage3 = tf.nn.relu(Mconv2_stage3)
Mconv3_stage3 = layers.conv2d(Mconv2_stage3, 128, 7, 1, activation_fn=None, scope='Mconv3_stage3')
Mconv3_stage3 = tf.nn.relu(Mconv3_stage3)
Mconv4_stage3 = layers.conv2d(Mconv3_stage3, 128, 7, 1, activation_fn=None, scope='Mconv4_stage3')
Mconv4_stage3 = tf.nn.relu(Mconv4_stage3)
Mconv5_stage3 = layers.conv2d(Mconv4_stage3, 128, 7, 1, activation_fn=None, scope='Mconv5_stage3')
Mconv5_stage3 = tf.nn.relu(Mconv5_stage3)
Mconv6_stage3 = layers.conv2d(Mconv5_stage3, 128, 1, 1, activation_fn=None, scope='Mconv6_stage3')
Mconv6_stage3 = tf.nn.relu(Mconv6_stage3)
Mconv7_stage3 = layers.conv2d(Mconv6_stage3, 15, 1, 1, activation_fn=None, scope='Mconv7_stage3')
concat_stage4 = tf.concat(3, [Mconv7_stage3, conv4_7_CPM, pool_center_lower])
Mconv1_stage4 = layers.conv2d(concat_stage4, 128, 7, 1, activation_fn=None, scope='Mconv1_stage4')
Mconv1_stage4 = tf.nn.relu(Mconv1_stage4)
Mconv2_stage4 = layers.conv2d(Mconv1_stage4, 128, 7, 1, activation_fn=None, scope='Mconv2_stage4')
Mconv2_stage4 = tf.nn.relu(Mconv2_stage4)
Mconv3_stage4 = layers.conv2d(Mconv2_stage4, 128, 7, 1, activation_fn=None, scope='Mconv3_stage4')
Mconv3_stage4 = tf.nn.relu(Mconv3_stage4)
Mconv4_stage4 = layers.conv2d(Mconv3_stage4, 128, 7, 1, activation_fn=None, scope='Mconv4_stage4')
Mconv4_stage4 = tf.nn.relu(Mconv4_stage4)
Mconv5_stage4 = layers.conv2d(Mconv4_stage4, 128, 7, 1, activation_fn=None, scope='Mconv5_stage4')
Mconv5_stage4 = tf.nn.relu(Mconv5_stage4)
Mconv6_stage4 = layers.conv2d(Mconv5_stage4, 128, 1, 1, activation_fn=None, scope='Mconv6_stage4')
Mconv6_stage4 = tf.nn.relu(Mconv6_stage4)
Mconv7_stage4 = layers.conv2d(Mconv6_stage4, 15, 1, 1, activation_fn=None, scope='Mconv7_stage4')
concat_stage5 = tf.concat(3, [Mconv7_stage4, conv4_7_CPM, pool_center_lower])
Mconv1_stage5 = layers.conv2d(concat_stage5, 128, 7, 1, activation_fn=None, scope='Mconv1_stage5')
Mconv1_stage5 = tf.nn.relu(Mconv1_stage5)
Mconv2_stage5 = layers.conv2d(Mconv1_stage5, 128, 7, 1, activation_fn=None, scope='Mconv2_stage5')
Mconv2_stage5 = tf.nn.relu(Mconv2_stage5)
Mconv3_stage5 = layers.conv2d(Mconv2_stage5, 128, 7, 1, activation_fn=None, scope='Mconv3_stage5')
Mconv3_stage5 = tf.nn.relu(Mconv3_stage5)
Mconv4_stage5 = layers.conv2d(Mconv3_stage5, 128, 7, 1, activation_fn=None, scope='Mconv4_stage5')
Mconv4_stage5 = tf.nn.relu(Mconv4_stage5)
Mconv5_stage5 = layers.conv2d(Mconv4_stage5, 128, 7, 1, activation_fn=None, scope='Mconv5_stage5')
Mconv5_stage5 = tf.nn.relu(Mconv5_stage5)
Mconv6_stage5 = layers.conv2d(Mconv5_stage5, 128, 1, 1, activation_fn=None, scope='Mconv6_stage5')
Mconv6_stage5 = tf.nn.relu(Mconv6_stage5)
Mconv7_stage5 = layers.conv2d(Mconv6_stage5, 15, 1, 1, activation_fn=None, scope='Mconv7_stage5')
concat_stage6 = tf.concat(3, [Mconv7_stage5, conv4_7_CPM, pool_center_lower])
Mconv1_stage6 = layers.conv2d(concat_stage6, 128, 7, 1, activation_fn=None, scope='Mconv1_stage6')
Mconv1_stage6 = tf.nn.relu(Mconv1_stage6)
Mconv2_stage6 = layers.conv2d(Mconv1_stage6, 128, 7, 1, activation_fn=None, scope='Mconv2_stage6')
Mconv2_stage6 = tf.nn.relu(Mconv2_stage6)
Mconv3_stage6 = layers.conv2d(Mconv2_stage6, 128, 7, 1, activation_fn=None, scope='Mconv3_stage6')
Mconv3_stage6 = tf.nn.relu(Mconv3_stage6)
Mconv4_stage6 = layers.conv2d(Mconv3_stage6, 128, 7, 1, activation_fn=None, scope='Mconv4_stage6')
Mconv4_stage6 = tf.nn.relu(Mconv4_stage6)
Mconv5_stage6 = layers.conv2d(Mconv4_stage6, 128, 7, 1, activation_fn=None, scope='Mconv5_stage6')
Mconv5_stage6 = tf.nn.relu(Mconv5_stage6)
Mconv6_stage6 = layers.conv2d(Mconv5_stage6, 128, 1, 1, activation_fn=None, scope='Mconv6_stage6')
Mconv6_stage6 = tf.nn.relu(Mconv6_stage6)
Mconv7_stage6 = layers.conv2d(Mconv6_stage6, 15, 1, 1, activation_fn=None, scope='Mconv7_stage6')
return Mconv7_stage6
84 changes: 84 additions & 0 deletions demo.py
@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
"""
Created on Dec 20 17:39 2016
@author: Denis Tome'
"""
import numpy as np
import cv2
import utils.config as config
import tensorflow as tf
import cpm
from utils.draw import *
from prob_model import Prob3dPose
import utils.process as ut

fname = 'images/test_image.png'

image = cv2.cvtColor(cv2.imread(fname), cv2.COLOR_BGR2RGB)
scale = config.INPUT_SIZE/(image.shape[0] * 1.0)
image = cv2.resize(image, (0, 0), fx=scale, fy=scale, interpolation=cv2.INTER_CUBIC)
b_image = np.array(image[np.newaxis] / 255.0 - 0.5, dtype=np.float32)

tf.reset_default_graph()

with tf.variable_scope('CPM'):
# placeholders for person network
image_in = tf.placeholder(tf.float32, [1, config.INPUT_SIZE, image.shape[1], 3])
heatmap_person = cpm.inference_person(image_in)
heatmap_person_large = tf.image.resize_images(heatmap_person, [config.INPUT_SIZE, image.shape[1]])

# placeholders for pose network
N = 16
pose_image_in = tf.placeholder(tf.float32, [N, config.INPUT_SIZE, config.INPUT_SIZE, 3])
pose_centermap_in = tf.placeholder(tf.float32, [N, config.INPUT_SIZE, config.INPUT_SIZE, 1])
heatmap_pose = cpm.inference_pose(pose_image_in, pose_centermap_in)


with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
saver.restore(sess, 'saved_sessions/person_MPI/init')
hmap_person = sess.run(heatmap_person_large, {image_in: b_image})

hmap_person = np.squeeze(hmap_person)
centers = ut.detect_objects_heatmap(hmap_person)
b_pose_image, b_pose_cmap = ut.prepare_input_posenet(b_image[0], centers, [config.INPUT_SIZE, image.shape[1]],
[config.INPUT_SIZE, config.INPUT_SIZE])

# sess = tf.InteractiveSession()
with tf.Session() as sess:
saver = tf.train.Saver()
saver.restore(sess, 'saved_sessions/pose_MPI/init')

feed_dict = {
pose_image_in: b_pose_image,
pose_centermap_in: b_pose_cmap
}

_hmap_pose = sess.run(heatmap_pose, feed_dict)

# Estimate 2D poses
parts, visible = ut.detect_parts_heatmaps(_hmap_pose, centers, [config.INPUT_SIZE, config.INPUT_SIZE])

# Estimate 3D poses
poseLifting = Prob3dPose()
pose2D, weights = Prob3dPose.transform_joints(parts, visible)
pose3D = poseLifting.compute_3d(pose2D, weights)

# Show 2D poses
plt.figure()
draw_limbs(image, parts, visible)
plt.imshow(image)
plt.axis('off')

# Show 3D poses
for single_3D in pose3D:
plot_pose(single_3D)

plt.show()





Binary file added images/teaser-github.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/test_image.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit ce4014a

Please sign in to comment.