Commit da363975 authored by Félix Hartmann's avatar Félix Hartmann
Browse files

A lot of changes:

- bugfixes for Py2/3 compatibility
- multilingual support with gettext (English-only for now)
- partial refactoring, for the multilingual support
- new ways of estimating the growth length
- new estimation of B, with the selection of a steady-state image
parent 94d84da1
......@@ -3,7 +3,7 @@
Created on Tue Jun 7 17:29:12 2016
@author: Hugo Chauvet
Modified by Félix Hartmann.
Modified and extended by Félix Hartmann.
Some Classes implementing drawable things to use in RootStemExtractor:
- DraggableLines
......@@ -18,8 +18,9 @@ import matplotlib.pyplot as plt
import matplotlib.pylab as mpl
class DraggableLines:
"""
Implement draggable line segments, horizontal or vertical.
"""Implements draggable line segments.
Each line segment has a drag direction: either horizontal or vertical.
A subset of the lines can be linked, i.e. they move together.
......@@ -27,24 +28,45 @@ class DraggableLines:
-------
fig = plt.figure()
ax1 = fig.add_subplot(211)
l1, = ax1.plot([0,0], [0,1], picker=5)
l1, = ax1.plot([0,0.1], [0,1], picker=5)
l2, = ax1.plot([1,1], [0,1], picker=5)
ax2 = fig.add_subplot(212)
l3, = ax2.plot([0,0], [0,1], picker=5)
l3, = ax2.plot([0,0.1], [0,1], picker=5)
ax1.set_xlim(-0.1, 1.1)
ax2.set_xlim(-0.1, 1.1)
test = DraggableLines([l1, l2, l3], linked=[l1, l3])
test = DraggableLines([l1, l2, l3], directions=["h", "h", "h"], linked=[l1, l3])
test.connect()
plt.show()
"""
lock = None # only one can be animated at a time
def __init__(self, lines, linked=None):
def __init__(self, lines, directions=None, linked=None):
self.lines = lines # Line2D objects: line, = plt.plot([],[])
self.line = lines[0]
self.press = None
self.background = None
self.changed = False
# 'directions' is a list of directions associated to self.lines,
# either 'vertical' or 'horizontal' (or simply 'v' or 'h').
if directions is not None:
self.directions = directions
else:
# Guess directions from line orientations.
# Does not work for an oblique line.
self.directions = []
for line in self.lines:
data = line.get_data()
if data[0][0] == data[0][1]:
# vertical line, therefore movements in the horizontal direction
self.directions.append("horizontal")
elif data[1][0] == data[1][1]:
# horizontal line, therefore movements in the vertical direction
self.directions.append("vertical")
else:
# oblique line, therefore no obvious movement direction
raise ValueError(
"Oblique draggable line without assigned direction!")
if linked is not None:
self.linked = linked # self.linked is a subset of self.lines
else:
......@@ -65,6 +87,20 @@ class DraggableLines:
if event.artist not in self.lines: return
self.line = event.artist
i = self.lines.index(self.line)
self.direction = self.directions[i]
data = self.line.get_data()
# If the line is oblique, let's keep track of initial reference position.
if data[0][0] != data[0][1] and data[1][0] != data[1][1]:
if "h" in self.direction: # horizontal movement
self.ref_pos = event.mouseevent.xdata # keep track of x reference
elif "v" in self.direction: # vertical movement
self.ref_pos = event.mouseevent.ydata # keep track of y reference
else:
self.ref_pos = None
self.changed = False
DraggableLines.lock = self
......@@ -90,11 +126,24 @@ class DraggableLines:
return
self.changed = True
data = self.line.get_data()
if data[1][0] == data[1][1]:
self.line.set_ydata([event.ydata]*2)
else:
self.line.set_xdata([event.xdata]*2)
if "h" in self.direction: # horizontal movement
if self.ref_pos is None: # vertical line
self.line.set_xdata([event.xdata]*2)
else: # oblique line
shift = event.xdata - self.ref_pos
data = self.line.get_data()
self.line.set_xdata([data[0][0] + shift, data[0][1] + shift])
self.ref_pos = event.xdata
elif "v" in self.direction: # vertical movement
if self.ref_pos is None: # horizontal line
self.line.set_ydata([event.ydata]*2)
else: # oblique line
shift = event.ydata - self.ref_pos
data = self.line.get_data()
self.line.set_ydata([data[1][0] + shift, data[1][1] + shift])
self.ref_pos = event.ydata
canvas = self.line.figure.canvas
axes = self.line.axes
......@@ -118,13 +167,14 @@ class DraggableLines:
# turn off the rect animation property and reset the background
self.line.set_animated(False)
# synchronisation between linked lines
data = self.line.get_data()
if self.linked and self.line in self.linked:
for l in self.linked:
if data[1][0] == data[1][1]:
l.set_ydata([data[1][1]]*2)
else:
l.set_xdata([data[0][0]]*2)
if "h" in self.direction: # horizontal movement
l.set_xdata([data[0][0], data[0][1]])
elif "v" in self.direction: # vertical movement
l.set_ydata([data[1][0], data[1][1]])
self.background = None
......@@ -153,6 +203,7 @@ class DraggablePoints:
plt.ylim(-1, 2)
test = DraggablePoints([P1, P2, P3], linked=True, closed=True)
test.connect()
plt.show()
"""
lock = None # only one can be animated at a time
......@@ -172,7 +223,7 @@ class DraggablePoints:
# Reinitialize if needed
while self.lines:
self.lines.pop(0).remove()
# Create the line
# Create the lines
if self.linked and len(self.points) >= 2:
self.couples = list(zip(self.points, self.points[1:]))
if self.closed:
......@@ -282,25 +333,25 @@ class DraggablePoints:
self.point.figure.canvas.mpl_disconnect(self.cidmotion)
if __name__ == '__main__':
# fig = plt.figure()
# ax1 = fig.add_subplot(211)
# l1, = ax1.plot([0,0], [0,1], picker=5)
# l2, = ax1.plot([1,1], [0,1], picker=5)
# ax2 = fig.add_subplot(212)
# l3, = ax2.plot([0,0], [0,1], picker=5)
# ax1.set_xlim(-0.1, 1.1)
# ax2.set_xlim(-0.1, 1.1)
# test = DraggableLines([l1, l2, l3], linked=[l1, l3])
# test.connect()
fig = plt.figure()
ax = fig.add_subplot(111)
P1, = ax.plot(0, 0, 'ro', ms=12, picker=5)
P2, = ax.plot(1, 1, 'ro', ms=12, picker=5)
P3, = ax.plot(0, 1, 'ro', ms=12, picker=5)
plt.xlim(-1, 2)
plt.ylim(-1, 2)
test = DraggablePoints([P1, P2, P3], linked=True, closed=True)
ax1 = fig.add_subplot(211)
l1, = ax1.plot([0,0.1], [0,1], picker=5)
l2, = ax1.plot([1,1], [0,1], picker=5)
ax2 = fig.add_subplot(212)
l3, = ax2.plot([0,0.1], [0,1], picker=5)
ax1.set_xlim(-0.1, 1.1)
ax2.set_xlim(-0.1, 1.1)
test = DraggableLines([l1, l2, l3], directions=["h", "h", "h"], linked=[l1, l3])
test.connect()
# fig = plt.figure()
# ax = fig.add_subplot(111)
# P1, = ax.plot(0, 0, 'ro', ms=12, picker=5)
# P2, = ax.plot(1, 1, 'ro', ms=12, picker=5)
# P3, = ax.plot(0, 1, 'ro', ms=12, picker=5)
# plt.xlim(-1, 2)
# plt.ylim(-1, 2)
# test = DraggablePoints([P1, P2, P3], linked=True, closed=True)
# test.connect()
plt.show()
This diff is collapsed.
......@@ -14,7 +14,7 @@ Les images sont enregistrer en jpeg dans un array qui contient l'image
au format binaire, c'est la solution la plus rapide est la moins
gourmande en espace.
Un groupes contenant les images
Un groupe contenant les images
/Images/
/Images/TO/RES0 qui enregistre l'image au temps 0 et à pleine résolution
/Images/TO/RES1 qui enregistre l'image au temps 0 et à la résolution plus petite 1
......@@ -34,7 +34,7 @@ Un groupe qui contient les données relatives à chaque tiges
/datas/tiges0/yc les coordonnees du centre; dimension (temps, abscisse curviligne)
/datas/tiges0/postprocessing Pour les données issues des fits etcs
/datas/tiges0/postprocessing/beta_fit les données du fit pour beta
/datas/tiges0/postprocessing/beta_fit les données du fit pour beta
/datas/tiges0/postprocessing/gamma_fit ....
"""
......@@ -54,8 +54,8 @@ COMPRESSION = "gzip" # compression en gzip, un peu lent mais comprime
# bien. En lzf beaucoup plus rapide mais comprime
# moins
def image_to_hdf(hdf5file, image_name, image_liste_position,
max_pyramid_layers=0, save_resolutions=False,
selected_resolutions=None):
......@@ -68,10 +68,10 @@ def image_to_hdf(hdf5file, image_name, image_liste_position,
/images/TO/RES1 (shape int(W/2), int(H/2), 3)
/images/TO/RES2 (shape int(W/4), int(H/4), 3)
Paramètres
----------
hdf5file, str:
Nom du fichier hdf5 dans lequel on veut sauvegarder les
données, ce nom doit contenir le chemin vers le fichier.
......@@ -87,7 +87,7 @@ def image_to_hdf(hdf5file, image_name, image_liste_position,
max_pyramid_layers, int:
Permet de faire une réduction de taille de l'image
initiale. On donne le nombre de fois que l'on réduit l'image
d'un facteur downscale fixé ici à 2.
d'un facteur downscale fixé ici à 2.
save_resolutions, true/false:
Permet de sauvegarder la pyramide des résolutions dans le hdf.
......@@ -129,17 +129,17 @@ def image_to_hdf(hdf5file, image_name, image_liste_position,
downscale_factor = 4.0
else:
downscale_factor = 2.0
pyramid = [(int(rows), int(cols))]
for i in range(max_pyramid_layers):
pyramid += [(int(rows/((i+1)*downscale_factor)),
int(cols/((i+1)*downscale_factor)))]
# On crée le type (de taille variable en 8bit) pour
# l'enregistrer dans hdf
dt = h5py.special_dtype(vlen=np.dtype('uint8'))
# On va les enregistrer
cpt_res = 0
......@@ -156,7 +156,7 @@ def image_to_hdf(hdf5file, image_name, image_liste_position,
else:
imgr = img.resize(p, resample=PIL.Image.LANCZOS)
#print(imgr.size)
# On la sauve au format jpg dans un fichier que l'on
# envoie dans un array numpy
with io.BytesIO() as fimg:
......@@ -164,7 +164,7 @@ def image_to_hdf(hdf5file, image_name, image_liste_position,
fimg.seek(0)
imgdata = np.fromstring(fimg.read(), dtype='uint8')
res = "RES%i"%(cpt_res)
res = "RES%i"%(cpt_res)
# On enregistre l'image
h5d = hdf5img.create_dataset(res, (1,), dt,
compression=COMPRESSION,
......@@ -172,7 +172,7 @@ def image_to_hdf(hdf5file, image_name, image_liste_position,
#shuffle=SHUFFLE,
compression_opts=6)
h5d[0] = imgdata
cpt_res += 1
# Pour chaque temps, on créé plusieurs attributs:
......@@ -247,7 +247,7 @@ def save_base_tige(hdf5file, tige_id, base_pts):
else:
print("Il faut créer la tige avant d'enregistrer les points de base")
def tige_to_hdf5(hdf5file, tige_id, tige_name, base_pts, tige_xc, tige_yc,
tige_theta, tige_diam, tige_xb1, tige_yb1, tige_xb2,
tige_yb2):
......@@ -257,12 +257,12 @@ def tige_to_hdf5(hdf5file, tige_id, tige_name, base_pts, tige_xc, tige_yc,
Paramètres
----------
hdf5file, string:
Nom du fichier hdf5 dans lequel sauvegarder les données
tige_id, int:
Indice de la tige
Indice de la tige
tige_name, string:
Si on a changer l'id ou le nom de la tige (données se trouvant
......@@ -303,7 +303,7 @@ def tige_to_hdf5(hdf5file, tige_id, tige_name, base_pts, tige_xc, tige_yc,
hdf5tige.create_dataset('base_points', tmpd.shape,
tmpd.dtype, data=tmpd,
compression=COMPRESSION)
# Sauvegarde des données issue du traitement de la tige
for dataname in ['xc', 'yc', 'diam', 'theta', 'xb1', 'yb1', 'xb2', 'yb2']:
......@@ -347,7 +347,7 @@ def get_tiges_indices(hdf5file):
Cette fonction permet de récupérer toutes les tiges par exemple
même si leur id n'est pas continu (expl on en a supprimer une).
"""
with h5py.File(hdf5file, 'a') as f:
if 'data' in f:
outid = []
......@@ -382,7 +382,7 @@ def image_to_bytesio(hdf5file, position, resolution):
resolution données et retourn un objet BytesIO contenant le
fichier de l'image brute
"""
with h5py.File(hdf5file, 'r') as f:
image_path = '/images/T%i/RES%i' % (position, resolution)
......@@ -393,10 +393,10 @@ def image_to_bytesio(hdf5file, position, resolution):
data_out = None
return data_out
def open_hdf5_image(hdf5file, position, resolution):
"""
Fonction pour ouvrir une image provenant d'un fichier hdf5, stockée sous la forme
Fonction pour ouvrir une image provenant d'un fichier hdf5, stockée sous la forme
/images/T{position}/RES{resolution}
retourne l'image sous la forme d'un numpy array
......@@ -434,7 +434,7 @@ def get_images_names(hdf5file, img_pos=None):
Paramètres:
-----------
img_pos, None or int:
Si on veut avoir l'info que pour une seule image, on donne sa position.
"""
......@@ -445,10 +445,20 @@ def get_images_names(hdf5file, img_pos=None):
max_img = len(f['/images'].keys())
for i in range(max_img):
key = 'T%i'%i
output_names += [f['/images/'+key].attrs['name'].decode()]
name = f['/images/'+key].attrs['name']
try: # if Python2
name = name.decode()
except:
pass
output_names += [name]
else:
key = 'T%i' % img_pos
output_names = f['/images/'+key].attrs['name'].decode()
name = f['/images/'+key].attrs['name']
try: # if Python2
name = name.decode()
except:
pass
output_names += [name]
return output_names
......@@ -461,7 +471,7 @@ def get_images_source_path(hdf5file, img_pos=None):
Paramètres:
-----------
img_pos, None or int:
Si on veut avoir l'info que pour une seule image, on donne sa position.
"""
......@@ -487,7 +497,7 @@ def get_images_datetimes(hdf5file, img_pos=None):
Paramètres:
-----------
img_pos, None or int:
Si on veut avoir l'info que pour une seule image, on donne sa position.
"""
......@@ -499,22 +509,26 @@ def get_images_datetimes(hdf5file, img_pos=None):
for i in range(max_img):
key = 'T%i'%i
str_datetime = f['/images/'+key].attrs['datetime']
try: # in case we get bytes
str_datetime = str_datetime.decode('ascii')
except:
pass
try:
output_datetime += [datetime.datetime.strptime(str_datetime,
'%Y-%m-%d %H:%M:%S')]
'%Y-%m-%d %H:%M:%S')]
except:
print('No datetime for image %s, set it to None' % key)
output_datetime += [None]
else:
key = 'T%i' % img_pos
str_datetime = f['/images/'+key].attrs['datetime']
str_datetime = f['/images/'+key].attrs['datetime'].decode('ascii')
try:
output_datetime = datetime.datetime.strptime(str_datetime,
'%Y-%m-%d %H:%M:%S')
except:
print('No datetime for image %s, set it to None' % key)
output_datetime = None
return output_datetime
......@@ -556,7 +570,7 @@ def save_tige_dict_to_hdf(hdf5file, tige_id, dict_data):
f.create_group(dict_group)
hdf5_create_args={"compression": COMPRESSION}
dicttoh5(treedict=dict_data, hdf5file=hdf5file, h5path=dict_group,
mode='a', create_dataset_args=hdf5_create_args)
......@@ -569,11 +583,11 @@ def save_pixelscale(hdf5file, scale_cmpix):
goods = None
else:
goods = float(scale_cmpix)
dict_data = {'scale_cmpix': goods}
dicttoh5(treedict=dict_data, hdf5file=hdf5file, h5path='/',
mode='a')
def get_pixelscale(hdf5file):
"""
Fonction pour récupérer l'échelle de l'image en cm
......@@ -584,9 +598,9 @@ def get_pixelscale(hdf5file):
scaleout = h5todict(hdf5file, path='scale_cmpix')
if scaleout == {}:
scaleout = None
return scaleout
def get_postprocessing(hdf5file, postprocessing_name, tige_num=None):
"""
......@@ -638,7 +652,7 @@ def is_postprocessing(hdf5file, postprocessing_name, tige_num):
"""
is_saved = False
with h5py.File(hdf5file, 'r') as f:
data_location = '/data/tige%i/postprocessing/%s' % (tige_num, postprocessing_name)
......@@ -668,7 +682,7 @@ def get_tiges_bases(hdf5file, tige_num=None):
if tige_num is None:
tiges_ids = get_tiges_indices(hdf5file)
if tiges_ids != []:
output = []
with h5py.File(hdf5file, 'r') as f:
......@@ -682,7 +696,7 @@ def get_tiges_bases(hdf5file, tige_num=None):
with h5py.File(hdf5file, 'r') as f:
if 'data/tige%i/base_points' % tige_num in f:
numpybase = f['data/tige%i/base_points' % tige_num][:]
output = numpybase.tolist()
output = numpybase.tolist()
else:
output = []
......@@ -701,7 +715,7 @@ def get_tiges_names(hdf5file, tige_num=None):
tiges_ids = [tige_num]
tiges_names = []
if tiges_ids != []:
with h5py.File(hdf5file, 'r') as f:
for idt in tiges_ids:
......@@ -715,7 +729,7 @@ def get_tiges_names(hdf5file, tige_num=None):
# Si c'est une seule tige dont on veut le nom on fait pas de liste
if tige_num is not None:
tiges_names = tiges_names[-1]
return tiges_names
def save_tige_name(hdf5file, tige_id, tige_name):
......@@ -728,7 +742,7 @@ def save_tige_name(hdf5file, tige_id, tige_name):
dicttoh5(treedict=tige_namedict, hdf5file=hdf5file,
h5path='/data/tige%i'%tige_id,
mode="a")
def get_tigesmanager(hdf5file):
"""
Fonction pour créer un objet TigesManager de new_libgravimacro à
......@@ -841,7 +855,7 @@ def get_photo_time(image_path):
Fonction pour obtenir le temps de la prise de vue d'une photo a
partir des données EXIFs
"""
stat = PIL.Image.open(image_path)._getexif()
ymd = stat[306].split(' ')[0].split(':')
hms = stat[306].split(' ')[1].split(':')
......@@ -850,12 +864,12 @@ def get_photo_time(image_path):
return t
if __name__ == '__main__':
from pylab import *
from new_libgravimacro import load_results
test_data = "/home/hugo/Documents/Boulo/test_mutants_arabido/02-06-16/rootstem_data.pkl"
rtst = load_results(test_data)
rtst = load_results(test_data)
# print(rtst.keys())
tiges_info = rtst['tiges_info']
tiges_data = rtst['tiges_data']
......@@ -911,10 +925,10 @@ if __name__ == '__main__':
def test_get_sourcefiles():
print(get_images_source_path(hdf5name))
##########################################################################
#test_load_image()
test_get_names()
test_get_datetime()
test_get_sourcefiles()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment