Source code for openalea.phenomenal.object.voxelGrid

# -*- python -*-
#
#       Copyright INRIA - CIRAD - INRA
#
#       Distributed under the Cecill-C License.
#       See accompanying file LICENSE.txt or copy at
#           http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
# ==============================================================================
from __future__ import division, print_function, absolute_import

import os
import re
import json
import numpy
import csv

from .image3D import Image3D
# ==============================================================================


[docs]class VoxelGrid(object):
[docs] def __init__(self, voxels_position, voxels_size): self._voxels_position = voxels_position self._voxels_size = voxels_size
# ========================================================================== # GETTER & SETTER # ========================================================================== @property def voxels_position(self): return self._voxels_position @voxels_position.setter def voxels_position(self, voxels_position): self._voxels_position = voxels_position @voxels_position.deleter def voxels_position(self): del self._voxels_position @property def voxels_size(self): return self._voxels_size @voxels_size.setter def voxels_size(self, voxels_size): self._voxels_size = voxels_size @voxels_size.deleter def voxels_size(self): del self._voxels_size # ========================================================================== # Analysis Data # ========================================================================== def bounding_box(self): if len(self._voxels_position) == 0: raise ValueError("Empty list") x_min = float("inf") y_min = float("inf") z_min = float("inf") x_max = - float("inf") y_max = - float("inf") z_max = - float("inf") for x, y, z in self._voxels_position: x_min = min(x_min, x) y_min = min(y_min, y) z_min = min(z_min, z) x_max = max(x_max, x) y_max = max(y_max, y) z_max = max(z_max, z) return (x_min, y_min, z_min), (x_max, y_max, z_max) def volume(self): """ Compute the volume of the voxel point cloud """ return len(self._voxels_position) * self._voxels_size ** 3 def __len__(self): return len(self._voxels_position) # ========================================================================== # SHOW # ========================================================================== def show(self): raise NotImplementedError # ========================================================================== # TRANSFORM # ========================================================================== def to_image_3d(self): (x_min, y_min, z_min), (x_max, y_max, z_max) = self.bounding_box() len_x = int((x_max - x_min) / self.voxels_size + 1) len_y = int((y_max - y_min) / self.voxels_size + 1) len_z = int((z_max - z_min) / self.voxels_size + 1) image_3d = Image3D.zeros((len_x, len_y, len_z), dtype=numpy.bool, voxels_size=self.voxels_size, world_coordinate=(x_min, y_min, z_min)) bound_min = numpy.array((x_min, y_min, z_min)) vs_pos = numpy.array(self.voxels_position) r = ((vs_pos - bound_min) / self.voxels_size).astype(int) image_3d[r[:, 0], r[:, 1], r[:, 2]] = 1 return image_3d @staticmethod def from_image_3d(image_3d, voxels_value=1, voxels_size=None, world_coordinate=None): xx, yy, zz = numpy.where(image_3d >= voxels_value) if voxels_size is None: voxels_size = image_3d.voxels_size if world_coordinate is None: world_coordinate = image_3d.world_coordinate xxx = world_coordinate[0] + xx * voxels_size yyy = world_coordinate[1] + yy * voxels_size zzz = world_coordinate[2] + zz * voxels_size voxels_position = numpy.column_stack((xxx, yyy, zzz)) # voxels_position = zip() return VoxelGrid(voxels_position, voxels_size) # ========================================================================== # READ / WRITE # ========================================================================== def write(self, filename): ext = filename.split(".")[-1] if ext == "npz": return self.write_to_npz(filename) if ext == "json": return self.write_to_json(filename) if ext == "csv": return self.write_to_csv(filename) raise ValueError("No extension") @staticmethod def read(filename): ext = filename.split(".")[-1] if ext == "npz": return VoxelGrid.read_from_npz(filename) if ext == "json": return VoxelGrid.read_from_json(filename) if ext == "csv": return VoxelGrid.read_from_csv(filename) raise ValueError("No extension") def write_to_npz(self, filename): image_3d = self.to_image_3d() image_3d.write_to_npz(filename) @staticmethod def read_from_npz(filename): image_3d = Image3D.read_from_npz(filename) return VoxelGrid.from_image_3d(image_3d) def write_to_json(self, filename): if (os.path.dirname(filename) and not os.path.exists( os.path.dirname(filename))): os.makedirs(os.path.dirname(filename)) with open(filename, 'w') as f: data = dict() data['voxels_size'] = self.voxels_size data['voxels_position'] = list(map(tuple, self.voxels_position)) json.dump(data, f) @staticmethod def read_from_json(filename): with open(filename, 'rb') as f: data = json.load(f) voxels_size = data['voxels_size'] voxels_position = data['voxels_position'] return VoxelGrid(voxels_position, voxels_size) def write_to_xyz(self, filename): if (os.path.dirname(filename) and not os.path.exists(os.path.dirname( filename))): os.makedirs(os.path.dirname(filename)) f = open(filename, 'wb') for x, y, z in self.voxels_position: f.write("%f %f %f \n" % (x, y, z)) f.close() @staticmethod def read_from_xyz(filename, voxels_size): voxels_position = list() with open(filename, 'r') as f: for line in f: point_3d = re.findall(r'[-0-9.]+', line) x = float(point_3d[0]) y = float(point_3d[1]) z = float(point_3d[2]) voxels_position.append((x, y, z)) f.close() return VoxelGrid(voxels_position, voxels_size) def write_to_csv(self, filename): if (os.path.dirname(filename) and not os.path.exists(os.path.dirname( filename))): os.makedirs(os.path.dirname(filename)) with open(filename, 'wb') as f: c = csv.writer(f) c.writerow(['x_coord', 'y_coord', 'z_coord', 'voxel_size']) for x, y, z in self.voxels_position: c.writerow([x, y, z, self.voxels_size]) @staticmethod def read_from_csv(filename): with open(filename, 'rb') as f: reader = csv.reader(f) next(reader) x, y, z, vs = next(reader) voxels_size = float(vs) voxels_position = list() voxels_position.append((float(x), float(y), float(z))) for x, y, z, vs in reader: voxels_position.append((float(x), float(y), float(z))) return VoxelGrid(voxels_position, voxels_size)