Coverage for navipy/database/__init__.py : 69%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
"""
"""
""" http://stackoverflow.com/a/31312102/190597 (SoulNibbler) """ if arr is None: raise ValueError('array must not be None') out = io.BytesIO() np.save(out, arr) out.seek(0) return sqlite3.Binary(out.read())
raise ValueError('text must not be None')
# Converts np.array to TEXT when inserting # Converts TEXT to np.array when selecting
"""DataBase It creates three sql table on initialisation. """
channels=['R', 'G', 'B', 'D'], arr_dtype=np.uint8): """Initialisation of the database the first database is the image database to store the images the second database is the position_orientation database to store the position and orientations of the corresponding image the third database is the normalisation database that stores the ranges of the images. :param filename: filename of the database to be loaded, stored created channels: channels for the images (Red,Green,Blue,Distance) :type filename: string channels: list """ # We try to determine if we need to load or create # the database # The file does not exist, and we want to read # it. This is not possible msg = 'Cannot read database {}' msg = msg.format(filename) self._logger.exception(msg) raise NameError(msg) # The file exist, and we want to write it # We need to create the database else: # The file exist, and we want to either # write it or append data to it. # We need to load the database
msg = 'channels must not be of nan value' self._logger.exception(msg) raise ValueError(msg) msg = 'channels must be single value' self._logger.exception(msg) raise ValueError(msg) msg = 'channels must be either\ R,G,B or D (Distance)' self._logger.exception(msg) raise ValueError(msg) filename, channels))
'file:' + filename + '?cache=shared', uri=True, detect_types=sqlite3.PARSE_DECLTYPES, timeout=10) # Check table msg = '{} does not contain a table\ named {}'.format(filename, tablename) self._logger.exception(msg) raise Exception(msg) else: 'file:' + filename + '?cache=shared', uri=True, detect_types=sqlite3.PARSE_DECLTYPES, timeout=10) # Create table "create table {} {}".format(key, columns))
def viewing_directions(self): """ SELECT data FROM {} WHERE (rowid=?) """.format(tablename), (rowid,))
def viewing_directions(self, viewdir): """Get the viewing direction from images
:param az_lim: (min,max) of the azimuth angles :param el_lim: (min,max) of the elevation angles :returns: viewing direction of every pixels :rtype: np.array
""" if self.__viewing_dir is None: msg = 'write viewing direction' self._logger.info(msg) if isinstance(viewdir, np.ndarray): tablename = 'viewing_directions' params = dict() params['rowid'] = 1 params['data'] = viewdir self.insert_replace(tablename, params) else: msg = 'viewdir should be a numpy nd.array' msg += ' and not {}'.format(type(viewdir)) self._logger.exception(msg) raise TypeError(msg) else: msg = 'viewing direction has already been set' self._logger.exception(msg) raise Exception(msg)
""" checks wether a table with name tablename exists in the database :param tablename: name of the table :type tablename: string :returns: validity :rtype: boolean """ """ SELECT count(*) FROM sqlite_master WHERE type='table' and name=?; """, (tablename,))
""" checks wether all three tables in the database (images,position_orientation, normalisation) contain an entry with the given id. :param rowid: id to be checked :type rowid: int :returns: validity :rtype: boolean """ msg = 'rowid must not be nan' self._logger.exception(msg) raise ValueError(msg) """ SELECT count(*) FROM position_orientation WHERE rowid=?; """, (rowid,)) """ SELECT count(*) FROM normalisation WHERE rowid=?; """, (rowid,)) """ SELECT count(*) FROM image WHERE rowid=?; """, (rowid,))
""" returns the id of a given position and orientation in the database :param posorient: position and orientation is a 1x6 vector containing: *in case of euler angeles the index should be ['location']['x'] ['location']['y'] ['location']['z'] [convention][alpha_0] [convention][alpha_1] [convention][alpha_2] **where convention can be: xyz, xzy, yxz, yzx, zyx, zxy *in case of quaternions the index should be ['location']['x'] ['location']['y'] ['location']['z'] [convention]['q_0'] [convention]['q_1'] [convention]['q_2'] [convention]['q_3'] **where convention can be: quaternion :type rowid: pd.Series :returns: id :rtype: int """ msg = 'position must not be empty' self._logger.exception(msg) raise Exception(msg)
else: msg = 'Old database without convention column' self._logger.warnings(msg) convention = 'xyz' convention == 'quaternion': msg = 'convention for rotation {} is not suppored\n' msg += msg.format(convention) msg += 'the following convention are supported\n:' for rconv in mconst._AXES2TUPLE.keys(): msg += '{}\n'.format(rconv) msg += 'quaternion\n' self._logger.exception(msg) raise KeyError(msg) # Check that the posorient contains valid columns # The user may be using alpha_ or q_ # and we therefore want to be able to handle both type ('q_{}'.format(ii) not in index_2ndlevel): msg = 'missing index alpha_{0: } or q_{0: }'.format(ii) self._logger.exception(msg) raise ValueError(msg) ('q_{}'.format(ii) in index_2ndlevel): msg = 'posorient should contains either alphas or qs' self._logger.exception(msg) raise ValueError(msg) else: naming_map.append('q_{}'.format(ii)) if 'q_3' not in index_2ndlevel: msg = 'missing index q_3' self._logger.exception(msg) raise ValueError(msg) else: naming_map.append('q_{}'.format(3)) else: # q_3 is unnecessary for convention # different than quaternion. The value # should be set to nan, and wil therefore block during check of # any nan. We drop it now. posorient.drop((convention, 'q_3'), inplace=True) posorient['location']['x'] - self.__float_tolerance, posorient['location']['x'] + self.__float_tolerance, posorient['location']['y'] - self.__float_tolerance, posorient['location']['y'] + self.__float_tolerance, posorient['location']['z'] - self.__float_tolerance, posorient['location']['z'] + self.__float_tolerance, posorient[convention][naming_map[0]] - self.__float_tolerance, posorient[convention][naming_map[0]] + self.__float_tolerance, posorient[convention][naming_map[1]] - self.__float_tolerance, posorient[convention][naming_map[1]] + self.__float_tolerance, posorient[convention][naming_map[2]] - self.__float_tolerance, posorient[convention][naming_map[2]] + self.__float_tolerance, convention, frame_i) where += """and q_3>=? and q_3<=?""" params = params + ( posorient[convention][naming_map[3]] - self.__float_tolerance, posorient[convention][naming_map[3]] + self.__float_tolerance) """ SELECT count(*) FROM position_orientation WHERE {};""".format(where), params) """ SELECT rowid FROM position_orientation WHERE {}; """.format(where), params) elif (self.mode in ['a', 'w']): if convention != 'quaternion': self.db_cursor.execute( """ INSERT INTO position_orientation(x,y,z,q_0,q_1,q_2,q_3,rotconv_id,frame_i) VALUES (?,?,?,?,?,?,?,?,?) """, ( posorient['location']['x'], posorient['location']['y'], posorient['location']['z'], posorient[convention]['alpha_0'], posorient[convention]['alpha_1'], posorient[convention]['alpha_2'], np.nan, convention, frame_i)) else: self.db_cursor.execute( """ INSERT INTO position_orientation(x,y,z,q_0,q_1,q_2,rotconv_id,frame_i) VALUES (?,?,?,?,?,?,?,?,?) """, ( posorient['location']['x'], posorient['location']['y'], posorient['location']['z'], posorient[convention]['q_0'], posorient[convention]['q_1'], posorient[convention]['q_2'], posorient[convention]['q_3'], convention, frame_i)) rowid = self.db_cursor.lastrowid self.db.commit() return rowid else: msg = 'posorient not found \n {} \n {} \n {}'.format( posorient, where, params) self._logger.exception(msg) raise ValueError(msg)
"""Iter through all position orientation in the database """ self.db_cursor.execute( """ SELECT * FROM position_orientation """)
columns_names = [] for col in self.db_cursor.description: columns_names.append(col[0]) for row in self.db_cursor: toyield = pd.Series(data=row, index=columns_names) toyield.name = toyield.id toyield.drop('id', inplace=True) yield toyield # # Access to single values #
def rotation_convention(self): """ Return the convention of the database
The database can technically contains more than one convention. Although it is discourage to do so, it is not forbidden.
If more than one convention is found in the database, this function will issue awarning when more than one convention is present in the database. """ "select * from position_orientation;", self.db) # we need to assign it from the posorient else: self._logger.warning( 'More than one convention have been found in database') self.__convention = None else: self._logger.warning("you are loading a database with old\ conventions, it will be transformed\ automatically into the new one") self.__convention = 'xyz'
"""Return the position orientations of all points in the \ database :params indexby: index posorients by 'frame_i' (default) or 'id' :returns: all position orientations :rtype: list of pd.Series """ "select * from position_orientation;", self.db) else: # Handle older db version print('Could not index by {}'.format(indexby)) posorient.set_index('id', inplace=True)
def normalisations(self): """Returns the normalised scenes of all points in the \ database :returns: all position orientations :rtype: list of pd.Series """ normal = pd.read_sql_query( "select * from normalisation;", self.db) normal.set_index('id', inplace=True) return normal
# # Read from database # """Read posorient with a given posorient or rowid
:param posorient: pd.Series with MuliIndex :param rowid: integer, rowid of the database :returns: return posorient :rtype: pd.Series
""" msg = 'rowid must not be nan' self._logger.exception(msg) raise ValueError(msg) # Read pososition porientation """ SELECT * FROM {} WHERE (rowid={}) """.format(tablename, rowid), self.db) # toreturn = toreturn.astype(float) ('location', 'z'), ('xyz', 'alpha_0'), ('xyz', 'alpha_1'), ('xyz', 'alpha_2')] names=['position', 'orientation']) else: tuples = [('location', 'x'), ('location', 'y'), ('location', 'z'), (convention, 'q_0'), (convention, 'q_1'), (convention, 'q_2'), (convention, 'q_3')] index = pd.MultiIndex.from_tuples(tuples, names=['position', 'orientation']) posorient = pd.Series(index=index) posorient['location']['x'] = toreturn.loc['x'] posorient['location']['y'] = toreturn.loc['y'] posorient['location']['z'] = toreturn.loc['z'] posorient[convention]['q_0'] = toreturn.loc['q_0'] posorient[convention]['q_1'] = toreturn.loc['q_1'] posorient[convention]['q_2'] = toreturn.loc['q_2'] posorient[convention]['q_3'] = toreturn.loc['q_3']
"""Read an image at a given position-orientation or given id of row in the \ database. :param posorient: is a 1x6 vector containing: *in case of euler angeles the index should be ['location']['x'] ['location']['y'] ['location']['z'] [convention][alpha_0] [convention][alpha_1] [convention][alpha_2] **where convention can be: xyz, xzy, yxz, yzx, zyx, zxy *in case of quaternions the index should be ['location']['x'] ['location']['y'] ['location']['z'] [convention]['q_0'] [convention]['q_1'] [convention]['q_2'] [convention]['q_3'] **where convention can be: quaternion :param rowid: an integer :returns: an image :rtype: numpy.ndarray """ msg = 'rowid must not be nan' self._logger.exception(msg) raise ValueError(msg) msg = 'posorient and rowid can not be both None' self._logger.exception(msg) raise Exception(msg) rowid = self.get_posid(posorient) # Read images """ SELECT data FROM {} WHERE (rowid=?) """.format(tablename), (rowid,)) # Check image size # and try to correct it whenever possible msg = 'image must be np.array' self._logger.exception(msg) raise TypeError(msg) if np.all(image.shape[3:] == np.ones_like(image.shape[3:])): image = image[:, :, :, 0] # Other dim are useless msg = 'image should be 3D array' msg += 'image size is {}'.format(image.shape) self._logger.exception(msg) raise Exception(msg) # Read cmaxminrange """ SELECT * FROM {} WHERE (rowid={}) """.format(tablename, rowid), self.db) msg = 'Error while reading normalisation factors' self._logger.exception(msg) raise Exception(msg) # # Write #
msg = 'params should be dictionary columns:val' self._logger.exception(msg) raise TypeError(msg) self._logger.warning('nothing to be done in {}'.format(tablename)) return """ INSERT OR REPLACE INTO {} ({}) VALUES ({}) """.format(tablename, columns_str, questionsmarks), tuple(params_list) ) self.db.commit()
"""stores an image in the database. Automatically calculates the cminmax range from the image and channels. :param posorient: is a 1x6 vector containing: *in case of euler angeles the index should be ['location']['x'] ['location']['y'] ['location']['z'] [convention][alpha_0] [convention][alpha_1] [convention][alpha_2] **where convention can be: xyz, xzy, yxz, yzx, zyx, zxy *in case of quaternions the index should be ['location']['x'] ['location']['y'] ['location']['z'] [convention]['q_0'] [convention]['q_1'] [convention]['q_2'] [convention]['q_3'] **where convention can be: quaternion :param image: image to be stored :type image: np.ndarray :type posorient: pd.Series """ normed_im, cmaxminrange = self.normalise_image(image, self.arr_dtype) rowid = self.get_posid(posorient) # Write image tablename = 'image' params = dict() params['rowid'] = rowid params['data'] = normed_im self.insert_replace(tablename, params) # tablename = 'normalisation' params = dict() params['rowid'] = rowid for chan_n in self.normalisation_columns: params[chan_n] = cmaxminrange.loc[chan_n] self.insert_replace(tablename, params) # # Image processing #
"""denomalises an image :param image: the image to be denormalised :param cmaxminrange: new range of the denormalised image :type image: np.ndarray :type cmaxminrange: pd.Series :returns: denormalised image :rtype: numpy.ndarray """ msg = 'image does not have the required' msg += 'number of channels {}'.format(len(self.channels)) self._logger.exception(msg) raise Exception(msg) msg = 'cmaxminrange must not be empty' self._logger.exception(msg) raise Exception(msg) msg = 'cminmax range is missing index {}_min' msg = msg.format(chan_n) self._logger.exception(msg) raise ValueError(msg) msg = 'cminmax range is missing index {}_range' msg = msg.format(chan_n) self._logger.exception(msg) raise ValueError(msg) msg = 'cmaxminrange contains nans' self._logger.exception(msg) raise ValueError(msg) # cmax, cmaxminrange.name)
"""normalises an image to a range between 0 and 1. :param image: image to be normalised :param dtype: type of the image (default: np.uint8) :type image: np.ndarray :returns: normalised image :rtype: np.ndarray """ msg = 'image dimensions incorrect' self._logger.exception(msg) raise Exception(msg) given channel number' msg = 'scene is of non numeric type' self._logger.exception(msg) raise TypeError(msg) #
# cimage should be equal to 0 # so crange is irelevant we can assign it to 1 crange = 1 |