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

Split processing into place and motion codes

parent 76364219
No related branches found
No related tags found
No related merge requests found
......@@ -116,10 +116,8 @@ It creates three sql table on initialisation.
def __init__(self, filename, channels=['R', 'G', 'B', 'D']):
"""Initialisation of the database """
if not isinstance(filename, str):
raise TypeError('filename should be a string')
if not isinstance(channels, list):
raise TypeError('nb_channel should be a list')
assert isinstance(filename, str), 'filename should be a string'
assert isinstance(channels, list), 'nb_channel should be an integer'
self.filename = filename
self.channels = channels
self.normalisation_columns = list()
......@@ -145,13 +143,14 @@ It creates three sql table on initialisation.
if os.path.exists(filename):
# Check database
self.db = sqlite3.connect(
filename, detect_types=sqlite3.PARSE_DECLTYPES)
'file:' + filename + '?cache=shared', uri=True,
detect_types=sqlite3.PARSE_DECLTYPES,
timeout=10)
self.db_cursor = self.db.cursor()
for tablename, _ in self.tablecolumns.items():
if not self.table_exist(tablename):
raise Exception('{} does not contain\
a table named {}'.format(
filename, tablename))
assert self.table_exist(tablename),\
'{} does not contain a table named {}'.format(
filename, tablename)
elif self.create():
# Create database
self.db = sqlite3.connect(
......@@ -176,8 +175,7 @@ It creates three sql table on initialisation.
self.viewing_directions[..., 1] = ma
def table_exist(self, tablename):
if not isinstance(tablename, str):
raise TypeError('tablename should be a string')
assert isinstance(tablename, str), 'tablename should be a string'
self.db_cursor.execute(
"""
SELECT count(*)
......@@ -191,19 +189,22 @@ It creates three sql table on initialisation.
"""
SELECT count(*)
FROM position_orientation
WHERE rowid=?;""", (rowid,))
WHERE rowid=?;
""", (rowid,))
valid = bool(self.db_cursor.fetchone()[0])
self.db_cursor.execute(
"""
SELECT count(*)
FROM normalisation
WHERE rowid=?;""", (rowid,))
WHERE rowid=?;
""", (rowid,))
valid = valid and bool(self.db_cursor.fetchone()[0])
self.db_cursor.execute(
"""
SELECT count(*)
FROM image
WHERE rowid=?;""", (rowid,))
WHERE rowid=?;
""", (rowid,))
valid = valid and bool(self.db_cursor.fetchone()[0])
return valid
......@@ -309,8 +310,8 @@ database
return posorient
def read_posorient(self, posorient=None, rowid=None):
if (posorient is None) and (rowid is None):
raise ValueError('posorient and rowid can not be both None')
assert (posorient is None) or (rowid is None),\
'posorient and rowid can not be both None'
if posorient is not None:
rowid = self.get_posid(posorient)
# Read images
......@@ -336,8 +337,8 @@ database
:returns: an image
:rtype: numpy.ndarray
"""
if (posorient is None) and (rowid is None):
raise ValueError('posorient and rowid can not be both None')
assert (posorient is None) or (rowid is None),\
'posorient and rowid can not be both None'
if posorient is not None:
rowid = self.get_posid(posorient)
# Read images
......@@ -357,20 +358,19 @@ database
FROM {}
WHERE (rowid={})
""".format(tablename, rowid), self.db)
if not cmaxminrange.shape[0] == 1:
raise Exception('Error while reading normalisation factors')
assert cmaxminrange.shape[0] == 1,\
'Error while reading normalisation factors'
cmaxminrange = cmaxminrange.iloc[0, :]
return self.denormalise_image(image, cmaxminrange)
def denormalise_image(self, image, cmaxminrange):
if not len(image.shape) == 3:
raise Exception('image should be 3D array')
if not image.shape[2] == len(self.channels):
raise Exception('image does not have the\
required number of channels {}'.format(
len(self.channels)))
if not isinstance(cmaxminrange, pd.Series):
raise TypeError('cmaxminrange should be a pandas Series')
assert len(image.shape) == 3,\
'image should be 3D array'
assert image.shape[2] == len(self.channels),\
'image does not have the required number of channels {}'.format(
len(self.channels))
assert isinstance(cmaxminrange, pd.Series),\
'cmaxminrange should be a pandas Series'
denormed_im = np.zeros(image.shape, dtype=np.float)
maxval_nim = np.iinfo(image.dtype).max
#
......@@ -383,9 +383,8 @@ database
cimage *= crange
cimage += cmin
denormed_im[:, :, chan_i] = cimage
if not np.max(cimage) == cmax:
raise Exception('denormalisation failed\
{}!={}'.format(np.max(cimage), cmax))
assert np.max(cimage) == cmax,\
'denormalisation failed {}!={}'.format(np.max(cimage), cmax)
return denormed_im
......@@ -421,10 +420,10 @@ class DataBaseSave(DataBase):
self.insert_replace(tablename, params)
def insert_replace(self, tablename, params):
if not isinstance(tablename, str):
raise TypeError('table are named by string')
if not isinstance(params, dict):
raise TypeError('params should be dictionary columns:val')
assert isinstance(tablename, str),\
'table are named by string'
assert isinstance(params, dict),\
'params should be dictionary columns:val'
params_list = list()
columns_str = ''
for key, val in params.items():
......
......@@ -4,14 +4,16 @@ Test of maths
import numpy as np
import pandas as pd
import navipy.moving.maths as navimaths
import unittest
class TestNavipyMovingMaths(unittest.TestCase):
""" A class to test some mathy function of the toolbox
"""
def test_motion_vec_pandas(self):
""" Test that a TypeError is correctly raised
"""
motion_vec = 'NotPandas'
move_mode = 'on_cubic_grid'
mode_param = dict()
......@@ -22,6 +24,8 @@ class TestNavipyMovingMaths(unittest.TestCase):
move_mode)
def test_notsupported_mofm(self):
""" Test that a TypeError is correctly raised
"""
motion_vec = pd.Series(data=0,
index=['x', 'y', 'z', 'dx', 'dy', 'dz'])
move_mode = 'NotSupportedMode'
......@@ -33,6 +37,12 @@ class TestNavipyMovingMaths(unittest.TestCase):
move_mode)
def test_null_velocity(self):
""" Test null velocity
When the agent has a null velocity, the next postion
should be equal to the current position. Here, we
test this by series equality.
"""
# Test if stay at same position.
motion_vec = pd.Series(data=0,
index=['x', 'y', 'z', 'dx', 'dy', 'dz'])
......@@ -44,7 +54,13 @@ class TestNavipyMovingMaths(unittest.TestCase):
'At null velocity the agent should not move')
def test_closest_cubic(self):
""" Test if the snaping to cubic is correct """
""" Test if the snaping to cubic is correct
When the agent move on the grid, its position has to be snapped
to the grid position. On a cubic grid, the instability is at
22.5 degrees modulo 45 degrees. We therefore test the functions
close to each instability.
"""
positions = pd.DataFrame({'x': [0, 0, 0, 1, 1, 1, 2, 2, 2],
'y': [0, 1, 2, 0, 1, 2, 0, 1, 2],
'z': [0, 0, 0, 0, 0, 0, 0, 0, 0]},
......
"""
The scene processing part of the toolbox defines methodes
to transform an image into a place code in the sense
of Basten and Mallot (2010).
The scene is either
* a 4d numpy array, used when the image is a equirectangular \
projection, i.e. a panoramic image.
* a 3d numpy array, used when the viewing direction can not \
be mapped/projected on a regular image (e.g. insect eye).
We thus define the following for a scene:
image based scene (IBS)
A classical image. Each pixel is viewed in a direction
(elevation,azimuth) in a regular manner.
In that case the scene is a 4d numpy array
[elevation-index,azimuth-index,channel-index,1].
Omatidium based scene (OBS)
In an ommatidia based scene, the viewing direction
do not need to be regularally spaced.
In that case the scene is a 3d numpy array
[ommatidia-index, channel-index,1].
By extension a place-code is either image based or ommatidium based.
The number of dimension of an ib-place-code is always 4, and of an
ob-place-code always 3.
image based place-code (IBPC)
A place code derived from IBS. Each pixel is viewed in a direction
(elevation,azimuth) in a regular manner.
In that case the scene is a 4d numpy array
[elevation-index,azimuth-index,channel-index,component-index].
Omatidium based place-code (OBPC)
A place code derived from OBS, the viewing direction
do not need to be regularally spaced.
In that case the scene is a 3d numpy array
[ommatidia-index, channel-index,component-index].
Abusing the terminology of a place-code, a scene can be a place-code.
Therefore ibs and obs have 4 and 3 dimension, respectively.
.. todo:
* implement optic flow vector
place code
"""
import numpy as np
import pandas as pd
......@@ -58,35 +10,8 @@ from .constants import __obpc_indeces__
from .tools import is_ibpc
from .tools import is_obpc
from .tools import spherical_to_cartesian
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.
Parameters
----------
array : `numpy.ndarray`-like
The array to check.
Returns
-------
is_numeric : `bool`
True if it is a recognized numerical and False if object or
string.
"""
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
from .tools import check_scene
from .tools import check_viewing_direction
def scene(database, posorient=None, rowid=None):
......@@ -147,61 +72,6 @@ def scene(database, posorient=None, rowid=None):
raise ValueError('either rowid or posoriend must be given')
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')
if not (scene.shape[3] == 1):
raise Exception('4rd dimension of scene must be one')
# 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 not len(viewing_direction.shape) == 3:
raise Exception('viewing direction must have 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[2] == 2):
raise Exception(' 3rd dimension of viewing direction must equal 2')
return True
def skyline(scene):
"""Return the average along the elevation of a scene
:param scene: the scenery at a given location (a 4d numpy array)
......@@ -373,8 +243,3 @@ def apcv(place_code, viewing_directions):
return (scaled_lv.sum(axis=0))[np.newaxis, ...]
else:
raise TypeError('place code is neither an ibpc nor obpc')
def optic_flow(place_code, viewing_directions, velocity):
"""NOT IMPLEMENTED"""
raise NameError('Not Implemented')
......@@ -6,6 +6,84 @@ 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')
if not (scene.shape[3] == 1):
raise Exception('4rd dimension of scene must be one')
# 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 not len(viewing_direction.shape) == 3:
raise Exception('viewing direction must have 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[2] == 2):
raise Exception(' 3rd 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
......
......@@ -88,7 +88,8 @@ harddrive space, as each image is composed of 4 channels of 180x360 pixels.
dataloger = DataBaseSave(database_filename,
channels=['R', 'G', 'B', 'D'],
arr_dtype=np.uint8)
for frame_i, posorient in self.__grid_posorients.iterrows():
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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment