Skip to content
Snippets Groups Projects
Commit 50730c6b authored by Olivier Bertrand's avatar Olivier Bertrand
Browse files

remove backup files

parent 5034afbc
Branches
Tags
No related merge requests found
Showing with 0 additions and 1098 deletions
File deleted
File deleted
File deleted
File deleted
File deleted
"""
Define some constant
"""
__spherical_indeces__ = {'elevation': 0,
'azimuth': 1,
'radius': 2}
__cartesian_indeces__ = {'x': 0,
'y': 1,
'z': 2}
__ibpc_indeces__ = {'elevation': 0,
'azimuth': 1,
'channel': 2,
'component': 3}
__obpc_indeces__ = {'ommatidia': 0,
'channel': 1,
'component': 2}
__eye_indeces__ = {'elevation': 0,
'azimuth': 1,
'component': 2}
__ommadia_indeces__ = {'ommatidia': 0,
'component': 1}
import unittest
import sqlite3
import numpy as np
import pandas as pd
import navipy.database as database
import navipy.processing.pcode as pcode
from navipy.processing.tools import is_numeric_array
import pkg_resources
class TestCase(unittest.TestCase):
def setUp(self):
self.mydb_filename = pkg_resources.resource_filename(
'navipy', 'resources/database.db')
self.mydb = database.DataBaseLoad(self.mydb_filename)
def test_scene_posorient(self):
conn = sqlite3.connect(self.mydb_filename)
c = conn.cursor()
c.execute(""" SELECT * FROM position_orientation WHERE (rowid=1) """)
rows = c.fetchall()[0]
# working case
posorient = pd.Series(index=['x', 'y', 'z',
'alpha_0', 'alpha_1', 'alpha_2'])
posorient.x = rows[5]
posorient.y = rows[6]
posorient.z = rows[1]
posorient.alpha_0 = rows[3]
posorient.alpha_1 = rows[2]
posorient.alpha_2 = rows[4]
image = self.mydb.read_image(posorient=posorient)
image = np.expand_dims(image, axis=3)
self.assertIsNotNone(image)
self.assertFalse(sum(image.shape) == 0)
# print("shape",image.shape)
self.assertTrue(len(image.shape) == 4)
self.assertTrue(image.shape[3] == 1)
# incorrect case missing column
posorient2 = pd.Series(index=['y', 'z',
'alpha_0', 'alpha_1', 'alpha_2'])
posorient2.y = posorient.y
posorient2.z = posorient.z
posorient2.alpha_0 = posorient.alpha_0
posorient2.alpha_1 = posorient.alpha_1
posorient2.alpha_2 = posorient.alpha_2
with self.assertRaises(Exception):
image = self.mydb.read_image(posorient=posorient2)
# incorrect case None
posorient2 = pd.Series(index=['x', 'y', 'z',
'alpha_0', 'alpha_1', 'alpha_2'])
posorient2.x = None
posorient2.y = posorient.y
posorient2.z = posorient.z
posorient2.alpha_0 = posorient.alpha_0
posorient2.alpha_1 = posorient.alpha_1
posorient2.alpha_2 = posorient.alpha_2
with self.assertRaises(ValueError):
image = self.mydb.read_image(posorient=posorient2)
# incorrect case nan
posorient2 = pd.Series(index=['x', 'y', 'z',
'alpha_0', 'alpha_1', 'alpha_2'])
posorient2.x = np.nan
posorient2.y = posorient.y
posorient2.z = posorient.z
posorient2.alpha_0 = posorient.alpha_0
posorient2.alpha_1 = posorient.alpha_1
posorient2.alpha_2 = posorient.alpha_2
with self.assertRaises(ValueError):
image = self.mydb.read_image(posorient=posorient2)
# incorrect case no pandas series but dict
posorient2 = {}
posorient2['x'] = posorient.x
posorient2['y'] = posorient.y
posorient2['z'] = posorient.z
posorient2['alpha_0'] = posorient.alpha_0
posorient2['alpha_1'] = posorient.alpha_1
posorient2['alpha_2'] = posorient.alpha_2
with self.assertRaises(TypeError):
image = self.mydb.read_image(posorient=posorient2)
# not working case empty
posorient2 = pd.Series(index=['x', 'y', 'z',
'alpha_0', 'alpha_1', 'alpha_2'])
with self.assertRaises(Exception):
image = self.mydb.read_image(posorient=posorient2)
def test_skyline_scene(self):
scene = self.mydb.read_image(rowid=1)
scene2 = scene.copy()
scene = np.expand_dims(scene, axis=3)
scene2 = np.expand_dims(scene2, axis=3)
scene2[3, 5, 2, 0] = np.nan
scene3 = [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
scene3 = [scene3, scene3, scene3]
scene3 = np.array(scene3)
scene4 = np.zeros((3, 4, 5, 0))
# put useless stuff here
with self.assertRaises(ValueError):
pcode.skyline(scene2)
with self.assertRaises(TypeError):
pcode.skyline(scene3)
with self.assertRaises(Exception):
pcode.skyline(scene4)
# should be working -> check if result(skyline) is correct
for s in [scene]:
skyline = pcode.skyline(s)
self.assertFalse(skyline.shape[1] <= 0)
self.assertTrue(skyline.shape[2] == 4)
self.assertFalse(np.any(np.isnan(skyline)))
# self.assertFalse(np.any(np.isNone(skyline)))
self.assertTrue(is_numeric_array(skyline))
self.assertTrue(skyline.shape[3] == 1)
self.assertTrue(skyline.shape[0] > 0)
self.assertTrue(skyline.shape[1] > 0)
def test_id(self):
for rowid in [0, -2]:
with self.assertRaises(ValueError):
# print("rowid",rowid)
self.mydb.read_image(rowid=rowid)
with self.assertRaises(TypeError):
self.mydb.read_image(rowid='T')
with self.assertRaises(TypeError):
self.mydb.read_image(rowid=None)
with self.assertRaises(TypeError):
self.mydb.read_image(rowid=np.nan)
with self.assertRaises(TypeError):
self.mydb.read_image(rowid=4.5)
for rowid in [1, 2, 3, 4, 5]:
image = self.mydb.read_image(rowid=rowid)
image = np.expand_dims(image, axis=3)
# image=np.array(image)
self.assertIsNotNone(image)
self.assertFalse(sum(image.shape) == 0)
self.assertTrue(len(image.shape) == 4)
self.assertFalse(np.any(np.isnan(image)))
self.assertTrue(image.shape[3] == 1)
self.assertTrue(image.shape[2] == 4)
self.assertTrue(image.shape[0] > 0)
self.assertTrue(image.shape[1] > 0)
def test_distance_channel(self):
scene = self.mydb.read_image(rowid=1)
scene = np.expand_dims(scene, axis=3)
# should not be working
for d in ['g', None, np.nan, 8.4]:
with self.assertRaises(TypeError):
pcode.contrast_weighted_nearness(scene,
distance_channel=d)
with self.assertRaises(ValueError):
pcode.contrast_weighted_nearness(scene,
distance_channel=-1)
# should work
d = 3
weighted_scene = \
pcode.contrast_weighted_nearness(scene,
distance_channel=d)
# print("last channel",d)
self.assertTrue(is_numeric_array(weighted_scene))
self.assertTrue(~np.any(np.isnan(weighted_scene)))
self.assertEqual(weighted_scene.shape, scene.shape)
def test_contr_weight_scene(self):
scene = self.mydb.read_image(rowid=1)
scene = np.expand_dims(scene, axis=3)
# working cases
contrast = pcode.contrast_weighted_nearness(scene)
self.assertIsNotNone(contrast)
self.assertFalse(sum(contrast.shape) == 0)
self.assertTrue(len(contrast.shape) == 4)
self.assertFalse(np.any(np.isnan(contrast)))
self.assertTrue(contrast.shape[3] == 1)
self.assertTrue(contrast.shape[2] == 4)
self.assertTrue(contrast.shape[0] > 0)
self.assertTrue(contrast.shape[1] > 0)
# not working case
scene2 = scene.copy()
scene2[3, 2, 1, 0] = np.nan
scene3 = [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
scene3 = [scene3, scene3, scene3]
scene3 = np.array(scene3)
scene4 = np.zeros((3, 4, 5, 0))
with self.assertRaises(ValueError):
contrast = pcode.contrast_weighted_nearness(scene2)
with self.assertRaises(Exception):
contrast = pcode.contrast_weighted_nearness(scene3)
with self.assertRaises(Exception):
contrast = pcode.contrast_weighted_nearness(scene4)
def test_contr_weight_contrast(self):
scene = self.mydb.read_image(rowid=1)
scene = np.expand_dims(scene, axis=3)
for size in [9.4, 'g', None, np.nan]:
with self.assertRaises(TypeError):
contrast = pcode.contrast_weighted_nearness(
scene, contrast_size=size)
for size in [8, 1, 0, -4]:
with self.assertRaises(ValueError):
contrast = \
pcode.contrast_weighted_nearness(
scene, contrast_size=size)
# working cases
for size in [2, 3, 4, 5]:
contrast = pcode.contrast_weighted_nearness(scene,
contrast_size=size)
self.assertIsNotNone(contrast)
self.assertFalse(sum(contrast.shape) == 0)
self.assertTrue(len(contrast.shape) == 4)
self.assertFalse(np.any(np.isnan(contrast)))
self.assertEqual(contrast.shape[3], 1)
self.assertEqual(contrast.shape[2], scene.shape[2])
self.assertEqual(contrast.shape[0], scene.shape[0])
self.assertEqual(contrast.shape[1], scene.shape[1])
def test_pcv(self):
# working case
rowid = 1
my_scene = self.mydb.read_image(rowid=rowid)
my_scene = np.expand_dims(my_scene, axis=3)
directions = self.mydb.viewing_directions
my_pcv = pcode.pcv(my_scene, directions)
self.assertIsNotNone(my_pcv)
self.assertFalse(sum(my_pcv.shape) == 0)
self.assertTrue(len(my_pcv.shape) == 4)
self.assertFalse(np.any(np.isnan(my_pcv)))
self.assertTrue(my_pcv.shape[3] == 3)
self.assertTrue(my_pcv.shape[2] == 4)
self.assertTrue(my_pcv.shape[0] > 0)
self.assertTrue(my_pcv.shape[1] > 0)
# not working cases doesnt match with shape of place code
testdirection = np.zeros((2, 4, 2))
with self.assertRaises(Exception):
my_pcv = pcode.pcv(my_scene, testdirection)
# not working cases wrong last dimension
testdirection = np.zeros((180, 360, 1))
with self.assertRaises(Exception):
my_pcv = pcode.pcv(my_scene, testdirection)
# not working cases too many dimensions
testdirection = np.zeros((180, 360, 2, 4))
with self.assertRaises(Exception):
my_pcv = pcode.pcv(my_scene, testdirection)
# not working cases empty
testdirection = np.zeros(())
with self.assertRaises(Exception):
my_pcv = pcode.pcv(my_scene, testdirection)
# not working cases nans
testdirection = np.zeros((180, 360, 2, 4))
testdirection[2, 3, 0] = np.nan
with self.assertRaises(ValueError):
my_pcv = pcode.pcv(my_scene, testdirection)
def test_apcv(self):
# working case
rowid = 1
my_scene = self.mydb.read_image(rowid=rowid)
my_scene = np.expand_dims(my_scene, axis=3)
# print("scene shape",my_scene.shape)
directions = self.mydb.viewing_directions
print("directions", directions.shape)
my_pcv = pcode.apcv(my_scene, directions)
self.assertIsNotNone(my_pcv)
self.assertFalse(sum(my_pcv.shape) == 0)
self.assertTrue(len(my_pcv.shape) == 4)
self.assertFalse(np.any(np.isnan(my_pcv)))
self.assertTrue(my_pcv.shape[3] == 3)
self.assertTrue(my_pcv.shape[2] == 4)
self.assertTrue(my_pcv.shape[0] == 1)
self.assertTrue(my_pcv.shape[1] == 1)
# not working cases doesnt match with shape of place code
testdirection = np.zeros((2, 4, 2))
with self.assertRaises(Exception):
my_pcv = pcode.apcv(my_scene, testdirection)
# not working cases wrong last dimension
testdirection = np.zeros((180, 360, 1))
with self.assertRaises(Exception):
my_pcv = pcode.apcv(my_scene, testdirection)
# not working cases too many dimensions
testdirection = np.zeros((180, 360, 2, 4))
with self.assertRaises(Exception):
my_pcv = pcode.apcv(my_scene, testdirection)
# not working cases empty
testdirection = np.zeros(())
with self.assertRaises(Exception):
my_pcv = pcode.apcv(my_scene, testdirection)
# not working cases nans
testdirection = np.zeros((180, 360, 2, 4))
testdirection[2, 3, 0] = np.nan
with self.assertRaises(ValueError):
my_pcv = pcode.apcv(my_scene, testdirection)
def test_size(self):
# not working cases:
scene = self.mydb.read_image(rowid=1)
scene = np.expand_dims(scene, axis=3)
for size in [8, 1, 0, -4]:
with self.assertRaises(ValueError):
contrast = pcode.michelson_contrast(
scene, size=size)
for size in [9.4, 'g', None, np.nan]:
with self.assertRaises(TypeError):
contrast = pcode.michelson_contrast(
scene, size=size)
# working cases
for size in [2, 3, 4, 5]:
contrast = pcode.michelson_contrast(scene, size=size)
self.assertIsNotNone(contrast)
self.assertFalse(sum(contrast.shape) == 0)
self.assertTrue(len(contrast.shape) == 4)
self.assertFalse(np.any(np.isnan(contrast)))
self.assertTrue(contrast.shape[3] == 1)
self.assertTrue(contrast.shape[2] == 4)
self.assertTrue(contrast.shape[0] > 0)
self.assertTrue(contrast.shape[1] > 0)
def test_michelsoncontrast_scene(self):
scene = self.mydb.read_image(rowid=1)
scene = np.expand_dims(scene, axis=3)
# working cases
contrast = pcode.michelson_contrast(scene)
self.assertIsNotNone(contrast)
self.assertFalse(sum(contrast.shape) == 0)
self.assertTrue(len(contrast.shape) == 4)
self.assertFalse(np.any(np.isnan(contrast)))
self.assertTrue(contrast.shape[3] == 1)
self.assertTrue(contrast.shape[2] == 4)
self.assertTrue(contrast.shape[0] > 0)
self.assertTrue(contrast.shape[1] > 0)
# not working case
scene2 = scene.copy()
scene2[3, 2, 1, 0] = np.nan
scene3 = [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
scene3 = [scene3, scene3, scene3]
scene3 = np.array(scene3)
scene4 = np.zeros((3, 4, 5, 0))
for s in [scene2, scene3, scene4]:
with self.assertRaises(Exception) as cm:
contrast = pcode.michelson_contrast(s,)
print("wanted exception occured", cm.exception)
if __name__ == '__main__':
unittest.main()
from .constants import __ibpc_indeces__
from .constants import __spherical_indeces__
from .constants import __cartesian_indeces__
from .constants import __obpc_indeces__
from .constants import __eye_indeces__
import numpy as np
def check_scene(scene):
if is_ibpc(scene):
# print("normal")
if not is_numeric_array(scene):
raise TypeError('scene is of non numeric type')
if not ~np.any(np.isnan(scene)):
raise ValueError('scene contains nans')
if not len(scene.shape) == 4:
raise Exception('scene has wrong shape, must have 4 dimensions')
if not (scene.shape[1] > 0):
raise Exception('scenes first dimension is empty')
if not (scene.shape[0] > 0):
raise Exception('scenes second dimension is empty')
if not (scene.shape[2] == 4):
raise Exception('3rd dimension of scene must be four')
if not (scene.shape[3] == 1):
raise Exception('4rd dimension of scene must be one')
# assert ~(np.any(np.isNone(scene)))
return True
elif is_obpc(scene):
if not is_numeric_array(scene):
raise TypeError('scene is of non numeric type')
if not ~np.any(np.isnan(scene)):
raise ValueError('scene contains nans')
if not len(scene.shape) == 3:
raise Exception('scene has wrong shape, must have 4 dimensions')
if not ~(scene.shape[1] <= 0):
raise Exception('scenes first dimension is empty')
if not ~(scene.shape[0] <= 0):
raise Exception('scenes second dimension is empty')
if not (scene.shape[2] == 4):
raise Exception('3rd dimension of scene must be four')
# assert ~(np.any(np.isNone(scene)))
return True
def check_viewing_direction(viewing_direction):
if not is_numeric_array(viewing_direction):
raise TypeError('viewing direction is of non numeric type')
if not ~np.any(np.isnan(viewing_direction)):
raise ValueError('viewing direction contains nans')
if len(viewing_direction.shape) < 3:
raise Exception('viewing direction must have at least 3 dimensions')
if not (viewing_direction.shape[1] > 0):
raise Exception('viewing direction has empty second dimension')
if not (viewing_direction.shape[0] > 0):
raise Exception('viewing direction has empty first dimension')
if not (viewing_direction.shape[-1] == 2):
raise Exception(' last dimension of viewing direction must equal 2')
return True
def is_numeric_array(array):
"""Checks if the dtype of the array is numeric.
Booleans, unsigned integer, signed integer, floats and complex are
considered numeric.
:param array : `numpy.ndarray`-like The array to check.
:returns: True if it is a recognized numerical and False \
if object or string.
:rtype:bool
"""
numerical_dtype_kinds = {'b', # boolean
'u', # unsigned integer
'i', # signed integer
'f', # floats
'c'} # complex
try:
return array.dtype.kind in numerical_dtype_kinds
except AttributeError:
# in case it's not a numpy array it will probably have no dtype.
return np.asarray(array).dtype.kind in numerical_dtype_kinds
def is_ibpc(place_code):
"""Test if a place code is image based
:param place_code: a place-code
:returns: True if image based place-code
:rtype: bool
"""
toreturn = isinstance(place_code, np.ndarray)
toreturn = toreturn and (len(place_code.shape) ==
len(__ibpc_indeces__))
return toreturn
def is_obpc(place_code):
"""Test if a place code is ommatidia based
:param place_code: a place-code
:returns: True if ommatidia based place-code
:rtype: bool
"""
toreturn = isinstance(place_code, np.ndarray)
toreturn = toreturn and (len(place_code.shape) ==
len(__obpc_indeces__))
return toreturn
def ibs_to_obs(scene, eye_map):
"""Convert an image based scene to an ommatidium based scene.
:param scene: The scene to be converted
:param eye_map: The eye_map to use
:returns: (obs_scene,ommatidia_map)
:rtype: (np.ndarray,np.ndarray)
"""
assert is_ibpc(scene),\
'scene should be an ibs scene'
assert isinstance(eye_map, np.ndarray), 'eye_map should be a numpy array'
assert len(eye_map.shape) == len(__eye_indeces__),\
'eye_map should have {} dimensions to be an ibs scene'.format(
len(__eye_indeces__))
for index_name in ['elevation', 'azimuth']:
index = __ibpc_indeces__[index_name]
assert eye_map.shape[index] == scene.shape[index],\
'eye_map and scene should have the same number of {}'.format(
index_name)
obs_size = (scene.shape[__ibpc_indeces__['elevation']] *
scene.shape[__ibpc_indeces__['azimuth']],
scene.shape[__ibpc_indeces__['channel']],
scene.shape[__ibpc_indeces__['component']])
obs_scene = scene.reshape(obs_size)
omm_size = (eye_map.shape[__ibpc_indeces__['elevation']] *
eye_map.shape[__ibpc_indeces__['azimuth']],
eye_map.shape[__ibpc_indeces__['component']])
ommatidia_map = eye_map.reshape(omm_size)
return (obs_scene, ommatidia_map)
def cartesian_to_spherical(x, y, z):
radius = np.sqrt(x**2 + y**2 + z**2)
elevation = np.arctan2(z, np.sqrt(x**2 + y**2))
azimuth = np.arctan2(y, x)
spherical = np.zeros_like(x)
spherical = np.tile(spherical[..., np.newaxis], (3,))
spherical[..., __spherical_indeces__['elevation']] = elevation
spherical[..., __spherical_indeces__['azimuth']] = azimuth
spherical[..., __spherical_indeces__['radius']] = radius
return spherical
def spherical_to_cartesian(elevation, azimuth, radius=1):
cartesian = np.zeros_like(elevation)
cartesian = np.tile(cartesian[..., np.newaxis], (3,))
cartesian[..., __cartesian_indeces__['x']] = np.cos(
elevation) * np.cos(azimuth)
cartesian[..., __cartesian_indeces__['y']] = np.cos(
elevation) * np.sin(azimuth)
cartesian[..., __cartesian_indeces__['z']] = np.sin(elevation)
cartesian = radius * cartesian
return cartesian
File deleted
File deleted
"""
The beesampling class
.. tothinkof: conditional bpy import to build doc from comments
"""
import bpy
import os
import numpy as np
import pandas as pd
import warnings
from navipy.rendering.cyber_bee import Cyberbee
from navipy.database import DataBaseSave
class BeeSampling(Cyberbee):
"""
BeeSampling is a class deriving from Cyberbee.
The BeeSampling can be used to generate a database of
images taken on a rectangular regular grid. For the database,
the BeeSampling rely on DataBase
It worth noting that the generated database can take a large
harddrive space, as each image is composed of 4 channels of 180x360 pixels.
"""
def __init__(self):
"""Initialise the BeeSampling"""
Cyberbee.__init__(self)
self.blenddirname = os.path.dirname(bpy.data.filepath)
self.blendfilename = os.path.basename(bpy.data.filepath)
self.__grid_posorients = None
self.__grid_size = None
self.world_dim = np.inf
def create_sampling_grid(self, x, y, z, alpha1, alpha2, alpha3):
"""Create a cubic grid from all the sampling points
:param x: the positions along the x-axis
:param y: the positions along the y-axis
:param z: the positions along the z-axis
:param alpha1: the first euler angles
:param alpha2: the 2nd euler angles
:param alpha3: the 3rd euler angles
"""
if not (isinstance(x, int) or isinstance(x, float)):
raise TypeError('x must be integer')
if not (isinstance(y, int) or isinstance(y, float)):
raise TypeError('y must be integer')
if not (isinstance(z, int) or isinstance(z, float)):
raise TypeError('z must be integer')
if not (isinstance(alpha1, float) or isinstance(alpha1, int)):
raise TypeError('alpha1 must be float')
if not (isinstance(alpha2, float) or isinstance(alpha2, int)):
raise TypeError('alpha2 must be float')
if not (isinstance(alpha3, float) or isinstance(alpha3, int)):
raise TypeError('alpha3 must be float')
[mx, my, mz, ma1, ma2, ma3] = np.meshgrid(x,
y,
z,
alpha1,
alpha2,
alpha3)
self.grid_size = mx.shape
mx = mx.flatten()
my = my.flatten()
mz = mz.flatten()
ma1 = ma1.flatten()
ma2 = ma2.flatten()
ma3 = ma3.flatten()
self.__grid_posorients = pd.DataFrame(index=range(mx.shape[0]),
columns=['x', 'y', 'z',
'alpha_0',
'alpha_1',
'alpha_2'])
self.__grid_posorients.loc[:, 'x'] = mx
self.__grid_posorients.loc[:, 'y'] = my
self.__grid_posorients.loc[:, 'z'] = mz
self.__grid_posorients.loc[:, 'alpha_0'] = ma1
self.__grid_posorients.loc[:, 'alpha_1'] = ma2
self.__grid_posorients.loc[:, 'alpha_2'] = ma3
self.__grid_posorients.index.name = 'grid_index'
self.__grid_posorients.name = 'grid_position_orientation'
@property
def grid_posorients(self):
"""return a copy of the posorientation matrix
:returns: position-orientations of the grid
:rtype: pandas array
.. todo: use @property
def grid_posorients(self)
.. todo: create @property.setter
def grid_posorients(self,posorients)
(need a type check, and col check, and copy of df)
"""
return self.__grid_posorients.copy()
def set_gridindeces2nan(self, indeces):
"""Set certain grid point to nan, so they will be ignore in the rendering
:param indeces: a list of indeces to be set to nan
.. todo: use @property.setter
def blacklist_indeces(self,indeces)
"""
if not isinstance(indeces, list):
raise TypeError('indeces must be a list')
if any(np.isnan(indeces)):
raise ValueError('indeces must not contain nans')
self.__grid_posorients.loc[indeces, :] = np.nan
def render(self, database_filename):
if not isinstance(database_filename, str):
raise TypeError('filename must be a string')
database_folder = os.path.dirname(database_filename)
if not os.path.exists(database_folder):
os.makedirs(database_folder)
dataloger = DataBaseSave(database_filename,
channels=['R', 'G', 'B', 'D'],
arr_dtype=np.uint8)
for frame_i, posorient in self.__grid_posorients.iloc[::-1].iterrows():
print(frame_i)
if np.any(np.isnan(posorient)):
# warnings.warn('frame_i: {} posorient nans'.format(frame_i))
continue
rowid = dataloger.posid(posorient)
if dataloger.check_data_validity(rowid):
warnings.warn(
'frame_i: {} data is valid rowid {}'.format(frame_i,
rowid))
continue
# The position-orientatios is valid (none nan)
# and the cmaxminrange has not already been assigned
# so the image need to be rendered
self.update(posorient)
distance = self.distance
distance[distance > self.world_dim] = self.world_dim
image = self.image
image[:, :, 3] = distance
dataloger.write_image(posorient, image)
print('rendering completed')
if __name__ == "__main__":
import tempfile
bee_samp = BeeSampling()
# Create mesh
world_dim = 15.0
x = np.linspace(-7.5, 7.5, 5)
y = np.linspace(-7.5, 7.5, 5)
z = np.arange(1, 8, 2)
alpha_1 = np.array([0]) + np.pi / 2
alpha_2 = np.array([0])
alpha_3 = np.array([0])
bee_samp.create_sampling_grid(
x, y, z, alpha1=alpha_1, alpha2=alpha_2, alpha3=alpha_3)
bee_samp.world_dim = world_dim
grid_pos = bee_samp.grid_posorients
condition = (grid_pos.x**2 + grid_pos.y**2) < ((bee_samp.world_dim / 2)**2)
bee_samp.set_gridindeces2nan(condition[condition == 0].index)
bee_samp.cycle_samples(samples=5)
with tempfile.TemporaryDirectory() as folder:
bee_samp.render(folder + '/database.db')
"""
How to test the script:
-----------------------
>>> blender test.blend --background --python Cyberbee.py
:Author: Olivier Bertrand (olivier.bertrand@uni-bielefeld.de)
:Parent module: Scene_rendering
..tothinkof for the doc bpy will raise an issue.
conditional import of bpy
"""
import bpy
import numpy as np
import tempfile
import os
class Cyberbee():
"""
Cyberbee is a small class binding python with blender.
With Cyberbee one can move the bee to a position, and render what
the bee see at this position.
The Bee eye is a panoramic camera with equirectangular projection
The light rays attaining the eyes are filtered with a gaussian.
"""
def __init__(self):
"""Initialise the Cyberbee
..todo check that TemporaryDirectory is writtable and readable
"""
# Rendering engine needs to be Cycles to support panoramic
# equirectangular camera
bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.render.layers["RenderLayer"].use_pass_z = True
# Look for object camera
camera_found = False
for obj in bpy.context.scene.objects:
if obj.type == 'CAMERA':
self.camera = obj
camera_found = True
break
assert camera_found, 'The blender file does not contain a camera'
# The bee eye is panoramic, and with equirectangular projection
self.camera.data.type = 'PANO'
self.camera.data.cycles.panorama_type = 'EQUIRECTANGULAR'
# Filtering props
bpy.context.scene.cycles.filter_type = 'GAUSSIAN'
# Call all set function with default values
self.camera_rotation_mode = 'XYZ'
self.camera_fov = [[-90, 90], [-180, 180]]
self.camera_gaussian_width = 1.5
self.camera_resolution = [360, 180]
self.cycle_samples = 30
# switch on nodes
# Create render link to OutputFile with Image and Z buffer
bpy.context.scene.use_nodes = True
scene = bpy.context.scene
nodes = scene.node_tree.nodes
render_layers = nodes['Render Layers']
output_file = nodes.new("CompositorNodeOutputFile")
output_file.format.file_format = "OPEN_EXR"
output_file.file_slots.remove(output_file.inputs[0])
tmp_fileoutput = dict()
tmp_fileoutput['Image'] = 'Image'
tmp_fileoutput['Depth'] = 'Depth'
tmp_fileoutput['Folder'] = tempfile.TemporaryDirectory().name
tmp_fileoutput['ext'] = '.exr'
output_file.file_slots.new(tmp_fileoutput['Image'])
output_file.file_slots.new(tmp_fileoutput['Depth'])
output_file.base_path = tmp_fileoutput['Folder']
scene.node_tree.links.new(
render_layers.outputs['Image'],
output_file.inputs['Image']
)
scene.node_tree.links.new(
render_layers.outputs['Z'],
output_file.inputs['Depth']
)
self.tmp_fileoutput = tmp_fileoutput
@property
def camera_rotation_mode(self):
"""get the current camera rotation mode
:returns: the mode of rotation used by the camera
:rtype: string
..todo: Use @property
def camera_rotation_mode(self)
"""
return bpy.data.scenes["Scene"].camera.rotation_mode
@camera_rotation_mode.setter
def camera_rotation_mode(self, mode='XYZ'):
"""change the camera rotation mode
:param mode: the mode of rotation for the camera see blender doc
(default: 'XYZ').
:type mode: a string
.. seealso: blender bpy.data.scenes["Scene"].camera.rotation_mode
..todo: Use @property.setter
def camera_rotation_mode(self, mode='XYZ')
"""
if not isinstance(mode, str):
raise TypeError('mode must be a string')
bpy.data.scenes["Scene"].camera.rotation_mode = mode
@property
def cycle_samples(self):
"""get the samples for rendering with cycle
:returns: the number of samples used for the rendering
:rtype: int
..todo use @property
def cycle_samples(self)
"""
return bpy.context.scene.cycles.samples
@cycle_samples.setter
def cycle_samples(self, samples=30):
"""change the samples for rendering with cycle
:param samples: the number of samples to use when rendering images
:type samples: int
..todo: Use @property.setter
def cycle_samples(self, samples=30)
"""
if not isinstance(samples, int):
raise TypeError('samples must be an integer')
bpy.context.scene.cycles.samples = samples
@property
def camera_fov(self):
"""get fov of camera
:returns: the field of view of the camera as min/max,longitude/latitude
in degrees
:rtype: dict
..todo use @property
def camera_fov()
..todo Change assert to if -> raise TypeError/KeyError
"""
assert self.camera.data.type == 'PANO', 'Camera is not panoramic'
assert self.camera.cycles.panorama_type == 'EQUIRECTANGULAR',\
'Camera is not equirectangular'
fov = dict()
fov['latitude_min'] = np.rad2ged(self.camera.data.cycles.latitude_min)
fov['latitude_max'] = np.rad2ged(self.camera.data.cycles.latitude_max)
fov['longitude_min'] = np.rad2ged(
self.camera.data.cycles.longitude_min)
fov['longitude_max'] = np.rad2ged(
self.camera.data.cycles.longitude_max)
return fov
@camera_fov.setter
def camera_fov(self, resolution=[[-90, 90], [-180, 180]]):
"""change the field of view of the panoramic camera
:param resolution: [[minimum latitude, maximum latitude],
[minimum longitude, maximum longitude]]
(in deg)
:type latmin: 2x2 float array or list
..todo use @property.setter
def camera_fov(self, latlongrange)
here latlongrange is a a 2x2 list or array:
[[latmin,latmax],[longmin,longmax]]
..todo Change assert to if -> raise TypeError()/KeyError()
"""
if not (isinstance(resolution, list) or
isinstance(resolution, np.ndarray)):
raise TypeError('resolution must be list or array')
if not self.camera.data.type == 'PANO':
raise Exception('Camera is not panoramic')
if not self.camera.data.cycles.panorama_type == 'EQUIRECTANGULAR':
raise Exception('Camera is not equirectangular')
self.camera.data.cycles.latitude_min = np.deg2rad(resolution[0, 0])
self.camera.data.cycles.latitude_max = np.deg2rad(resolution[0, 1])
self.camera.data.cycles.longitude_min = np.deg2rad(resolution[1, 0])
self.camera.data.cycles.longitude_max = np.deg2rad(resolution[1, 1])
@property
def camera_gaussian_width(self, gauss_w=1.5):
"""get width of the gaussian spatial filter
:returns: the width of the gaussian filter
:rtype: float
..todo use @property
def camera_gaussian_width(self)
"""
if not (isinstance(gauss_w, int) or isinstance(gauss_w, float)):
raise TypeError('gauss window must be integer or float')
return bpy.context.scene.cycles.filter_width
@camera_gaussian_width.setter
def camera_gaussian_width(self, gauss_w=1.5):
"""change width of the gaussian spatial filter
:param gauss_w: width of the gaussian filter
:type gauss_w: float
..todo use @property.setter
def camera_gaussian_width(self)
..todo check that input argument is of correct type,
if not raise TypeError()
"""
if not (isinstance(gauss_w, int) or isinstance(gauss_w, float)):
raise TypeError('gauss window must be integer or float')
bpy.context.scene.cycles.filter_width = gauss_w
@property
def camera_resolution(self):
"""return camera resolution (x,y)
:returns: the resolution of the camera along (x-axis,y-axis)
:rtype: (int,int)
..todo use @property
def camera_resolution(self)
"""
resolution_x = bpy.context.scene.render.resolution_x
resolution_y = bpy.context.scene.render.resolution_y
return resolution_x, resolution_y
@camera_resolution.setter
def set_camera_resolution(self, resolution=[360, 180]):
"""change the camera resolution (nb of pixels)
:param resolution_x: number of pixels along the x-axis of the camera
:type resolution_x: int
:param resolution_y: number of pixels along the y-axis of the camera
:type resolution_y: int
..todo use @property.setter
def camera_resolution(self,resolution)
here resolution is [res_x,res_y]
..todo check type and raise TypeError
"""
if not (isinstance(resolution, list) or isinstance(resolution, np.ndarray)):
raise TypeError('resolution list or array')
bpy.context.scene.render.resolution_x = resolution[0]
bpy.context.scene.render.resolution_y = resolution[1]
bpy.context.scene.render.resolution_percentage = 100
def update(self, posorient):
"""assign the position and the orientation of the camera.
:param posorient: is a 1x6 vector containing:
x,y,z, angle_1, angle_2, angle_3,
here the angles are euler rotation around the axis
specified by scene.camera.rotation_mode
:type posorient: 1x6 double array
"""
if len(posorient) != 6:
raise Exception('posorient should be a 1x6 double array')
if not (isinstance(posorient, np.ndarray) or
isinstance(posorient, list)):
raise TypeError('posorient must be of type array or list')
self.camera.location = posorient[:3]
self.camera.rotation_euler = posorient[3:]
# Render
bpy.ops.render.render()
@property
def image(self):
"""return the last rendered image as a numpy array
:returns: the image (height,width,4)
:rtype: a double numpy array
.. note: A temporary file will be written on the harddrive,
due to API blender limitation
.. todo: use @property
def image(self)
"""
# save image as a temporary file, and then loaded
# sadly the rendered image pixels can not directly be access
filename = os.path.join(self.tmp_fileoutput['Folder'],
self.tmp_fileoutput['Image'] + '0001' +
self.tmp_fileoutput['ext'])
im_width, im_height = self.camera_resolution
im = bpy.data.images.load(filename)
pixels = np.array(im.pixels)
# im=PIL.Image.open(filename)
# pixels=np.asarray(im)
pixels = pixels.reshape([im_height, im_width, 4])
return pixels
@property
def distance(self):
"""return the last rendered distance map as a numpy array
:returns: the distance map (height, width)
:rtype: a double numpy array
.. note: A temporary file will be written on the harddrive,
due to API blender limitation
.. todo: use @property
def distance(self)
"""
# save image as a temporary file, and then loaded
# sadly the rendered image pixels can not directly be access
filename = os.path.join(self.tmp_fileoutput['Folder'],
self.tmp_fileoutput['Depth'] + '0001' +
self.tmp_fileoutput['ext'])
im_width, im_height = self.camera_resolution
im = bpy.data.images.load(filename)
distance = np.array(im.pixels)
# im=PIL.Image.open(filename)
# distance=np.asarray(im)
distance = distance.reshape([im_height, im_width, 4])
distance = distance[:, :, 0]
return distance
if __name__ == "__main__":
# Initiate the Cyberbee
mybee = Cyberbee()
frames_per_revolution = 5.0
step_size = 2 * np.pi / frames_per_revolution
posorients = np.zeros((frames_per_revolution, 6))
posorients[:, 0] = np.sin(np.arange(frames_per_revolution) * step_size) * 5
posorients[:, 1] = np.cos(np.arange(frames_per_revolution) * step_size) * 5
for frame_i, posorient in enumerate(posorients):
mybee.update(posorient)
# Test image
image = mybee.image
# Test distance
distance = mybee.distance
print('Cyberbee OK')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment