diff --git a/navipy/database/__init__.py b/navipy/database/__init__.py index 814069643f410a072f5c0a98f0de6ccd7f41a4b8..bef05641d49792b26df16014a7cf02f0e7b5df79 100644 --- a/navipy/database/__init__.py +++ b/navipy/database/__init__.py @@ -84,12 +84,15 @@ import pandas as pd import sqlite3 import io import warnings +import navipy.processing.tools as tools def adapt_array(arr): """ http://stackoverflow.com/a/31312102/190597 (SoulNibbler) """ + if array is None: + raise ValueError('array must not be None') out = io.BytesIO() np.save(out, arr) out.seek(0) @@ -97,6 +100,8 @@ def adapt_array(arr): def convert_array(text): + if text is None: + raise ValueError('text must not be None') out = io.BytesIO(text) out.seek(0) return np.load(out) @@ -118,8 +123,11 @@ It creates three sql table on initialisation. """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 an integer') + if (not isinstance(channels, list) or not isinstance(channels,np.array)): + raise TypeError('nb_channel should be a list or np array') + """for c in channels: + if not c in ['R','G','B','D']: + raise ValueError('channels must be either R,G,B or D (Distance)')""" self.filename = filename self.channels = channels self.normalisation_columns = list() @@ -150,9 +158,9 @@ It creates three sql table on initialisation. timeout=10) self.db_cursor = self.db.cursor() for tablename, _ in self.tablecolumns.items(): - assert self.table_exist(tablename),\ - '{} does not contain a table named {}'.format( - filename, tablename) + if not self.table_exist(tablename): + raise Exception('{} does not contain a table named {}'.format( + filename, tablename)) elif self.create: # Create database self.db = sqlite3.connect( @@ -177,7 +185,8 @@ It creates three sql table on initialisation. self.viewing_directions[..., 1] = ma def table_exist(self, tablename): - assert isinstance(tablename, str), 'tablename should be a string' + if not isinstance(tablename, str): + raise TypeError('tablename should be a string') self.db_cursor.execute( """ SELECT count(*) @@ -187,6 +196,12 @@ It creates three sql table on initialisation. return bool(self.db_cursor.fetchone()) def check_data_validity(self, rowid): + if not isinstance(rowid,int): + raise TypeError('rowid must be an integer') + if rowid <= 0: + raise ValueError('rowid must be greater zero') + if rowid is np.nan: + raise ValueError('rowid must not be nan') self.db_cursor.execute( """ SELECT count(*) @@ -210,9 +225,28 @@ It creates three sql table on initialisation. valid = valid and bool(self.db_cursor.fetchone()[0]) return valid - def posid(self, posorient): - assert isinstance(posorient, pd.Series),\ - 'posorient should be a pandas Series' + def get_posid(self, posorient): + if no isinstance(posorient, pd.Series): + ('posorient should be a pandas Series') + if posorient is not None: + if not isinstance(posorient, pd.Series): + raise TypeError('posorient should be a pandas Series') + if posorient.empty: + raise Exception('position must not be empty') + if 'x' not in posorient.index: + raise ValueError('missing index x') + if 'y' not in posorient.index: + raise ValueError('missing index y') + if 'z' not in posorient.index: + raise ValueError('missing index z') + if 'alpha_0' not in posorient.index: + raise ValueError('missing index alpha_0') + if 'alpha_1' not in posorient.index: + raise ValueError('missing index alpha_1') + if 'alpha_2' not in posorient.index: + raise ValueError('missing index alpha_2') + if not ~np.any(pd.isnull(posorient)): + raise ValueError('posorient must not contain nan') where = """x>=? and x<=?""" where += """and y>=? and y<=?""" where += """and z>=? and z<=?""" @@ -277,6 +311,13 @@ class DataBaseLoad(DataBase): def __init__(self, filename, channels=['R', 'G', 'B', 'D']): """Initialise the DataBaseLoader""" + if not isinstance(filename, str): + raise TypeError('filename should be a string') + if (not isinstance(channels, list) or not isinstance(channels,np.array)): + raise TypeError('nb_channel should be a list or np array') + for c in channels: + if not c in ['R','G','B','D']: + raise ValueError('channels must be either R,G,B or D (Distance)') DataBase.__init__(self, filename, channels=channels) @property @@ -315,10 +356,37 @@ database return posorient def read_posorient(self, posorient=None, rowid=None): - assert (posorient is None) or (rowid is None),\ - 'posorient and rowid can not be both None' + if no isinstance(posorient, pd.Series): + ('posorient should be a pandas Series') if posorient is not None: - rowid = self.posid(posorient) + if not isinstance(posorient, pd.Series): + raise TypeError('posorient should be a pandas Series') + if posorient.empty: + raise Exception('position must not be empty') + if 'x' not in posorient.index: + raise ValueError('missing index x') + if 'y' not in posorient.index: + raise ValueError('missing index y') + if 'z' not in posorient.index: + raise ValueError('missing index z') + if 'alpha_0' not in posorient.index: + raise ValueError('missing index alpha_0') + if 'alpha_1' not in posorient.index: + raise ValueError('missing index alpha_1') + if 'alpha_2' not in posorient.index: + raise ValueError('missing index alpha_2') + if not ~np.any(pd.isnull(posorient)): + raise ValueError('posorient must not contain nan') + if not isinstance(rowid,int): + raise TypeError('rowid must be an integer') + if rowid <= 0: + raise ValueError('rowid must be greater zero') + if rowid is np.nan: + raise ValueError('rowid must not be nan') + if (posorient is None) and (rowid is None): + Exception('posorient and rowid can not be both None') + if posorient is not None: + rowid = self.get_posid(posorient) # Read images tablename = 'position_orientation' toreturn = pd.read_sql_query( @@ -333,26 +401,9 @@ database toreturn = toreturn.astype(float) return toreturn - def scene(self, posorient=None, rowid=None): - """ Return a scene at a position orientation or given rowid \ - in a given database. - - :param database: a DataBaseLoad class \ - :param posorient: a pandas Series with index: \ - ['x','y','z','alpha_0,'alpha_1,'alpha_2'] (default None, i.e. not used) - :param rowid: a row identification integer for directly reading \ - in the database (default None, i.e. not used). - :returns: a scene [elevation, azimuth, channel, 1] or \ - [ommatidia,channel,1]. - :rtype: np.ndarray - - .. literalinclude:: example/database/scene.py - :lines: 14-15 - - .. plot:: example/database/scene.py - """ - if (posorient is None) and (rowid is None): - raise ValueError('posorient and rowid can not be both None') + def read_image(self, posorient=None, rowid=None): + if no isinstance(posorient, pd.Series): + ('posorient should be a pandas Series') if posorient is not None: if not isinstance(posorient, pd.Series): raise TypeError('posorient should be a pandas Series') @@ -372,16 +423,29 @@ database raise ValueError('missing index alpha_2') if not ~np.any(pd.isnull(posorient)): raise ValueError('posorient must not contain nan') - rowid = self.posid(posorient) - - if rowid is not None: - if not isinstance(rowid, int): - raise TypeError('rowid must be of type integer') - if rowid <= 0: - raise ValueError('rowid must be greater zero') - if rowid is np.nan: - raise ValueError('rowid must not be nan') - + if not isinstance(rowid,int): + raise TypeError('rowid must be an integer') + if rowid <= 0: + raise ValueError('rowid must be greater zero') + if rowid is np.nan: + raise ValueError('rowid must not be nan') + if (posorient is None) and (rowid is None): + raise Exception('posorient and rowid can not be both None') + if posorient is not None: + rowid = self.get_posid(posorient) + """Read an image at a given position-orientation or given id of row in the \ + database. + + :param posorient: a pandas Series with index \ + ['x','y','z','alpha_0','alpha_1','alpha_2'] + :param rowid: an integer + :returns: an image + :rtype: numpy.ndarray + """ + if (posorient is None) and (rowid is None): + Exception('posorient and rowid can not be both None') + if posorient is not None: + rowid = self.get_posid(posorient) # Read images tablename = 'image' self.db_cursor.execute( @@ -399,24 +463,37 @@ database FROM {} WHERE (rowid={}) """.format(tablename, rowid), self.db) - assert cmaxminrange.shape[0] == 1,\ - 'Error while reading normalisation factors' + if cmaxminrange.shape[0] != 1: + raise Exception('Error while reading normalisation factors') cmaxminrange = cmaxminrange.iloc[0, :] cmaxminrange.name = cmaxminrange.id cmaxminrange.drop('id') cmaxminrange = cmaxminrange.astype(float) - scene = self.denormalise_image(image, cmaxminrange) - scene = scene[..., np.newaxis] - return scene + return self.denormalise_image(image, cmaxminrange) def denormalise_image(self, image, cmaxminrange): - 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' + if len(image.shape) != 3: + raise Exception('image should be 3D array') + if 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 Exception('cmaxminrange should be a pandas Series') + if cmaxminrange.empty: + raise Exception('cmaxminrange must not be empty') + for chan_n in self.channels: + if str(chan_n) + '_max' not in posorient.index: + raise ValueError('cminmax range is missing index '+str(chan_n) + '_max') + if str(chan_n) + '_min' not in posorient.index: + raise ValueError('cminmax range is missing index '+str(chan_n) + '_min') + if str(chan_n) + '_range' not in posorient.index: + raise ValueError('cminmax range is missing index '+str(chan_n) + '_range') + if any(np.isnan(cmaxminrange.loc[str(chan_n) + '_max'])): + raise ValueError('cmaxminrange contains nans') + if any(np.isnan(cmaxminrange.loc[str(chan_n) + '_min'])): + raise ValueError('cmaxminrange contains nans') + if any(np.isnan(cmaxminrange.loc[str(chan_n) + '_range'])): + raise ValueError('cmaxminrange contains nans') denormed_im = np.zeros(image.shape, dtype=np.float) maxval_nim = np.iinfo(image.dtype).max # @@ -453,7 +530,7 @@ class DataBaseSave(DataBase): def write_image(self, posorient, image): normed_im, cmaxminrange = self.normalise_image(image, self.arr_dtype) - rowid = self.posid(posorient) + rowid = self.get_posid(posorient) # Write image tablename = 'image' params = dict() @@ -469,10 +546,10 @@ class DataBaseSave(DataBase): self.insert_replace(tablename, params) def insert_replace(self, tablename, params): - assert isinstance(tablename, str),\ - 'table are named by string' - assert isinstance(params, dict),\ - 'params should be dictionary columns:val' + if not isinstance(tablename, str): + raise ValueError('table are named by string') + if not isinstance(params, dict): + raise ValueError('params should be dictionary columns:val') params_list = list() columns_str = '' for key, val in params.items(): @@ -498,6 +575,16 @@ class DataBaseSave(DataBase): self.db.commit() def normalise_image(self, image, dtype=np.uint8): + if not isinstance(image,np.ndarray): + raise TypeError('image must be np.array') + if any(np.isnan(image)): + raise ValueError('image must not contain nan values') + if image.shape[0]<=0 or image.shape[1]<=0: + raise Exception('image dimensions incorrect') + if image.shape[2]!=len(self.channels): + raise Exception('image channels number differs from given channel number') + if not tools.is_numeric_array(scene): + raise TypeError('scene is of non numeric type') normed_im = np.zeros(image.shape, dtype=dtype) maxval_nim = np.iinfo(normed_im.dtype).max #