|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"""Implementations for Im2Vox PTN (NIPS16) model.""" |
|
from __future__ import absolute_import |
|
from __future__ import division |
|
from __future__ import print_function |
|
|
|
import os |
|
|
|
import numpy as np |
|
from six.moves import xrange |
|
import tensorflow as tf |
|
|
|
import losses |
|
import metrics |
|
import model_voxel_generation |
|
import utils |
|
from nets import im2vox_factory |
|
|
|
slim = tf.contrib.slim |
|
|
|
|
|
class model_PTN(model_voxel_generation.Im2Vox): |
|
"""Inherits the generic Im2Vox model class and implements the functions.""" |
|
|
|
def __init__(self, params): |
|
super(model_PTN, self).__init__(params) |
|
|
|
|
|
def preprocess_with_all_views(self, raw_inputs): |
|
(quantity, num_views) = raw_inputs['images'].get_shape().as_list()[:2] |
|
|
|
inputs = dict() |
|
inputs['voxels'] = [] |
|
inputs['images_1'] = [] |
|
for k in xrange(num_views): |
|
inputs['matrix_%d' % (k + 1)] = [] |
|
inputs['matrix_1'] = [] |
|
for n in xrange(quantity): |
|
for k in xrange(num_views): |
|
inputs['images_1'].append(raw_inputs['images'][n, k, :, :, :]) |
|
inputs['voxels'].append(raw_inputs['voxels'][n, :, :, :, :]) |
|
tf_matrix = self.get_transform_matrix(k) |
|
inputs['matrix_%d' % (k + 1)].append(tf_matrix) |
|
|
|
inputs['images_1'] = tf.stack(inputs['images_1']) |
|
inputs['voxels'] = tf.stack(inputs['voxels']) |
|
for k in xrange(num_views): |
|
inputs['matrix_%d' % (k + 1)] = tf.stack(inputs['matrix_%d' % (k + 1)]) |
|
|
|
return inputs |
|
|
|
def get_model_fn(self, is_training=True, reuse=False, run_projection=True): |
|
return im2vox_factory.get(self._params, is_training, reuse, run_projection) |
|
|
|
def get_regularization_loss(self, scopes): |
|
return losses.regularization_loss(scopes, self._params) |
|
|
|
def get_loss(self, inputs, outputs): |
|
"""Computes the loss used for PTN paper (projection + volume loss).""" |
|
g_loss = tf.zeros(dtype=tf.float32, shape=[]) |
|
|
|
if self._params.proj_weight: |
|
g_loss += losses.add_volume_proj_loss( |
|
inputs, outputs, self._params.step_size, self._params.proj_weight) |
|
|
|
if self._params.volume_weight: |
|
g_loss += losses.add_volume_loss(inputs, outputs, 1, |
|
self._params.volume_weight) |
|
|
|
slim.summaries.add_scalar_summary(g_loss, 'im2vox_loss', prefix='losses') |
|
|
|
return g_loss |
|
|
|
def get_metrics(self, inputs, outputs): |
|
"""Aggregate the metrics for voxel generation model. |
|
|
|
Args: |
|
inputs: Input dictionary of the voxel generation model. |
|
outputs: Output dictionary returned by the voxel generation model. |
|
|
|
Returns: |
|
names_to_values: metrics->values (dict). |
|
names_to_updates: metrics->ops (dict). |
|
""" |
|
names_to_values = dict() |
|
names_to_updates = dict() |
|
|
|
tmp_values, tmp_updates = metrics.add_volume_iou_metrics(inputs, outputs) |
|
|
|
names_to_values.update(tmp_values) |
|
names_to_updates.update(tmp_updates) |
|
|
|
for name, value in names_to_values.iteritems(): |
|
slim.summaries.add_scalar_summary( |
|
value, name, prefix='eval', print_summary=True) |
|
|
|
return names_to_values, names_to_updates |
|
|
|
def write_disk_grid(self, |
|
global_step, |
|
log_dir, |
|
input_images, |
|
gt_projs, |
|
pred_projs, |
|
input_voxels=None, |
|
output_voxels=None): |
|
"""Function called by TF to save the prediction periodically.""" |
|
summary_freq = self._params.save_every |
|
|
|
def write_grid(input_images, gt_projs, pred_projs, global_step, |
|
input_voxels, output_voxels): |
|
"""Native python function to call for writing images to files.""" |
|
grid = _build_image_grid( |
|
input_images, |
|
gt_projs, |
|
pred_projs, |
|
input_voxels=input_voxels, |
|
output_voxels=output_voxels) |
|
|
|
if global_step % summary_freq == 0: |
|
img_path = os.path.join(log_dir, '%s.jpg' % str(global_step)) |
|
utils.save_image(grid, img_path) |
|
return grid |
|
|
|
save_op = tf.py_func(write_grid, [ |
|
input_images, gt_projs, pred_projs, global_step, input_voxels, |
|
output_voxels |
|
], [tf.uint8], 'write_grid')[0] |
|
slim.summaries.add_image_summary( |
|
tf.expand_dims(save_op, axis=0), name='grid_vis') |
|
return save_op |
|
|
|
def get_transform_matrix(self, view_out): |
|
"""Get the 4x4 Perspective Transfromation matrix used for PTN.""" |
|
num_views = self._params.num_views |
|
focal_length = self._params.focal_length |
|
focal_range = self._params.focal_range |
|
phi = 30 |
|
theta_interval = 360.0 / num_views |
|
theta = theta_interval * view_out |
|
|
|
|
|
camera_matrix = np.zeros((4, 4), dtype=np.float32) |
|
intrinsic_matrix = np.eye(4, dtype=np.float32) |
|
extrinsic_matrix = np.eye(4, dtype=np.float32) |
|
|
|
sin_phi = np.sin(float(phi) / 180.0 * np.pi) |
|
cos_phi = np.cos(float(phi) / 180.0 * np.pi) |
|
sin_theta = np.sin(float(-theta) / 180.0 * np.pi) |
|
cos_theta = np.cos(float(-theta) / 180.0 * np.pi) |
|
|
|
rotation_azimuth = np.zeros((3, 3), dtype=np.float32) |
|
rotation_azimuth[0, 0] = cos_theta |
|
rotation_azimuth[2, 2] = cos_theta |
|
rotation_azimuth[0, 2] = -sin_theta |
|
rotation_azimuth[2, 0] = sin_theta |
|
rotation_azimuth[1, 1] = 1.0 |
|
|
|
|
|
rotation_elevation = np.zeros((3, 3), dtype=np.float32) |
|
rotation_elevation[0, 0] = cos_phi |
|
rotation_elevation[0, 1] = sin_phi |
|
rotation_elevation[1, 0] = -sin_phi |
|
rotation_elevation[1, 1] = cos_phi |
|
rotation_elevation[2, 2] = 1.0 |
|
|
|
rotation_matrix = np.matmul(rotation_azimuth, rotation_elevation) |
|
displacement = np.zeros((3, 1), dtype=np.float32) |
|
displacement[0, 0] = float(focal_length) + float(focal_range) / 2.0 |
|
displacement = np.matmul(rotation_matrix, displacement) |
|
|
|
extrinsic_matrix[0:3, 0:3] = rotation_matrix |
|
extrinsic_matrix[0:3, 3:4] = -displacement |
|
|
|
intrinsic_matrix[2, 2] = 1.0 / float(focal_length) |
|
intrinsic_matrix[1, 1] = 1.0 / float(focal_length) |
|
|
|
camera_matrix = np.matmul(extrinsic_matrix, intrinsic_matrix) |
|
return camera_matrix |
|
|
|
|
|
def _build_image_grid(input_images, |
|
gt_projs, |
|
pred_projs, |
|
input_voxels, |
|
output_voxels, |
|
vis_size=128): |
|
"""Builds a grid image by concatenating the input images.""" |
|
quantity = input_images.shape[0] |
|
|
|
for row in xrange(int(quantity / 3)): |
|
for col in xrange(3): |
|
index = row * 3 + col |
|
input_img_ = utils.resize_image(input_images[index, :, :, :], vis_size, |
|
vis_size) |
|
gt_proj_ = utils.resize_image(gt_projs[index, :, :, :], vis_size, |
|
vis_size) |
|
pred_proj_ = utils.resize_image(pred_projs[index, :, :, :], vis_size, |
|
vis_size) |
|
gt_voxel_vis = utils.resize_image( |
|
utils.display_voxel(input_voxels[index, :, :, :, 0]), vis_size, |
|
vis_size) |
|
pred_voxel_vis = utils.resize_image( |
|
utils.display_voxel(output_voxels[index, :, :, :, 0]), vis_size, |
|
vis_size) |
|
if col == 0: |
|
tmp_ = np.concatenate( |
|
[input_img_, gt_proj_, pred_proj_, gt_voxel_vis, pred_voxel_vis], 1) |
|
else: |
|
tmp_ = np.concatenate([ |
|
tmp_, input_img_, gt_proj_, pred_proj_, gt_voxel_vis, pred_voxel_vis |
|
], 1) |
|
if row == 0: |
|
out_grid = tmp_ |
|
else: |
|
out_grid = np.concatenate([out_grid, tmp_], 0) |
|
|
|
return out_grid |
|
|